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

相关文章

Python进行JSON和Excel文件转换处理指南

《Python进行JSON和Excel文件转换处理指南》在数据交换与系统集成中,JSON与Excel是两种极为常见的数据格式,本文将介绍如何使用Python实现将JSON转换为格式化的Excel文件,... 目录将 jsON 导入为格式化 Excel将 Excel 导出为结构化 JSON处理嵌套 JSON:

在macOS上安装jenv管理JDK版本的详细步骤

《在macOS上安装jenv管理JDK版本的详细步骤》jEnv是一个命令行工具,正如它的官网所宣称的那样,它是来让你忘记怎么配置JAVA_HOME环境变量的神队友,:本文主要介绍在macOS上安装... 目录前言安装 jenv添加 JDK 版本到 jenv切换 JDK 版本总结前言China编程在开发 Java

Spring Boot Actuator应用监控与管理的详细步骤

《SpringBootActuator应用监控与管理的详细步骤》SpringBootActuator是SpringBoot的监控工具,提供健康检查、性能指标、日志管理等核心功能,支持自定义和扩展端... 目录一、 Spring Boot Actuator 概述二、 集成 Spring Boot Actuat

Spring Boot 中的默认异常处理机制及执行流程

《SpringBoot中的默认异常处理机制及执行流程》SpringBoot内置BasicErrorController,自动处理异常并生成HTML/JSON响应,支持自定义错误路径、配置及扩展,如... 目录Spring Boot 异常处理机制详解默认错误页面功能自动异常转换机制错误属性配置选项默认错误处理

MySQL多实例管理如何在一台主机上运行多个mysql

《MySQL多实例管理如何在一台主机上运行多个mysql》文章详解了在Linux主机上通过二进制方式安装MySQL多实例的步骤,涵盖端口配置、数据目录准备、初始化与启动流程,以及排错方法,适用于构建读... 目录一、什么是mysql多实例二、二进制方式安装MySQL1.获取二进制代码包2.安装基础依赖3.清

SpringBoot 异常处理/自定义格式校验的问题实例详解

《SpringBoot异常处理/自定义格式校验的问题实例详解》文章探讨SpringBoot中自定义注解校验问题,区分参数级与类级约束触发的异常类型,建议通过@RestControllerAdvice... 目录1. 问题简要描述2. 异常触发1) 参数级别约束2) 类级别约束3. 异常处理1) 字段级别约束

Java堆转储文件之1.6G大文件处理完整指南

《Java堆转储文件之1.6G大文件处理完整指南》堆转储文件是优化、分析内存消耗的重要工具,:本文主要介绍Java堆转储文件之1.6G大文件处理的相关资料,文中通过代码介绍的非常详细,需要的朋友可... 目录前言文件为什么这么大?如何处理这个文件?分析文件内容(推荐)删除文件(如果不需要)查看错误来源如何避

使用Python构建一个高效的日志处理系统

《使用Python构建一个高效的日志处理系统》这篇文章主要为大家详细讲解了如何使用Python开发一个专业的日志分析工具,能够自动化处理、分析和可视化各类日志文件,大幅提升运维效率,需要的可以了解下... 目录环境准备工具功能概述完整代码实现代码深度解析1. 类设计与初始化2. 日志解析核心逻辑3. 文件处

Java docx4j高效处理Word文档的实战指南

《Javadocx4j高效处理Word文档的实战指南》对于需要在Java应用程序中生成、修改或处理Word文档的开发者来说,docx4j是一个强大而专业的选择,下面我们就来看看docx4j的具体使用... 目录引言一、环境准备与基础配置1.1 Maven依赖配置1.2 初始化测试类二、增强版文档操作示例2.

MyBatis-Plus通用中等、大量数据分批查询和处理方法

《MyBatis-Plus通用中等、大量数据分批查询和处理方法》文章介绍MyBatis-Plus分页查询处理,通过函数式接口与Lambda表达式实现通用逻辑,方法抽象但功能强大,建议扩展分批处理及流式... 目录函数式接口获取分页数据接口数据处理接口通用逻辑工具类使用方法简单查询自定义查询方法总结函数式接口