1.FreeRTOS系列教程(四):如何使用信号量
2.在学习freertos之前,源码应学习哪些东西
3.如何在项目中使用RTOS分析工具SystemView?
4.FreeRTOSv202212.01移植到STM32
5.keil AC6移植freeRTOS解决(100+)报错问题
6.嵌入式实时操作系统RTOS市场和技术发展的源码变化
FreeRTOS系列教程(四):如何使用信号量
大家好,我是源码旭辉君,一个智能硬件领域深度探索的源码技术博主。
在上篇文章中,源码我们理解了在FreeRTOS中如何使用消息队列进行任务间的源码黄金溯源码数据传递,链接如下:
本文我们就一起来探索信号量的源码使用。所谓信号量,源码可以简单的源码理解为就是一个状态标志,我们可以用这个状态标志来进行任务间的源码同步,有序访问,源码或者互斥访问。源码从这些对于信号量不同的源码应用,常用的源码信号量可以分为:
本文我们将重点讲述二值信号量与计数信号量的使用。互斥信号量放在下一篇文章讲解。源码通过本文,我们将会知道:
接下来让我们一起,进入信号量的探索之旅!
如前文所述,信号量可以提供任务间数据的同步机制。我们假设有两个任务TaskA和TaskB,其中TaskB等待TaskA产生的数据并进行处理,按照之前我们在裸机编程时候的思路,一般都是设置一个全局变量,然后在while1中轮流执行这两个任务,若TaskA产生的数据让这个全局变量发生改变,TaskB在轮询到之后就能处理这些数据,但是,如果TaskA里面的数据久久不发生改变,那么一直轮询TaskB就是无效的,CPU做了许多的无用功。
所以应该怎么优化呢?
假若在TaskA数据发生不改变的时候,TaskB进入阻塞态不执行,当TaskA数据发生改变的时候才去执行TaskB,这样就不会浪费CPU的资源。为此,FreeRTOS引入了信号量(Semaphore)概念,通过信号量的同步机制可以使任务在数据还没到达的时候进入阻塞状态,在数据到达之后才得以执行,提高系统资源利用率。筹码承接指标源码
二进制信号量只有两个状态,只能用于两个任务间的同步;计数信号量中信号量的数目可以自定义设定为多个,可用于多个任务间的同步。
创建信号量时, 系统会为创建的信号量对象分配内存, 二值信号量的最大可用信号量个数为 1。创建成功后,任何任务都可以从创建的二值信号量资源中获取这个二值信号量,获取成功则任务继续运行, 否则任务会根据用户指定的阻塞超时时间来等待其它任务或者中断释放信号量。在等待这段时间,系统将任务变成阻塞态, 任务将被挂到该信号量的阻塞等待列表中。下图为任务获取信号量时的示意图:获取信号量无效时任务进入阻塞,其他任务释放信号量后,信号量有效,该任务恢复为就绪态。
相比于二值信号量,计数信号量允许多个任务获取同一个信号量,这多个任务的数目可以由我们设定。比如我们设定,某个资源只能有 3 个任务访问,那么第 4 个任务访问的时候,会因为获取不到信号量而进入阻塞,等到有任务(比如任务 1)释放掉该资源的时候,第 4 个任务才能获取到信号量从而进行资源的访问,其运作的机制具体见下图:
观察信号量控制块结构体以及信号量创建函数的源码,我们就会惊奇的发现:FreeRTOS 的信号量控制块结构体与消息队列结构体是一模一样的!信 号 量 的 创 造 实 际 调 用 的 函 数 xQueueGenericCreate()也与消息队列一样!只是参数或者其代表的意义有一些差异。
所以我们可以理解为:信号量就是一种特殊的消息队列!由于我们只关注信号状态,不关注消息内容,这个队列就没有设置消息存储空间。
其中,xSemaphoreCreateBinary()是一个宏定义,展开后调用xQueueGenericCreate(),也就是上一篇文章我们创建队列时候使用的函数,只是nft市场源码传递的参数不同。
与二值信号量一样,xSemaphoreCreateCounting()展开后也是调用xQueueGenericCreate(),创建的计数信号量只有消息队列控制块结构体存储空间而没有消息存储空间 。
删除信号量函数vSemaphoreDelete()是一个宏定义,其调用的是vQueueDelete()函数。删除信号量过程其实就是删除消息队列过程, 因为信号量其实就是特殊的,无法存储消息的消息队列。
xSemaphoreGive()是一个用于释放信号量的宏, 真正的实现该过程是调用消息队列通用发送函数xQueueGenericSend()。释放信号量实际上是一次入队操作,并且阻塞时间为0,也就是释放信号量时,如果信号量计数值已满,就返回信号量释放错误。
xSemaphoreTake()是一个用于获取信号量的宏, 真正的实现该过程是调用消息队列通用接收函数xQueueGenericReceive()。信号量获取实际上就是一次消息出队操作,所以我们也可以按照消息队列的接收机制来理解信号量的获取:当有任务试图获取信号量的时候,当且仅当信号量有效,也就是队列中存在可用信号量的时候,任务才能获取到信号量。
如果信号量无效,在用户指定的阻塞超时时间中,该任务将保持阻塞状态以等待信号量有效。在阻塞超时等待的时间内,如果有其它任务或中断释放了有效的信号量,该任务将自动由阻塞态转移为就绪态。如果任务等待的时间超过了指定的阻塞时间,即使信号量中还是没有可用信号量,任务也会自动从阻塞态转移为就绪态。
创建三个任务,task_example_1,task_example_2和task_example_3。其中task_example_1用于计时,每3s让task_example_2释放二值信号量,task_example_3用于信号量获取,在获取不到信号量的时候一直死等。主体代码如下:
下图为运行后的鸿蒙2.0源码解析串口输出结果:可以看到,cnt计数的时候,每3s释放一个二值信号量,然后立即就能被获取到,实现了Task2与Task3两个任务间的同步。
创建计数信号量xSemaphoreCreateCounting(5,3),其中参数5表示最大可容纳五个状态,任务每获取一个信号量,信号量计数减一,每释放一个信号量,信号量计数加一。初始值为3,表示初始里面已经有了三个信号量。同样三个任务,task_example_3每ms获取一个信号量, task_example_2每2s释放一个信号量,task_example_1用于每1s的计时显示。程序主体代码如下:
运行程序后串口输出如下:可以看到,初始计数信号量有3个,随着不断获取,计数信号量为空,之后就获取失败,只有计数信号量释放后才能继续获取。
本文主要探索了二值信号量与计数信号量的原理及其使用方法,包括信号量的原理,信号量的运行机制,信号量与消息队列的比较,信号量的相关API函数,以及信号量的使用实验等。通过本文,不知道大家对第一节的几个问题,有没有自己的答案。有疑问的同学,欢迎评论区留言交流。原创不易,大家的点赞和关注是对我持续更新最大的鼓励,谢谢!也为坚持看到系列文章此处的你点赞!
想要文中工程源码的同学,可以关注我的码易销源码微信公众号:硬件电子与嵌入式小栈,留言:freertos源码 即可获取。同时我还整理了一些学习FreeRTOS实用的书籍资料,公众号留言:freertos资料 即可获取。公众号里也会不定期更新干货文章哦。
在学习freertos之前,应学习哪些东西
学习FreeRTOS前的准备工作 这里只要做好两点就可以了。 1, 从官网下载最新的程序包 2, 官网有FreeRTOS每个函数的API说明,已经相应API的例子,其实源码的.h文件里面也有大部分函数的使用例子 教程计划 1 先把自己做的这几个例子讲解一下,关键是分析一下源码,源码必须得分析,要不知其然不知其所以然。 2 然后把官方的这几个例子讲解一下,说这几个例子的主要目的是充分学习官方是如何使用这个RTOS的,非常有参考价值。 3 针对我们板子自己的外设,做一套完整的,基于FreeRTOS的底层驱动,让这些驱动能够更加有效的在FreeRTOS下面工作。在学习freertos之前,应学习哪些东西
如何在项目中使用RTOS分析工具SystemView?
在RTOS应用设计中,开发者往往难以直接观察到多任务系统运行时的实时行为,因为这些行为不仅受源代码影响,还与任务、中断、输入及其相互作用紧密相关。为解决这一问题,可视化分析工具如SEGGER公司的SystemView应运而生。SystemView提供全面洞察,通过时间轴、CPU负载、运行时间信息和上下文运行时信息的可视化窗口,帮助开发者深入理解应用的执行过程。
本文将介绍如何使用Segger J-Link和NXP LPC开发板,实现SystemView的移植与使用,以FreeRTOS .3.0版本为例。SystemView支持多种RTOS系统,包括uC/OS-II、μC/OS-III、FreeRTOS、embOS和裸机系统。
SystemView工作模式包括持续记录、Single-Shot和Post-Mortem模式。持续记录模式通过J-Link调试器和实时传输技术(RTT)实现,实时记录目标程序运行情况。Single-Shot模式适用于不支持RTT或未使用J-Link的情况,记录数据直至缓冲区满为止。Post-Mortem模式在缓冲区满时覆盖旧事件,用于分析系统崩溃前的情况。
为了在目标设备上使用SystemView,首先需要在应用工程中添加SystemView和RTT的源码文件。这包括配置文件、实现源码和针对不同OS及版本的接口文件。配置FreeRTOS跟踪功能,通过编译宏在FreeRTOSConfig.h中包含SystemView相关代码。此外,还需设置SystemView工作模式、事件缓存大小,并在任务创建前调用初始化函数。
在PC端,安装和设置SystemView软件。通过Target->Recorder Configuration选项配置目标设置、调试接口类型和接口速度。选择Auto检测RTT控制块地址。点击Target->Start Recording开始跟踪记录。在持续记录模式下,跟踪视图显示RTOS应用中的中断和任务,直观展示任务抢占过程,有助于开发者优化代码。
借助SystemView,开发者能更直观地理解RTOS应用的实时行为,有效提升代码质量,创造更高性能的系统。
FreeRTOSv.移植到STM
介绍
将FreeRTOSv.移植到STMFC8T6单片机的过程概述。此版本为当前最新,适用于开发者进行系统级编程。
硬件平台
选用STMFC8T6作为移植目标,此型号单片机提供丰富的外设资源,适合各种嵌入式应用。
软件架构与操作步骤
1. 从freertos.org/zh-cn-cmn下载源代码。注意,V9.0以后版本由Amazon收购后开发,V9.0被认为较为稳定。本文档介绍的移植方法适用于最新版本,与旧版本相比,源代码变化不大,可进行对比学习。
2. 解压源码并复制FreeRTOS目录内容至项目目录下。删除除Source文件夹外的所有文件,Source文件夹是核心模块,包含实际移植所需的文件。
3. 进入Source文件夹,删除非源代码文件,保留include和portable目录,前者包括头文件,后者为接口文件。
4. 进入Source下的portable文件夹,删除非必要的文件和文件夹(如RVDS和MemMang),仅保留与M3内核相关的ARM_CM3接口文件以及heap_4.c,其余可保留但暂不使用。
5. 从FreeRTOSv.\FreeRTOS\Demo\CORTEX_STMF_Keil复制FreeRTOSConfig.h至include文件夹。此配置文件用于系统裁剪。
6. 将保留的文件添加到工程中,并配置文件路径。确保编译无错误。
创建任务的详细步骤
在main.c文件中,创建任务。关注stmfx_it.h文件,增加xPortSysTickHandler外部声明,并注释掉SVC_Handler和PendSV_Handler。SysTick_Handler作为定时器回调函数,用于调度处理。
在FreeRTOSConfig.h中添加中断宏定义,由port.c中的汇编语言实现,用于任务启动和切换。设置INCLUDE_xTaskGetSchedulerState为1。
在main.h中加入RTOS头文件,包含操作系统所需的所有调用文件。
至此,重新编译即可运行程序。最后,确保工程总目录包含标准库stdlib(3.5.0版本),以支持完整的硬件抽象层。
keil AC6移植freeRTOS解决(+)报错问题
在使用keil移植freeRTOS时,需注意ac5与ac6编译器差异导致移植port文件.c和.h时可能出现报错问题。移植过程遵循以下步骤:
首先,下载freeRTOS源码,网络上教程丰富。
其次,在hal库或校准库下建立文件,接着移植源码,注意删除无用内容。
然后,将移植的.c和.h文件在keil中关联起来,编译过程中会显示未使用功能的报错信息,需针对具体错误注释或删除相关代码。
特别注意,在port.c文件中包含头文件(如f示例),之后编译时若发现函数重定义错误,应根据报错内容注释到相应的函数。
对于stmf4xx_it.c文件,确保注释或删除PendSV_Handler、SysTick_Handler和SVC_Handler,避免此类函数的未定义导致的报错。
解决报错的关键在于定义freeRTOS中未使用的钩子函数(vApplicationStackOverflowHook、vApplicationIdleHook、vApplicationTickHook 和 vApplicationMallocFailedHook),即使不实际使用,也需提供空定义以确保编译通过。
具体实现方式是将空定义添加到项目源文件中,例如main.c文件。正确操作后,所有报错解决,移植freeRTOS至keil AC6过程完成。
嵌入式实时操作系统RTOS市场和技术发展的变化
随着世纪年代的到来,RTOS在嵌入式系统设计中的主导地位日益稳固,众多工程师纷纷选择使用预置的RTOS,而非自建。技术发展方面,呈现了以下几个关键点:
首先,为适应日益多样化的微处理器,RTOS的设计趋向于更加灵活和可移植。新的处理器技术推动了RTOS能在短时间内支持多种硬件平台,提升了其适用性。
其次,开源趋势也影响到了RTOS市场。越来越多的RTOS供应商开始提供源代码,甚至包含生产版税,以满足开发者对于灵活性和降低成本的需求。
在后PC时代,对实时性要求不高的产品,如手持设备,开始广泛采用RTOS,如微软的WinCE、Plam OS和Java OS等,这些产品正是针对这些新兴应用场景进行的定制开发。
对于电信设备和控制系统,高可靠性成为新要求。例如,瑞典Enea公司的OSE和WindRiver的Vxwork AE着重于支持高可用性和热切换功能,以满足此类应用的严格标准。
然而,RTOS市场的格局并非一成不变。Windriver收购ISI后一度形成垄断,但其决定放弃PSOS,转而发展Vxwork与PSOS融合版本,这为其他RTOS供应商提供了新的竞争机会,使得用户有了更多选择。
最后,嵌入式Linux在消费电子领域崭露头角,韩国和日本的企业已将其应用在手持设备上。这一趋势得到了Intel和Motorola等半导体厂商的大力支持与投资,显示出嵌入式Linux市场的强劲增长势头。
FreeRTOS移植过程-STM基于STMCubeMX环境
移植FreeRTOS到STM微控制器的过程相对直接,得益于FreeRTOS提供的示例和支持STM HAL库。以下是关键步骤的概述:
首先,使用STMCubeMX创建新项目,配置好MCU系列、型号、时钟设置及所需外设。
接着,集成FreeRTOS,STMCubeMX会帮助你添加必要的代码和配置文件。配置周期性中断,通常通过STM的硬件定时器来触发FreeRTOS调度。
内存管理是关键,FreeRTOS提供了多种方案,需在`FreeRTOSConfig.h`中选择。调整任务堆栈大小和优先级,根据应用需求选择静态或动态分配方式。
确保上下文切换和中断管理代码与STM系列兼容,可能涉及特定Cortex-M核心的细节。同时,确认使用的编译器与FreeRTOS兼容。
将FreeRTOS源代码添加到项目,编译并链接,可能需要修改`FreeRTOSConfig.h`以适应需求。通过调试器加载到设备,检查初始化和中断功能。
运行基础示例任务如LED闪烁或串口通信,验证系统运行。进一步进行性能和稳定性测试,确保移植的稳定性和效率。
移植过程可能因所选STM系列和开发环境的不同而有所差异。STMCubeMX和STMCubeIDE提供了FreeRTOS集成,简化配置步骤。在其他环境,可能需要更手动地进行配置。