AT-START-F425提供了官方例程,还是相当齐全的,在外部中断例程中,看到了2个例程,分别是外部中断以及软件触发中断
具体代码位于 AT32F425_Firmware_Library_V2.0.1\project\at_start_f425\examples\exint
外部中断触发毕竟简单,就是用户按键
具体代码及解释如下
void exint_line0_config(void)
{
exint_init_type exint_init_struct; //外部中断结构体
crm_periph_clock_enable(CRM_SCFG_PERIPH_CLOCK, TRUE); //开启端口复用时钟,便于将端口挂在外部中断线上
crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE); //开启端口A时钟,用户按键是连接的PA0
scfg_exint_line_config(SCFG_PORT_SOURCE_GPIOA, SCFG_PINS_SOURCE0); //将PA0挂在外部中断线上
exint_default_para_init(&exint_init_struct); //初始化结构体变量
exint_init_struct.line_enable = TRUE;
exint_init_struct.line_mode = EXINT_LINE_INTERRUPUT;
exint_init_struct.line_select = EXINT_LINE_0; //外部0号中断,对应管脚0
exint_init_struct.line_polarity = EXINT_TRIGGER_RISING_EDGE; //上升沿触发
exint_init(&exint_init_struct);
nvic_priority_group_config(NVIC_PRIORITY_GROUP_4); // < 4 bits for preemption priority, 0 bits for subpriority > 可见配置的是全抢占中断,没有响应中断
nvic_irq_enable(EXINT1_0_IRQn, 1, 0); //抢占优先级1级
}
/**
* [url=home.php?mod=space&uid=159083]@brief[/url] exint0 interrupt handler
* @param none
* @retval none
*/
void EXINT1_0_IRQHandler(void)
{
if(exint_flag_get(EXINT_LINE_0) != RESET) //中断标志位置位?
{
at32_led_toggle(LED2); //各LED翻转
at32_led_toggle(LED3);
at32_led_toggle(LED4);
exint_flag_clear(EXINT_LINE_0); //中断标志位清零
}
}
按下用户按钮,触发外部0号中断,中断例程中直接翻转LED2\3\4
运行过程中发现,有时候会产生错乱,按照代码,应该是上升沿触发或者设置成下降沿,但有时候会出现一次按键触发两次翻转的情况,应该是按钮电路部分未做处理导致的,建议后面的开发板中按钮两端并联一颗电容。
另一个中断是软件触发中断,比较有意思
main函数设置的是全部抢占优先级
nvic_priority_group_config(NVIC_PRIORITY_GROUP_4); //全部抢占优先级
定时器设置函数
static void tmr1_config(void)
{
crm_clocks_freq_type crm_clocks_freq_struct = {0};
/* get system clock */
crm_clocks_freq_get(&crm_clocks_freq_struct);
//上述两行代码感觉是多余的,因为后面没有用到这个结构及数组
//打开定时器1时钟,实际应该是打开总线,使能定时器1的总线
crm_periph_clock_enable(CRM_TMR1_PERIPH_CLOCK, TRUE);
/* (systemclock / (system_core_clock/10000)) / 10000 = 1Hz(1s) */
//由于系统主频为96Mhz,分频10000后,即system_core_clock/10000 = 9.6Khz
//以9.6Khz计数10000个数,即9600 / 10000 = 0.96s 约为1Hz
tmr_base_init(TMR1, 10000-1, system_core_clock/10000-1);
tmr_cnt_dir_set(TMR1, TMR_COUNT_UP); //向上计数
tmr_clock_source_div_set(TMR1, TMR_CLOCK_DIV1); //不分频
tmr_interrupt_enable(TMR1, TMR_OVF_INT, TRUE); //溢出中断,即0.96S产生一次中断
nvic_irq_enable(TMR1_BRK_OVF_TRG_HALL_IRQn, 0, 0); //前面0抢占优先级,后面0响应优先级
}
定时器中断例程
void TMR1_BRK_OVF_TRG_HALL_IRQHandler(void)
{
if(tmr_flag_get(TMR1,TMR_OVF_FLAG) != RESET)
{
at32_led_toggle(LED2); //LED2翻转
exint_software_interrupt_event_generate(EXINT_LINE_4); //软件设置外部4号中断标志位
tmr_flag_clear(TMR1,TMR_OVF_FLAG);
}
}
外部中断4号设置
void exint_line4_config(void)
{
exint_init_type exint_init_struct;
crm_periph_clock_enable(CRM_SCFG_PERIPH_CLOCK, TRUE);
exint_default_para_init(&exint_init_struct);
exint_init_struct.line_enable = TRUE;
exint_init_struct.line_mode = EXINT_LINE_INTERRUPUT;
exint_init_struct.line_select = EXINT_LINE_4;
exint_init_struct.line_polarity = EXINT_TRIGGER_FALLING_EDGE; //EXINT_TRIGGER_FALLING_EDGE EXINT_TRIGGER_RISING_EDGE
exint_init(&exint_init_struct);
exint_flag_clear(EXINT_LINE_4);
nvic_irq_enable(EXINT15_4_IRQn, 1, 0); //抢占优先级1,响应优先级0
}
由于是软件触发,所以觉得上升沿和下降沿的设置效果是一样的
中断例程中翻转LED3\4
void EXINT15_4_IRQHandler(void)
{
if(exint_flag_get(EXINT_LINE_4) != RESET)
{
at32_led_toggle(LED3); //LED3\4翻转
at32_led_toggle(LED4);
exint_flag_clear(EXINT_LINE_4);
}
}
按照软件逻辑,定时器1溢出中断例程中软件触发外部4号中断,LED2翻转后,在外部4号中断中LED3\4翻转
这个时间差应该是感觉不到的,也就是LED2\3\4应该一起翻转,可实际效果
从优先级的角度来说,定时器1号设置的中断优先级更高,外部4号中断级别要低,所以这种情况,应该是程序启动时,就产生了外部4号中断,然后定时器1才产生溢出中断。
但是还没找到外部4号中断标志位置位的相关部分。
引用: Jacktang 发表于 2022-4-24 09:14 那外部4号中断标志是怎么回事
外部4号是定时器中断中软件设置的
引用: lugl4313820 发表于 2022-4-25 08:32 很用心的学习了,感谢分享。有空也得学习学习中断。
惭愧啊,复杂的感觉没精力,也没时间,只能整点简单的了。感谢大佬的鼓励!