外部中断&高优先级级任务
前言:在外部中断种发送一个任务通知,引起任务切换到高优先级任务,在任务中运行耗时长的函数 BMI088_read(gyro, accel, &temp);
ulTaskNotifyTake(pdTRUE, portMAX_DELAY)
当任务调用 ulTaskNotifyTake 函数时,它将进入阻塞状态,等待接收任务通知。ulTaskNotifyTake 函数的第一个参数是一个布尔值,用于指定是否要清除任务通知的计数值。在这种情况下,参数 pdTRUE 意味着在接收到任务通知后,将自动清除计数值。
ulTaskNotifyTake 函数的第二个参数是一个超时值,用于指定任务在等待任务通知时的最长等待时间。在这里,portMAX_DELAY 表示任务将一直等待,直到接收到任务通知。
如果任务在等待任务通知期间没有被其他地方发送的任务通知唤醒,那么任务将一直保持阻塞状态。只有当任务通知被发送,并且任务成功接收到通知(返回值为 pdPASS),任务才会从 ulTaskNotifyTake 函数中解除阻塞并继续执行。
在给定的代码中,任务可能在 ulTaskNotifyTake(pdTRUE, portMAX_DELAY) != pdPASS 这一行卡住的原因可能是任务没有接收到任务通知。这可能是由于其他地方没有发送任务通知,或者发送的任务通知没有成功到达该任务。你可以检查任务通知的发送代码,确保任务通知被正确发送,并且任务通知的接收者正确处理了接收任务通知的逻辑。
portYIELD_FROM_ISR(xHigherPriorityTaskWoken)
在 FreeRTOS 中,中断服务函数通常不能直接调用任务切换函数(如 taskYIELD()),因为它们运行在中断上下文中,具有较高的优先级。为了在中断服务函数中触发任务切换,可以将任务切换请求传递给 FreeRTOS 内核,由内核在适当的时候进行任务切换。
portYIELD_FROM_ISR(xHigherPriorityTaskWoken) 宏的作用是将任务切换请求传递给 FreeRTOS 内核,并根据参数 xHigherPriorityTaskWoken 的值来确定是否进行任务切换。如果 xHigherPriorityTaskWoken 的值为 pdTRUE,则表示有更高优先级的任务需要立即执行,内核将在退出中断服务函数后立即进行任务切换。如果 xHigherPriorityTaskWoken 的值为 pdFALSE,则表示没有更高优先级的任务需要立即执行,内核将在合适的时机进行任务切换。
在给定的代码中,xHigherPriorityTaskWoken 是在 vTaskNotifyGiveFromISR 函数中传递的指针,用于指示是否有更高优先级的任务需要立即执行。如果 xHigherPriorityTaskWoken 的值为 pdTRUE,则任务切换请求将被触发。如果 xHigherPriorityTaskWoken 的值为 pdFALSE,则任务切换请求将被忽略。
这段代码来自RobomasterC板示例
void StartTask02(void *argument)
{
osDelay(500);
PID_init(&imu_temp_pid, PID_POSITION, imu_temp_PID, TEMPERATURE_PID_MAX_OUT, TEMPERATURE_PID_MAX_IOUT);
uint8_t i = BMI088_init();
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
if (HAL_SPI_Init(&hspi1) != HAL_OK)
{
Error_Handler();
}
printf("%d", i);
HAL_TIM_PWM_Start(&htim10, TIM_CHANNEL_1);
INS_task_local_handler = xTaskGetHandle(pcTaskGetName(NULL));
imu_start_flag = 1;
// printf("ok?");
for (;;)
{
while (ulTaskNotifyTake(pdTRUE, portMAX_DELAY) != pdPASS)
{
printf("ok?");
vTaskDelay(300);
}
printf("ok?");
BMI088_read(gyro, accel, &temp);
vTaskDelay(20);
PID_calc(&imu_temp_pid, temp, 40.0f);
if (imu_temp_pid.out < 0.0f)
{
imu_temp_pid.out = 0.0f;
}
tempPWM = (uint16_t)imu_temp_pid.out;
imu_pwm_set(tempPWM);
printf("l:%f,%d\n",temp,tempPWM);
}
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == INT1_ACCEL_Pin)
{
if (imu_start_flag)
{
// wake up the task
// 唤醒任务
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
{
static BaseType_t xHigherPriorityTaskWoken;
vTaskNotifyGiveFromISR(INS_task_local_handler, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
}
}
else if (GPIO_Pin == INT1_GYRO_Pin)
{
}
}