Free RTOS实时操作系统
目录
修改 FreeRTOSConfig.h 文件(操作系统的配置文件)
裸机和实时操作系统
裸机: 早期嵌入式开发没有嵌入式操作系统的概念 ,直接操作裸机,在裸机上写程序,比如用51单片机基本就没有操作系统的概念。
通常把程序设计为前后台系统,主要分为两部分:前台系统和后台系统。这样的程序包括一个死循环和若干个中断服务程序(应用程序是一个无限循环,循环中调用API函数完成所需的操作,这个大循环就叫做后台系统;中断服务程序用于处理系统的异步事件,也就是前台系统),前台是中断级,后台是任务级。
问题:这里就是平时我们裸机的运行结果,现在比如我在运行task3,突然又想马上运行task1,这怎么办?
前后台程序就会让后面的任务执行之后,再去执行task1,这样实时性受到影响。如果是裸机,要实现也可以,用中断,可是这样会让程序结构变得复杂,因为我想什么时候跳过就跳过,想什么时候执行就执行,所以固定的中断触发方式虽然也可以实现一些简单的跳转功能,但是当程序复杂之后,这样的裸机程序难以阅读和维护。但是引入操作系统的任务调度之后,就会让系统响应更具有实时性。
RTOS: RTOS全称为:Real Time OS,就是实时操作系统,强调的是:实时性。在实时操作系统中,我们可以把要实现的功能划分为多个任务,每个任务负责实现其中的一部分,每个任务都是一个很简单的程序,通常是一个死循环。 RTOS操作系统:FreeRTOS,UCOS,RTX,RT-Thread,DJYOS等。 RTOS操作系统的核心内容在于:实时内核。
其他操作系统: 分时操作系统:一台计算机采用时间片轮转的方式同时为几个、几十个甚至几百个用户服务的一种操作系统,如:UNIX系统就采用剥夺式动态优先的CPU调度,有力地支持分时操作。
实时操作系统:当外界事件或数据产生时,能够接受并以足够快的速度予以处理,其处理的结果又能在规定的时间之内来控制生产过程或对处理系统做出快速响应,调度一切可利用的资源完成实时任务,并控制所有实时任务协调一致运行的操作系统。提供及时响应和高可靠性是其主要特点。永远执行最高优先级,最高优先级任务只有1个。如:UCOS-II/III。
半实时操作系统:允许任务具有相同的优先级。如:FreeRTOS。
嵌入式操作系统的作用
-- 操作系统是个软件(管理底层硬件,并且上层应用提供接口)
嵌入式(实时)操作系统特点:用于嵌入式设备的操作系统,具有通用操作系统的基本特点,又具有系统实时性、硬件的相关依赖性、软件固态化以及应用的专用性等特点;
评判嵌入式(实时)操作系统的重要指标:实时性(中断响应时间、任务切换时间等)、尺寸(可裁剪性 )、可扩展性(内核、中间件);
-- 嵌入式操作系统的发展
-- 相关术语
-- 查询相关嵌入式里可用的实时操作系统有哪些??怎么评判一个实时操作系统的性能?
Linux ecos freertos rtthread osii
实时性 尺寸 可扩展性
-- 了解操作系统在计算机的分层
-- 操作系统最基础的就是任务(类似线程)
-- 逻辑不会发生资源的抢占,因为是按顺序执行的
-- 操作系统中会产生资源的抢占,因为操作系统会根据优先级来决定哪个任务先执行
向裸机工程中添加 FreeRTOS 源码
-- 可以参考移植笔记
- 1、
首先在我们的 STM32 裸机工程模板根目录下新建一个文件夹,命名为“FreeRTOS”, 并且在 FreeRTOS 文件夹下新建两个空文件夹,分别命名为“src”与“port”,src 文件夹用于 保存 FreeRTOS 中的核心源文件,也就是我们常说的‘.c 文件’, port 文件夹用于保存内存 管理以及处理器架构相关代码,这些代码 FreeRTOS 官方已经提供给我们的,直接使用即可, 在前面已经说了, FreeRTOS 是软件,我们的开发版是硬件,软硬件必须有桥梁来连接,这 些与 处 理 器 架 构 相 关 的 代 码 , 可以 称 之 为 RTOS 硬件 接 口 层 , 它 们 位 于 FreeRTOS/Source/Portable 文件夹下。
- 2、打开 FreeRTOS 源码,在“FreeRTOSvX.X.X\FreeRTOS\Source”目录下找到所有的‘.c 文 件’,将它们拷贝到我们新建的 src 文件夹中。
-
3、打开 FreeRTOS VX.X.X 源码,在“FreeRTOS VX.X.X \FreeRTOS\Source\portable”目录 下找到“ MemMang”文件夹与“ RVDS”文件夹,将它们拷贝到我们新建的 port 文件夹中。
-
4、打开 FreeRTOS VX.X.X 源码,在“FreeRTOS VX.X.X \FreeRTOS\Source” 目录下找到 “include”文件夹,它是我们需要用到 FreeRTOS 的一些头文件,将它直接拷贝到我们新建的 FreeRTOS 文件夹中,完成这一步之后就可以看到我们新建的 FreeRTOS 文件夹已经有 3 个文件夹,这 3 个文件夹就包含 FreeRTOS 的核心文件,至此,FreeRTOS 的源码就提取 完成。
-
5、拷贝 FreeRTOSConfig.h 文件到 user 文件夹 FreeRTOSConfig.h 文件是 FreeRTOS 的工程配置文件,因为 FreeRTOS 是可以裁剪的 实时操作内核,应用于不同的处理器平台,用户可以通过修改这个 FreeRTOS 内核的配置头 文件来裁剪 FreeRTOS 的功能,所以我们把它拷贝一份放在 user 这个文件夹下面
-
6、添加 FreeRTOS 源码到工程组文件夹
- 7、 配置 FreeRTOS 头文件路径
修改 FreeRTOSConfig.h 文件(操作系统的配置文件)
-- 将以下代码复制到FreeRTOSConfig.h的开头
#include "stm32f10x.h"
/* 我们可以添加的宏定义 */
#define configUSE_TIME_SLICING 1 //使能时间片调度(默认式使能的)
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 //硬件计算前导零指令,如果所使用的, MCU 没有这些硬件指令的话此宏应该设置为 0
#define configUSE_TICKLESS_IDLE 0 //置 1:使能低功耗 tickless 模式;置 0:保持系统节拍(tick)中断一直运行
#define configUSE_QUEUE_SETS 1 //启用队列
#define configUSE_TASK_NOTIFICATIONS 1 //开启任务通知功能,默认开启
#define configUSE_MUTEXES 1 //使用互斥信号量
#define configUSE_RECURSIVE_MUTEXES 1 //使用递归互斥信号量
#define configUSE_COUNTING_SEMAPHORES 1 //为 1 时使用计数信号量
#define configQUEUE_REGISTRY_SIZE 10 //设置可以注册的信号量和消息队列个数
#define configUSE_APPLICATION_TASK_TAG 0
#define configSUPPORT_DYNAMIC_ALLOCATION 1 //支持动态内存申请
#define configUSE_MALLOC_FAILED_HOOK 0 //使用内存申请失败钩子函数
#define configCHECK_FOR_STACK_OVERFLOW 1// 大于 0 时启用堆栈溢出检测功能,如果使用此功能用户必须提供一个栈溢出钩子函数如果使用的话此值可以为 1 或者 2,因为有两种栈溢出检测方法
#define configGENERATE_RUN_TIME_STATS 0 //启用运行时间统计功能
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
#define configUSE_TIMERS 1 //启用软件定时器
#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES-1) //软件定时器优先级
#define configTIMER_QUEUE_LENGTH 10 //软件定时器队列长度
#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE*2) //软件定时器任务堆栈大小
//可选函数配置选项
#define INCLUDE_xTaskGetSchedulerState 1
#define INCLUDE_eTaskGetState 1
#define INCLUDE_xTimerPendFunctionCall 1
//中断服务函数 也可以修改起始文件
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_Handler
-- 之后不想用的话可以将这些宏定义关闭
-- 修改 stm32f10x_it.c
-- 将下面这些函数注释,因为这三个函数操作系统在使用
-- 以后就不能在工程中用滴答定时器
-- 如果在 FreeRTOSConfig.h 将 configCHECK_FOR_STACK_OVERFLOW 宏定义成 1 ,则 需要添加一个钩子函数,否则编译报错。(将这个函数写在main.c的最下面)
--
创建任务 – 动态内存
FreeRTOS 做法是在 SRAM 里面定义一个大数组,也就是堆内存,供 FreeRTOS 的动 态内存分配函数使用,在第一次使用的时候,系统会将定义的堆内存进行初始化,这些代码 在 FreeRTOS 提供的内存管理方案中实现(heap_1.c、heap_2.c、 heap_4.c 等)。
-
1、创建任务函数
-
2、定义任务栈 使用动态内存的时候,任务栈在任务创建的时候创建,不用跟使用静态内存那样要预 先定义好一个全局的静态的栈空间,动态内存就是按需分配内存,随用随取。
-
3、定义任务控制块指针 任务控制块是在任务创建的时候分配内存空间创建,任务创建函数会返回一个指针,用 于指向任务控制块,所以要预先为任务栈定义一个任务控制块指针,也是我们常说的任务句 柄。
-
4、动态创建任务 使用动态内存的时,使用 xTaskCreate()函数来创建一个任务。
-
5、main() 函数编写
-
6、 编译,下载,运行 将写好的代码编译,并下载到节点板中,观察节点板现象,会发现节点板上的 LED 灯在 闪烁。
-
7、开始任务的创建 一般我们在创建任务时会先创建一个起始任务(开始任务),然后在开始任务中创建其 他任务,然后在主函数中调用开始任务并启动任务调度。
编译运行之后会发现系统卡死,调试之后发现程序死在任务栈区溢出钩子函数,说明我 们创建的任务中有任务开辟的占空间内存过小,改大一点即可
-- 这里我们写一个简单的灯闪烁的程序
int main()
{
TaskHandle_t Led1TaskCreat_Handle = NULL;//任务句柄
BaseType_t xReturn = pdPASS;
xReturn = xTaskCreate(LED1TaskCreat, //任务函数接口 函数名称
"led1", //任务别名不能一样
128, //任务栈空间(字节)
NULL, //任务传参
1, //任务优先级 那个任务重要,优先级高
&Led1TaskCreat_Handle); //任务句柄
if(xReturn == pdPASS)
vTaskStartScheduler();//任务调度器
}
-- 正常情况下任务调度器后面的代码不会被执行
-- 之后在main函数的上面写上以下这个函数,就会使LED1闪烁
void LED1TaskCreat(void *pvParameters)
{
while(1)
{
LED1(1);
vTaskDelay(100); //任务周期 100个时钟节拍 释放cpu
LED1(0);
vTaskDelay(100); //任务周期
}
}
FreeRTOS 文件夹介绍
FreeRTOS 包含 Demo 例程和内核源码(比较重要,我们就需要提取该目录下的大部 分文件)。 FreeRTOS 文件夹下的 Source 文件夹里面包含的是 FreeRTOS 内核的源代码, 我们移植 FreeRTOS 的时候就需要这部分源代码; FreeRTOS 文件夹下的 Demo 文件夹里 面包含了 FreeRTOS 官方为各个单片机移植好的工程代码, FreeRTOS 为了推广自己,会 给各种半导体厂商的评估板写好完整的工程程序,这些程序就放在 Demo 这个目录下,这 部分 Demo 非常有参考价值。我们把 FreeRTOS 到 STM32 的时候,FreeRTOSConfig.h 这 个头文件就是从这里拷贝过来的,下面我们对 FreeRTOS 的文件夹进行分析说明。
- Source 文件夹 这里我们再重点分析下 FreeRTOS/ Source 文件夹下的文件,具体见图 13-6。 “include” 文件夹和“portable”文件夹包含的是 FreeRTOS 的通用的头文件和 C 文件,这两部分的文 件试用于各种编译器和 include 处理器, 是通用的。需要移植的头文件和 C 文件放在编号 portblle 这个文件夹。
我们打开 portable 这个文件夹,可以看到里面很多与编译器相关的文件夹, 在不同的 编译器中使用不同的支持文件。文件夹“Keil”就是我们就是我们使用的编译器,当打开 “Keil”文件夹的时候,你会看到一句话“See-also-the-RVDS-directory.txt”,其实 “Keil” 里面的内容跟 RVDS 里面的内容一样,所以我们只需要 RVDS 文件夹里面的内容即可。而 MemMang文件夹下存放的是跟内存管理相关的,稍后具体介绍。
打开 RVDS 文件夹, 下面包含了各种处理器相关的文件夹,从文件夹的名字我们就非 常熟悉了,有 M0、 M3、 M4 等各种系列, FreeRTOS 是一个软件,单片机是一个硬件, FreeRTOS 要想运行在一个单片机上面,它们就必须关联在一起,那么怎么关联?还是得通 过写代码来关联,这部分关联的文件叫接口文件,通常由汇编和 C 联合编写。这些接口文 件都是跟硬件密切相关的,不同的硬件接口文件是不一样的,但都大同小异。编写这些接口 文件的过程我们就叫移植,移植的过程通常由 FreeRTOS 和 MCU 原厂的人来负责,移植 好的这些接口文件就放在 RVDS 这个文件夹的目录下。
FreeRTOS 为我们提供了 cortex-m0、 m3、 m4 和 m7 等内核的单片机的接口文件, 只要是使用了这些内核的 MCU 都可以使用里面的接口文件。我们这里以 ARM_CM3 这个 文件夹为例,看看里面的文件,里面只有“port.c”与“portmacro.h”两个文件, port.c 文件里面的内容是由 FreeRTOS 官方的技术人员为 Cortex-M3 内核的处理器写的接口文件,里面核心的上下文切换代码是由汇编语言编写而成;portmacro.h 则是 port.c 文件对应的头文件,主要是一些数据类型和宏定义。
MemMang 文件夹下存放的是跟内存管理相关的,总共有五个 heap 文件以及一 个 readme 说明文件,这五个 heap 文件在移植的时候必须使用一个,因为 FreeRTOS 在 创建内核对象的时候使用的是动态分配内存,而这些动态内存分配的函数则在这几个文件里 面实现,不同的分配算法会导致不同的效率与结果,后面在内存管理中我们会讲解每个文件 的区别,由于现在是初学,所以我们选用 heap4.c 即可。
Demo 文件夹:
这个目录下内容就是 Deme 例程,我们可以直接打开里面的工程文件, 各种开发平台 的完整 Demo,开发者可以方便的以此搭建出自己的项目,甚至直接使用。 FreeRTOS 当 然也为 ST 写了很多 Demo,其中就有 F1、 F4、 F7 等工程,这样子对我们学习 FreeRTOS 是非常方便的,当遇到不懂的直接就可以参考官方的 Demo。
- License 文件夹
这里面只有一个许可文件“license.txt”,用 FreeRTOS 做产品的话就需要看看这个文件, 但是我们是学习 FreeRTOS,所以暂时不需要理会这个文件。 - FreeRTOS-Plus 文件夹
FreeRTOS-Plus 文件 夹 里 面 包 含 的 是 第 三 方 的 产 品 , 一 般 我 们 不 需 要 使 用 , FreeRTOSPlus 的预配置演示项目组件(组件大多数都要收费),大多数演示项目都是在 Windows 环境中运行的,使用 FreeRTOS windows 模拟器,所以暂时不需要关注这个文件 夹。
更改过后的代码
-- FreeRTOSConfig.h
-- 重点注意这几个宏定义
/*
* FreeRTOS Kernel V10.2.1
* Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
/*-----------------------------------------------------------
* Application specific definitions.
*
* These definitions should be adjusted for your particular hardware and
* application requirements.
*
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
*
* See http://www.freertos.org/a00110.html
*----------------------------------------------------------*/
#include "stm32f10x.h"
/* 我们可以添加的宏定义 */
#define configUSE_TIME_SLICING 1 //使能时间片调度(默认式使能的)
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 //硬件计算前导零指令,如果所使用的, MCU 没有这些硬件指令的话此宏应该设置为 0
#define configUSE_TICKLESS_IDLE 0 //置 1:使能低功耗 tickless 模式;置 0:保持系统节拍(tick)中断一直运行
#define configUSE_QUEUE_SETS 1 //启用队列
#define configUSE_TASK_NOTIFICATIONS 1 //开启任务通知功能,默认开启
#define configUSE_MUTEXES 1 //使用互斥信号量
#define configUSE_RECURSIVE_MUTEXES 1 //使用递归互斥信号量
#define configUSE_COUNTING_SEMAPHORES 1 //为 1 时使用计数信号量
#define configQUEUE_REGISTRY_SIZE 10 //设置可以注册的信号量和消息队列个数
#define configUSE_APPLICATION_TASK_TAG 0
#define configSUPPORT_DYNAMIC_ALLOCATION 1 //支持动态内存申请
#define configUSE_MALLOC_FAILED_HOOK 0 //使用内存申请失败钩子函数
#define configCHECK_FOR_STACK_OVERFLOW 1// 大于 0 时启用堆栈溢出检测功能,如果使用此功能用户必须提供一个栈溢出钩子函数如果使用的话此值可以为 1 或者 2,因为有两种栈溢出检测方法
#define configGENERATE_RUN_TIME_STATS 0 //启用运行时间统计功能
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
#define configUSE_TIMERS 1 //启用软件定时器
#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES-1) //软件定时器优先级
#define configTIMER_QUEUE_LENGTH 10 //软件定时器队列长度
#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE*2) //软件定时器任务堆栈大小
//可选函数配置选项
#define INCLUDE_xTaskGetSchedulerState 1
#define INCLUDE_eTaskGetState 1
#define INCLUDE_xTimerPendFunctionCall 1
//中断服务函数 也可以修改起始文件
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_Handler
#define configUSE_PREEMPTION 1
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configCPU_CLOCK_HZ ( ( unsigned long ) 72000000 ) // 系统时钟频率
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 ) //时钟节拍 1s内要产生1000个时钟节拍(用于操作系统内部的工作)
#define configMAX_PRIORITIES ( 5 ) //指的是最大优先级(给任务赋优先级,最大赋5)
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 128 ) //空闲任务(优先级最低)128是空闲任务的空间
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 17 * 1024 ) ) //单片机给操作系统分配的空间(单片机的空间剩下64-17)
#define configMAX_TASK_NAME_LEN ( 16 )
#define configUSE_TRACE_FACILITY 0
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
/* Co-routine definitions. */
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskCleanUpResources 1
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
/* This is the raw value as per the Cortex-M3 NVIC. Values can be 255
(lowest) to 0 (1?) (highest). */
#define configKERNEL_INTERRUPT_PRIORITY 255
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 191 /* equivalent to 0xb0, or priority 11. */
/* This is the value being used as per the ST library which permits 16
priority values, 0 to 15. This must correspond to the
configKERNEL_INTERRUPT_PRIORITY setting. Here 15 corresponds to the lowest
NVIC value of 255. */
#define configLIBRARY_KERNEL_INTERRUPT_PRIORITY 15
#endif /* FREERTOS_CONFIG_H */
-- main.c
#include "STM32f10x.h"
#include "led.h"
#include "delay.h"
#include "buzzer.h"
#include "relay.h"
#include "key.h"
#include "exti.h"
#include "stm32f10x_it.h"
#include "usart.h"
#include "string.h"
#include "kqm6600.h"
#include "su03t.h"
#include "dht11.h"
#include "adc.h"
#include "pwm.h"
#include "rtc.h"
#include "bsp_lcd.h"
#include "esp.h"
#include "stm32_eval_spi_flash.h"
#include "freertos.h"
#include "task.h"
void LED1TaskCreat(void *pvParameters)
{
while(1)
{
LED1(1);
vTaskDelay(100); //任务周期 100个时钟节拍 释放cpu
LED1(0);
vTaskDelay(100); //任务周期
}
}
int main()
{
led_init();
Delay_nms(2000);
TaskHandle_t Led1TaskCreat_Handle = NULL;//任务句柄
BaseType_t xReturn = pdPASS;
xReturn = xTaskCreate(LED1TaskCreat, //任务函数接口 函数名称
"led1", //任务别名不能一样
128, //任务栈空间(字节)
NULL, //任务传参
1, //任务优先级 那个任务重要,优先级高
&Led1TaskCreat_Handle); //任务句柄
if(xReturn == pdPASS)
vTaskStartScheduler();//任务调度器
}
标签:FreeRTOS,configUSE,RTOS,Free,任务,文件夹,实时操作系统,include,define
From: https://blog.csdn.net/m0_71813740/article/details/143023339