任务中断的两套API函数(改进FormISR的实时性)资源管理_互斥操作的本质(解决DH11经常出错的问题)

任务中断的两套API函数

为什么需要两套 API

在任务函数中,我们可以调用各类 API 函数,比如队列操作函数:xQueueSendToBack。
但是在 ISR 中使用这个函数会导致问题,应该使用另一个函数:xQueueSendToBackFromISR,
它的函数名含有后缀"FromISR",表示"从 ISR 中给队列发送数据"。
FreeRTOS 中很多 API 函数都有两套:一套在任务中使用,另一套在 ISR 中使用。后者的
函数名含有 "FromISR" 后缀。
为什么要引入两套 API 函数?
⚫ 很多 API 函数会导致任务计入阻塞状态:
◼ 运行这个函数的 任务 进入阻塞状态
◼ 比如写队列时,如果队列已满,可以进入阻塞状态等待一会
⚫ ISR 调用 API 函数时, ISR 不是 " 任务 " , ISR 不能进入阻塞状态
⚫ 所以,在任务中、在 ISR 中,这些函数的功能是有差别的
FreeRTOS 使用两套函数,而不是使用一套函数,是因为有如下好处:
⚫ 使用同一套函数的话,需要增加额外的判断代码、增加额外的分支,是的函
数更长、更复杂、难以测试
⚫ 在任务、 ISR 中调用时,需要的参数不一样,比如:
◼ 在任务中调用:需要指定超时时间,表示如果不成功就阻塞一会
◼ 在 ISR 中调用:不需要指定超时时间,无论是否成功都要即刻返回
◼ 如果强行把两套函数揉在一起,会导致参数臃肿、无效
⚫ 移植 FreeRTOS 时,还需要提供监测上下文的函数,比如 is_in_isr()
⚫ 有些处理器架构没有办法轻易分辨当前是处于任务中,还是处于 ISR 中,就
需要额外添加更多、更复杂的代码
使用两套函数可以让程序更高效,但是也有一些缺点,比如你要使用第三方库函数时,
即会在任务中调用它,也会在 ISR 总调用它。这个第三方库函数用到了 FreeRTOS 的 API 函数,
你无法修改库函数。这个问题可以解决:
⚫ 把中断的处理推迟到任务中进行 (Defer interrupt processing) ,在任务中调用库
函数
⚫ 尝试在库函数中使用 "FromISR" 函数:
◼ 在任务中、在 ISR 中都可以调用 "FromISR" 函数
◼ 反过来就不行,非 FromISR 函数无法在 ISR 中使用
⚫ 第三方库函数也许会提供 OS 抽象层,自行判断当前环境是在任务还是在
ISR 中,分别调用不同的函数

两套 API 函数列表

区别

ISR

有任务的唤醒,但是不进行调度

在中断API中,中断的特性是必须快速执行,所以在运行中,如果有更高级的任务B来执行,那就会唤醒B,但是不会去执行B

ISR执行操作有唤醒任务,将任务放入Readylist,并记录是否有更高优先级的任务被唤醒,以便在中断结束后执行

非中断

有任务的唤醒,进行任务的调度

改进FormISR的实时性代码

cpp 复制代码
void XXX_ISR()
{
 int i;
 BaseType_t xHigherPriorityTaskWoken = pdFALSE;//保证高优先级的任务被及时执行
 
 for (i = 0; i < N; i++)
 {
 xQueueSendToBackFromISR(..., &xHigherPriorityTaskWoken); /* 被多次调用 */
 }
 /* 最后再决定是否进行任务切换
 * xHigherPriorityTaskWoken 为 pdTRUE 时才切换
 */
 portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}










/**********************************************************************
 * 函数名称: GetKeyFromBuf
 * 功能描述: 从环形缓冲区读取按键数据
 * 输入参数: 无
 * 输出参数: 无
 * 返 回 值: 0xff - 读不到数据, 其他值-按键值(device或key)
 * 修改日期:      版本号     修改人	      修改内容
 * -----------------------------------------------
 * 2023/08/04	     V1.0	  韦东山	      创建
 ***********************************************************************/
static unsigned char GetKeyFromBuf(void)
{
	unsigned char key = 0xff;
	if (!isKeysBufEmpty())
	{
		key = g_KeysBuf[g_KeysBuf_R];
		g_KeysBuf_R = NEXT_POS(g_KeysBuf_R);
	}
	return key;
}

