1、GD32F427V-START例程学习笔记
1.1. Demo-01_GPIO-Running-LED
该例程实现对板载LED连接的IO引脚(PC6)设置高/低电平,实现LED的亮灭闪烁。
1.1.1. 打开项目
使用Keil打开项目文件,初次运行会提示未知设备GD32F427,可以在Keil的Pack Installer里安装对应的DFP文件包。(实际测试发现,不安装也能编译,但是下载算法需要将DFP包中的GD32F4xx_3MB.FLM文件复制到Keil安装目录的ARMFlash下,这样才能顺利下载)
1.1.2. 代码分析
分析main函数代码运行过程,首先设置systick,然后使能LED对应的GPIO的时钟,最后设置PC6为推挽输出,并初始化为低电平。
然后在无限循环中,每隔1000ms设置PC6引脚为高/底电平,实现LED的亮灭。
int main(void)
{
systick_config();
rcu_periph_clock_enable(RCU_GPIOC);
gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_6);
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
gpio_bit_reset(GPIOC, GPIO_PIN_6);
while(1) {
gpio_bit_set(GPIOC, GPIO_PIN_6);
delay_1ms(1000);
gpio_bit_reset(GPIOC, GPIO_PIN_6);
delay_1ms(1000);
}
}
1.1.3. 运行效果
编译后,下载到开发板,
1.2. Demo-02_GPIO-Key-polling-mode
1.2.1. 代码分析
本例程代码在前一个例程GPIO-Running-LED的基础上,
对连接在User Key按键上的IO引脚(PA0)设置为输入模式,
然后在无限循环中,检测该按键的电平,
当按键按下时,设置LED翻转,然后等待按键释放,如此循环往复。
int main(void)
{
systick_config();
rcu_periph_clock_enable(RCU_GPIOC);
gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_6);
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
gpio_bit_reset(GPIOC, GPIO_PIN_6);
rcu_periph_clock_enable(RCU_GPIOA);
gpio_mode_set(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN_0);
while(1) {
if(RESET == gpio_input_bit_get(GPIOA, GPIO_PIN_0)) {
delay_1ms(100);
if(RESET == gpio_input_bit_get(GPIOA, GPIO_PIN_0)) {
gpio_bit_write(GPIOC, GPIO_PIN_6, (bit_status)(1 - gpio_input_bit_get(GPIOC, GPIO_PIN_6)));
}
while(RESET == gpio_input_bit_get(GPIOA, GPIO_PIN_0)) {
}
}
}
}
1.2.2. 运行效果
编译后,下载到开发板,
1.3. Demo-03_EXTI-Key-Interrupt_mode
本例程将按键设置为中断模式,并在中断响应函数中,闪烁LED。
1.3.1. 代码分析
main函数
设置systick、LED的GPIO,同前;
PA0对应的GPIO的设置;
EXTI_0对应的NVIC中断相关的设置
int main(void)
{
/* configure systick */
systick_config();
rcu_periph_clock_enable(RCU_GPIOC);
gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_6);
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
gpio_bit_reset(GPIOC, GPIO_PIN_6);
led_flash(1);
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_SYSCFG);
gpio_mode_set(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN_0);
nvic_irq_enable(EXTI0_IRQn, 2U, 0U);
syscfg_exti_line_config(EXTI_SOURCE_GPIOA, EXTI_SOURCE_PIN0);
exti_init(EXTI_0, EXTI_INTERRUPT, EXTI_TRIG_FALLING);
exti_interrupt_flag_clear(EXTI_0);
while(1) {
}
}
在中断处理函数EXTI0_IRQHandler中,
- 首先确认是EXTI_0的中断标志,
- 然后翻转PC6的电平,
- 最后清除EXTI_0的中断标志。
void EXTI0_IRQHandler(void)
{
if(RESET != exti_interrupt_flag_get(EXTI_0)) {
gpio_bit_toggle(GPIOC, GPIO_PIN_6);
exti_interrupt_flag_clear(EXTI_0);
}
}
systick相关函数
- 内核定时器的初始化配置函数systick_config中,将其主频的1/1000,即每1ms中断一次,
- 中断处理函数SysTick_Handler中,调用delay_decrement,
- delay_decremen函数中,变量delay,果非零则减1,从而实现精确的毫秒定时。
void systick_config(void)
{
if(SysTick_Config(SystemCoreClock / 1000U)) {
while(1) {
}
}
NVIC_SetPriority(SysTick_IRQn, 0x00U);
}
void SysTick_Handler(void)
{
delay_decrement();
}
void delay_decrement(void)
{
if(0U != delay) {
delay--;
}
}
1.3.2. 运行效果
编译后,下载到开发板,运行效果同Demo-02,不再重复。
1.4. Demo-04_Timer-Key-EXTI
本例程在前一个例程的基础上,添加了Timer输出到PA6,然后PA6通过杜邦线连接到PA4,PA4也跟PA0同样设置为EXTI中断,在中断响应函数中闪烁LED.
1.4.1. 代码分析
main函数
- main函数完成key、led、systick等设置同前。
- 然后闪烁一次LED;
- 分别调用exti、gpio、timer的设置函数。
- 进入无限循环。
int main(void)
{
gd_eval_key_init(KEY_USER, KEY_MODE_EXTI);
led_config();
systick_config();
led_flash(1);
exti_config();
gpio_config();
timer_config();
while(1){
}
}
PA6设置为TIMER2_CH0的输出
void gpio_config(void)
{
rcu_periph_clock_enable(RCU_GPIOA);
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_6);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_6);
gpio_af_set(GPIOA, GPIO_AF_2, GPIO_PIN_6);
}
PA4设置为EXTI_4,并在中断响应函数EXTI4_IRQHandler中翻转LED。
void exti_config(void)
{
rcu_periph_clock_enable(RCU_GPIOA);
nvic_irq_enable(EXTI4_IRQn, 1U, 0U);
exti_init(EXTI_4, EXTI_INTERRUPT, EXTI_TRIG_FALLING);
exti_interrupt_flag_clear(EXTI_4);
}
void EXTI4_IRQHandler(void)
{
if(RESET != exti_interrupt_flag_get(EXTI_4)){
gd_eval_led_toggle(LED2);
}
exti_interrupt_flag_clear(EXTI_4);
}
Timer2设置为时钟100KHz,计数到25000/50000,在CH0分别输出高低电平。
void timer_config(void)
{
timer_oc_parameter_struct timer_ocintpara;
timer_parameter_struct timer_initpara;
rcu_periph_clock_enable(RCU_TIMER2);
timer_deinit(TIMER2);
timer_initpara.prescaler = 999;
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection = TIMER_COUNTER_UP;
timer_initpara.period = 49999;
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_initpara.repetitioncounter = 0;
timer_init(TIMER2,&timer_initpara);
timer_ocintpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
timer_ocintpara.outputstate = TIMER_CCX_ENABLE;
timer_channel_output_config(TIMER2, TIMER_CH_0, &timer_ocintpara);
timer_channel_output_pulse_value_config(TIMER2, TIMER_CH_0, 24999);
timer_channel_output_mode_config(TIMER2, TIMER_CH_0, TIMER_OC_MODE_PWM0);
timer_channel_output_shadow_config(TIMER2, TIMER_CH_0, TIMER_OC_SHADOW_DISABLE);
timer_auto_reload_shadow_enable(TIMER2);
timer_enable(TIMER2);
}
1.4.2. 运行效果
将PA6通过杜邦线连接到PA4,并接上示波器观察Timer2_CH0输出波形,
1.5. Demo-05_USB-MSC-Device
本例程实现一个USB大容量存储设备,使用MCU的USB-FS或者USB-HS模块作为USB接口,实现标准的MSC类,使用内部RAM作为存储空间,可以在PC上对存储空间进行格式化、文件读写等操作。
在编译时会出现“cannot find cortex-m4f.h”错误,原因在于CMSIS没有自动包含在编译头文件目录中,在Keil的options选项卡设置,
1.5.1. 运行效果
用另一个USB线连接USB-FS/USB-HS对应的USB接口到PC,就可以弹出新移动存储设备的窗口,格式化后,文件的复制、读写、删除等操作,与普通U盘一致。
原作者:mars4zhu