上篇 "【GD32450I-EVAL】+ 02软件开发环境配置(KEIL 5)与流水灯测试" 介绍了软件开发环境的配置,这篇我们来看看GD32库函数的基础使用方法。
之前使用过STM32单片机,对比现在的GD32,使用库函数开发,编程思路基本一致,只是用到的库函数名称不一样,
下面以光盘资料中的 "03_GPIO_KeyBoard_Interrupt_mode"为例,分析一下库函数的使用方法。
1 程序分析
首先看一下例程中的主函数部分:
int main(void)
{
gd_eval_key_init(KEY_TAMPER, KEY_MODE_EXTI);
gd_eval_led_init(LED1);
while(1)
{
}
}
逻辑很简单,就是按键和LED进行初始化配置,然后就进入while(1)死循环中,监测中断的发生。
1.1 按键配置
先来看一下按键的初始化部分:
void gd_eval_key_init(key_typedef_enum key_num, keymode_typedef_enum key_mode)
{
/* enable the key clock */
rcu_periph_clock_enable(KEY_CLK[key_num]);
rcu_periph_clock_enable(RCU_SYSCFG);
/* configure button pin as input */
gpio_mode_set(KEY_PORT[key_num], GPIO_MODE_INPUT, GPIO_PUPD_NONE,KEY_PIN[key_num]);
if (key_mode == KEY_MODE_EXTI)
{
/* enable and set key EXTI interrupt to the lowest priority */
nvic_irq_enable(KEY_IRQn[key_num], 2U, 0U);
/* connect key EXTI line to key GPIO pin */
syscfg_exti_line_config(KEY_PORT_SOURCE[key_num], KEY_PIN_SOURCE[key_num]);
/* configure key EXTI line */
exti_init(KEY_EXTI_LINE[key_num], EXTI_INTERRUPT, EXTI_TRIG_FALLING);
exti_interrupt_flag_clear(KEY_EXTI_LINE[key_num]);
}
}
1.1.1 时钟配置
首先是使能按键引脚的时钟源,包括GPIO时钟和RCU时钟,通过rcu_periph_clock_enable() 调用函数来完成。
该函数就是操作寄存器:
void rcu_periph_clock_enable(rcu_periph_enum periph)
{
RCU_REG_VAL(periph) |= BIT(RCU_BIT_POS(periph));
}
1.1.2 GPIO配置
然后是按键GPIO的模式配置,通过调用gpio_mode_set() 函数来完成,该函数的声明为:
void gpio_mode_set(uint32_t gpio_periph,uint32_t mode,uint32_t pull_up_down,uint32_t pin);
参数:
gpio_periph :GPIO外设选
GPIOx (x = A,B,C,D,E,F,G,H,I)
mode:GPIO 引脚模式
GPIO_MODE_INPUT: 输入模式
GPIO_MODE_OUTPUT: 输出模式
GPIO_MODE_AF: 复用功能模式
GPIO_MODE_ANALOG: 模拟信号模式
pull_up_dowm:GPIO 引脚 “上/下拉” 设置
GPIO_PUPD_NONE: 无上/下拉
GPIO_PUPD_PULLUP: 上拉模式
GPIO_PUPD_PULLDOWN: 下拉模式
pin:GPIO 引脚选择
GPIO_PIN_x (x=0..15), GPIO_PIN_ALL
另外,这里GPIO外设与引脚使用了数组与宏定义管理,如:
gpio_mode_set(KEY_PORT[key_num], GPIO_MODE_INPUT, GPIO_PUPD_NONE,KEY_PIN[key_num]);
这句中的KEY_PORT[key_num] 与KEY_PIN[key_num] (函数调用时传入的key_num为KEY_TAMPER),找到其定义,在 "gd32f450i_eval.h"与"gd32f450i_eval.c"中有:
#define TAMPER_KEY_PIN GPIO_PIN_13
#define TAMPER_KEY_GPIO_PORT GPIOC
static uint32_t KEY_PORT[KEYn] = {WAKEUP_KEY_GPIO_PORT,
TAMPER_KEY_GPIO_PORT,
USER_KEY_GPIO_PORT};
static uint32_t KEY_PIN[KEYn] = {WAKEUP_KEY_PIN, TAMPER_KEY_PIN,USER_KEY_PIN};
所以板子上Tamper这个用户按键对应的PC13脚就是通过这样的方式定义的。
1.1.3 中断配置
接着是中断的配置,包括NVIC的配置和EXTI配置:
nvic_irq_enable(KEY_IRQn[key_num], 2U, 0U);
syscfg_exti_line_config(KEY_PORT_SOURCE[key_num], KEY_PIN_SOURCE[key_num]);
配置完后,将设置的参数初始化进行生效:
exti_init(KEY_EXTI_LINE[key_num], EXTI_INTERRUPT, EXTI_TRIG_FALLING);
exti_interrupt_flag_clear(KEY_EXTI_LINE[key_num]);
1.2 LED配置
再来看一下LED的初始化部分:
void gd_eval_led_init (led_typedef_enum lednum)
{
/* enable the led clock */
rcu_periph_clock_enable(GPIO_CLK[lednum]);
/* configure led GPIO port */
gpio_mode_set(GPIO_PORT[lednum], GPIO_MODE_OUTPUT, GPIO_PUPD_NONE,GPIO_PIN[lednum]);
gpio_output_options_set(GPIO_PORT[lednum], GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN[lednum]);
GPIO_BC(GPIO_PORT[lednum]) = GPIO_PIN[lednum];
}
首先还是调用rcu_periph_clock_enable() 函数来使能时钟,然后调用gpio_mode_set() 函数来设置模式。
另外,LED的控制引脚作为输出模式,还要调用gpio_output_options_set() 函数来设置输出配置:
void gpio_output_options_set(uint32_t gpio_periph,uint8_t otype,uint32_t speed,uint32_t pin);
参数:
gpio_periph : GPIO外设选择
GPIOx (x = A,B,C,D,E,F,G,H,I)
otype : GPIO 引脚输出模式
GPIO_OTYPE_PP: 推挽模式(push pull mode)
GPIO_OTYPE_OD: 开漏模式(open drain mode)
speed : GPIO 引脚最大输出速度(频率)
GPIO_OSPEED_2MHZ: 2MHz
GPIO_OSPEED_25MHZ: 25MHz
GPIO_OSPEED_50MHZ: 50MHz
GPIO_OSPEED_200MHZ: 200MHz
pin : GPIO 引脚选择
GPIO_PIN_x (x=0..15), GPIO_PIN_ALL
程序中使用的是:推挽模式输出,速度50MHz。LED
最后,使用GPIO_BC() 将GPIO引脚清零(Bit Clear),即低电平,这样,LED默认就是熄灭状态。
1.3 中断处理函数
中断函数在“gd32f4xx_it.c”文件中:
void EXTI10_15_IRQHandler(void)
{
if(RESET != exti_interrupt_flag_get(EXTI_13))
{
gd_eval_led_toggle(LED1);
}
exti_interrupt_flag_clear(EXTI_13);
}
当检测到按键按下时,会触发中断处理函数,这时,调用gd_eval_led_toggle() 来翻转电平,实现LED的点亮。
这个函数实际是调用库函数中的GPIO_TG() 函数:
void gd_eval_led_toggle(led_typedef_enum lednum)
{
GPIO_TG(GPIO_PORT[lednum]) = GPIO_PIN[lednum];
}
翻转过LED后,调用exti_interrupt_flag_clear() 来清除中断标志。
2 程序编译下载
编译一下,可以看到如下编译信息:
...省略若干行
compiling gd32f450i_eval.c...
assembling startup_gd32f450.s...
linking...
Program Size: Code=1564 RO-data=460 RW-data=100 ZI-data=1028
FromELF: creating hex file...
".\output\GD32450I_EVAL.axf" - 0 Error(s), 0 Warning(s).
Build Time Elapsed: 00:00:14
这里顺便说名一下这几个Program Size:
Code 是代码占用的空间。 Code=1564,即1564字节,1K多。
RO-data 是 Read Only 只读常量的大小,如const型。 RO-data=460,即460字节。
RW-data 是 Read Write 可读可写变量的大小,初始化时已经赋值的。 RW-data=100,即100字节。
ZI-data 是 Zero Initialize 没有初始化的可读可写变量的大小,没有初始化的变量都赋值一个0。 ZI-data=1028,即1028字节,1K多一点。
其中:
RW + ZI就是程序总共使用的RAM字节数。
RAM就是掉电后丢失的那种(类比计算机的内存,从来存放程序运行时的数据),这个板子的RAM(内部SRAM)有256KB。
Code + RO + RW就是程序下载到Flash中的字节数。
Flash就是掉电后不会丢失的那种,这个板子的内部Flash有3MB。
注:
虽然RAM中存储了RW与ZI变量数据,但Flash中也要存RW,因为RAM掉电后数据就丢失,而Flash可以不包含ZI,因为ZI数据都是0,只要程序运行前将ZI数据所在的区域都清0即可,包含进去则浪费存储空间。
3 效果展示
按下按键,LED亮起,再次按下,LED熄灭。
本帖最后由 DDZZ669 于 2020-9-18 22:05 编辑