嵌入式实时操作系统FreeRTOS原理及应用-基于STM32微控制器教学课件_第1页
嵌入式实时操作系统FreeRTOS原理及应用-基于STM32微控制器教学课件_第2页
嵌入式实时操作系统FreeRTOS原理及应用-基于STM32微控制器教学课件_第3页
嵌入式实时操作系统FreeRTOS原理及应用-基于STM32微控制器教学课件_第4页
嵌入式实时操作系统FreeRTOS原理及应用-基于STM32微控制器教学课件_第5页
已阅读5页,还剩344页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

v《嵌入式实时操作系统

FreeRTOS原理及应用——基于STM32微控制器》·嵌入式实时操作系统FreeRTOS原理及应用·STM32

Cortex-M4通用开发·嵌入式实时操作系统FreeRTOS原理及应用·嵌入式实时操作系统介绍·主要内容:嵌入式系统的基本概念FreeRTOS简介一、嵌入式系统的基本概念·嵌入式实时操作系统介绍嵌入式系统

IEEE(国际电气和电子工程师协会):——嵌入式系统是控制、监视或者辅助机器和设备运行的装置(Device

used

to

control,monitor,or

assist

theoperation

of

equipment,machinery

or

plants)。

我国比较流行的定义:——嵌入式系统是以应用为中心,以计算机技术为基础,软硬件可裁剪,满

足应用系统对功能、可靠性、成本、体积和功耗

等严格要求的专用计算机系统。

嵌入式系统一般由嵌入式微处理器、外围硬件设备、嵌入式操作系统、特定的应用程序四部分组成。·嵌入式系统的基本概念嵌入式操作系统

嵌入式操作系统(Embedded

Operating

System,EOS)是指用于嵌入式系统的操作系统。它是一种用途广泛的系统软件,通常包括与硬件相关的底层驱动软件、系统内核、设备驱动接口、通信协议、图形界面、标准化浏览器等。

嵌入式操作系统负责嵌入式系统的全部软硬件资源的分配、任务调度、控制与协调并发活动。它能体现其所在系统的特征,并且可以通过裁剪某些模块来达到系统所要求的功能。·嵌入式系统的基本概念嵌入式操作系统特点

微型化。没有大容量的内存,几乎没有外存,软件一般都固化在存储器芯片中。

代码质量高。在大多数应用中,存储空间依然是宝贵的资源,要求程序代码质量高,尽量精简。

专业化。针对不同的应用领域而专门设计,要有好的适应性和移植性,还要支持多种开发平台。实时性强。嵌入式系统广泛应用于过程控制、通信、多媒体信息处理等要求实时响应的场合。

可裁减、可配置。根据应用的特点和具体要求进行灵活配置和裁减,以适应微型化和专业化要求。·嵌入式系统的基本概念实时操作系统v能使计算机系统及时的响应外部事件请求,并能控制所有实时设备和实时任务协调运行,且能在一个规定的时间内完成对事件的处理,那么这种系统就称为实时操作系统(Real

Time

Operating

System,RTOS)。·嵌入式系统的基本概念实时操作系统特征高精度计时。多级中断机制。实时调度机制。·嵌入式系统的基本概念嵌入式实时操作系统特性满足嵌入式应用的高可靠性。满足应用需要的可裁剪能力。内存需求少。运行的可预测性。采用实时调度策略。系统的规模紧凑。支持从ROM或RAM上引导和运行。对不同的硬件平台均有较好的可移植性。·嵌入式系统的基本概念二、FreeRTOS简介·嵌入式实时操作系统介绍FreeRTOS

FreeRTOS是一个源码开放的嵌入式实时操作系统内核,体积小巧,支持抢占式任务调度。其作者是Richard

Barry,由Real

Time

Engineers

Ltd出品,支持市面大部分处理器架构。

FreeRTOS设计十分小巧,可以在资源非常有限的微控制器中运行,甚至可以在51架构的单片机上运行。

FreeRTOS是一个开源、免费的实时操作系统,相较于UCOS等需要收费的RTOS,尤其适合在嵌入式系统中使用,能有效降低嵌入式产品生产成本。·FreeRTOS简介·FreeRTOS简介FreeRTOS特点开源、免费。支持抢占式、合作式和时间片三种调度方式。

支持的芯片种类多,已经在超过30种架构的芯片上进行了移植。系统简单、小巧、易用,通常情况下内核仅占用4k~9k字节的ROM空间。代码主要用C语言编写,可移植性高。

支持Corex-M系列中的MPU(内存保护)单元,比如STM32F429等有MPU的芯片。任务数量不限。任务优先级不限。·FreeRTOS简介FreeRTOS特点任务与任务、任务与中断之间可以使用任务通知、消息队列、信号量进行通信和同步。高效的软件定时器。强大的跟踪执行功能。堆栈溢出检测功能。

适应低功耗应用,FreeRTOS提供了一个用于低功耗的Tickless模式。任务、消息队列、信号量、软件定时器等系统组件,在创建时可以选择动态或者静态RAM。

SafeRTOS作为FreeRTOS的衍生品,具有比FreeRTOS更高的代码完整性。商业许可·FreeRTOS简介·FreeRTOS简介为何选择FreeRTOS

免费。像μC/OS-II、VxWorks等都是收费的。使用

FreeRTOS可有效降低嵌入式产品成本。

得到众多半导体厂商支持。很多半导体产品的SDK包使用了FreeRTOS,尤其是蓝牙、WiFi等带协议栈的芯片或模块。

容易移植到不同架构处理器。如STM32的F1、F3、F4、F7的Cortex-M架构,MSP430架构、RISC-V架构等。文件数量少,占用内存少,使用简单、高效。社会占有量高。FreeRTOS社会占有量·FreeRTOS简介v《嵌入式实时操作系统

FreeRTOS原理及应用——基于STM32微控制器》·张超主编·嵌入式实时操作系统FreeRTOS原理及应用·STM32

Cortex-M4通用开发·嵌入式实时操作系统FreeRTOS原理及应用·FreeRTOS在STM32上的移植·主要内容:FreeRTOS内核文件FreeRTOS移植移植验证添加串口调试功能一、FreeRTOS内核文件·FreeRTOS在STM32上的移植·FreeRTOS内核文件文件准备

使用FreeRTOS版本为2020.2.8的10.3.0版本。可从网址/FreeRTOS/FreeRTOS/releases下载到FreeRTOS最新源码。或者登录FreeRTOS官网

www.FreeRTOS.org进行下载。

随着zip文件中的库数不断增加,为了更好地反映

zip文件实际上包含集成在一起的库的集合,将来的发行版将使用日期戳版本而不是内核版本,比如

