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

相关文章

SQL Server数据库死锁处理超详细攻略

《SQLServer数据库死锁处理超详细攻略》SQLServer作为主流数据库管理系统,在高并发场景下可能面临死锁问题,影响系统性能和稳定性,这篇文章主要给大家介绍了关于SQLServer数据库死... 目录一、引言二、查询 Sqlserver 中造成死锁的 SPID三、用内置函数查询执行信息1. sp_w

Java对异常的认识与异常的处理小结

《Java对异常的认识与异常的处理小结》Java程序在运行时可能出现的错误或非正常情况称为异常,下面给大家介绍Java对异常的认识与异常的处理,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参... 目录一、认识异常与异常类型。二、异常的处理三、总结 一、认识异常与异常类型。(1)简单定义-什么是

canal实现mysql数据同步的详细过程

《canal实现mysql数据同步的详细过程》:本文主要介绍canal实现mysql数据同步的详细过程,本文通过实例图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的... 目录1、canal下载2、mysql同步用户创建和授权3、canal admin安装和启动4、canal

使用jenv工具管理多个JDK版本的方法步骤

《使用jenv工具管理多个JDK版本的方法步骤》jenv是一个开源的Java环境管理工具,旨在帮助开发者在同一台机器上轻松管理和切换多个Java版本,:本文主要介绍使用jenv工具管理多个JD... 目录一、jenv到底是干啥的?二、jenv的核心功能(一)管理多个Java版本(二)支持插件扩展(三)环境隔

Linux实现线程同步的多种方式汇总

《Linux实现线程同步的多种方式汇总》本文详细介绍了Linux下线程同步的多种方法,包括互斥锁、自旋锁、信号量以及它们的使用示例,通过这些同步机制,可以解决线程安全问题,防止资源竞争导致的错误,示例... 目录什么是线程同步?一、互斥锁(单人洗手间规则)适用场景:特点:二、条件变量(咖啡厅取餐系统)工作流

Golang 日志处理和正则处理的操作方法

《Golang日志处理和正则处理的操作方法》:本文主要介绍Golang日志处理和正则处理的操作方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考... 目录1、logx日志处理1.1、logx简介1.2、日志初始化与配置1.3、常用方法1.4、配合defer

springboot加载不到nacos配置中心的配置问题处理

《springboot加载不到nacos配置中心的配置问题处理》:本文主要介绍springboot加载不到nacos配置中心的配置问题处理,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑... 目录springboot加载不到nacos配置中心的配置两种可能Spring Boot 版本Nacos

Mysql的主从同步/复制的原理分析

《Mysql的主从同步/复制的原理分析》:本文主要介绍Mysql的主从同步/复制的原理分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录为什么要主从同步?mysql主从同步架构有哪些?Mysql主从复制的原理/整体流程级联复制架构为什么好?Mysql主从复制注意

Python中bisect_left 函数实现高效插入与有序列表管理

《Python中bisect_left函数实现高效插入与有序列表管理》Python的bisect_left函数通过二分查找高效定位有序列表插入位置,与bisect_right的区别在于处理重复元素时... 目录一、bisect_left 基本介绍1.1 函数定义1.2 核心功能二、bisect_left 与

Spring中管理bean对象的方式(专业级说明)

《Spring中管理bean对象的方式(专业级说明)》在Spring框架中,Bean的管理是核心功能,主要通过IoC(控制反转)容器实现,下面给大家介绍Spring中管理bean对象的方式,感兴趣的朋... 目录1.Bean的声明与注册1.1 基于XML配置1.2 基于注解(主流方式)1.3 基于Java