本文章基于兆易创新GD32 MCU所提供的2.2.4版本库函数开发
向上代码兼容GD32F450ZGT6中使用
后续项目主要在下面该专栏中发布:
https://blog.youkuaiyun.com/qq_62316532/category_12608431.html?spm=1001.2014.3001.5482
感兴趣的点个关注收藏一下吧!
电机驱动开发可以跳转:
GD32F103RCT6/GD32F303RCT6-实战项目-无刷电机驱动(1)_gd32f103rct6例程-优快云博客
BMS电源系统开发可以跳转:
暂未放链接
DCDC-双向BUCK-BOOST实战链接:
向上代码兼容GD32F303RCT6中使用
本项目配套开发板:
基于GD32F103RCT6国产GD32平台,以下教程编写基于该开发板
本小结为GPIO外设使用的实验章程,在此小结我们会带大家手把手写几个常见的程序
跑马灯实验
实现开发板上两个LED灯实现跑马灯的效果。
LED硬件电路如下:
根据硬件电路图知,四个LED灯对应的IO引脚分别为PB3,PB4,PD2,PC12。当四个引脚为低电平时,二极管导通;当四个引脚为高电平时,二极管截止,因此对这两个IO引脚设置高低电平变化即可。
这里我们不需要使用四个,我们只需要使用PB3和PB4就行
在前一小结我们说过:
在复位期间或复位之后,备用功能并未激活,所有GPIO端口都被配置成输入浮空模式,这种输入模式禁用上拉(PU)/下拉(PD)电阻。但是复位后,串行线调试端口(JTAG/Serial-Wired Debug pins)为输入PU/PD模式:
PA15:JTDI为上拉模式;
PA14:JTCK / SWCLK为下拉模式;
PA13:JTMS / SWDIO为上拉模式;
PB4:NJTRST为上拉模式;
PB3:JTDO为浮空模式。
所以我们需要先对PB3,PB4进行重映射
//管脚复用时钟使能
rcu_periph_clock_enable(RCU_AF);
//PB4和PB3管脚默认是NJTRST,要当GPIO,需要重映射
gpio_pin_remap_config(GPIO_SWJ_SWDPENABLE_REMAP, ENABLE)
接下来我们就可以开始编写代码了!
需要按步骤进行以下操作:
1.使能 GPIO 端口时钟
2.初始化 GPIO 目标引脚为推挽输出
3.控制 GPIO 引脚输出高、低电平
//GPIOB时钟使能
rcu_periph_clock_enable(RCU_GPIOB);
//PB4配置成输出
gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_4);
写法一:
//引脚输出低电平
gpio_bit_reset(GPIOB, GPIO_PIN_3);
//引脚输出高电平
gpio_bit_set(GPIOB, GPIO_PIN_3);
//引脚输出低电平
gpio_bit_reset(GPIOB, GPIO_PIN_4);
//引脚输出高电平
gpio_bit_set(GPIOB, GPIO_PIN_4);
写法二:
//引脚输出低电平
gpio_bit_write(GPIOB, GPIO_PIN_3, RESET);
//引脚输出高电平
gpio_bit_write(GPIOB, GPIO_PIN_3, SET);
//引脚输出低电平
gpio_bit_write(GPIOB, GPIO_PIN_4, RESET);
//引脚输出高电平
gpio_bit_write(GPIOB, GPIO_PIN_4, SET);
代码如下:
编译下载:
发现灯怎么常亮?
其实并不是灯常亮,只是PB3和PB4翻转太快了,人眼捕捉不到,那么我们需要加上一个延时函数,放慢他翻转的进程
好让我们观察到。
因为本节还没有学到滴答定时器,所以采用阻塞延时的方式:
//简单的延时函数
void Delay(__IO uint32_t nCount)
{
for(; nCount != 0; nCount--);
}
更改完以后的主函数:
编译烧录!
两个灯轮流闪烁,实验成功!
蜂鸣器实验
实现开发板上蜂鸣器发声,并用一个指示灯LED0指示蜂鸣器正在发声。
蜂鸣器硬件电路如下:
根据硬件电路图可知,当 PC13 输出高电平的时候,蜂鸣器将发声, 当 PC13输出低电平的时候,蜂鸣器停止发声。因此对该IO引脚设置高低电平变化即可。
需要按步骤进行以下操作:
1.使能 GPIO 端口时钟
2.初始化 GPIO 目标引脚为推挽输出
3.控制 GPIO 引脚输出高、低电平
代码如下:
//GPIOB时钟使能
rcu_periph_clock_enable(RCU_GPIOC);
//PC12配置成输出
gpio_init(GPIOC, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13);
//引脚输出高电平
gpio_bit_set(GPIOC, GPIO_PIN_13);
Delay(0xfffff);
//引脚输出低电平
gpio_bit_reset(GPIOC, GPIO_PIN_13);
Delay(0xfffff);
编译烧录!
发现蜂鸣器正常工作
实验成功!
按键输入实验
使用开发板上三个按键控制三LED灯亮灭。
按键硬件电路如下:
如果硬件上已外部上拉或下拉,则选择浮空输入模式。
如果硬件外部没有上拉,则选择内部上拉模式。
当PB5、PB6、PB7为低电平时,按键按下才有效。并且外部都没有上拉电阻,所以,需要在内部设置上拉。
因为在硬件上实现了硬件消抖,所以我们软件就不需要再设置消抖了。
关于为什么要按键消抖:
抖动时间的长短由按键的机械特性决定,一般为5ms~10ms。这是一个很重要的时间参数,在很多场合都要用到。按键稳定闭合时间的长短则是由操作人员的按键动作决定的,一般为零点几秒至数秒。为确保CPU对键的一次闭合仅作一次处理,必须去除键抖动。在键闭合稳定时读取键的状态,并且必须判别到键释放稳定后再作处理。
需要按步骤进行以下操作:
1.使能 GPIO 端口时钟
2.初始化 GPIO 目标引脚为输入模式(由于硬件电路没有外部上拉电阻,这里使用内部上拉输入)
3.检测按键的状态
//GPIOB时钟使能
rcu_periph_clock_enable(RCU_GPIOB);
//PB5配置成上拉输入
gpio_init(GPIOB, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_5);
//PB6配置成上拉输入
gpio_init(GPIOB, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
//PB7配置成上拉输入
gpio_init(GPIOB, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_7);
//读取引脚电平
gpio_input_bit_get(GPIOB, GPIO_PIN_5);
//读取引脚电平
gpio_input_bit_get(GPIOB, GPIO_PIN_6);
//读取引脚电平
gpio_input_bit_get(GPIOB, GPIO_PIN_7);
这一次实验开始我们将会分模块文件进行!
建立文件夹在放在外设文件夹中:
新建bsp_key文件夹,用来放置按键相关函数
新建bsp_key.c和bsp_key.h分别放置按键代码源文件和头文件
同理新建bsp_led.c和bsp_key.h分别放置LED代码源文件和头文件
在编译器中包含
将代码加入组别
编译发现0个错误0个警告再继续:
文件结构建好以后,接下来就让我们正式编写代码!
先在两个.h文件中加入预编译指令(这里以bsp_key.c为例):
头:(这里以bsp_key.c为例)
尾:(这里以bsp_key.c为例)
在.h中放入库函数头文件(这里以bsp_key.c为例)
因为GPIO输入的函数包含在该库函数中,所以我们需要引用该函数!
为了方便后期的代码移植,随时更换引脚,这里采用宏定义的方式对每个变量进行单独代替
对按键宏进行定义
完成一会我们就可以去编写.c源文件了
首先需要在.c开头加入需要使用到的头文件和各自的.h文件(这里以bsp_key.c为例):
然后是按键初始化函数
void Key_GPIO_Init(void)
{
// GPIO时钟使能
rcu_periph_clock_enable(KEY1_GPIO_CLK);
// 配置为内部上拉输入模式
gpio_init(KEY1_GPIO_PORT, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, KEY1_GPIO_PIN);
}
然后是按键按下检测函数
uint8_t Key_Scan(uint32_t gpio_periph, uint32_t pin)
{
/*检测是否有按键按下 */
if(gpio_input_bit_get(gpio_periph, pin) == KEY_ON)
{
/*等待按键释放 */
while(gpio_input_bit_get(gpio_periph, pin) == KEY_ON);
return KEY_ON;
}
else
return KEY_OFF;
}
到此完成bsp_key.c的代码编写。
注意:函数在.c编写完后需要在其对应的.h文件中对函数进行声明,不然就无法在外部调用该函数!
完成bsp_key.c以及bsp_key.h的编写以后,让我们继续编写bsp_led.c以及bsp_led.h
首先是.h文件的编写:
预编译指令:
头:
尾:
然后是头文件调用:因为GPIO输出的函数包含在该库函数中,所以我们需要引用该函数!
为了方便后期的代码移植,随时更换引脚,这里采用宏定义的方式对每个变量进行单独代替
/* 定义LED连接的GPIO端口, 用户只需要修改下面的代码即可改变控制的LED引脚 */
#define LED_1_GPIO_PORT GPIOB /* GPIO端口 */
#define LED_1_GPIO_CLK RCU_GPIOB /* GPIO端口时钟 */
#define LED_1_GPIO_PIN GPIO_PIN_3
#define LED_2_GPIO_PORT GPIOB /* GPIO端口 */
#define LED_2_GPIO_CLK RCU_GPIOB /* GPIO端口时钟 */
#define LED_2_GPIO_PIN GPIO_PIN_4
#define LED_3_GPIO_PORT GPIOC /* GPIO端口 */
#define LED_3_GPIO_CLK RCU_GPIOC /* GPIO端口时钟 */
#define LED_3_GPIO_PIN GPIO_PIN_12
#define LED_4_GPIO_PORT GPIOD /* GPIO端口 */
#define LED_4_GPIO_CLK RCU_GPIOD /* GPIO端口时钟 */
#define LED_4_GPIO_PIN GPIO_PIN_2
对寄存器编写,定义直接控制I/O口的宏
/* 定义控制IO的宏 */
#define LED1_ON gpio_bit_set(LED_1_GPIO_PORT,LED_1_GPIO_PIN)
#define LED1_OFF gpio_bit_reset(LED_1_GPIO_PORT,LED_1_GPIO_PIN)
#define LED1_TOG \
do{ \
if(gpio_output_bit_get(LED_1_GPIO_PORT,LED_1_GPIO_PIN)) \
gpio_bit_reset(LED_1_GPIO_PORT,LED_1_GPIO_PIN); \
else \
gpio_bit_set(LED_1_GPIO_PORT,LED_1_GPIO_PIN); \
}while(0)
#define LED2_ON gpio_bit_set(LED_2_GPIO_PORT,LED_2_GPIO_PIN)
#define LED2_OFF gpio_bit_reset(LED_2_GPIO_PORT,LED_2_GPIO_PIN)
#define LED2_TOG \
do{ \
if(gpio_output_bit_get(LED_2_GPIO_PORT,LED_2_GPIO_PIN)) \
gpio_bit_reset(LED_2_GPIO_PORT,LED_2_GPIO_PIN); \
else \
gpio_bit_set(LED_2_GPIO_PORT,LED_2_GPIO_PIN); \
}while(0)
#define LED3_ON gpio_bit_set(LED_3_GPIO_PORT,LED_3_GPIO_PIN)
#define LED3_OFF gpio_bit_reset(LED_3_GPIO_PORT,LED_3_GPIO_PIN)
#define LED3_TOG \
do{ \
if(gpio_output_bit_get(LED_3_GPIO_PORT,LED_3_GPIO_PIN)) \
gpio_bit_reset(LED_3_GPIO_PORT,LED_3_GPIO_PIN); \
else \
gpio_bit_set(LED_3_GPIO_PORT,LED_3_GPIO_PIN); \
}while(0)
#define LED4_ON gpio_bit_set(LED_4_GPIO_PORT,LED_4_GPIO_PIN)
#define LED4_OFF gpio_bit_reset(LED_4_GPIO_PORT,LED_4_GPIO_PIN)
#define LED4_TOG \
do{ \
if(gpio_output_bit_get(LED_4_GPIO_PORT,LED_4_GPIO_PIN)) \
gpio_bit_reset(LED_4_GPIO_PORT,LED_4_GPIO_PIN); \
else \
gpio_bit_set(LED_4_GPIO_PORT,LED_4_GPIO_PIN); \
}while(0)
定义完毕后,就可以直接调用以上函数对LED进行操作
写完bsp_led.h以后,我们转入bsp_led.c的源代码编写:
//管脚复用时钟使能
rcu_periph_clock_enable(RCU_AF);
//PB4管脚默认是NJTRST,要当GPIO,需要重映射
gpio_pin_remap_config(GPIO_SWJ_SWDPENABLE_REMAP, ENABLE);
// GPIO时钟使能
rcu_periph_clock_enable(LED1_GPIO_CLK);
rcu_periph_clock_enable(LED2_GPIO_CLK);
rcu_periph_clock_enable(LED3_GPIO_CLK);
rcu_periph_clock_enable(LED4_GPIO_CLK);
// 配置为推挽输出模式
gpio_init(LED1_GPIO_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, LED1_GPIO_PIN);
gpio_init(LED2_GPIO_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, LED2_GPIO_PIN);
gpio_init(LED3_GPIO_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, LED3_GPIO_PIN);
gpio_init(LED4_GPIO_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, LED4_GPIO_PIN);
// 初始化引脚为高电平
gpio_bit_set(LED1_GPIO_PORT, LED1_GPIO_PIN);
gpio_bit_set(LED2_GPIO_PORT, LED2_GPIO_PIN);
gpio_bit_set(LED3_GPIO_PORT, LED3_GPIO_PIN);
gpio_bit_set(LED4_GPIO_PORT, LED4_GPIO_PIN);
到此完成bsp_led.c的代码编写。
注意:函数在.c编写完后需要在其对应的.h文件中对函数进行声明,不然就无法在外部调用该函数!
以上完成代码编写
现在开始编写主函数:
先在头文件里面包含实验所需要的声明.h
实验发现三个按键成功控制各个LED,实验完成!
群号:621154399
有问题欢迎大家加入我们一起交流,这个群是开源性技术交流群。