FreeRTOSv202012.00。·FreeRTOS内核文件FreeRTOS源码vFreeRTOS源码包含3个文件夹、6个HTML和1个txt文档·FreeRTOS内核文件Source文件夹源码只有7个.c文件。include文件夹——放置对应.c文件的头文件。portable文件夹——具体硬件相关移植层文件夹。·FreeRTOS内核文件portable文件夹vMDK编译环境,需要keil、MemMang、RVDS这3个文件夹里的文件。RVDS文件夹vRVDS文件夹针对不同架构的MCU实现了FreeRTOS与硬件相关的操作和宏定义,不同架构的MCU,使用与其架构相对应的文件夹。STM32F4xx使用ARM_CM4F文件夹。·FreeRTOS内核文件基础工程v准备好一个LED闪烁的基础工程,每隔1秒闪烁1次LED0。LED闪烁工程能方便观察程序是否正常运行,从而方便判断移植是否成功。LED闪烁基础工程对应的硬件连接如下。·FreeRTOS内核文件基础工程v与硬件相关的初始化函数,可用MDK-ARM及其RTE环境,由STM32CubeMX进行配置和生成,CubeMX使用的是HAL库。用标准库、寄存器或者是它们的组合进行初始化及编程也是可以的,基础工程的项目分组如右。·FreeRTOS内核文件基础工程vMDK-ARM的RTE环境配置:

v勾选Device->STM32CubeFramework->STM32CubeMX,即可以使用

STM32CubeMX来生成配置及初始化代码。·FreeRTOS内核文件二、FreeRTOS移植·FreeRTOS在STM32上的移植拷贝源码v将FreeRTOS源码中Source文件夹下的全部文件拷贝到基础工程中新建好的FreeRTOS文件夹。·FreeRTOS移植将源码添加到工程

新建FreeRTOS/Source和FreeRTOS/Portable二个分组。

将Source文件夹下的7个.c文件添加到FreeRTOS/Source分组。

将portable\RVDS\ARM_CM4F文件夹下的port.c及portable\MemMang下的

heap4.c添加到

FreeRTOS/Portable分组。·FreeRTOS移植配置头文件包含路径v在option配置选项中的C/C++选项卡里,添加

FreeRTOS\include和FreeRTOS\portable\RVDS\ARM_CM4F二个头文件路径。·FreeRTOS移植配置FreeRTOSvFreeRTOS使用FreeRTOSConfig.h进行配置和裁剪,这个文件可以从解压的FreeRTOS源码

FreeRTOS\Demo\CORTEX_M4F_STM32F407ZG-SK例程中拷贝。·FreeRTOS移植·FreeRTOS移植配置FreeRTOS

FreeRTOSConfig.h配置文件中使用SystemCoreClock这个全局变量来标记系统时钟,从例程中拷贝过来的

FreeRTOSConfig.h文件中使用了条件编译来声明

SystemCoreClock这个全局变量。

ICCARM

编译宏对应的是IAR

EWARM编译环境,MDK-ARM编译环境对应的宏名为

CC_

ARM,在条件编译中添加这个宏。配置FreeRTOSv修改FreeRTOSConfig.h配置文件中的

configUSE_IDLE_HOOK、configUSE_TICK_HOOK、configUSE_MALLOC_FAILED_HOOK及configCHECK_FOR_STACK_OVERFLOW四个宏定义的值为

0。·FreeRTOS移植修改stm32f4xx_it.cv用STM32CubeMX自动生成的配置代码,默认会在

stm32f4xx_it.c文件中生成SysTick、PendSV和SVC三个系统中断服务函数,这3个中断服务函数已经在FreeRTOS中实现,从而造成了重复定义,配置STM32CubeMX的NVIC代码生成选项,不生成这3个中断服务函数。·FreeRTOS移植编译项目v按编译按钮,完成后显示0

Error(s),0

Warning(s),至此,FreeRTOS在STM32F429芯片上的移植全部完成。如

果编译过程中有错误,再根据错误提示回到之前的步

骤中进行检查、排错。·FreeRTOS移植三、移植验证·FreeRTOS在STM32上的移植·移植验证引入FreeRTOSv在main.c中包含freertos.h和task.h二个头文件。若要用

STM32CubeMX再次修改工程,则包含头文件语句要放在/*

USER

CODE

BEGIN

Includes

*/和/*

USER

CODE

ENDIncludes

*/之间。·移植验证编写测试任务函数v任务函数是一个无限循环,类似于裸机程序main函数

中的while(1)死循环。任务函数while(1)里面的代码,直接拷贝基础工程中while(1)中的代码。·移植验证创建测试任务v用xTaskCreate()函数创建任务,这个创建任务函数共有6个参数。·移植验证开启任务调度器v用vTaskStartScheduler()开启任务调度,正常情况下,程序不会执行到此语句后面的代码。下载测试v编译无误后下载到目标开发板中,可以看到LED0每秒闪烁1次,与基础工程中的裸机程序运行结果一模一样,从而验证了FreeRTOS-10.3.0在STM32F429目标板上移植成功。·移植验证四、添加串口调试功能·FreeRTOS在STM32上的移植连接串口vSTM32微控制器的开发板都会带有若干个串口,具体是那个串口可用,采用的什么连接方式,哪种电平接口则需要查阅对应开发板的硬件原理图来确定。·添加串口调试功能初始化串口v串口初始化工作由STM32CubeMX辅助完成。在工程的

RTE环境中启动CubeMX,配置好串口使用的硬件引脚,串口通讯参数配置为:波特率115200bps,8位数据位,1位停止位,无奇偶校验位,无流控,收发模式。·添加串口调试功能·添加串口调试功能使用printf()v重新生成初始化代码后,将usart.c文件添加到工程项

目分组。发送采用查询方式,使用stdio.h中声明的

printf()函数格式发送,在usart.c中添加串口发送相关代码。·添加串口调试功能添加串口输出代码v修改FreeRTOS移植例程中的LED0闪烁任务函数,添加串口发送代码。下载测试v编译无误后下载到开发板,可看到LED0以1秒的间隔闪烁。

v打开屏幕串口助手软件,正确设置串口通讯参数后,打开串口,可以看到串口助手每隔0.5秒打印一行提示信息·添加串口调试功能v《嵌入式实时操作系统

FreeRTOS原理及应用——基于STM32微控制器》·张超主编·嵌入式实时操作系统FreeRTOS原理及应用·STM32

Cortex-M4通用开发·嵌入式实时操作系统FreeRTOS原理及应用·FreeRTOS的裁剪和配置·主要内容:FreeRTOS基础配置FreeRTOS与中断相关配置FreeRTOS可选API函数配置FreeRTOS其它配置FreeRTOS参考配置示例一、FreeRTOS基础配置·FreeRTOS的裁剪和配置·FreeRTOS基础配置常用配置项·是运行FreeRTOS比较常用的一些配置,涉及调度方式、时钟节拍、堆内存大小、空闲任务堆栈等。configUSE_PREEMPTIONconfigUSE_PORT_OPTIMISED_TASK_SELECTIONconfigCPU_CLOCK_HZconfigTICK_RATE_HZconfigMAX_PRIORITIESconfigMINIMAL_STACK_SIZE·FreeRTOS基础配置常用配置项configTOTAL_HEAP_SIZEconfigUSE_16_BIT_TICKSconfigIDLE_SHOULD_YIELDconfigMAX_TASK_NAME_LENconfigUSE_TICKLESS_IDLE队列信号量相关