void RegisterQueueHandle(QueueHandle_t queueHandle)
{
	if (g_queue_cnt < 10)
	{
		g_xQueues[g_queue_cnt] = queueHandle;
		g_queue_cnt++;
	}
}


static void DispatchKey(struct ir_data *pidata)
{
	BaseType_t xHigherPriorityTaskWoken = pdFALSE;
#if 0	
	extern QueueHandle_t g_xQueueCar1;
	extern QueueHandle_t g_xQueueCar2;
	extern QueueHandle_t g_xQueueCar3;

	xQueueSendFromISR(g_xQueueCar1, pidata, NULL);
	xQueueSendFromISR(g_xQueueCar2, pidata, NULL);
	xQueueSendFromISR(g_xQueueCar3, pidata, NULL);
#else
	int i;
	for (i = 0; i < g_queue_cnt; i++)
	{
		xQueueSendFromISR(g_xQueues[i], pidata, &xHigherPriorityTaskWoken);
	}
	
	portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
	
#endif	
}

资源管理_互斥操作的本质

在前面讲解互斥量时,引入过临界资源的概念。在前面课程里,已经实现了临界资源的
互斥访问。
本章节的内容比较少,只是引入两个功能:屏蔽 / 使能中断、暂停 / 恢复调度器。
要独占式地访问临界资源,有 3 种方法:
⚫ 公平竞争:比如使用互斥量,谁先获得互斥量谁就访问临界资源,这部分内
容前面讲过。
⚫ 谁要跟我抢,我就灭掉谁:
◼ 中断要跟我抢?我屏蔽中断
◼ 其他任务要跟我抢?我禁止调度器,不运行任务切换

屏蔽中断

屏蔽中断有两套宏:任务中使用、ISR 中使用:
⚫ 任务中使用: taskENTER_CRITICA()/taskEXIT_CRITICAL()
⚫ ISR 中使用:
taskENTER_CRITICAL_FROM_ISR()/taskEXIT_CRITICAL_FROM_ISR()

cpp 复制代码
void vAnInterruptServiceRoutine( void )
{
 /* 用来记录当前中断是否使能 */
 UBaseType_t uxSavedInterruptStatus;
 
 /* 在 ISR 中,当前时刻中断可能是使能的,也可能是禁止的
  * 所以要记录当前状态, 后面要恢复为原先的状态
  * 执行这句代码后,屏蔽中断
  */
 uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();
 
 /* 访问临界资源 */
 /* 恢复中断状态 */
 taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
 /* 现在,当前 ISR 可以被更高优先级的中断打断了 */
}

暂停调度器

如果有别的任务来跟你竞争临界资源,你可以把中断关掉:这当然可以禁止别的任务运
行,但是这代价太大了。它会影响到中断的处理。
如果只是禁止别的任务来跟你竞争,不需要关中断,暂停调度器就可以了:在这期间,
中断还是可以发生、处理。

cpp 复制代码
/* 暂停调度器 */
void vTaskSuspendAll( void );
/* 恢复调度器
* 返回值: pdTRUE 表示在暂定期间有更高优先级的任务就绪了
* 可以不理会这个返回值
*/
BaseType_t xTaskResumeAll( void );
相关推荐
吗喽也有梦想1 小时前
STM32F4----DCA数字量转换成模拟量
stm32·单片机·嵌入式硬件
mftang3 小时前
STM32 Nucleo-64 boards板卡介绍
stm32·单片机·嵌入式硬件
code_snow4 小时前
STM32-- 技巧-延时
stm32·单片机·嵌入式硬件
霖霖7144 小时前
基本功能实现
单片机·嵌入式硬件
Shaun_青璇4 小时前
stm32 点亮LED
stm32·单片机·嵌入式硬件·mcu·物联网
7yewh4 小时前
嵌入式硬件实战基础篇(三)-四层板PCB设计-步进电机驱动(TMC2208/TMC2209)
驱动开发·嵌入式硬件·mcu·物联网·硬件架构·硬件工程·pcb工艺
辞丶1765 小时前
STM32基于HALL库的串口以及DMA(串口总篇)
stm32·单片机·嵌入式硬件
相醉为友6 小时前
003 STM32基础、架构以及资料介绍——常识
stm32·单片机·嵌入式硬件
HZU_Puzzle6 小时前
【6】STM32·FreeRTOS·列表和列表项
stm32·单片机·嵌入式硬件