任务中断的两套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 );
相关推荐
m0_748254091 小时前
STM32--超声波模块(HC—SR04)(标准库+HAL库)
stm32·单片机·嵌入式硬件
南城花随雪。1 小时前
单片机:实现FFT快速傅里叶变换算法(附带源码)
单片机·嵌入式硬件·算法
逝灮2 小时前
【蓝桥杯——物联网设计与开发】基础模块8 - RTC
stm32·单片机·嵌入式硬件·mcu·物联网·蓝桥杯·rtc
LXL_242 小时前
模拟——郑益慧_笔记1_绪论
嵌入式硬件
weixin_452600698 小时前
串行时钟保持芯片D1380/D1381,低功耗工作方式自带秒、分、时、日、日期、月、年的串行时钟保持芯片,每个月多少天以及闰年能自动调节
科技·单片机·嵌入式硬件·时钟·白色家电电源·微机串行时钟
森旺电子11 小时前
51单片机仿真摇号抽奖机源程序 12864液晶显示
单片机·嵌入式硬件·51单片机
不过四级不改名67713 小时前
蓝桥杯嵌入式备赛教程(1、led,2、lcd,3、key)
stm32·嵌入式硬件·蓝桥杯
小A15913 小时前
STM32完全学习——SPI接口的FLASH(DMA模式)
stm32·嵌入式硬件·学习
Rorsion13 小时前
各种电机原理介绍
单片机·嵌入式硬件
善 .16 小时前
单片机的内存是指RAM还是ROM
单片机·嵌入式硬件