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

相关文章

SpringBoot中使用 ThreadLocal 进行多线程上下文管理及注意事项小结

《SpringBoot中使用ThreadLocal进行多线程上下文管理及注意事项小结》本文详细介绍了ThreadLocal的原理、使用场景和示例代码,并在SpringBoot中使用ThreadLo... 目录前言技术积累1.什么是 ThreadLocal2. ThreadLocal 的原理2.1 线程隔离2

使用C++将处理后的信号保存为PNG和TIFF格式

《使用C++将处理后的信号保存为PNG和TIFF格式》在信号处理领域,我们常常需要将处理结果以图像的形式保存下来,方便后续分析和展示,C++提供了多种库来处理图像数据,本文将介绍如何使用stb_ima... 目录1. PNG格式保存使用stb_imagephp_write库1.1 安装和包含库1.2 代码解

C#使用DeepSeek API实现自然语言处理,文本分类和情感分析

《C#使用DeepSeekAPI实现自然语言处理,文本分类和情感分析》在C#中使用DeepSeekAPI可以实现多种功能,例如自然语言处理、文本分类、情感分析等,本文主要为大家介绍了具体实现步骤,... 目录准备工作文本生成文本分类问答系统代码生成翻译功能文本摘要文本校对图像描述生成总结在C#中使用Deep

Spring Boot 整合 ShedLock 处理定时任务重复执行的问题小结

《SpringBoot整合ShedLock处理定时任务重复执行的问题小结》ShedLock是解决分布式系统中定时任务重复执行问题的Java库,通过在数据库中加锁,确保只有一个节点在指定时间执行... 目录前言什么是 ShedLock?ShedLock 的工作原理:定时任务重复执行China编程的问题使用 Shed

Redis如何使用zset处理排行榜和计数问题

《Redis如何使用zset处理排行榜和计数问题》Redis的ZSET数据结构非常适合处理排行榜和计数问题,它可以在高并发的点赞业务中高效地管理点赞的排名,并且由于ZSET的排序特性,可以轻松实现根据... 目录Redis使用zset处理排行榜和计数业务逻辑ZSET 数据结构优化高并发的点赞操作ZSET 结

微服务架构之使用RabbitMQ进行异步处理方式

《微服务架构之使用RabbitMQ进行异步处理方式》本文介绍了RabbitMQ的基本概念、异步调用处理逻辑、RabbitMQ的基本使用方法以及在SpringBoot项目中使用RabbitMQ解决高并发... 目录一.什么是RabbitMQ?二.异步调用处理逻辑:三.RabbitMQ的基本使用1.安装2.架构

Linux内存泄露的原因排查和解决方案(内存管理方法)

《Linux内存泄露的原因排查和解决方案(内存管理方法)》文章主要介绍了运维团队在Linux处理LB服务内存暴涨、内存报警问题的过程,从发现问题、排查原因到制定解决方案,并从中学习了Linux内存管理... 目录一、问题二、排查过程三、解决方案四、内存管理方法1)linux内存寻址2)Linux分页机制3)

一文详解Python中数据清洗与处理的常用方法

《一文详解Python中数据清洗与处理的常用方法》在数据处理与分析过程中,缺失值、重复值、异常值等问题是常见的挑战,本文总结了多种数据清洗与处理方法,文中的示例代码简洁易懂,有需要的小伙伴可以参考下... 目录缺失值处理重复值处理异常值处理数据类型转换文本清洗数据分组统计数据分箱数据标准化在数据处理与分析过

mysql外键创建不成功/失效如何处理

《mysql外键创建不成功/失效如何处理》文章介绍了在MySQL5.5.40版本中,创建带有外键约束的`stu`和`grade`表时遇到的问题,发现`grade`表的`id`字段没有随着`studen... 当前mysql版本:SELECT VERSION();结果为:5.5.40。在复习mysql外键约

高效管理你的Linux系统: Debian操作系统常用命令指南

《高效管理你的Linux系统:Debian操作系统常用命令指南》在Debian操作系统中,了解和掌握常用命令对于提高工作效率和系统管理至关重要,本文将详细介绍Debian的常用命令,帮助读者更好地使... Debian是一个流行的linux发行版,它以其稳定性、强大的软件包管理和丰富的社区资源而闻名。在使用