configUSE_QUEUE_SETS用于定义是否使用队列集。

configUSE_MUTEXES用于定义是否使用互斥信号量。

configUSE_RECURSIVE_MUTEXES用于定义是否使用递归互斥信号量。

configUSE_COUNTING_SEMAPHORES用于定义是否使用计数信号量。

configUSE_TASK_NOTIFICATIONS用于定义是否使用任务通知。当宏设置为1时,相应功能的API函数就会被编译。·FreeRTOS基础配置钩子函数相关configUSE_IDLE_HOOK用于使能空闲任务钩子函数。configUSE_TICK_HOOK用于使能时间片钩子函数。

configUSE_MALLOC_FAILED_HOOK用于使能动态内存分配失败钩子函数。

configCHECK_FOR_STACK_OVERFLOW用于使能堆栈溢出检测钩子函数。

钩子函数需要用户实现,当对应的宏不为0时,必须提供相应的钩子函数。·FreeRTOS基础配置二、FreeRTOS与中断相关配置·FreeRTOS的裁剪和配置·FreeRTOS与中断相关配置Cortex-M优先级·STM32微控制器使用ARM

Cortex-M内核,Cortex-M内核采用8个二进制位来表示可编程的优先级,共有256级。实际的优先级数由芯片生产厂家决定,像STM32微控制器,就没有使用全部的8个二进制位,而只是使用了4位,共16个优先级。不管采用多少位表达优先级,均采用MSB对齐方式,使用4位来表达优先级时MSB对齐的情形如下:·FreeRTOS与中断相关配置configPRIO_BITS·设置硬件用于表达优先级的二进制位数。STM32微控制器使用的是4位,此宏应该设定为4。因在

core_cm4.h头文件中定义了表达优先级位数据的宏

NVIC_PRIO_BITS,且该宏已设为4,可通过这个宏来

设定configPRIO_BITS,或者直接将configPRIO_BITS设定为4。·FreeRTOS与中断相关配置configLIBRARY_LOWEST_INTERRUPT_PRIORIT

Y·用于设置中断最低优先级。STM32微控制器使用4位二进制位表达优先级,优先级数最多就是16个。但

STM32微控制器表达优先级高低与优先级数的关系比

较特殊,数值越大,优先级反而越低,数值为0时表示最高优先级。所以,此宏的值应设为15。·FreeRTOS与中断相关配置configKERNEL_INTERRUPT_PRIORITY·用于设置内核的中断优先级,即嘀嗒定时器和

PendSV的中断优先级。此宏定义通过

configLIBRARY_LOWEST_INTERRUPT_PRIORITY<<(8-configPRIO_BITS)替换得到,替换结果应该是中断系统中的最低优先级。用前面定义好的宏,替换为

0x0F<<(8-4),结果为0xF0,高4位正好就是15,也就是

STM32微控制器的最低中断优先级。·FreeRTOS与中断相关配置configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORI

TY·用于设置FreeRTOS可管理的最大优先级。可以在硬件中断优先级数量之内任意设置,比如设置为5,表示高于优先级5的中断(对于STM32微控制器,为优先级

0至4)不归FreeRTOS管理。·FreeRTOS与中断相关配置configMAX_SYSCALL_INTERRUPT_PRIORITY·由宏

configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY<<(8-configPRIO_BITS)得到。例如,宏

configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY设为5,表示优先级高于5的中断不归FreeRTOS管理,在这些中断服务函数中不能调用FreeRTOS相关API函数。三、FreeRTOS可选API函数配置·FreeRTOS的裁剪和配置·FreeRTOS可选API函数配置可选API·通过配置INCLUDE_开始的宏,可对FreeRTOS一些可选API函数进行配置,当对应的宏为1时,表示使能相应功能的API函数,这些API函数就会参与编译,从而可供应用程序调用。例如,当INCLUDE_vTaskDelay宏定义为1时,函数vTaskDelay()将会被编译,从而在应用程序中可用vTaskDelay()实现阻塞式延时。·FreeRTOS可选API函数配置可选API·常用的使能API函数对应的宏。#define

INCLUDE_vTaskPrioritySet#define

INCLUDE_uxTaskPriorityGet#define

INCLUDE_vTaskDelete#define

INCLUDE_vTaskSuspend#define

INCLUDE_vTaskDelayUntil#define

INCLUDE_vTaskDelay·FreeRTOS可选API函数配置可选API·常用的使能API函数对应的宏。#define

INCLUDE_xTaskGetSchedulerState#define

INCLUDE_xTaskGetCurrentTaskHandle#define

INCLUDE_uxTaskGetStackHighWaterMark#define

INCLUDE_xTaskGetIdleTaskHandle#define

INCLUDE_xTimerGetTimerDaemonTaskHandle#define

INCLUDE_pcTaskGetTaskName四、FreeRTOS其它配置·FreeRTOS的裁剪和配置·FreeRTOS其它配置协程相关

1、configUSE_CO_ROUTINES。定义是否使用协程,

0为不使用,1为使用。在抢占式调度中也可使用协程,协程可以节约开销,但功能将受到限制,现在的微处理器功能都已经很强大,协程已经很少采用,此宏应该设为0。

2、configMAX_CO_ROUTINE_PRIORITIES。定义协程的有效优先级数目,优先级从0到configMAX_CO_ROUTINE_PRIORITIES-1,0为最低优先级。·FreeRTOS其它配置任务运行信息相关

1、configUSE_TRACE_FACILITY,用于使能可视化跟踪和调试,为1时使能。

2、configUSE_STATS_FORMATTING_FUNCTIONS,当此宏与configUSE_TRACE_FACILITY宏同时为1时,vTaskList()和vTaskGetRunTimeStats()函数会参与编译,从而可以通过这二个函数获取任务运行信息。·FreeRTOS其它配置任务运行信息相关

3、configGENERATE_RUN_TIME_STATS,用于定义是否开启时间统计功能,为1时表示开启。当此宏为1时,还需要用户实现这二个宏:

portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()和portGET_RUN_TIME_COUNTER_VALUE()。前者对应

一个精度高于嘀嗒定时器时间精度10倍以上的定时器初始化函数,后者对应一个获取统计时间值的函数,这二个函数均需由用户实现。·FreeRTOS其它配置软件定时器相关

1、configUSE_TIMERS,定义是否使用软件定时器功能,为1时使用。当此宏为1时,会在调度器开启功能函数中自动创建定时器服务任务,同时需要正确配置后面几个宏。

2、configTIMER_TASK_PRIORITY,用于定义软件定时器任务的默认优先级。

3、configTIMER_QUEUE_LENGTH,用于定义软件定时器命令队列长度。

4、configTIMER_TASK_STACK_DEPTH,用于定义软件定时器任务堆栈大小。·FreeRTOS其它配置是否使用断言·用于代码调试阶段检查传入的参数是否合理。

FreeRTOS内核在关键点均会调用configASSERT(x),如果

x结果为0,说明有错误发生。·错误发生时有多种处理方法,可通过串口输出信息,可直接停机,下面是一种停机处理方法示例,发生错误时直接停机。·#define

