任务中断的两套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 );
相关推荐
2501_9226395814 小时前
率能半导体 SS6635E直流双向马达驱动芯片:30V/4.5A,覆盖电子锁、玩具、无线充电、机器人四大应用场景
单片机·嵌入式硬件·硬件工程
wuyk55514 小时前
TinyML 初探:在 MCU 上部署异常检测模型,实现本地振动故障诊断
stm32·单片机·嵌入式硬件·重构
新晨单片机设计14 小时前
S031A-基于STM32单片机指纹考勤系统【Proteus仿真+Keil程序+原理图】
stm32·单片机·嵌入式硬件·proteus·指纹考勤系统
新时代牛马14 小时前
`arch_timer`、`IPI5`、`HRTIMER`、`ksoftirqd` 的关系
网络·单片机·tcp/ip
元器件BOM超人15 小时前
STM32F103R8T6 中密度Cortex-M3 MCU 解析
stm32·单片机·嵌入式硬件
服务器硬件项目经理15 小时前
《超节点修仙录》· 第一卷·炼气期【第02话】 超节点的「身体构造」——CPU、GPU、内存、网卡都是干啥的
服务器·嵌入式硬件·gru·硬件工程·硬件
萌动的小火苗15 小时前
PCB设计中线宽、线距与过孔的基本概念
嵌入式硬件·pcb工艺
少卿.55515 小时前
wokwi搭建仿真超声波雷达测距判断(保姆级教学)
单片机·嵌入式硬件·arduino
工控存储研习16 小时前
嵌入式设备启动时间优化:从上电到应用就绪,每一毫秒怎么抠
arm开发
C++ 老炮儿的技术栈16 小时前
机器人的坐标,像 XYZ 的坐标值,是用单精度浮点还是用双精度浮点?
c语言·c++·人工智能·单片机·c