FreeRTOS 中断管理之延迟中断处理 -- 二值信号量同步

2023-11-21 03:59

本文主要是介绍FreeRTOS 中断管理之延迟中断处理 -- 二值信号量同步,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

3.1 概览

3.1.1 事件:嵌入式实时操作系统需要对整个系统环境产生的事件作出反应,例如:按一下按键,灯闪一下

3.1.2 ISR 中断服务函数尽量越短越好,应快速执行完,然后退出中断服务函数

3.1.3 在中断服务函数中只能使用以 FromISR 或 FROM_ISR结尾的函数或宏

3.2 延迟中断处理

3.2.1 采用二值信号量同步

二值信号量可以在某个特殊的中断发生时,让任务解除阻塞,相当于让任务与中断同步。这样就可以让中断事件处理量大的工作在同步任务中完成,中断服务例程(ISR)中只是快速处理少部份工作。如此,中断处理可以说是被”推迟(deferred)”到一个”处理(handler)”任务。
如果某个中断处理要求特别紧急,可以将其延迟处理任务的优先级可以设为最高,以保证延迟处理任务随时都抢占系统中的其它任务。这样,延迟处理任务就成为其对应的 ISR退出后第一个执行的任务,在时间上紧接着 ISR 执行,相当于所有的处理都在 ISR 中完成一样。
在这里插入图片描述

延迟处理任务对一个信号量进行带阻塞性质的”take”调用,意思是进入阻塞态以等待事件发生。当事件发生后,ISR 对同一个信号量进行”give”操作,使得延迟处理任务解除阻塞,从而事件在延迟处理任务中得到相应的处理。

3.2.2 信号量的P、V 操作:take - P 操作,give - V操作

P 源自荷兰语 Parsseren,即英语的 Pass;V 源自荷兰语 Verhoog,即英语的 Increment。P(S)/V(S)操作是信号量的两个原子操作,S 为信号量 Semaphore,相当于一个标志,可以代表一个资源,一个事件等等,初始值视应用场合而定。
P(S) / V(S)原子操作有如下行为:
P(S) : IF (S <= 0) THEN 将本线程加入 S 的等待队列
S = S – 1
V(S) : S = S + 1
IF (S > 0) THEN 唤醒某个等待线程

在这种中断同步的情形下,信号量可以看作是一个深度为 1 的队列。这个队列由于最多只能保存一个数据单元,所以其不为空则为满(所谓”二值”)。延迟处理任务调用xSemaphoreTake()时,等效于带阻塞时间地读取队列,如果队列为空的话任务则进入阻塞态。当事件发生后,ISR 简单地通过调用 xSemaphoreGiveFromISR()放置一个令牌(信号量)到队列中,使得队列成为满状态。这也使得延迟处理任务切出阻塞态,并移除令牌,使得队列再次成为空。当任务完成处理后,再次读取队列,发现队列为空,又进入阻塞态,等待下一次事件发生。
中断给出信号量,甚至是在信号量第一次被获取之前就给出;而任务在获取信号量之后再也不给回来。在其它场合下,任务获得(Take)了信号量之后,必须得给(Give)回来。

3.3 创建信号量 vSemaphoreCreateBinary(xSemaphore)

FreeRTOS 中各种信号量的句柄都存储在 xSemaphoreHandle 类型的变量中。在使用信号量之前,必须先创建它

typedef void * QueueHandle_t;typedef QueueHandle_t SemaphoreHandle_t;#define xSemaphoreHandle    SemaphoreHandle_tSemaphoreHandle_t xSemaphore = NULL;#if (1 == configSUPPORT_DYNAMIC_ALLOCATION)
#define vSemaphoreCreateBinary(xSemaphore)    \
{ \(xSemaphore) = xQueueGenericCreate((UBaseType_t)1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE); \if ((xSemaphore) != NULL) \{ \(void)xSemaphoreGive((xSemaphore)); \} \
}
#endif

3.3.1 参数1:xSemaphore,void * 类型的,创建的信号量