configASSERT(

x

)

if(

(

x

)

==

0

)

{taskDISABLE_INTERRUPTS();

for(

;;

);

}·使用断言会增加系统开销,一般是在调试阶段使用,要关闭这个功能,注释掉configASSERT(x)就可以。·FreeRTOS其它配置中断服务函数·在FreeRTOS移植层port.c文件里,分别定义了

vPortSVCHandler、xPortPendSVHandler和xPortSysTickHandler三个中断服务处理函数,需要与

STM32的SVC_Handler、PendSV_Handler和SysTick_Handler进行一一对应。四、FreeRTOS参考配置·FreeRTOS的裁剪和配置·FreeRTOS参考配置FreeRTOSConfig.h·典型的FreeRTOSConfig.h配置文件,后面的例子,均使用这个配置文件。除个别有改动的会特别说明外,不再描述FreeRTOS配置文件,默认使用本配置文件。v《嵌入式实时操作系统

FreeRTOS原理及应用——基于STM32微控制器》·嵌入式实时操作系统FreeRTOS原理及应用·张超主编·STM32

Cortex-M4通用开发·嵌入式实时操作系统FreeRTOS原理及应用·FreeRTOS任务基础·主要内容:FreeRTOS任务任务的创建和删除任务创建与删除示例一、FreeRTOS任务·FreeRTOS任务基础任务的特性简单,每个任务尽可能完成简单的操作。没有使用限制,每个任务都可能被调度器选中运行。支持优先级,不同任务可以设置不同的优先级。支持抢占,高优先级的任务能抢占低优先级的任务。每个任务都有堆栈,将导致RAM使用量增大。·FreeRTOS任务任务的状态·FreeRTOS的任务有4个状态,分别是运行态、就绪态、阻塞态和挂起态。·FreeRTOS任务·FreeRTOS任务任务的优先级

可以设置不同的优先级,FreeRTOS对任务的优先级数量没有限制。优先级数字越大,代表优先级越高。

FreeRTOS调度器能确保处于就绪态或运行态的高优先级任务获得处理器使用权。

当多个任务的优先级相同时,FreeRTOS将使用时间片调度,使处于就绪态优先级又相同的任务共享处理器的执行时间,前提是在配置文件中使能了时间片调度功能。·FreeRTOS任务任务堆栈·任务堆栈是任务的重要组成部分。所谓堆栈,就是在存储器中按照“后进先出”的原则组织的连续数据存储空间。任务堆栈可以在创建任务的时候自动创建或指定。·FreeRTOS任务任务控制块·FreeRTOS用来记录任务的堆栈指针、任务的当前状态、任务的优先级等一些与任务管理相关的属性表叫做任务控制块(TCB)。任务控制块

TCB在创建任务时初始化,若任务创建成功,则TCB中的pxTopOfStack指向任务栈的栈顶,该指针随着出入栈的操作而不断更新,而pxStack指明任务栈的起始地址。

FreeRTOS使用列表来处理就绪、挂起、延时等任务,通过TCB中的状态列表项xStateListItem和事件列表项

xEventListItem挂接到不同的列表来实现。·FreeRTOS任务就绪任务中的列表和列表项·FreeRTOS任务列表和列表项·列表和列表项是FreeRTOS中定义的数据结构,

FreeRTOS列表使用指针指向列表项。一个列表下面可能有很多个列表项,而每个列表项都有一个指针指向列表。列表和列表项的定义及代码实现在文件list.c和list.h中。·FreeRTOS任务·FreeRTOS任务列表·列表用于跟踪任务。处于就绪、挂起、阻塞的任务,都会被挂接到各自的列表中。列表类型名字叫List_t,在list.h中的定义如下:列表·在列表结构中,uxNumberOfItems用来记录这个列表

有多少个列表项。pxIndex指向列表项,用来遍历列表。

xListEnd是一个迷你列表项,用来挂接列表项。·FreeRTOS任务·FreeRTOS任务列表项·列表项就是存放在列表中的具体项目。FreeRTOS提供了两种列表项,全功能列表项(以下简称列表项)和迷你列表项,列表项在list.h中的定义:列表项·与列表结构体一样,第一个和最后一个成员是用来检查列表项完整性。去掉完整性检查后的列表项结构如下:·FreeRTOS任务·FreeRTOS任务迷你列表项·迷你列表项除去完整性检查这个成员变量外,只保留了列表项中最核心的3个成员。迷你列表项·FreeRTOS任务·在列表中,最后一个成员就是迷你列表项,刚创建的列表用它表示列表的结束,随着列表项的插入,列表项就被链接在这个迷你列表项之下。二、任务的创建和删除·FreeRTOS任务基础任务函数·任务的创建和删除·无论采用何种方法创建任务,均需要用到任务函数。

FreeRTOS规定任务函数的返回值必须为void,而且带有一个void型指针参数,任务函数的一般形式为:·任务的创建和删除任务创建和删除API·FreeRTOS提供的任务创建函数有4个,以Static结尾的表示在创建任务时使用静态内存分配方法,带有

Restricted限定词的表示使用MPU(内存保护单元)进行保护限制。·任务的创建和删除用动态方法创建任务·xTaskCreate()任务创建函数使用动态内存分配方法创建任务,并将其加入就绪任务列表。函数原型:·任务的创建和删除用静态方法创建任务·xTaskCreateStatic()函数也是创建任务,并将其加入就绪任务列表,但创建任务所需的内存不是采用动态内存

分配,而是需要由用户指定。函数原型:任务的删除

vTaskDelete()用于删除一个已创建好的任务,包括就绪、阻塞或挂起状态的任务,也可在任务运行时删除任务本身。

如果被删除的任务是用动态内存分配方法创建的,分配给该任务的堆栈和控制块内存会在空闲任务中自动释放。

用静态内存分配方法创建任务时分配的堆栈、任务控制块内存,以及任务中由用户自行分配给任务的内存,需要由用户程序进行释放。函数原型:·任务的创建和删除三、任务创建与删除示例·FreeRTOS任务基础任务描述通过函数appStartTask(),创建二个FreeRTOS任务。

任务1的任务函数为Led0Task(),其功能是使LED0每秒闪烁1次,在完成5次闪烁后删除任务2。

任务2的任务函数是Led1Task(),其功能是使LED1每秒闪烁2次。硬件连接请参考自己的开发板电路原理图。·任务创建与删除示例代码组织·采用一对文件的方式来组织代码,先在工程根目录建立appTask文件夹,用来存放与任务相关的文件,再编写

appTask.c及appTask.h一对文件,将appTask.c添加到

Application/MDK-USER项目分组,在C/C++选项卡中添加文件包含路径。·任务创建与删除示例编写任务函数·按任务描述分别编写LED0及LED1闪烁任务函数。·任务创建与删除示例创建任务·任务的创建在函数appStartTask()中完成,先进入临界区,调用xTaskCreate()函数创建LED0闪烁及LED1闪烁任务,在创建任务之前,要先定义这2个任务的任务句柄。函数在appTask.h文件中声明,在appTask.c文件中实现。·任务创建与删除示例开启任务调度·任务创建完成之后,用vTaskStartScheduler()开启任务调度器。调度器开启之后,正常情况下,程序不会执行

