17届蓝桥杯嵌入式赛道开发板外设使用教程------LED
引言
在本系列文章中我会分享17届嵌入式赛道中官方指定开发板的外设使用以及操作方法,本文章中所介绍的开发方式是HAL库开发,项目配置也会通过CubeMX软件实现
硬件介绍
第17届蓝桥杯嵌入式赛道使用的开发板板载的芯片为STM32G431RBT6,外形图如下

本次即将使用的LED灯位于单片机的左下角,一共8个LED灯,LED灯的硬件连接图如下

通过观察硬件连接图我们不难发现LED灯和单片机的引脚之间并非是直接连接的,在单片机引脚和LED灯之间有一个锁存器(SN74HC573ADWR),单片机上的锁存器是8位D型锁存器,一共有20个引脚。其功能为存储高低电平信息,当锁存器的使能端为高电平时,输出端引脚电平与输入端引脚电平保持一致,当使能端为低电平时输出端的电平信号会被锁住,接下来无论我们如和修改输入端引脚的电平信号输出端都不会发生任何变化,并会一直保持原来的电平状态。
了解完锁存器的作用之后我们再来观察当前的LED连接图,其中PD2引脚连接的是锁存器的使能端,PC8~PC15引脚连接着对应的LED,此时我们不难发现:在锁存器使能的情况下,如果LED对应的引脚电平为低电平那么LED将会被点亮,如果引脚为高电平那么LED灯将会熄灭。
项目配置
在了解完基本的硬件信息后我们就可以着手进行项目的基本配置了,我们打开CubeMX软件,选择对应的芯片型号,进入图形化配置界面后先对项目进行基础配置
CubeMX软件的基本项目配置以及Keil软件的高级文件配置操作在之前的文章中有所介绍,这里就不做过多赘述,如果有小伙伴不知道的话可以直接跳转到对应文章去查看
因此接下来仅演示一下当前单片机中比较特殊部分的配置操作
时钟配置如下,当前单片机的主频最高可以设置为170MHz,相当于我们之前使用的F1系列单片机最高主频的两倍多

LED相关引脚配置如下

