1.在学习freertos之前,源码应学习哪些东西
2.keil AC6移植freeRTOS解决(100+)报错问题
3.FreeRTOS系列教程(四):如何使用信号量
4.FreeRTOS递归互斥信号量
5.FreeRTOS简介
6.FreeRTOS移植过程-STM32基于STM32CubeMX环境
在学习freertos之前,源码应学习哪些东西
学习FreeRTOS前的源码准备工作 这里只要做好两点就可以了。 1,源码 从官网下载最新的程序包 2, 官网有FreeRTOS每个函数的API说明,已经相应API的源码例子,其实源码的源码会计公司网站源码.h文件里面也有大部分函数的使用例子 教程计划 1 先把自己做的这几个例子讲解一下,关键是源码分析一下源码,源码必须得分析,源码要不知其然不知其所以然。源码 2 然后把官方的源码这几个例子讲解一下,说这几个例子的源码主要目的是充分学习官方是如何使用这个RTOS的,非常有参考价值。源码 3 针对我们板子自己的源码外设,做一套完整的源码,基于FreeRTOS的源码底层驱动,让这些驱动能够更加有效的在FreeRTOS下面工作。在学习freertos之前,应学习哪些东西
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),即使不实际使用,php 转静态源码也需提供空定义以确保编译通过。
具体实现方式是将空定义添加到项目源文件中,例如main.c文件。正确操作后,所有报错解决,移植freeRTOS至keil AC6过程完成。
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(),终极买点指标源码也就是上一篇文章我们创建队列时候使用的函数,只是传递的参数不同。
与二值信号量一样,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用于信号量获取,在获取不到信号量的时候一直死等。主体代码如下:
下图为运行后的c 仿 皮肤 源码串口输出结果:可以看到,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递归互斥信号量
递归互斥信号量是一种特殊的互斥信号量,不同于普通互斥信号量,已经获取递归互斥信号量的任务可以再次获取此信号量,即任务可以嵌套使用,次数不限。递归互斥信号量同样需解决优先级继承问题,获取的次数必须释放相同的次数,且不能在中断服务函数中使用。
递归互斥信号量的实现通过宏调用xQueueCreateMutex()函数创建,此函数源码细节参考互斥信号量章节3.1的介绍。释放递归互斥信号量使用宏调用xSemaphoreGiveRecursive()函数,调用xQueueGiveMutexRecursive()完成释放过程。获取递归互斥信号量使用宏调用xSemaphoreTakeRecursive()函数,执行xQueueTakeMutexRecursive()实现获取。
实例展示了递归互斥信号量的应用。通过STMCubeMX将FreeRTOS移植至工程,创建优先级高低不同的三个任务与一个递归互斥信号量。在MDK-ARM软件中编程,编译无误后下载至开发板,使用串口调试助手观察调试信息。
如需获取FreeRTOS递归互斥信号量实例的完整工程源代码,请关注公众号并在公众号内发送指定消息。
FreeRTOS简介
FreeRTOS,一个专为小型嵌入式系统设计的迷你操作系统内核,它的存在旨在提供基础的系统功能。它的核心特性包括任务管理、精准的时间管理、信号量机制、消息队列服务以及内存和记录功能,这些使得它在资源有限的小型系统中展现出强大的适应性。[1] 由于实时操作系统对系统资源,特别是RAM的需求,像μC/OS-II、embOS和salvo这样的RTOS能够在小容量RAM的单片机上运行,而FreeRTOS就是其中之一。相比于商业的μC/OS-II和embOS,FreeRTOS的一大亮点是其开源的性质,用户可以自由获取和使用源代码。此外,它还具有高度的可移植性和可裁剪性,开发者可以根据项目需求灵活定制和移植到各种类型的单片机上。目前,FreeRTOS的最新版本为7.4.0,这表明其持续更新和优化,以满足不断变化的嵌入式系统需求。扩展资料
在嵌入式领域中,嵌入式实时操作系统正得到越来越广泛的应用。采用嵌入式实时操作系统(RTOS)可以更合理、更有效地利用CPU的资源,简化应用软件的设计,缩短系统开发时间,更好地保证系统的实时性和可靠性。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集成,简化配置步骤。在其他环境,可能需要更手动地进行配置。
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版本),以支持完整的硬件抽象层。
FreeRTOS源码探析之——消息队列
消息队列是FreeRTOS中的一种关键数据结构,用于实现进程间通信。其运作机制首先由FreeRTOS分配内存空间给消息队列,并初始化为空,此时队列可用。任务或中断服务程序可以给消息队列发送消息,发送紧急消息时,消息将直接放置于队头,确保接收者能优先处理。这种机制保证了紧急消息的优先级。
为了防止消息队列被并发读写时的混乱,FreeRTOS提供了阻塞机制,确保操作的进程能够顺利完成,不受其他进程干扰。接收消息时,若队列为空,进程可选择等待,直到消息到达。在发送消息时,只有队列允许入队时,发送才成功,避免了队列溢出。优先级较高的进程将优先访问消息队列,这通过任务优先级排序实现。
消息队列控制块包含了队列的管理信息,如消息存储位置、头尾指针、消息大小和队列长度等。这些信息在创建队列时即被初始化,并且无法改变。每个消息队列与消息空间共享同一段连续内存,只有在队列被删除时,这段内存才会被释放。消息队列长度在创建时指定,决定了消息空间总数。
FreeRTOS通过xQueueGenericCreate()函数创建消息队列,该函数首先分配内存,然后初始化队列。初始化过程涉及队列长度和消息大小等参数的设置,并通过xQueueGenericReset()函数进行队列复位。
队列复位时,vListInitialise()函数构建了列表结构,这是消息队列内部的组织形式。列表结构体定义了节点类型,而vListInitialise函数初始化了列表,为消息队列的使用做好准备。
发送消息时,xQueueSend()或其底层实现xQueueGenericSend()函数根据参数选择发送位置。默认情况下,消息会发送至队尾。接收消息则通过xQueueReceive()或xQueueGenericReceive()函数实现,参数通常包括队列句柄和接收的消息指针。
消息队列的发送和接收过程中,若队列已满或为空,可能会触发任务切换,以避免阻塞进程。这种机制确保了消息队列在进程间通信中的高效和有序,是FreeRTOS系统中实现进程间协作的关键组件。