到此语句之外。·任务创建与删除示例下载测试

在main.c中,调用创建任务并开启调度器的函数

appStartTask()。

编译程序,无误后下载到开发板,打开串口调试助手,可以看到LED0以每秒1次的频率闪烁,

LED1以每秒2次的频率闪烁,LED0闪烁5次后,

LED1停止闪烁,因为此时LED1闪烁任务已经被删除。·任务创建与删除示例v《嵌入式实时操作系统

FreeRTOS原理及应用——基于STM32微控制器》·张超主编·嵌入式实时操作系统FreeRTOS原理及应用·STM32

Cortex-M4通用开发·嵌入式实时操作系统FreeRTOS原理及应用·FreeRTOS任务调度·主要内容:开启调度器任务的挂起和恢复任务的调度FreeRTOS内核函数一、开启调度器·FreeRTOS任务调度调度器开启函数·调度器开启函数为vTaskStartScheduler(),该函数在

tasks.c中定义。·开启调度器调度器开启过程首先会创建一个空闲任务。

如果配置了宏configUSE_TIMERS为1,则创建定时器服务任务。

如果前面的任务创建成功,通过

调用xPortStartScheduler()来初始化SysTick嘀嗒定时器作FreeRTOS操作系统的心跳时钟。

然后启动第一个任务,启动任务后,程序将不会退出任务调度。·开启调度器启动第一个任务

在调度器的开启过程中,使用与移植层硬件密切相

关的xPortStartScheduler()来初始化中断、嘀嗒定时器并启动第一个任务。

这部分代码与硬件密切相关,先设置PendSV和嘀嗒定时器的中断优先级为最低优先级,然后初始化嘀嗒定时器并使能嘀嗒定时器中断,对于有浮点运算的Cortex-M4等微控制器,使能FPU,最后调用prvStartFirstTask()打开中断,并触发SVC中断来启动第一个要运行的任务,至此,调度器开启完成。·开启调度器二、任务的挂起和恢复·FreeRTOS任务调度任务的挂起任务挂起函数——vTaskSuspend()。

此函数用于将某个任务设置为挂起态,进入挂起态的任务永远都不会运行。退出挂起态的唯一方法就是调用任务恢复函数。任务挂起函数原型为:·任务的挂起和恢复任务的恢复·将一个任务从挂起态恢复到就绪态,要使用任务恢复函数。任务恢复函数有二个版本,vTaskResume()和xTaskResumeFromISR(),后者是中断版本,在受

FreeRTOS管理的中断服务函数中调用。

1、任务恢复函数——vTaskResume()。只有通过

vTaskSuspend()挂起的任务,才能用vTaskResume()恢复,其函数原型为:·任务的挂起和恢复任务的恢复

2、中断版本任务恢复函数—xTaskResumeFromISR()在中断服务函数中使用,其函数原型为:·任务的挂起和恢复三、任务的调度·FreeRTOS任务调度FreeRTOS任务切换场合·FreeRTOS支持三种任务调度方式:抢占式调度、时间片调度和合作式调度。

抢占式调度用于任务有不同优先级的场合。每一个任务都有不同的优先级,任务会一直运行到被高优先级任务抢占,或者遇到阻塞式的API函数调用,最简单的如vTaskDelay(),才让出CPU的使用权。

抢占式任务调度总是选择就绪列表中最高优先级的任务来运行。

时间片调度用于多个任务具有相同优先级场的合,当多个任务优先级相同时,每个任务在运行一个时间片后就让出CPU使用权。·任务的调度FreeRTOS任务切换场合·FreeRTOS会在下面二种情况下执行任务切换(也称上下文切换)。1、执行一个系统调用。2、嘀嗒定时器中断。·任务的调度PendSV中断

在STM32微控制器中,有SVC和PendSV二个系统中

断,前者叫系统服务调用,简称系统调用,后者叫可挂起的系统调用。

触发PendSV中断的方法是往ICSR(中断控制和状态寄存器)的bit28置1。

PendSV中断的优先级可以通过编程进行设置,bit28置1后,若其中断优先级不够,则将等待更高优先

级的中断执行完毕才会执行,这种特性,使PendSV中断非常适合在操作系统中用于任务切换。·任务的调度PendSV中断·FreeRTOS通过将PendSV中断设置成最低优先级,使得在PendSV中断中进行的任务切换,延迟到所有其它中断服务函数都已处理完成之后才进行。·任务的调度查找下一个要运行的任务·在PendSV中断服务函数里通过vTaskSwitchContext()函数来查找下一个要运行的已经就绪且为最高优先级的任务,该函数在tasks.c中实现,去掉条件编译后的代码为:·任务的调度查找下一个要运行的任务·任务的调度FreeRTOS时间片调度

当多个任务拥有相同的优先级时,相同优先级的每个任务只运行一个时钟节拍,然后让出CPU使用权,让另一个相同优先级的任务运行的方法来实现同优先级任务的调度,称之为时间片调度。

要使用时间片调度,需要将宏configUSE_PREEMPTION和configUSE_TIME_SLICING设置为1,时间片的长度由宏configTICK_RATE_HZ定义的系统时钟节拍决定,即嘀嗒定时器的溢出周期,当该宏为1000时,时间片长度就是1毫秒。时间片的调度在嘀嗒定时器的中断服务函数里完成。·任务的调度FreeRTOS时间片调度·任务的调度空闲任务

FreeRTOS调度器开启后,至少会有一个任务处于运行态。FreeRTOS在调用vTaskStartScheduler()开启调度器时,会自动创建一个空闲任务。

空闲任务是一个非常短小的循环,且拥有最低优先级(优先级0)以保证其不会妨碍具有更高优先级的应用任务进入运行态。

空闲任务运行在最低优先级,可以保证一旦有更高优先级的任务进入就绪态,空闲任务就会立即切出运行态。·任务的调度空闲任务·空闲任务的主要功能:1、释放内存。2、处理空闲优先级任务。3、执行空闲任务钩子函数。

4、实现低功耗tickless模式。FreeRTOS的tickless空闲模式会在空闲周期时停止嘀嗒定时器,从而让微

控制器长时间处于低功耗模式。移植层需要配置外

部唤醒中断,当唤醒事件到来时,将微控制器从低

功耗模式唤醒。微控制器唤醒后,要重新使能嘀嗒

定时器。·任务的调度四、FreeRTOS内核函数·FreeRTOS任务调度·FreeRTOS内核函数临界段操作函数程序运行过程中,一些关键代码的执行不能被打断,称这一段不能被打断的程序为临界段或临界区。

能打断程序执行的往往是中断,所以进入退出临界段都要进行开关中断操作。

在STM32微控制器上,FreeRTOS进入和退出临界段主要是通过操作寄存器basepri来实现。进入临界段时,操作寄存basepri关闭所有低于宏