在引脚配置过程中我们只需要注意不要忘记配置PD2引脚即可,否则我们无法将电平信号通过锁存器传递给对应的单片机引脚,随后检查一下项目的其它配置,确认无误后点击右上角的生成代码即可自动生成相应项目
使用CubeMX软件进行基本的项目配置之后,我们还需要通过Keil软件进行进一步的高阶配置,主要配置内容为将对应的LED驱动文件添加到项目中,并添加对应的头文件搜索路径,这样可以使整体的项目层级更加合理,便于我们后期进行维护和修改,相关的操作在对应文章中也有介绍,大家可以根据自己的情况决定是否要进行相应的配置操作
代码编写
项目配置完毕后我们就可进行LED灯驱动代码的编写了
头文件代码
由于单片机上总共有8个LED灯,因此为了方便后续的函数传参等一系列操作我们最好使用枚举类型来记录每一个LED灯的信息
c
typedef enum
{
LED1,
LED2,
LED3,
LED4,
LED5,
LED6,
LED7,
LED8
} LEDID;
随后声明对应的LED灯操作函数,以供其它文件调用
c
// 反转单个LED灯电平状态
void LED_Toggle(LEDID num);
//开启对应LED灯
void LED_TurnOn(LEDID num);
//开启所有LED灯
void LED_TurnOnALL(void);
//关闭对应LED灯
void LED_TurnOff(LEDID num);
//关闭所有LED灯
void LED_TurnOffALL(void);
源文件代码
在头文件中声明了对应的驱动函数后接下来就要在源文件中实现对应的函数功能
-
翻转LED灯状态函数
c/** * @brief 反转LED状态函数 * * @param num 目标LED灯编号 */ void LED_Toggle(LEDID num) { //先使能锁存器 HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET); //写入电平信息 switch (num) { case LED1: { HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin); break; } case LED2: { HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin); break; } case LED3: { HAL_GPIO_TogglePin(LED3_GPIO_Port, LED3_Pin); break; } case LED4: { HAL_GPIO_TogglePin(LED4_GPIO_Port, LED4_Pin); break; } case LED5: { HAL_GPIO_TogglePin(LED5_GPIO_Port, LED5_Pin); break; } case LED6: { HAL_GPIO_TogglePin(LED6_GPIO_Port, LED6_Pin); break; } case LED7: { HAL_GPIO_TogglePin(LED7_GPIO_Port, LED7_Pin); break; } case LED8: { HAL_GPIO_TogglePin(LED8_GPIO_Port, LED8_Pin); break; } } //失能锁存器,释放引脚 HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET); }当前函数与普通的LED驱动函数的主要区别就是在向LED输出高低电平信号之前需要先使能锁存器,虽然当前单片机上搭载的
G4系列芯片主频比我们之前所使用的F103ZET6芯片相比要高,但是引脚数量较少,因此我们在将对应的信号传递给引脚之后可以关闭锁存器,这样我们后续还可以使用这8个引脚去进行其它操作,这样就帮我们节省了对应的引脚资源 -
点亮LED灯函数
当前函数被的操作逻辑与上面的LED状态翻转函数逻辑类似,大家可以自行体会
c/** * @brief 开启对应LED灯 * * @param num 目标 */ void LED_TurnOn(LEDID num) { HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET); switch (num) { case LED1: { HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET); break; } case LED2: { HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET); break; } case LED3: { HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_RESET); break; } case LED4: { HAL_GPIO_WritePin(LED4_GPIO_Port, LED4_Pin, GPIO_PIN_RESET); break; } case LED5: { HAL_GPIO_WritePin(LED5_GPIO_Port, LED5_Pin, GPIO_PIN_RESET); break; } case LED6: { HAL_GPIO_WritePin(LED6_GPIO_Port, LED6_Pin, GPIO_PIN_RESET); break; } case LED7: { HAL_GPIO_WritePin(LED7_GPIO_Port, LED7_Pin, GPIO_PIN_RESET); break; } case LED8: { HAL_GPIO_WritePin(LED8_GPIO_Port, LED8_Pin, GPIO_PIN_RESET); break; } } HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET); } -
开启所有LED灯
c/** * @brief 开启所有LED灯 * */ void LED_TurnOnALL() { LED_TurnOn(LED1); LED_TurnOn(LED2); LED_TurnOn(LED3); LED_TurnOn(LED4); LED_TurnOn(LED5); LED_TurnOn(LED6); LED_TurnOn(LED7); LED_TurnOn(LED8); }当前函数开启所有LED灯只需要调用前面写好的开启单个
LED灯函数即可 -
关闭单个LED灯
当前函数的实现逻辑与前面的开启单个LED灯逻辑基本一致
c/** * @brief 关闭单个LED灯 * * @param num 目标LED灯的编号 */ void LED_TurnOff(LEDID num) { HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET); switch (num) { case LED1: { HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET); break; } case LED2: { HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_SET); break; } case LED3: { HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_SET); break; } case LED4: { HAL_GPIO_WritePin(LED4_GPIO_Port, LED4_Pin, GPIO_PIN_SET); break; } case LED5: { HAL_GPIO_WritePin(LED5_GPIO_Port, LED5_Pin, GPIO_PIN_SET); break; } case LED6: { HAL_GPIO_WritePin(LED6_GPIO_Port, LED6_Pin, GPIO_PIN_SET); break; } case LED7: { HAL_GPIO_WritePin(LED7_GPIO_Port, LED7_Pin, GPIO_PIN_SET); break; } case LED8: { HAL_GPIO_WritePin(LED8_GPIO_Port, LED8_Pin, GPIO_PIN_SET); break; } } HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET); } -
关闭所有LED灯
当前函数逻辑与前面的开启所有LED灯逻辑保持高度一致
c/** * @brief 关闭所有LED灯 * */ void LED_TurnOffALL(void) { LED_TurnOff(LED1); LED_TurnOff(LED2); LED_TurnOff(LED3); LED_TurnOff(LED4); LED_TurnOff(LED5); LED_TurnOff(LED6); LED_TurnOff(LED7); LED_TurnOff(LED8); }
总结
至此你就完成了开发板上LED灯底层驱动函数的编写了,以后需要使用的LED的时候直接将对应的源文件和头文件添加到对应的项目中即可