前言
上节我们讲了 GD32VF103CBT6的点灯与按键的外部中断的NucleiStudio工程:
GD32VF103_环境配置_GPIO_外部中断
本节我们继续点灯, 只不过用定时器中断的方式2s翻转一次灯的状态.
新建工程
- File -> New -> C/C++ Project, 选择C Managed Build
- 选择GigaDevice RISC-V Project, 填入工程名
- MCU默认暂时只有GD32VF103, 然后Demo也没法选, 只有Running_LED, 不变
- 下一步, 完成.
定时器
具体可参考 GD32VF103用户手册:
我们要做的就是 设置预分频器降频, 向上计数到预设的计数值就产生了定时器中断, 中断中清除中断标志位, 定时器会自动加载计数值, 重新从0开始计数.
定时器中断代码
main.c我们删掉代码, 重新改为:
#include "gd32vf103.h"
#include "systick.h"
#define LED_PIN GPIO_PIN_7
#define LED_GPIO_PORT GPIOA
#define LED_GPIO_CLK RCU_GPIOA
void led_config(void) {
rcu_periph_clock_enable(LED_GPIO_CLK); //enable the peripherals clock
gpio_init(LED_GPIO_PORT, GPIO_MODE_OUT_PP,
GPIO_OSPEED_50MHZ, LED_PIN); //GPIO output with push-pull
GPIO_BC(LED_GPIO_PORT) = LED_PIN; //bit clear
}
void led_toggle(void) {
gpio_bit_write(LED_GPIO_PORT, LED_PIN,
(bit_status)(1-gpio_input_bit_get(LED_GPIO_PORT, LED_PIN)));
}
void timer_config(uint32_t timer_periph, uint32_t time_interval_ms) {
timer_parameter_struct timer_initpara;
switch(timer_periph){
case TIMER0:
rcu_periph_clock_enable(RCU_TIMER0);
break;
case TIMER1:
rcu_periph_clock_enable(RCU_TIMER1);
break;
case TIMER2:
rcu_periph_clock_enable(RCU_TIMER2);
break;
case TIMER3:
rcu_periph_clock_enable(RCU_TIMER3);
break;
case TIMER4:
rcu_periph_clock_enable(RCU_TIMER4);
break;
case TIMER5:
rcu_periph_clock_enable(RCU_TIMER5);
break;
case TIMER6:
rcu_periph_clock_enable(RCU_TIMER6);
break;
default:
break;
}
timer_deinit(timer_periph);
timer_struct_para_init(&timer_initpara);
timer_initpara.prescaler = 10799; //108M/10800 = 10K Hz
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection = TIMER_COUNTER_UP;
timer_initpara.period = (uint32_t)10*time_interval_ms;//(uint32_t)1000000U/time_interval_us;
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_init(timer_periph, &timer_initpara);
timer_interrupt_enable(timer_periph, TIMER_INT_UP); //update interrupt
timer_enable(timer_periph);
}
int main(void) {
led_config();
eclic_global_interrupt_enable();
eclic_set_nlbits(ECLIC_GROUP_LEVEL3_PRIO1);
eclic_irq_enable(TIMER3_IRQn,1,0);
timer_config(TIMER3, 2000); //2s
while(1) {
}
return 0;
}
void TIMER3_IRQHandler(void) {
if(SET == timer_interrupt_flag_get(TIMER3, TIMER_INT_FLAG_UP)){
/* clear channel 0 interrupt bit */
timer_interrupt_flag_clear(TIMER3, TIMER_INT_FLAG_UP);
led_toggle();
}
}
我们设置定时器预分配(prescaler)为10799, 也就是定时器的时钟为108M / 10800 = 10K Hz
, 一个周期计数 2000 * 10 = 20K
, 所以一个周期 20K / 10K = 2s
.
调试运行, 可以看到灯2s翻转一次状态.