configMAX_SYSCALL_INTERRUPT_PRIORITY所设定的中断优先级的中断,也就是FreeRTOS能管理的所有中断,不属FreeRTOS管理的中断不会被关闭。退出临界段时,操作寄存器basepri打开所有中断。·FreeRTOS内核函数临界段操作函数·进入和退出临界段的函数有四个:taskENTER_CRITICAL()。taskEXIT_CRITICAL()。taskENTER_CRITICAL_FROM_ISR()taskEXIT_CRITICAL_FROM_ISR()。

后二个在中断服务函数中使用,进入和退出临界段必须成对使用,而且要求临界段的代码尽量短小,以免破坏实时性。·FreeRTOS内核函数·FreeRTOS内核函数挂起和恢复调度器函数vTaskSuspendAll()函数用于挂起任务调度器。xTaskResumeAll()函数用于恢复调度器。

调度器挂起后,介于vTaskSuspendAll()和

xTaskResumeAll()之间的代码不会被更高优先级的任务抢占,即任务调度被禁止。挂起调度器不用关闭中断,这一点与进入临界段不一样。·FreeRTOS内核函数任务切换函数

taskYIELD()是任务切换函数,其实是一个宏,最终由宏portYIELD()实现。通过向中断控制和状态寄存器ICSR的bit28位写入1,以启动一个PendSV中断,在PendSV中断里完成任务切换。·FreeRTOS内核函数时钟节拍追加

vTaskStepTick()用于设置时钟节拍的追加值,在低功耗tickless模式下使用。

当宏configUSE_TICKLESS_IDLE为1时,就使能了低功耗tickless模式,一般情况下,会在空闲任务中让系统时钟节拍停止运行,恢复系统时钟节拍后,时钟

节拍停止运行的节拍数,就可用vTaskStepTick()补上。v《嵌入式实时操作系统

FreeRTOS原理及应用——基于STM32微控制器》·张超主编·嵌入式实时操作系统FreeRTOS原理及应用·STM32

Cortex-M4通用开发·嵌入式实时操作系统FreeRTOS原理及应用·FreeRTOS任务函数·主要内容:延时函数优先级控制获取任务状态信息任务运行时间信息·FreeRTOS任务函数·任务管理是FreeRTOS的核心功能,除内核函数中的任务创建、挂起、恢复、删除和任务切换等之外,还有用于让出CPU使用权的阻塞式延时,任务优先级查询、设置,获取任务状态信息,以及获取任务运行时间信息等辅助函数。·FreeRTOS任务函数一、延时函数·FreeRTOS任务函数系统时钟节拍

任何操作系统都会有一个时钟节拍,以供系统处理延时、超时等与时间相关的事件。时钟节拍有时也称之为心跳,是一个周期性的中断,时钟节拍越快,系统的额外开销就越大。在STM32微控制器中,时钟节拍由嘀嗒定时器提供。FreeRTOS定义了一个静态全局变量xTickCount用来对时钟节拍计数,每个嘀嗒定时器中断

xTickCount就会加一。时钟节拍长短在

FreeRTOSConfig.h里配置。·延时函数相对延时·相对延时是指每次延时都是从任务执行函数

vTaskDelay()开始,延时指定的时钟节拍后结束,恢复任务到就绪状态。函数的原型为:·延时函数绝对延时·绝对延时是指每隔指定的时钟节拍,执行一次调用

vTaskDelayUntil()函数的任务。也就是

说,任务以固定的

频率执行。函数的

原型为:·延时函数延时函数使用示例

本示例通过一个函数appStartTask(),创建二个相同优先级的FreeRTOS任务,均运行于优先级3。

任务1的任务函数为Led0Task(),其功能是使LED0闪烁,在任务中调用相对延时函数vTaskDelay(500),延时500毫秒,并将任务1的执行总节拍数通过串口发送。

任务2的任务函数是Led1Task(),其功能是使LED1闪烁,在任务中调用绝对延时函数

vTaskDelayUntil(&xNextTime,500),延时500毫秒,并将任务2的执行总节拍数通过串口发送。·延时函数二、优先级控制·FreeRTOS任务函数获取任务优先级·uxTaskPriorityGet()用于获取某个任务的优先级,使用此函数需要配置宏INCLUDE_uxTaskPriorityGet为1,函数的原型为:·优先级控制设置任务优先级·vTaskPrioritySet()用于设置指定任务的优先级。使用此函数,需要配置宏INCLUDE_vTaskPrioritySet为1,函数的原型为:·优先级控制改变任务优先级示例

本示例通过一个函数appStartTask(),创建二个相同优先级的FreeRTOS任务,均运行于优先级3。

为便于观察,将宏configUSE_TIME_SLICING设为0,禁止时间片调度,并且在任务1和任务2中均不调用任何会使任务进入阻塞的API函数,这样任务1和任务2中就只有一个任务能得到运行。

任务1的任务函数为Led0Task(),当检测到WAKEUP键按下时,将任务2的优先级提升到本任务的高一级。

任务2的任务函数是Led1Task(),当检测到KEY0键按下时,将任务2的优先级降低到任务1的低一级。·优先级控制三、获取任务状态信息·FreeRTOS任务函数任务状态信息获取函数·1、uxTaskGetSystemState()·用于获取所有任务的任务状态,任务句柄、任务名字、堆栈、优先级等信息会保存在一个TaskStatus_t类型的结构体数组里。使用此函数需将宏

configUSE_TRACE_FACILITY设为1。函数的原型为:·获取任务状态信息·获取任务状态信息任务状态信息获取函数·2、vTaskGetInfo()·用于获取单个任务的任务状态,任务句柄、任务名字、堆栈、优先级等信息会保存在一个TaskStatus_t类型的结构体里。使用此函数需将宏

configUSE_TRACE_FACILITY设为1。函数的原型为:任务状态信息获取函数·3、uxTaskGetStackHighWaterMark()·每个任务都有自己的堆栈,堆栈到底取多大,与任务复杂程度,任务中使用的变量多少等因素相关,很难有一个准确的计算方法。利用这个函数,可以检测任务从创建运行以来的历史剩余最小值,这个值越小,说明堆栈溢出的可能性就越大,而堆栈溢出是灾难性的。FreeRTOS把这个堆栈历史剩余最小值称之为“高水位线”。使用此函数,要将宏

INCLUDE_uxTaskGetStackHighWaterMark设为1,函数的原型为:·获取任务状态信息任务状态信息获取函数·4、eTaskGetState()·用于查询指定任务的状态,任务的状态有:运行态、阻塞态、挂起态和就绪态。函数的原型为:·获取任务状态信息任务状态信息获取函数·5、vTaskList()·将每一个任务的状态信息,以字符串的形式,存入到字符数组或指定的存储区。任务的状态信息包括:任务名、任务状态、优先级、剩余堆栈大小,以及任务号。函数的原型为:·获取任务状态信息任务状态信息获取示例

本示例通过一个函数appStartTask(),创建三个

FreeRTOS任务。

任务1的任务函数为Led0Task(),其功能是使LED0每秒闪烁一次,任务优先级为3。

