说明

本文仅作为学习FreeRTOS的记录文档,作为初学者肯定很多理解不对甚至错误的地方,望网友指正。

FreeRTOS是一个RTOS(实时操作系统)系统,支持抢占式、合作式和时间片调度。适用于微处理器或小型微处理器的实时应用。

本文档使用的FreeRTOS版本:FreeRTOS Kernel V10.4.1

参考文档:《FreeRTOS_Reference_Manual_V10.0.0.pdf》《FreeRTOS_Real_Time_Kernel-A_Hands-On_Tutorial_Guide.pdf》《STM32F4 FreeRTOS开发手册_V1.1.pdf》

参考视频:正点原子FreeRTOS手把手教学-基于STM32_哔哩哔哩_bilibili

6 内核控制函数

内核控制函数就是FreeRTOS内核所使用的函数,一般情况下应用程序不使用这些函数。

官网API说明:FreeRTOS - Task Control Functions and Macros for the Free Open Source RTOS FreeRTOS

6.1 任务切换

函数原型:

#include “FreeRTOS.h”
#include “task.h”
void taskYIELD( void );

函数描述:任务切换函数。如果没有与当前任务同等优先级或高优先级的任务,则任务调度器会选择当前任务继续运行。必须在调度器初始化之后使用。

函数参数:

返回值:

测试代码:创建两个任务,任务task0优先级为2,任务函数中每次从0计数到2进行一次任务切换;任务task1优先级也为2,任务函数中每次打印之后就挂起自己。

configSTACK_DEPTH_TYPE Task0_STACK_SIZE = 5;
UBaseType_t Task0_Priority = 2;
TaskHandle_t Task0_xhandle; configSTACK_DEPTH_TYPE Task1_STACK_SIZE = 5;
UBaseType_t Task1_Priority = 2;
TaskHandle_t Task1_xhandle; void task0_code(void *para)
{
unsigned int i = 0; for (;;)
{
for (i = 0; i < 4; i++) {
PRINT(" task0 cnt %u...", i);
if (i == 2) {
vTaskResume(Task1_xhandle);
taskYIELD();
}
}
vTaskDelay(2000);
}
} void task1_code(void *para)
{
static unsigned int cnt = 0; for (;;)
{
PRINT(" task1 cnt %u...", cnt);
cnt++;
vTaskSuspend(Task1_xhandle);
}
} void creat_task(void)
{
taskENTER_CRITICAL(); if (xTaskCreate(task0_code, "task0 task",
Task0_STACK_SIZE, NULL, Task0_Priority,
&Task0_xhandle) != pdPASS)
{
PRINT("creat task failed!\n");
} if (xTaskCreate(task1_code, "task1 task",
Task1_STACK_SIZE, NULL, Task1_Priority,
&Task1_xhandle) != pdPASS)
{
PRINT("creat task failed!\n");
} taskEXIT_CRITICAL();
vTaskStartScheduler();
}

编译、运行,结果符合预期,每次调度taskYIELD()之后执行一次任务切换,结果如下:

$ ./build/freertos-simulator
task0 cnt 0...
task0 cnt 1...
task0 cnt 2...
task1 cnt 0...
task0 cnt 3...
task0 cnt 0...
task0 cnt 1...
task0 cnt 2...
task1 cnt 1...
task0 cnt 3...

现在将任务task0的优先级改为3,大于任务task1的优先级:

UBaseType_t  Task0_Priority = 3;

编译、运行,结果符合预期,每次调度taskYIELD()之后不会任务切换,结果如下:

$ ./build/freertos-simulator
task0 cnt 0...
task0 cnt 1...
task0 cnt 2...
task0 cnt 3...
task1 cnt 0...
task0 cnt 0...
task0 cnt 1...
task0 cnt 2...
task0 cnt 3...
task1 cnt 1...
task0 cnt 0...

6.2 进入临界区

函数原型:

#include “FreeRTOS.h”
#include “task.h”
void taskENTER_CRITICAL( void );

函数描述:进入临界区,不能在中断服务函数中调用。中断服务函数中调用taskENTER_CRITICAL_FROM_ISR()进入临界区。

