4. SysTick定时器实现精准延时

任务目标

本案例基于GD32V开发板,通过按键触发外部中断(EXTI),在中断服务函数中翻转LED的亮灭状态。核心目标是理解RISC-V中断向量、EXTI外部中断配置流程以及中断服务函数的编写与注册方法。

硬件连接

  • LED:连接到PA7(低电平点亮)
  • 按键:连接到PA0(按下为低电平),PA0同时复用为EXTI0输入

核心实现

代码基于GD32V官方固件库,完整实现EXTI0中断配置与LED翻转逻辑。关键配置步骤包括:使能GPIO与AFIO时钟、配置PA0为输入模式并连接到EXTI0、设置EXTI触发方式为下降沿、配置NVIC中断优先级并使能EXTI0中断。

#include "gd32vf103.h"

void led_gpio_init(void) {
    /* 使能GPIOA时钟 */
    rcu_periph_clock_enable(RCU_GPIOA);
    
    /* 配置PA7为推挽输出,最大速度50MHz */
    gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_7);
    /* 初始状态:LED灭(PA7输出高电平) */
    gpio_bit_set(GPIOA, GPIO_PIN_7);
}

void exti_key_init(void) {
    /* 使能GPIOA和AFIO时钟 */
    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_AF);
    
    /* 配置PA0为下拉输入 */
    gpio_init(GPIOA, GPIO_MODE_IN_PD, GPIO_OSPEED_50MHZ, GPIO_PIN_0);
    
    /* 将PA0连接到EXTI0 */
    gpio_exti_source_select(GPIO_EVENT_PORT_GPIOA, GPIO_EVENT_PIN_0);
    
    /* 配置EXTI0:下降沿触发 */
    exti_init(EXTI_0, EXTI_INTERRUPT, EXTI_TRIG_FALLING);
    exti_interrupt_flag_clear(EXTI_0);
    
    /* 配置NVIC:使能EXTI0中断,优先级1 */
    nvic_irq_enable(EXTI0_IRQn, 1, 0);
}

void EXTI0_IRQHandler(void) {
    /* 检查EXTI0中断标志 */
    if (exti_interrupt_flag_get(EXTI_0)) {
        /* 翻转PA7输出状态 */
        gpio_bit_write(GPIOA, GPIO_PIN_7, 
                       (gpio_input_bit_get(GPIOA, GPIO_PIN_7) == RESET) ? SET : RESET);
        /* 清除中断标志 */
        exti_interrupt_flag_clear(EXTI_0);
    }
}

int main(void) {
    led_gpio_init();
    exti_key_init();
    
    while (1) {
        /* 主循环为空,等待外部中断触发 */
    }
}

编译与烧录

使用RISC-V GCC工具链编译,通过OpenOCD和JTAG调试器烧录到GD32V开发板:

# 编译(假设项目文件位于当前目录)
riscv-none-embed-gcc -march=rv32imac -mabi=ilp32 -O2 -T gd32vf103_flash.ld \
    -o exti_led.elf main.c startup_gd32vf103.s system_gd32vf103.c \
    -I./ -L./ -lgd32vf103

# 生成hex文件
riscv-none-embed-objcopy -O ihex exti_led.elf exti_led.hex

# 通过OpenOCD烧录
openocd -f interface/ftdi/jtag-lock-pick_tiny_2.cfg \
        -f target/gd32vf103.cfg \
        -c "program exti_led.hex verify reset exit"

验证方法

烧录成功后,按下连接在PA0的按键,每次按下时LED(PA7)的亮灭状态应翻转一次。具体判定标准:

  • 上电后LED处于熄灭状态(PA7输出高电平)
  • 第一次按下按键,LED点亮(PA7输出低电平)
  • 第二次按下按键,LED熄灭
  • 重复按键,LED状态始终跟随按键动作翻转,无遗漏或抖动导致的异常翻转

若LED状态不变化,可通过调试器检查EXTI0_IRQHandler是否被触发,以及PA0引脚电平是否在按键按下时正确拉低。

关键机制说明

本案例的中断响应路径为:按键按下→PA0电平下降→EXTI0检测到下降沿→置位中断标志→NVIC响应中断→跳转到EXTI0_IRQHandler执行→翻转LED后清除中断标志。RISC-V内核通过中断向量表定位到对应的处理函数,GD32V的固件库已封装好向量表跳转逻辑,开发者只需实现与中断号匹配的IRQHandler函数即可。