需要说明的是 vSemaphoreCreateBinary()在实现上是一个宏,所以信号量变量应当直接传入,而不是传址。信号量 API 实际上是由一组宏实现的,而不是函数。
在这里插入图片描述

3.4 获取信号量,P操作, xSemaphoreTake(xSemaphore, xBlockTime)

#define xSemaphoreTake(xSemaphore, xBlockTime)    xQueueGenericReceive((QueueHandle_t)(xSemaphore), NULL, (xBlockTime), pdFALSE)

“带走(Taking)”一个信号量意为”获取(Obtain)”或”接收(Receive)”信号量。只有当信号量有效的时候才可以被获取。在经典信号量术中,xSemaphoreTake()等同于一次 P()操作。
除互斥信号量外,所有类型的信号量都可以调用函数 xSemaphoreTake() 来获取。
xSemaphoreTake()不能在中断服务函数中调用

3.5 给出信号量,V操作, xSemaphoreGiveFromISR(xSemaphore, pxHigherPriorityTaskWoken)

除互斥信号量外, FreeRTOS 支持的其它类型的信号量都可以通过调用 xSemaphoreGiveFromISR() 给出
xSemaphoreGiveFromISR() 是 xSemaphoreGive() 的特殊形式,专门用于中断服务例程中。

3.6 在STM32系列单片机上,软件模拟产生一个中断