函数参数:

返回值:

6.3 退出临界区

函数原型:

#include “FreeRTOS.h”
#include “task.h”
void taskEXIT_CRITICAL( void );

函数描述:退出临界区,不能在中断服务函数中调用。中断服务函数中调用taskEXIT_CRITICAL_FROM_ISR()退出临界区。

函数参数:

返回值:

taskENTER_CRITICAL()和taskEXIT_CRITICAL()函数用于临界段代码保护(任务级)。

taskENTER_CRITICAL_FROM_ISR()和taskEXIT_CRITICAL_FROM_ISR()函数用于中断级临界段代码保护。

临界段代码:也叫做临界区,指那些必须完整运行,不能被打断的代码。比如某些外设的初始化。FreeRTOS在进入临界段代码的时候需要关闭中断,当处理完临界段代码以后再打开中断。

6.4 关闭可屏蔽中断

函数原型:

#include “FreeRTOS.h”
#include “task.h”
void taskDISABLE_INTERRUPTS( void );

函数描述:关闭可屏蔽中断。不可嵌套使用。

函数参数:

返回值:

6.4 打开可屏蔽中断

函数原型:

#include “FreeRTOS.h”
#include “task.h”
void taskENABLE_INTERRUPTS( void );

函数描述:关闭可屏蔽中断。不可嵌套使用。

函数参数:

返回值:

6.5 启动任务调度器

函数原型:

#include “FreeRTOS.h”
#include “task.h”
void vTaskStartScheduler( void );

函数描述:启动任务调度器。典型应用为:main()函数先于调度器使用,调度器启动之后,执行任务及中断函数。调度器启动之后将选择优先级最高的任务进行执行。调度器启动之后,空闲任务(Idle task)将自动被创建。

函数参数:

返回值:

6.5 关闭任务调度器

函数原型:

#include “FreeRTOS.h”
#include “task.h”
void vTaskEndScheduler( void );

函数描述:关闭任务调度器。仅支持x86架构处理器。关闭任务调度器之后,内核时钟将停止计数,所有创建的任务都会自动删除。

函数参数:

返回值:

7 时间管理

FreeRTOS延时函数分为相对模式和绝对模式。vTaskDelay()是相对延时函数。vTaskDelayUntil()是绝对延时函数。

官网API说明:Links to the FreeRTOS task control API function vTaskDelay, vTaskDelayUntil, uxTaskPriorityGet, vTaskPrioritySet, vTaskSuspend, vTaskResume, xTaskResumeFromISR, vTaskSetApplicationTaskTag, xTaskCallApplicationTaskHook

7.1 相对延时

函数原型:

#include "FreeRTOS.h"
#include "task.h" void vTaskDelay( const TickType_t xTicksToDelay );

函数描述:调用该函数的任务将进入阻塞态,中断一段固定的时钟周期。使用这个函数必须将宏INCLUDE_vTaskDelay置1。

函数参数:xTicksToDelay表示调用函数的任务的阻塞态保持时间,单位为时钟节拍数。真正的延时时间取决于时钟节拍频率。宏 portTICK_PERIOD_MS被用来根据时钟节拍数来计算一个时钟节拍的延时周期。

#define portTICK_PERIOD_MS			( ( TickType_t ) 1000 / configTICK_RATE_HZ )
#define configTICK_RATE_HZ ( 1000 )

可以看出,单个时钟节拍计数时间为1ms,比如参数xTicksToDelay设为100,就表示延时100ms。

延时达到之后将进入就绪态。例如:当时钟计数到10000时,函数调用了vTaskDelay(100),然后任务进入阻塞态,并且保持阻塞态直到时钟计数到10100。

宏pdMS_TO_TICKS()可以被使用来延时毫秒。例如:调用vTaskDelay( pdMS_TO_TICKS(100) ),任务将进入阻塞态100毫秒。

如果参数xTicksToDelay为0,则等同于调用了一次taskYIELD()函数进行了一次任务切换。

返回值:

7.2 绝对延时

函数原型:

