1)實驗平臺:正點原子APM32E103最小系統(tǒng)板
2)平臺購買地址:https://detail.tmall.com/item.htm?id=609294757420
3)全套實驗源碼+手冊+視頻下載地址: http://www.openedv.com/docs/boards/xiaoxitongban
第十章 跑馬燈實驗
跑馬燈程序是嵌入式開發(fā)的一個經(jīng)典程序,類似于學(xué)習(xí)C語言時,編寫的“Hello World”程序。跑馬燈本質(zhì)上是控制單片機的GPIO輸出高低電平,以此達到控制LED等亮滅狀態(tài)的切換。通過本章的學(xué)習(xí),讀者將學(xué)習(xí)到GPIO輸出模式的使用。
本章分為如下幾個小節(jié):
10.1 硬件設(shè)計
10.2 程序設(shè)計
10.3 下載驗證
10.1 硬件設(shè)計
10.1.1 例程功能
- LED0和LED1以500毫秒的頻率交替閃爍,實現(xiàn)類似跑馬燈的效果。
10.1.2 硬件資源 - LED
LED0 - PB5
LED1 - PE5
10.1.3 原理圖
本章實驗用的兩個APM32E103最小系統(tǒng)板板載LED,分別為LED0(紅色)和LED1(綠色),其與板載MCU的連接原理圖,如下圖所示:
10.1.3.1 LED與MCU的連接原理圖
從上面原理圖中可以看出,LED0和LED1的正極分別通過一個限流電阻連接到了電源正極,而負極分別與MCU的PB5引腳和PE5引腳相連接,因此只需通過控制PB5引腳或PE5引腳輸出低電平,則能分別控制LED0和LED1點亮,反之,則熄滅。
10.2 程序設(shè)計
10.2.1 Geehy標準庫的GPIO驅(qū)動
本章實驗中要通過控制GPIO引腳輸出高低電平來控制LED的亮滅狀態(tài),因此需要以下兩個步驟:
①:配置GPIO引腳為推挽輸出模式
②:設(shè)置GPIO引腳輸出電平
在Geehy標準庫中對應(yīng)的驅(qū)動函數(shù)如下:
①:配置GPIO引腳
該函數(shù)用于配置GPIO引腳的功能和各項參數(shù),其函數(shù)原型如下所示:
void GPIO_Config(GPIO_T* port, GPIO_Config_T* gpioConfig);
該函數(shù)的形參描述,如下表所示:
形參 描述
port 指向GPIO端口結(jié)構(gòu)體的指針
例如:GPIOA、GPIOB等(在apm32e10x.h文件中有定義)
gpioConfig 指向GPIO初始化結(jié)構(gòu)體的指針
需自行定義,并根據(jù)GPIO的配置參數(shù)填充結(jié)構(gòu)體中的成員變量
表10.2.1.1 函數(shù)GPIO_Config()形參描述
該函數(shù)的返回值描述,如下表所示:
返回值 描述
無 無
表10.2.1.2 函數(shù)GPIO_Config()返回值描述
該函數(shù)使用GPIO_Config_T類型的結(jié)構(gòu)體變量傳入GPIO引腳的配置參數(shù),該結(jié)構(gòu)體的定義如下所示:
typedef enum
{
GPIO_SPEED_10MHz = 1,
GPIO_SPEED_2MHz,
GPIO_SPEED_50MHz
}GPIO_SPEED_T;
typedef enum
{
GPIO_MODE_ANALOG = 0x0, /* 模擬模式 */
GPIO_MODE_IN_FLOATING = 0x04, /* 浮空輸入模式 */
GPIO_MODE_IN_PD = 0x28, /* 下拉輸入模式 */
GPIO_MODE_IN_PU = 0x48, /* 上拉輸入模式 */
GPIO_MODE_OUT_PP = 0x80, /* 通用推挽輸出 */
GPIO_MODE_OUT_OD = 0x84, /* 通用推挽輸出 */
GPIO_MODE_AF_PP = 0x88, /* 復(fù)用推挽輸出 */
GPIO_MODE_AF_OD = 0x8C, /* 復(fù)用開漏輸出 */
}GPIO_MODE_T;
typedef enum
{
GPIO_PIN_0 = ((uint16_t)BIT0),
GPIO_PIN_1 = ((uint16_t)BIT1),
GPIO_PIN_2 = ((uint16_t)BIT2),
GPIO_PIN_3 = ((uint16_t)BIT3),
GPIO_PIN_4 = ((uint16_t)BIT4),
GPIO_PIN_5 = ((uint16_t)BIT5),
GPIO_PIN_6 = ((uint16_t)BIT6),
GPIO_PIN_7 = ((uint16_t)BIT7),
GPIO_PIN_8 = ((uint16_t)BIT8),
GPIO_PIN_9 = ((uint16_t)BIT9),
GPIO_PIN_10 = ((uint16_t)BIT10),
GPIO_PIN_11 = ((uint16_t)BIT11),
GPIO_PIN_12 = ((uint16_t)BIT12),
GPIO_PIN_13 = ((uint16_t)BIT13),
GPIO_PIN_14 = ((uint16_t)BIT14),
GPIO_PIN_15 = ((uint16_t)BIT15),
GPIO_PIN_ALL = ((uint32_t)0XFFFF),
} GPIO_PIN_T;
typedef struct
{
uint16_t pin; /* 指定要配置的GPIO引腳 */
GPIO_SPEED_T speed; /* 輸出速度 */
GPIO_MODE_T mode; /* 模式 */
}GPIO_Config_T;
該函數(shù)的使用示例,如下所示:
#include "apm32e10x.h"
#include "apm32e10x_gpio.h"
void example_fun(void)
{
GPIO_Config_T gpio_init_struct;
/* 配置PA0引腳為輸出模式 */
gpio_init_struct.pin = GPIO_PIN_0;
gpio_init_struct.mode = GPIO_MODE_OUT;
gpio_init_struct.speed = GPIO_SPEED_50MHz;
GPIO_Config(GPIOA, &gpio_init_struct);
}
②:設(shè)置GPIO引腳輸出電平
該函數(shù)用于設(shè)置GPIO引腳輸出指定電平(高電平或低電平),其函數(shù)原型如下所示:
void GPIO_WriteBitValue(GPIO_T* port, uint16_t pin, uint8_t bitVal);
該函數(shù)的形參描述,如下表所示:
表10.2.1.3 函數(shù)GPIO_WriteBitValue()形參描述
該函數(shù)的返回值描述,如下表所示:
返回值 描述
無 無
表10.2.1.4 函數(shù)GPIO_WriteBitValue()返回值描述
該函數(shù)的使用示例,如下所示:
#include "apm32e10x.h"
#include "apm32e10x_gpio.h"
void example_fun(void)
{
/* 設(shè)置PA0引腳輸出低電平 */
GPIO_WriteBitValue(GPIOA, GPIO_PIN_0, BIT_RESET);
/* 設(shè)置PA0引腳輸出高電平 */
GPIO_WriteBitValue(GPIOA, GPIO_PIN_0, BIT_SET);
}
③:翻轉(zhuǎn)GPIO引腳輸出電平(補充)
該函數(shù)用于翻轉(zhuǎn)GPIO引腳的輸出電平,其函數(shù)原型如下所示:
void GPIO_SetBit(GPIO_T* port, uint16_t pin);
void GPIO_ResetBit (GPIO_T* port, uint16_t pin);
該函數(shù)的形參描述,如下表所示:
形參 描述
port 指向GPIO端口結(jié)構(gòu)體的指針
例如:GPIOA、GPIOB等(在apm32e10x.h文件中有定義)
pin 待設(shè)置的GPIO引腳號
例如:GPIO_PIN_0、GPIO_PIN_1等(在apm32e10x_gpio.h文件中有定義)
表10.2.1.5 GPIO_ToggleBit()形參描述
該函數(shù)的返回值描述,如下表所示:
返回值 描述
無 無
表10.2.1.6 GPIO_TogglePin()返回值描述
該函數(shù)的使用示例,如下所示:
#include "apm32e10x.h"
#include "apm32e10x_gpio.h"
void example_fun(void)
{
/* 翻轉(zhuǎn)PA0引腳輸出電平 */
GPIO_SetBit (GPIOA, GPIO_PIN_0);
delay_ms(10);
GPIO_ResetBit (GPIOA, GPIO_PIN_0);
delay_ms(10);
}
10.2.2 LED驅(qū)動
LED驅(qū)動主要就是控制GPIO引腳輸出高低電平,來控制LED亮起或熄滅。本章實驗中,LED的驅(qū)動代碼包括led.c和led.h兩個文件(本書配套實驗例程中,器件或外設(shè)的驅(qū)動代碼基本都由一個C源文件和一個對應(yīng)的頭文件組成)。
根據(jù)原理圖可知,應(yīng)當將PB5引腳和PE5引腳配置為推挽輸出模式,并在需要控制LED0(LED1)亮起的時候,設(shè)置PB5引腳(PE5引腳)輸出低電平,在需要控制LED0(LED1)熄滅的時候,設(shè)置PB5引腳(PE5引腳)輸出高電平。
LED驅(qū)動中,對引腳的定義,如下所示:
#define LED0_GPIO_PORT GPIOB
#define LED0_GPIO_PIN GPIO_PIN_5
#define LED0_GPIO_CLK_ENABLE() \
do { \
RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOB); \
} while (0)
#define LED1_GPIO_PORT GPIOE
#define LED1_GPIO_PIN GPIO_PIN_5
#define LED1_GPIO_CLK_ENABLE() \
do { \
RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOE); \
} while (0)
在后續(xù)的實驗代碼中,基本都會使用上述的宏定義的方式定義GPIO引腳的各種信息(GPIO端口、GPIO引腳號、GPIO端口時鐘使能和GPIO復(fù)用功能等信息)。
LED驅(qū)動中,操作引腳的定義,如下所示:
#define LED0(x) \
do { x ? \
GPIO_SetBit(LED0_GPIO_PORT, LED0_GPIO_PIN) : \
GPIO_ResetBit(LED0_GPIO_PORT, LED0_GPIO_PIN); \
} while (0)
#define LED1(x) \
do { x ? \
GPIO_SetBit(LED1_GPIO_PORT, LED1_GPIO_PIN) : \
GPIO_ResetBit(LED1_GPIO_PORT, LED1_GPIO_PIN); \
} while (0)
#define LED0_TOGGLE()
do{ GPIO_ReadOutputBit(LED0_GPIO_PORT,LED0_GPIO_PIN) ? \
(GPIO_ResetBit(LED0_GPIO_PORT, LED0_GPIO_PIN)): \
(GPIO_SetBit(LED0_GPIO_PORT, LED0_GPIO_PIN)); \
}while(0)
#define LED1_TOGGLE()
do{ GPIO_ReadOutputBit(LED1_GPIO_PORT, LED1_GPIO_PIN) ? \
(GPIO_ResetBit(LED1_GPIO_PORT, LED1_GPIO_PIN)): \
(GPIO_SetBit(LED1_GPIO_PORT, LED1_GPIO_PIN)); \
}while(0)
在后續(xù)實驗代碼中,基本都會使用上述的宏定義的方式定義GPIO引腳的操作(設(shè)置GPIO引腳輸出高電平或低電平、翻轉(zhuǎn)GPIO引腳輸出電平和讀取GPIO引腳輸入電平等操作)。
LED驅(qū)動中,LED的初始化函數(shù),如下所示:
/**
* @brief 初始化LED
* @param 無
* @retval 無
*/
void led_init(void)
{
GPIO_Config_T gpio_init_struct;
LED0_GPIO_CLK_ENABLE(); /* LED0時鐘使能 */
LED1_GPIO_CLK_ENABLE(); /* LED1時鐘使能 */
gpio_init_struct.pin = LED0_GPIO_PIN; /* LED0引腳 */
gpio_init_struct.mode = GPIO_MODE_OUT_PP; /* 推挽輸出 */
gpio_init_struct.speed = GPIO_SPEED_50MHz; /* 高速 */
GPIO_Config(LED0_GPIO_PORT, &gpio_init_struct); /* 初始化LED0引腳 */
gpio_init_struct.pin = LED1_GPIO_PIN; /* LED1引腳 */
gpio_init_struct.mode = GPIO_MODE_OUT_PP; /* 推挽輸出 */
gpio_init_struct.speed = GPIO_SPEED_50MHz; /* 高速 */
GPIO_Config(LED1_GPIO_PORT, &gpio_init_struct); /* 初始化LED1引腳 */
LED0(1); /* 關(guān)閉LED0 */
LED1(1); /* 關(guān)閉LED1 */
}
LED的初始化函數(shù)中,使能了LED0和LED1控制引腳的GPIO端口時鐘,并將其配置為推挽輸出模式,最后默認將LED的狀態(tài)設(shè)置為熄滅狀態(tài)。
10.2.3 實驗應(yīng)用代碼
本實驗的應(yīng)用代碼,如下所示:
int main(void)
{
NVIC_ConfigPriorityGroup(NVIC_PRIORITY_GROUP_4); /* 設(shè)置中斷優(yōu)先級分組為組4 */
sys_apm32_clock_init(15); /* 配置系統(tǒng)時鐘 */
delay_init(120); /* 初始化延時功能 */
usart_init(115200); /* 初始化串口 */
led_init(); /* 初始化LED */
while (1)
{
LED0(0); /* LED0亮 */
LED1(1); /* LED1滅 */
delay_ms(500); /* 延時500毫秒 */
LED0(1); /* LED0滅 */
LED1(0); /* LED1亮 */
delay_ms(500); /* 延時500毫秒 */
}
}
可以看到,在調(diào)用LED初始化之前,會先調(diào)用以下函數(shù):
NVIC_ConfigPriorityGroup(NVIC_PRIORITY_GROUP_4); /* 設(shè)置中斷優(yōu)先級分組為組4 */文章來源:http://www.zghlxwxcb.cn/news/detail-786221.html
sys_apm32_clock_init(15); /* 配置系統(tǒng)時鐘 */
delay_init(120); /* 初始化延時功能 */
usart_init(115200); /* 初始化串口 */
①:第一行代碼用于設(shè)置中斷優(yōu)先級分組為組4,主要用于后續(xù)配置中斷時使用,并且在后續(xù)應(yīng)用代碼運行時,強烈不建議再修改中斷優(yōu)先級分組設(shè)置,因此在一開始初始化時先設(shè)置好中斷優(yōu)先級分組。
②:第二行代碼用于配置系統(tǒng)時鐘,因為大部分實驗例程都無需考慮低功耗應(yīng)用,因此大部分實驗例程配置系統(tǒng)時鐘的參數(shù)都與本實驗一致,將系統(tǒng)主頻配置為120MHz。
③:第三行代碼用于初始化延時功能,為后續(xù)的應(yīng)用代碼提供微秒級和毫秒級的延時的功能。
④:第四行代碼用于初始化用于調(diào)試功能的USART1,為后續(xù)的應(yīng)用代碼提供printf等功能,方面通過串口調(diào)試助手查看程序運行情況。
⑤:以上四行代碼都是執(zhí)行一些必要的初始化,基本在后續(xù)的每一個實驗例程中都會看見,后續(xù)不再贅述。
執(zhí)行完必要的初始化后,緊接著初始化LED,然后在一個while循環(huán)中重復(fù)地控制板載LED0和LED1輪流亮起和熄滅,輪流時間為500毫秒,以此實現(xiàn)跑馬燈的效果。
10.3 下載驗證
在完成編譯和燒錄操作后,可以看到板子上的LED0和LED1輪流亮起和熄滅,輪流的時間大約為500毫秒,與預(yù)期的實驗效果相符。文章來源地址http://www.zghlxwxcb.cn/news/detail-786221.html
到了這里,關(guān)于【正點原子STM32連載】第十章 跑馬燈實驗 摘自【正點原子】APM32E103最小系統(tǒng)板使用指南的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!