任务2的任务函数是Led1Task(),其功能是使LED1每秒闪烁2次,任务优先级为2。

任务3的任务函数是getTaskInfo(),其功能是当

WAKEUP按键按下时,获取所有任务的状态信息,并通过串口发送,任务优先级为1。·获取任务状态信息四、任务运行时间信息·FreeRTOS任务函数时间信息统计函数·FreeRTOS提供了一个用于统计系统中任务运行时间信息的函数vTaskGetRunTimeStats()。函数的原型为:·使用此函数需将宏

configGENERATE_RUN_TIME_STATS、configUSE_TRACE_FACILITY以及宏

configUSE_STATS_FORMATTING_FUNCTIONS都设置为1,同时,用户还须在FreeRTOSConfig.h中实现二个宏:·portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()和·portGET_RUN_TIME_COUNTER_VALUE()。·任务运行时间信息任务运行时间信息示例

本示例在获取任务信息示例的基础上,增加任务运行时间统计功能。通过一个函数appStartTask(),创建三个FreeRTOS任务。

任务1的任务函数为Led0Task(),其功能是使LED0每秒闪烁一次,任务优先级为3。

任务2的任务函数是Led1Task(),其功能是使LED1每秒闪烁2次,任务优先级为2。

任务3的任务函数是getTaskInfo(),其功能是当

WAKEUP按键按下时,获取所有任务的状态信息,

当KEY0按键按下时,获取所有任务的运行时间信息,并通过串口发送,任务优先级为4。·任务运行时间信息v《嵌入式实时操作系统

FreeRTOS原理及应用——基于STM32微控制器》·张超主编·嵌入式实时操作系统FreeRTOS原理及应用·STM32

Cortex-M4通用开发·嵌入式实时操作系统FreeRTOS原理及应用·FreeRTOS队列与消息传递·主要内容:FreeRTOS队列及其结构队列操作用队列实现串口守护任务一、FreeRTOS队列及其结构·FreeRTOS队列与消息传递FreeRTOS队列特性

1、存储数据:通常情况下,队列被作为FIFO(先进先出)使用。

2、多任务访问:队列不属于某个任务,所有任务都可以操作队列。3、读队列时阻塞:当某个任务试图读一个队列时,可以指定一个阻塞超时时间,当等待的时间超过了指定的阻塞时间,即使队列中尚无有效数据,任务也会自动从阻塞态转移为就绪态。

4、写队列时阻塞:同读队列一样,任务也可以在写队列时指定一个阻塞超时时间。·FreeRTOS队列及其结构队列读写过程·FreeRTOS队列及其结构二、队列操作·FreeRTOS队列与消息传递队列创建

与任务创建一样,队列创建也有动态方法和静态方法两种,用xQueueCreate()动态方法创建队列和用

xQueueCreateStatic()静态方法创建队列。

动态创建方法使用动态内存分配,而静态方法需要用户指定相应内存区。·队列操作队列创建·队队列列操操作作·1、xQueueCreate()·用动态内存分配方法创建队列,这其实是一个宏,定义如下:·真正用来创建队列的是xQueueGenericCreate()函数,函数的原型为:·队列操作队列创建·2、xQueueCreateStatic()·用静态方法创建队列,创建过程中使用的内存,需要用户事先分配。这也是一个宏,定义如下:·队队列列操操作作队队列列创创建建·真正用来创建队列的是xQueueGenericCreateStatic()函数入队操作入队操作API有xQueueSend()、xQueueSendToBack()、xQueueSendToFront()、xQueueOverwrite()四个,它们都是长得像函数的宏,实际操作的是

xQueueGenericSend()函数。

xQueueSendFromISR()、

xQueueSendToBackFromISR()、

xQueueSendToFrontFromISR()、

xQueueOverwriteFromISR()是入队函数的中断安全版本,实际操作的是xQueueGenericSendFromISR()函数。·队列操作·队列操作入队操作·1、xQueueGenericSend()·通用入队函数,函数原型为:·队列操作入队操作·2、xQueueGenericSendFromISR()·中断服务中使用的入队函数,函数原型为:出队操作·从队列中获取数据,需要用到出队操作。出队操作有

xQueueReceive()和xQueuePeek()二个函数,它们的中断安全版本是xQueueReceiveFromISR()和xQueuePeekFromISR()。·队列操作出队操作·1、xQueueReceive()·从指定的队列中读取消息,读取成功后会将队列中的这个数据删除,函数的原型为:·队列操作出队操作·2、xQueuePeek()·从指定的队列中读取消息,读取成功后并不删除队列中的这个数据,函数的原型为:·队列操作出队操作·3、xQueueReceiveFromISR()·用于中断服务函数中,从指定的队列中读取消息,读取成功后会将队列中的这个数据删除。函数的原型为:·队列操作出队操作·4、xQueuePeekFromISR()·用于中断服务函数中,从指定的队列中读取消息,读取成功后并不删除队列中的这个数据。函数的原型为:·队列操作其它队列操作函数·队列操作三、用队列实现串口守护任务·FreeRTOS队列与消息传递守护任务

守护任务是对某个资源具有唯一所有权的任务。只有守护任务才可以直接访问其守护的资源——其它任务要访问该资源只能间接地通过守护任务提供的服务。

守护任务提供了一种干净利落的方法来实现互斥功能,也不用担心会发生优先级反转和死锁。·用队列实现串口守护任务串口守护任务示例

本示例对例子“延时函数使用示例”进行改写,将原来二个任务通过临界段代码保护实现串口输出改写成通过串口守护任务输出。

本示例通过一个函数appStartTask(),创建3个相同优先级的FreeRTOS任务,均运行于优先级3,抢占

式调度和时间片调度开启。

任务1的任务函数为Led0Task(),任务1的执行总节拍数通过队列传给守护任务打印。

任务2的任务函数是Led1Task(),将任务2的执行总节拍数通过队列传给守护任务打印。任务3是串口输出守护任务,任务函数是printTask(),任何时候只有该守护任务能访问串口。·用队列实现串口守护任务v《嵌入式实时操作系统

FreeRTOS原理及应用——基于STM32微控制器》·张超主编·嵌入式实时操作系统FreeRTOS原理及应用·STM32

Cortex-M4通用开发·嵌入式实时操作系统FreeRTOS原理及应用·FreeRTOS信号量与任务同步·主要内容:二值信号量计数信号量互斥信号量递归互斥信号量一、二值信号量·FreeRTOS信号量与任务同步·二值信号量二值信号量相当于只有一个队列项的队列。

创建二值信号量使用的创建函数与创建队列使用的是同一个函数。

二值信号量只关心这个特殊的队列状态,要不为空,要不为满,它并不关心队列中存放的是什么消息。·二值信号量·二值信号量主要用于同步,用于任务和任务之间的同步或者中断和任务之间的同步。创建二值信号量·FreeRTOS创建二值信号量使用的是宏

vSemaphoreCreateBinary()和xSemaphoreCreateBinary(),这二个宏最终被队列创建函数

xQueueGenericCreate()所替换,使用这二个宏创建二值信号量,需要宏