#include “FreeRTOS.h”
#include “task.h”
void vTaskDelayUntil( TickType_t *pxPreviousWakeTime, TickType_t xTimeIncrement );

函数描述:调用该函数的任务将进入阻塞态直到一个绝对的时间到来。周期任务可以调用这个函数来实现一个固定的执行频率。使用这个函数必须将宏INCLUDE_vTaskDelayUntil置1。

函数参数:pxPreviousWakeTime:上一次任务延时结束被唤醒的时间点,任务中第一次调用函数vTaskDelayUntil()需要将pxPreviousWakeTime初始化为进入任务的while()循环体的时间点值。在以后的运行中函数vTaskDelayUntil()会自动更新pxPreviousWakeTime。

xTimeIncrement:任务需要延时的节拍数(相对于pxPreviousWakeTime本次延时的节拍数),也就是任务在pxPreviousWakeTime+xTimeIncrementpd时钟计数时从阻塞态恢复。MS_TO_TICKS()宏可用于延时毫秒。

(1)为任务主体,也就是任务执行的工作;(2)为任务调用vTaskDelayUntil()函数;(3)为其它任务执行。任务延时时间为xTimeIncrement,可看出任务总的执行时间一定小于任务的延时时间,也就是说使用vTaskDelayUntil()函数任务的执行周期永远是xTimeIncrement,而任务一定要在这个时间内完成,这个延时值就是绝对延时时间。

上面图中,xConstTickCount和xTimeToWake可能溢出,这些情况暂不讨论,这里仅说明函数的用法。

测试代码:创建一个任务,使用绝对延时函数延时50ms。

configSTACK_DEPTH_TYPE Task1_STACK_SIZE = 5;
UBaseType_t Task1_Priority = 2;
TaskHandle_t Task1_xhandle; void task1_code(void *para)
{
unsigned int cnt = 0;
TickType_t xLastWakeTime;
const TickType_t xPeriod = pdMS_TO_TICKS(500); xLastWakeTime = xTaskGetTickCount();
for (;;)
{
vTaskDelayUntil(&xLastWakeTime, xPeriod);
PRINT(" task1 cnt %u...", cnt);
cnt++;
} } void creat_task(void)
{ if (xTaskCreate(task1_code, "task1 task",
Task1_STACK_SIZE, NULL, Task1_Priority,
&Task1_xhandle) != pdPASS)
{
PRINT("creat task failed!\n");
} }

7.3 系统时钟节拍

xTickCount是FreeRTOS系统时钟节拍计数器,每个滴答定时器中断中xTickCount就会加1。xTickCount具体操作过程在xTaskIncrementTick()函数中进行,这个函数在时钟计数器中断函数中调用。

