F030使用定时器中断卡死的问题

博主在使用STM32F030进行定时器初始化时遇到程序卡死的问题,通过逐步排查确定问题出在中断配置上。原本的NVIC设置中未清除中断标志,加入TIM_ClearITPendingBit()函数后解决了问题。这提示我们在处理中断时需要注意及时清除中断标志。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、出现的问题

初始化定时器,配置NVIC,然后运行,就卡死了。

原代码如下:

//初始化定时器2,10ms,NVIC设置中断优先级
static void timer2_init(void)
{
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	NVIC_InitTypeDef 		 NVIC_InitStructure;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	
	//定时器TIM2初始化 -> 10ms
	TIM_TimeBaseStructure.TIM_Period = 99; 					//自动重装载寄存器周期的值	
	TIM_TimeBaseStructure.TIM_Prescaler = 7199; 			//设置用来作为TIMx时钟频率除数的预分频值
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//TIM向上计数模式
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); 		//根据指定的参数初始化TIMx的时间基数单位	
	
	//中断优先级NVIC设置
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; 	//TIM2中断
	NVIC_InitStructure.NVIC_IRQChannelPriority = 1; 	//优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 	//IRQ通道被使能
	NVIC_Init(&NVIC_InitStructure);  					//初始化NVIC寄存器
	
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); 			//使能指定的TIM2中断,允许更新中断
    TIM_Cmd(TIM2,ENABLE);		                        //使能定时器
}
void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET){  //检查TIM2更新中断发生与否
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);      //清除TIMx更新中断标志 
	}
}

2、分析及解决

要看下是哪一段代码导致的,所以先是注释了整个定时器初始化部分,正常,所以问题定位要定时器初始化。

根据参数初始化定时器,感觉没什么问题,写错了也不至于卡死,NVIC配置的话由于涉及到中断,所以可能是中断这部分的问题,注释了NVIC_Init正常了,所以问题就在定时器中断这部分的配置。

灵光一现,想到了个错误(其实不是哈哈哈),main函数里没有设置NVIC分组,然后发现F030就没NVIC分组这回事。

然后,根据这个现象查找资料,大家不同问题导致各有各的解决方法,最终是在TIM_ITConfig前加了清除中断标志TIM_ClearITPendingBit(TIM2, TIM_IT_Update);   ,奇怪,以前我也没加没遇到这个问题,难道是F030特有的?如有知道,不吝赐教,谢谢。

现代码:

//初始化定时器2,10ms,NVIC设置中断优先级
static void timer2_init(void)
{
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	NVIC_InitTypeDef 		 NVIC_InitStructure;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	
	//定时器TIM2初始化 -> 10ms
	TIM_TimeBaseStructure.TIM_Period = 99; 					//自动重装载寄存器周期的值	
	TIM_TimeBaseStructure.TIM_Prescaler = 7199; 			//设置用来作为TIMx时钟频率除数的预分频值
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//TIM向上计数模式
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); 		//根据指定的参数初始化TIMx的时间基数单位	
	
	//中断优先级NVIC设置
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; 	//TIM2中断
	NVIC_InitStructure.NVIC_IRQChannelPriority = 1; 	//优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 	//IRQ通道被使能
	NVIC_Init(&NVIC_InitStructure);  					//初始化NVIC寄存器
	
    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);  		//清除TIMx更新中断标志 
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); 			//使能指定的TIM2中断,允许更新中断
    TIM_Cmd(TIM2,ENABLE);		                        //使能定时器
}
好的,以下是一个简单的基于GD32F303定时器2和ADC2的中断的代码示例,中断时间为100微秒: ```c #include "gd32f30x.h" void adc_config(void); void timer_config(void); uint16_t adc_value; int main(void) { adc_config(); timer_config(); while(1); } void adc_config(void) { rcu_periph_clock_enable(RCU_ADC1); rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV8); adc_sync_mode_config(ADC_SYNC_MODE_INDEPENDENT); adc_mode_config(ADC_MODE_FREE); adc_data_alignment_config(ADC1, ADC_DATAALIGN_RIGHT); adc_channel_length_config(ADC1, ADC_INSERTED_CHANNEL, 1); adc_inserted_channel_config(ADC1, 0, ADC_CHANNEL_1, ADC_SAMPLETIME_55POINT5); adc_external_trigger_source_config(ADC1, ADC_INSERTED_CHANNEL, ADC0_1_EXTTRIG_INSERTED_NONE); adc_external_trigger_config(ADC1, ADC_INSERTED_CHANNEL, ENABLE); adc_enable(ADC1); } void timer_config(void) { rcu_periph_clock_enable(RCU_TIMER2); timer_oc_parameter_struct timer_ocinitpara; timer_parameter_struct timer_initpara; timer_ic_parameter_struct timer_icinitpara; timer_deinit(TIMER2); timer_struct_para_init(&timer_initpara); timer_initpara.prescaler = 95; // 定时器分频系数 timer_initpara.alignedmode = TIMER_COUNTER_EDGE; timer_initpara.counterdirection = TIMER_COUNTER_UP; timer_initpara.period = 1000; // 定时器重载值 timer_initpara.clockdivision = TIMER_CKDIV_DIV1; timer_init(TIMER2, &timer_initpara); timer_struct_para_init(&timer_icinitpara); timer_icinitpara.icpolarity = TIMER_IC_POLARITY_FALLING; timer_icinitpara.icselection = TIMER_IC_SELECTION_DIRECTTI; timer_icinitpara.icprescaler = TIMER_IC_PSC_DIV1; timer_icinitpara.icfilter = 0x0; timer_input_capture_config(TIMER2, TIMER_CH_0, &timer_icinitpara); timer_struct_para_init(&timer_ocinitpara); timer_ocinitpara.ocpolarity = TIMER_OC_POLARITY_HIGH; timer_ocinitpara.ocoutputstate = TIMER_OC_OUTPUT_STATE_ENABLE; timer_ocinitpara.ocidlestate = TIMER_OC_IDLE_STATE_RESET; timer_ocinitpara.compare = 500; // 比较值 timer_output_compare_config(TIMER2, TIMER_CH_0, &timer_ocinitpara); nvic_irq_enable(TIMER2_IRQn, 0, 0); timer_interrupt_enable(TIMER2, TIMER_INT_CH0); timer_enable(TIMER2); } void TIMER2_IRQHandler(void) { if (timer_interrupt_flag_get(TIMER2, TIMER_INT_CH0)) { adc_software_trigger_enable(ADC1, ADC_INSERTED_CHANNEL); // ADC转换触发 while(!adc_flag_get(ADC1, ADC_FLAG_EOC)); adc_value = adc_inserted_data_read(ADC1, ADC_INSERTED_CHANNEL); timer_interrupt_flag_clear(TIMER2, TIMER_INT_CH0); } } ``` 在这个例子中,我们使用定时器2通道0的比较匹配来触发中断,ADC2在中断服务程序中进行转换并将结果存储在变量adc_value中。注意,在这个例子中,我们使用了一个简单的while循环来等待ADC转换完成,这可能会导致程序卡死。在实际应用中,您应该实现更好的等待ADC转换完成的方法,例如使用ADC转换完成中断
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值