configSUPPORT_DYNAMIC_ALLOCATION为1。·二值信号量·二值信号量创建二值信号量·1、vSemaphoreCreateBinary()·这是旧版本使用的二值信号量创建宏,在semphr.h文件中定义:·二值信号量创建二值信号量·2、xSemaphoreCreateBinary()·新版本的FreeRTOS使用此宏创建二值信号量,同样是通过调用xQueueGenericCreate()队列创建函数来创建二值信号量,只不过创建成功后,并没有释放此二值信号量。·二值信号量释放二值信号量·1、xSemaphoreGive()·xSemaphoreGive()是一个宏,用于释放信号量,最终实现功能的是xQueueGenericSend()队列发送函数。释放二值信号量·2、xSemaphoreGiveFromISR()·释放信号量的中断版本,在中断服务函数中使用,同样也是一个宏。可以用来释放二值信号量和计数型信号量,但不能用于释放互斥信号量。最终实现功能的是xQueueGiveFromISR()函数。·二值信号量获取二值信号量·1、xSemaphoreTake()·xSemaphoreTake()是一个宏,用于获取信号量,不止是二值信号量,计数型信号量、互斥信号量也都是使用此宏来释放信号量。其宏定义为:·二值信号量·二值信号量获取二值信号量·2、xSemaphoreTakeFromISR()·获取信号量的中断版本,在中断服务函数中使用,同样也是一个宏。可以用来获取二值信号量和计数型信号量,但不能用于获取互斥信号量。最终实现功能的是xQueueReceiveFromISR()函数。·二值信号量用二值信号量进行任务同步

本示例通过对二值信号量的操作,实现任务与任务之间,以及中断与任务之间的同步。

任务1,优先级3,其功能是使LED0闪烁,通过二值信号量实现任务之间同步,输出信息到串口。

任务2,优先级3,其功能是使LED1闪烁,通过二值信号量实现中断与任务之间同步,输出信息到串口。任务3是串口输出守护任务,优先级3。

任务4是按键扫描任务,优先级4,其功能是按键扫描,并根据返回的键值执行释放信号量、启动定时器等操作。二、计数信号量·FreeRTOS信号量与任务同步·计数信号量

计数信号量相当于长度大于1的队列,主要用在事件计数或资源管理。

用在事件计数时,创建时初值一般为0,事件处理函数每释放一次信号量,其值就加一,其它任务获取信号量时,其值就减一。

用作资源管理时,信号量代表资源可用的数量,初值为可用资源的最大值。创建计数信号量·xSemaphoreCreateCounting()是动态方法创建计数信号量宏,定义如下:·计数信号量计数信号量的释放和获取·计数信号量的释放和获取与二值信号量完全相同,使用相同的释放和获取函数,包括中断版本的释放和获取都一样。·计数信号量·计数信号量用计数信号量进行任务同步·本示例改写自“用二值信号量进行任务同步”例子,将原例子中断服务函数释放的二值信号量换成计数信号量,观察中断与任务同步的情况。三、互斥信号量·FreeRTOS信号量与任务同步·互斥信号量

互斥信号量是一种特殊的二值信号量,用于控制在两个或多个任务间访问共享资源。

互斥信号量提供一种“优先级继承”机制,让持有互斥量的任务优先级提升到等待这个互斥量的任务优先级。

与二值信号量主要用于同步不同,互斥信号量主要用于互斥访问。·互斥信号量·除优先级继承外,二者的区别在于信号量被获取后发生的事情:用于互斥的信号量必须归还。

用于同步的信号量通常是完成同步之后便丢弃,不再归还。创建互斥信号量·宏xSemaphoreCreateMutex()使用动态内存分配方法来创建互斥信号量,定义如下:·互斥信号量·互斥信号量互斥信号量的获释放和获取

因为有优先级继承机制,互斥信号量不能用于中断服务函数中,因此中断版本的信号量释放与获取函数不能用于互斥量。

在任务中使用互斥量,其释放和获取与二值信号量完全相同,使用相同的释放和获取函数。优先级翻转·在抢占式内核上使用二值信号量,往往容易出现优先级翻转现象。所谓优先级翻转,是指任务的事务处理顺序上,高优先级任务事务处理反而滞后于低优先级任务的事务处理的现象。·互斥信号量优先级翻转示例

本示例通过函数appStartTask(),创建4个不同优先级的FreeRTOS任务,开启抢占式调度和时间片调度。

低优先级任务:优先级为1,任务需要获取信号量来运行,同时将运行信息送往串口。

中优先级任务:优先级为2,任务简单地将运行信息送往串口。

高优先级任务:优先级为3,任务需要获取与低优先级任务相同的信号量来运行,同时将运行信息送往串口。

串口输出守护任务:任务优先级4,其功能是将通过队列传送过来的字符信息在串口上输出,任何时候只有该守护任务能访问串口。·互斥信号量·互斥信号量用互斥量抑制优先级翻转

互斥信号量拥有优先级继承机制,能够将持有互斥量任务的优先级提升到等待这个互斥量任务的优先级,从而抑制优先级翻转。

本示例仅仅将优先级翻转示例中的二值信号量换成互斥信号量,其它代码完全相同。创建互斥信号量是在appStartTask()函数中完成。四、递归互斥信号量·FreeRTOS信号量与任务同步·递归互斥信号量

互斥信号量在使用时,已经获取了这个互斥量的任务不能再次获取这个互斥信号量。

递归互斥信号量则是一种特殊的互斥信号量,允许已经获取了递归互斥信号量的任务可以重复获取这个递归互斥信号量,而且没有次数的限制。

同互斥信号量一样,递归互斥信号量也有优先级继承机制,同样不能用在中断服务函数中。

其它诸如创建、释放和获取的操作与互斥量完全相同,只是API函数的名字不一样而已。·递归互斥信号量操作函数v《嵌入式实时操作系统

FreeRTOS原理及应用——基于STM32微控制器》·张超主编·嵌入式实时操作系统FreeRTOS原理及应用·STM32

Cortex-M4通用开发·嵌入式实时操作系统FreeRTOS原理及应用·FreeRTOS事件标志组·主要内容:事件标志组用事件标志组进行任务同步一、事件标志组·FreeRTOS事件标志组·事件标志组

用一个二进制位来表示一个事件,当这个二进制位为1时,表明发生了对应事件,为0时没有发生,这样,多个二进制位组合在一起就可以用来表示事件标志组。

在FreeRTOS中,事件标志组中的所有事件位使用一个EventBits_t的数据类型来存储。这个数据类型与处理器的字长有关,在STM32微控制器上,这个数据类型为32位。FreeRTOS事件标志组只使用低24位用来存储事件位,故事件标志组最多只能存储24个事件。创建事件标志组·用函数xEventGroupCreate()来创建事件标志组,函数的原型为:·事件标志组设置事件位·设置事件位涉及二种操作,置1和清0。·1、xEventGroupClearBits()·事件标志位清0函数,函数原型如下:·事件标志组设置事件位·2、xEventGroupClearBitsFromIS

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论