项目背景:
1、电机转速是20000RPM ,电机转一圈触发4次中断,中断中有一个全局变量pulse_count进行累加动作;
2、在任务中,会清零这个全局变量,并且读取该变量,判断这个变量是不是达到了指定圈数;
操作:
在pulse_count++操作前加taskENTER_CRITICAL()与不加这条进入进入临界区;
现象:
加了taskENTER_CRITICAL(),系统异常,比如打断点后,没有按照想象的流程走;
分析:
该外部中断GPIO_EXIT优先级是5,正好能够调用FreeRTOS的API函数
configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY = 5:可以安全调用FreeRTOS API的最高中断优先级
SysTick的中断优先级是15,最低优先级;
考虑到以下:
- 在32位处理器上,64位变量的读取和写入操作不是原子的,需要两个32位操作来完成
所以想在pulse_count++上面添加taskENTER_CRITICAL()操作;确保原子操作;
中断触发频率:

结论:

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == Motor_FG_IT_Pin)
{
//taskENTER_CRITICAL(); // 进入临界区 我草 不能加这个代码
pulse_count++;
//taskEXIT_CRITICAL(); // 退出临界区
}
}
unsigned char task(unsigned char quanNum)
{
static unsigned int begintime = 0;
static unsigned int delaytime = 0;
unsigned char ret = 1;
uint32_t count_to_print = 0;
switch(Step)
{
case 0:
begintime = GetCurTick();
delaytime = 2000;//时间
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, 0);//低电平全速
taskENTER_CRITICAL();// 进入临界区后再操作共享变量
pulse_count = 0;
Step++;
taskEXIT_CRITICAL(); // 操作完成后立即退出临界区
ret = 1;
//debug_printf("beg SongSi\r\n");
break;
case 1://pulse_count++ 加了taskENTER_CRITICAL后,不进这里中断,感觉整个任务调度都出问题了
if(GetTickDly(begintime)>delaytime)
{
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, 100);//高电平停止
taskENTER_CRITICAL();
Step = 0;
taskEXIT_CRITICAL();
ret = 0;
}
taskENTER_CRITICAL();
if(pulse_count >= quanNum*4)
{
count_to_print = g_uTimesCount;
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, 100);//高电平停止
pulse_count = 0;
Step = 0;
ret = 0;
}
taskEXIT_CRITICAL();
break;
default:
break;
}
return ret;
}