static void vPeriodicTask(void *pvParameters)
{for(;;){/* 此任务通过每500毫秒产生一个软件中断来”模拟”中断事件 */vTaskDelay( 500 / portTICK_RATE_MS );/* 产生中断,并在产生之前和之后输出信息,以便在执行结果中直观直出执行流程 */printf("Periodic task - About to generate an interrupt.\r\n");NVIC_SetPendingIRQ(IRQn); // creat a interrupt by stm32fxx mcuprintf("Periodic task - Interrupt generated.\r\n\r\n\r\n");}
}

3.7 中断延迟服务函数,在退出中断服务函数后会立马执行该中断延迟任务,P操作

static void vHandlerTask( void *pvParameters )
{for( ;; ){/* P operation, 使用信号量等待一个事件。任务被无超时阻塞, 该任务运行到这里会被挂起 vHandlerTask, 后面的不会执行了, 直到等到了信号量才会再次运行。此处也没有必要检测返回值 */xSemaphoreTake(xBinarySemaphore, portMAX_DELAY);/* 程序运行到这里时,事件必然已经发生。本例的事件处理只是简单地打印输出一个信息 */printf("Handler task - Processing event.\r\n");}
}

3.8 中断服务函数,软件触发中断,然后执行中断服务函数,给出信号量,V操作,然后跳转到中断延迟服务函数

static void IRQHandler(void)
{static portBASE_TYPE xHigherPriorityTaskWoken;xHigherPriorityTaskWoken = pdFALSE;/* 'Give' the semaphore to unblock the task. V operation*/xSemaphoreGiveFromISR(xBinarySemaphore, &xHigherPriorityTaskWoken);if (pdTRUE == xHigherPriorityTaskWoken){portYIELD();}
}

3.9 在主函数中创建信号量 & 任务

int main(void)
{vSemaphoreCreateBinary(xBinarySemaphore); // create a semaphoreNVIC_SetPriority(IRQn, priority); // set a soft interrupt for stm32fxx mcu// check wether the semaphore has been created successif(xBinarySemaphore != NULL){/* 创建延迟处理任务。此任务将与中断同步。延迟处理任务在创建时使用了一个较高的优先级,以保证中断退出后会被立即执行。在本例中,为延迟处理任务赋予优先级3 */xTaskCreate(vHandlerTask, "Handler", 1000, NULL, 3, NULL);/* 创建一个任务用于周期性产生软件中断。此任务的优先级低于延迟处理任务。每当延迟处理任务切出阻塞态,就会抢占周期任务*/xTaskCreate(vPeriodicTask, "Periodic", 1000, NULL, 1, NULL);vTaskStartScheduler();}for(;;){}
}

3.10 任务执行流程,任务切换过程

![[Pasted image 20230626190044.png]]

这篇关于FreeRTOS 中断管理之延迟中断处理 -- 二值信号量同步的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/399668

相关文章

MyBatis延迟加载与多级缓存全解析

《MyBatis延迟加载与多级缓存全解析》文章介绍MyBatis的延迟加载与多级缓存机制,延迟加载按需加载关联数据提升性能,一级缓存会话级默认开启,二级缓存工厂级支持跨会话共享,增删改操作会清空对应缓... 目录MyBATis延迟加载策略一对多示例一对多示例MyBatis框架的缓存一级缓存二级缓存MyBat

Linux创建服务使用systemctl管理详解

《Linux创建服务使用systemctl管理详解》文章指导在Linux中创建systemd服务,设置文件权限为所有者读写、其他只读,重新加载配置,启动服务并检查状态,确保服务正常运行,关键步骤包括权... 目录创建服务 /usr/lib/systemd/system/设置服务文件权限:所有者读写js,其他

解决docker目录内存不足扩容处理方案

《解决docker目录内存不足扩容处理方案》文章介绍了Docker存储目录迁移方法:因系统盘空间不足,需将Docker数据迁移到更大磁盘(如/home/docker),通过修改daemon.json配... 目录1、查看服务器所有磁盘的使用情况2、查看docker镜像和容器存储目录的空间大小3、停止dock

5 种使用Python自动化处理PDF的实用方法介绍

《5种使用Python自动化处理PDF的实用方法介绍》自动化处理PDF文件已成为减少重复工作、提升工作效率的重要手段,本文将介绍五种实用方法,从内置工具到专业库,帮助你在Python中实现PDF任务... 目录使用内置库(os、subprocess)调用外部工具使用 PyPDF2 进行基本 PDF 操作使用

在Node.js中使用.env文件管理环境变量的全过程

《在Node.js中使用.env文件管理环境变量的全过程》Node.js应用程序通常依赖于环境变量来管理敏感信息或配置设置,.env文件已经成为一种流行的本地管理这些变量的方法,本文将探讨.env文件... 目录引言为什么使php用 .env 文件 ?如何在 Node.js 中使用 .env 文件最佳实践引

分析 Java Stream 的 peek使用实践与副作用处理方案

《分析JavaStream的peek使用实践与副作用处理方案》StreamAPI的peek操作是中间操作,用于观察元素但不终止流,其副作用风险包括线程安全、顺序混乱及性能问题,合理使用场景有限... 目录一、peek 操作的本质:有状态的中间操作二、副作用的定义与风险场景1. 并行流下的线程安全问题2. 顺

Python异常处理之避免try-except滥用的3个核心原则

《Python异常处理之避免try-except滥用的3个核心原则》在Python开发中,异常处理是保证程序健壮性的关键机制,本文结合真实案例与Python核心机制,提炼出避免异常滥用的三大原则,有需... 目录一、精准打击:只捕获可预见的异常类型1.1 通用异常捕获的陷阱1.2 精准捕获的实践方案1.3

Pandas处理缺失数据的方式汇总

《Pandas处理缺失数据的方式汇总》许多教程中的数据与现实世界中的数据有很大不同,现实世界中的数据很少是干净且同质的,本文我们将讨论处理缺失数据的一些常规注意事项,了解Pandas如何表示缺失数据,... 目录缺失数据约定的权衡Pandas 中的缺失数据None 作为哨兵值NaN:缺失的数值数据Panda

C++中处理文本数据char与string的终极对比指南

《C++中处理文本数据char与string的终极对比指南》在C++编程中char和string是两种用于处理字符数据的类型,但它们在使用方式和功能上有显著的不同,:本文主要介绍C++中处理文本数... 目录1. 基本定义与本质2. 内存管理3. 操作与功能4. 性能特点5. 使用场景6. 相互转换核心区别

Python动态处理文件编码的完整指南

《Python动态处理文件编码的完整指南》在Python文件处理的高级应用中,我们经常会遇到需要动态处理文件编码的场景,本文将深入探讨Python中动态处理文件编码的技术,有需要的小伙伴可以了解下... 目录引言一、理解python的文件编码体系1.1 Python的IO层次结构1.2 编码问题的常见场景二