说明

本文仅作为学习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. redis实现分布式锁天然的缺陷

    redis分布式锁基本原理 采用 redis 实现分布式锁,主要是利用其单线程命令执行的特性,一般是 setnx, 只会有一个线程会执行成功,也就是只有一个线程能成功获取锁: 看着很完美 看看可能有什 ...

  2. 在Excel中当遇到多个对象的目标值都不同时,如何快速设置条件格式突出未达标的对象

    1.选择实际值的一个单元格,选择条件格式,新建规则,选择图中选项. 2.这里选择大于,然后选择对比的单元格.选择需要的格式确定.(因为要对比的目标值不同,所以需要给单元格去掉绝对引用,也就是$符号). ...

  3. 24、mysql数据库优化

    24.1.如何判断网站慢的排查顺序: 客户端->web->nfs->数据库: 24.2.uptime命令详解: [root@backup ~]#uptime 13:03:23 up ...

  4. js 获取系统当前时间,判断时间大小

    1.获取系统当前时间 getNowTime(tempminit) { if (!tempminit) { tempminit = 0; } var date = new Date(); date.se ...

  5. POJ 1039 直线和线段相交

    题意: 题意很好理解,从左边射过来的光线,最远能经过管道到右边多少距离. 分析: 光线一定经过一个上端点和一个下端点,这一点很容易想到.然后枚举上下端点即可 #include <iostream ...

  6. Tiling 简单递推+大数

    Tiling c[0]=1,c[1]=1,c[2]=3;   c[n]=c[n-1]+c[n-2]*2;   0<=n<=250.   大数加法 java  time  :313ms 1 ...

  7. Hibernate框架(五)面向对象查询语言和锁

    Hibernate做了数据库中表和我们实体类的映射,使我们不必再编写sql语言了.但是有时候查询的特殊性,还是需要我们手动来写查询语句呢,Hibernate框架为了解决这个问题给我们提供了HQL(Hi ...

  8. MindInsight:一款基于MindSpore框架的训练可视化插件

    技术背景 在深度学习或者其他参数优化领域中,对于结果的可视化以及中间网络结构的可视化,也是一个非常重要的工作.一个好的可视化工具,可以更加直观的展示计算结果,可以帮助人们更快的发掘大量的数据中最有用的 ...

  9. python使用笔记26--多线程、多进程

    1.概念 线程.进程 进程是资源的集合,也就是一个程序 线程是一个程序运行的最小单位 线程是在进程里面的 默认,一个进程就只有一个线程 一个电脑有几核CPU就只能同时运行几个任务,比如4核CPU只能同 ...

  10. C语言:数组长度的检测方法

    //数组长度的检测方法 #include <stdio.h> int main() { int arr[] = { 22, 34, 3, 32, 82, 55, 89, 50, 37, 5 ...