靈動微電子ARM Cortex M0 MM32F0010 GPIO的配置
目錄:
1、前言
2、學習方法簡要說明
3、要點提示
4、注意事項
5、MM32F0010系統時鍾的配置
6、MM32F0010的GPIO初始化配置
7、MM32F0010 GPIOA PA7驅動LED燈每隔一秒翻轉一次
1、前言:
MM32F0010是基於ARM Cortex M0核的32位微控制器(MCU)即32位的單片機,使用庫函數開發,每一個片上外設都有與之對應的外設xx.c和xx.h庫函數,例如:hal_rcc.c和hal_rcc.h,hal_gpio.c和hal_gpio.h等,針對外設初的初始化工程師即可參考外設對應的庫函數外xx.c和外設xx.h文件。不知道大家每接觸一款新的ARM Cortex核心MCU是如何快速入門的?筆者簡單說一下個人的學習方法,當筆者每接觸一款不同廠家的ARM Cortex M0/M3/M4核心的MCU時,筆者是這樣快速入門的:
2、學習方法簡要說明:
(1)訪問廠家的官網下載ARM Cortex 對應型號和版本的MCU的DS數據手冊(手冊一般描述了GPIO管腳定義、GPIO管腳復用功能、封裝信息、電氣特性、各個外設工作的電氣特性、工作環境等);
下載ARM Cortex對應型號和版本的MCU的UM用戶手冊(手冊一般對MCU的每一個片上外設資源的各個寄存器及其位定義做了詳細的描述)單片機工程師做編程開發時可以參考以上DS和UM手冊,有些廠家還會提供該MCU的庫函數編程手冊指南等。
(2)從官網下載對應MCU型號版本的Demo例程,Demo例程一般包含ARM Cortex 核心片上外設各個外設的Demo的使用(包含各個外設功能的初始化和實現簡單功能的演示實例具有一定參考價值)。
(3)從官網下載對應MCU型號版本系列的Pack包,簡單的說Pack包里面定義了該系列MCU型號的選型,開發時需要選擇對應MCU型號,筆者習慣使用MDK Keil開發環境,MDK Keil從5.0以上版本官方就對各個廠家MCU設備型號使用Pack包形式進行管理。
(4)關於程序的仿真燒錄工具,筆者習慣使用JLINK進行ARM Cotex核MCU的仿真燒錄,很多同行會問各個廠家的ARM Cotex核心的MCU都支持JLINK仿真燒錄程序嗎?答案是肯定的,為什么呢?ARM Cortex核已經形成了一個世界標准,並且研發JLINK的SEGGER公司和ARM以及各個芯片半導體公司都有深入合作已經形成了標准的生態鏈,各家芯片設計公司只要設計的芯片使用的是ARM Cortex核都可以支持JLINK仿真燒錄的,筆者目前學習單片機開發使用的JLINK版本為V9版本,因此大家可以放心的使用JLINK作為開發仿真、調試和燒錄程序。
(5)搭建開發環境,筆者針對ARM Cotex核的MCU單片機開發習慣使用MDK Keil開發環境,安裝好MDK Keil開發環境,然后安裝廠家提供的Pack包,再配置一個JLINK v9仿真調試器,加上官網下載的DS和UM手冊或編程手冊以及官網的MCU例程就可以開始進入入門開發了。
3、要點提示:
在實現本實例之前呢,筆者已經搭建好了基於MDK Keil5.30的MM32F0010的開發環境,請事先搭建好MDK Keil開發環境。
4、注意事項:
基於ARM Cotex M0/M3/M4等核心的MCU都有共同的特點即:系統(System Clock)時鍾和片上外設時鍾是獨立配置的,系統時鍾配置一般在加載MCU啟動文件xx.s時調用了System_xx.c文件里的SystemInit函數,用戶只需在System_xx.c文件里開啟對應的宏定義時鍾項即可,然后就是外設時鍾了,ARM Cortex 核的MCU每一個片上外設都有各自獨立的時鍾配置使能位,因此用戶對片上外初始化外設時,首先要開啟使能外設時鍾,再配置外設的其它成員參數(注:基於ARM Cortex核心的MCU各個外設參數的配置都是以結構體成員、聯合體、枚舉參數進行配置的因此用戶要有一定的C語言基礎)。
5、MM32F0010系統時鍾的配置:
參考官網下載的LED工程例程,Keil左邊欄Project工程目錄下單擊MM32Series前面的加號“+”展開工程目錄,單擊"STARTUP"文件夾的“+”號展開文件目錄,可以看到2個文件分別是system_mm32f0010.c配置時鍾文件和startup_mm32f0010_keil.s啟動文件(基於keil環境)如下圖1所示:用戶在system_mm32f0010.c里開啟宏定義時鍾,即去掉雙斜杠用於配置系統時鍾(如果需要使用外部HSE 8M時鍾去掉“#define SYSCLK_FREQ_HSE HSE_VALUE”前面的雙斜杠,使用雙斜桿屏蔽“#define SYSCLK_HSI_48MHz 48000000”即可)
圖1
#define SYSCLK_HSI_48MHz 48000000時鍾即可,程序運行啟動文件時會對該宏定義的系統時鍾進行初始化
6、MM32F0010的GPIO初始化配置:
(1)不知道大家平時編寫外設驅動代碼是什么樣的風格特點,筆者有自己的一套編程風格,本實例是使用MM32F0010的GPIO外設驅動LED燈,低電平點亮,那么筆者針對該驅動會編寫一個外設xx.c和外設xx.h文件即:bsp_gpio_led.c和bsp_gpio_led.h文件。
(2)關於配置MM32F0010 GPIO管腳的工作模式有以下8種模式:
輸入模式:
<1>GPIO_Mode_AIN 模擬輸入輸入模擬量
<2>GPIO_Mode_FLOATING 浮空輸入(一般會在外部接上拉或下拉電阻,否則電平狀態為不確定狀態)
<3>GPIO_Mode_IPD 帶內部下拉電阻的下拉輸入(弱下拉)
<4>GPIO_Mode_IPU 帶內部上拉電阻的上拉輸入(弱上拉)
輸出模式:
<5>GPIO_Mode_Out_OD 開漏輸出(如需啟動外部電路需外接適當的上拉或下拉電阻)
<6>GPIO_Mode_Out_PP 推挽輸出(最大灌電流20mA)
<7>GPIO_Mode_AF_OD 復用功能開漏輸出(如果IO有配置成復用功能需在外部接適當的上拉或下拉電阻)
<8>GPIO_Mode_AF_PP 復用功能推挽輸出(如果IO有配置成復用功能,可使用該模式,最大灌電流20mA)
(3)配置MM32F0010初始化GPIO的步驟:
1>使能GPIOx端口時鍾(這點很重要不要忘了)
2>定義GPIO結構體變量引用GPIO結構體成員使用庫函數自定義值初始化GPIO 結構體成員參數
3>配置GPIO結構體成員管腳定義;
4>配置GPIO結構體成員管腳的輸出速度;
5>配置GPIO結構體成員管腳為輸入或輸出模式;
6>根據給定的結構體成員變量配置的參數初始化GPIOx端口和引腳參數;
(4)本實例是要用到普通的GPIO功能輸出電平驅動LED1,因此無需復用IO,直接配置為推挽輸出即可。在bsp_gpio_led.c文件里編輯MM32F0010的GPIO外設驅動LED燈的初始化代碼函數如下所示:
1 #include "bsp_gpio_led.h" 2 3 /** 4 *********************************************************************************************************************** 5 *@函數名稱:void Bsp_LED_Init(void) 6 *@功能描述:LED Init 7 *@輸入參數:None 8 *@返回參數:None 9 *********************************************************************************************************************** 10 */ 11 void Bsp_LED_Init(void) 12 { 13 //定義GPIO 初始化結構體成員變量 14 GPIO_InitTypeDef GPIO_InitStructure; 15 //使能GPIO外設GPIOA端口時鍾 16 RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE); 17 //使用庫函數自定義值初始化GPIO 結構體成員參數 18 GPIO_StructInit(&GPIO_InitStructure); 19 //GPIOA PA7管腳配置 20 GPIO_InitStructure.GPIO_Pin = LED1_PIN; 21 //GPIOA PA7輸出速度 22 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 23 //GPIOA PA7推挽輸出 24 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 25 //根據以上配置的的參數初始化GPIOA PA7成員參數 26 GPIO_Init(LED1_PORT, &GPIO_InitStructure); 27 28 //初始化熄滅LED1 29 LED1_OFF(); 30 }
(5)在bsp_gpio_led.h文件里編輯MM32F0010的GPIO外設驅動LED燈的頭文件代碼如下所示,編輯頭文件宏定義的好處是方便代碼維護,當需要更換IO只需修改宏定義即可;
1 #ifndef __BSP_GPIO_LED_H__ 2 #define __BSP_GPIO_LED_H__ 3 4 #include "mm32_device.h" 5 #include "hal_conf.h" 6 7 //GPIOA LED1端口宏定義 8 #define LED1_PORT GPIOA 9 //GPIOA LED1管腳宏定義 10 #define LED1_PIN GPIO_Pin_7 11 12 //GPIOA PA7輸出低電平 LED1 ON 13 #define LED1_ON() GPIO_ResetBits(LED1_PORT,LED1_PIN) 14 //GPIOA PA7輸出高電平 LED1 OFF 15 #define LED1_OFF() GPIO_SetBits(LED1_PORT,LED1_PIN) 16 //根據讀取的GPIOA PA7電平狀態,按當前狀態翻轉 17 #define LED1_TOGGLE() (GPIO_ReadOutputDataBit(LED1_PORT,LED1_PIN))?(GPIO_ResetBits(LED1_PORT,LED1_PIN)):(GPIO_SetBits(LED1_PORT,LED1_PIN)) 18 void Bsp_LED_Init(void); 19 #endif
7、MM32F0010 GPIOA PA7驅動LED燈每隔一秒翻轉一次:
(1)在main.c文件里包含bsp_gpio_led.h頭文件,然后包含官方寫好的“delay.h”頭文件,調用bsp_gpio_led.h頭文件里聲明的void Bsp_LED_Init(void)函數初始化GPIOA PA7端口引腳,初始化為驅動LED1,main函數初始化時同時也調用“delay.h”頭文件聲明的SysTick函數初始化即void DELAY_Init(void);最后在while(1)主循環里調用bsp_gpio_led.h頭文件里宏定義的LED1狀態翻轉代碼並調用“delay.h”頭文件聲明的SysTick毫秒級別延時函數,實現LED1每隔一秒LED1燈狀態翻轉一次,以此循環,main函數代碼如下所示:
1 #include "delay.h" 2 #include "bsp_gpio_led.h" 3 4 /** 5 *********************************************************************************************************************** 6 *@函數名稱:int main(void) 7 *@功能描述:main函數,主函數入口代碼在這里開始執行 8 *@輸入參數:None 9 *@返回參數:int:0(和編譯器有關) 10 *********************************************************************************************************************** 11 */ 12 int main(void) 13 { 14 //SysTick Init 15 DELAY_Init(); 16 //LED Init 17 Bsp_LED_Init(); 18 19 while(1) 20 { 21 //LED1 Toggle 22 LED1_TOGGLE(); 23 //Delay 1000ms 24 DELAY_Ms(1000); 25 } 26 }
(2)在MDK Keil IDE集成開發環境中編譯代碼,GPIOA PA7硬件連接LED1,可用MM32F0010開發板或核心板(PA7連接到LED負極)或用戶自己設計的板子即可,MCU支持DC2~5.5V寬電壓供電,一般選擇VDD 3.3V或VDD5.0V給MCU供電,本實例使用VDD3.3V給MCU供電,最后使用JLINK v9把編譯好的代碼燒錄到板子上,可看到板子實物LED1燈每隔1000ms即1s狀態翻轉一次,看到LED1周期2s點亮和熄滅一次,以此循環。
結束語:
(1)有些讀者可能會問我怎么知道GPIOA PA7是怎么初始化的呢?問的好,其實在博客開篇筆者已經提到關於ARM Cortex 核的MCU每一個片上外設都有與之對應的外設xx.c和xx.h庫函數,例如:hal_rcc.c和hal_rcc.h,hal_gpio.c和hal_gpio.h等;
(2)頭文件一般聲明了可供main函數初始化調用的外設初始化函數以及參數,以及外設結構體成員,外設枚舉參數等,C文件一般描述了使用該外設的功能配置可供初始化的函數;
(3)比如hal_rcc.c描述了系統時鍾和總線時鍾以及各個外設時鍾的配置,hal_rcc.h描述了可被主函數調用的外設初始化的時鍾參數等,hal_gpio.c和hal_gpio.h描述了GPIO口初始化函數,各端口、管腳宏定義,通過GPIO結構體成員、GPIO的枚舉參數,以及有些以函數聲明的形式給出,這樣我們使用每個外設時一方面可參考官網例程,另一方面參考庫函數外設的xx.c和外設xx.h文件結合UM手冊寄存器的描述以及DS手冊IO口復用,即可去初始化每一個需要使用的外設,因此掌握良好的方法規律對MCU外設底層初始化配置非常重要,尤其是在沒有專門的庫函數編程手冊的情況下,該方法是最優的方法之一。