FreeRTOS-04-内核控制函数+时间管理函数的更多相关文章

  1. μC/OS-Ⅲ系统的时间管理函数和定时器

    一.时间管理函数 μC/OS-Ⅲ系统提供一些列时间管理服务函数: 1.OSTimeDly():任务延时n个时钟节拍. 2.OSTimeDlyHMSM():任务延时指定的时间,采用“时:分:秒:毫秒”方 ...

  2. RTX——第12章 系统时钟节拍和时间管理

    以下内容转载自安富莱电子: http://forum.armfly.com/forum.php 本章节为大家讲解 RTX 操作系统的时钟节拍和时间管理函数,其中时间管理函数是 RTX 的基本函数,初学 ...

  3. 【uTenux实验】时间管理(系统时间/周期性处理/警报处理)

    1.系统时间管理 系统时间管理函数用来对系统时间进行操作,是OS的一个基础性的东西.个人认为,设置系统时间和获取系统时间对OS来说基本是可有可无的. uTenux提供了三个系统时间相关API.分别用于 ...

  4. (笔记)Linux内核学习(八)之定时器和时间管理

    一 内核中的时间观念 内核在硬件的帮助下计算和管理时间.硬件为内核提供一个系统定时器用以计算流逝的时间.系 统定时器以某种频率自行触发,产生时钟中断,进入内核时钟中断处理程序中进行处理. 墙上时间和系 ...

  5. linux设备驱动归纳总结(七):1.时间管理与内核延时【转】

    本文转载自:http://blog.chinaunix.net/uid-25014876-id-100005.html linux设备驱动归纳总结(七):1.时间管理与内核延时 xxxxxxxxxxx ...

  6. 《Linux内核设计与实现》读书笔记(十一)- 定时器和时间管理【转】

    转自:http://www.cnblogs.com/wang_yb/archive/2013/05/10/3070373.html 系统中有很多与时间相关的程序(比如定期执行的任务,某一时间执行的任务 ...

  7. Linux内核——定时器和时间管理

    定时器和时间管理 系统定时器是一种可编程硬件芯片.它能以固定频率产生中断.该中断就是所谓的定时器中断.它所相应的中断处理程序负责更新系统时间,还负责执行须要周期性执行的任务. 系统定时器和时钟中断处理 ...

  8. Linux内核入门到放弃-时间管理-《深入Linux内核架构》笔记

    低分辨率定时器的实现 定时器激活与进程统计 IA-32将timer_interrupt注册为中断处理程序,而AMD64使用的是timer_event_interrupt.这两个函数都通过调用所谓的全局 ...

  9. 解析Linux内核的基本的模块管理与时间管理操作---超时处理【转】

    转自:http://www.jb51.net/article/79960.htm 这篇文章主要介绍了Linux内核的基本的模块管理与时间管理操作,包括模块加载卸载函数的使用和定时器的用法等知识,需要的 ...

随机推荐

  1. SpringBoot实战:10分钟快速搞定环境

    什么是 springboot Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程. 该框架使用了特定的方式来进行配置,从而使开发人 ...

  2. DNS 解析过程

    DNS 是应用层协议,用于将域名转换成 IP 地址. 1. 解析过程 DNS 的核心系统是一个三层的树状.分布式服务,基本对应域名的结构. 根域名服务器:管理顶级域名服务器,返回 com.net.cn ...

  3. 理解vertical-align

    vertical-align 支持的属性值及组成 inherit 线类baseline, top, middle, bottom 文本类text-top, text-bottom 上标下标类sub, ...

  4. 什么IP欺骗?

    1.什么是IP欺骗? IP欺骗是指创建源地址经过修改的Internet协议(IP) 数据包,目的要么是隐藏发送方的身份,要么是冒充其他计算机系统,或者两者兼具.恶意用户往往采用这项技术对目标设备或周边 ...

  5. 8、mysql乱码问题及字符集实战

    8.1.mysql插入中文数据乱码案例: mysql建库的字符集为latin1,客户端的字符集为utf8; use lc; 1.查看库的编码: mysql> show create databa ...

  6. 八皇后O(1)算法题解

    题目描述 在国际象棋棋盘上(8*8)放置八个皇后,使得任意两个皇后之间不能在同一行,同一列,也不能位于同于对角线上.问共有多少种不同的方法,并且按字典序从小到大指出各种不同的放法. 题解 见证奇迹的时 ...

  7. MongoDB数据库 5分钟快速上手

    安装 本次安装使用docker镜像,安装无障碍,一行命令即可解决 # 安装镜像并启动 可以自行修改命令中的参数 ## 账户 tanoak 密码 123123 ## -p 27018:27017 映射端 ...

  8. Linux文件编辑工具——VIM

    Linux文件编辑工具--VIM 1.VIM基本概述 1.1 什么是vim vi 和 vim 是 Linux 下的一个文本编辑工具.(可以理解为 windows 的记事本,或 Notepad++ 1. ...

  9. shiro框架基础

    一.shiro框架简介 Apache Shiro是Java的一个安全框架.其内部架构如下: 下面来介绍下里面的几个重要类: Subject:主体,应用代码直接交互的对象就是Subject.代表了当前用 ...

  10. spring boot.2x 集成swagger 加入拦截器后 swagger不能访问

    忽略掉 swagger-resources下面的请求 以及忽略掉 v2下面的请求即可 转自:https://blog.csdn.net/hanwenyi520/article/details/7989 ...