第17章
FreeRTOS系统时钟节拍和时间管理
本文完整版地址:http://bbs.armfly.com/read.php?tid=21196
本章节为大家讲解FreeRTOS操作系统的系统时钟节拍和时间管理函数,其中时间管理函数是FreeRTOS的基本函数,初学者务必要掌握。
本章教程配套的例子含Cortex-M3内核的STM32F103和Cortex-M4内核的STM32F407以及F429。
17.1
FreeRTOS的时钟节拍
17.2
FreeRTOS的时间管理
17.3
实验例程说明
17.4
总结
17.1 FreeRTOS的时钟节拍
任何操作系统都需要提供一个时钟节拍,以供系统处理诸如延时、超时等与时间相关的事件。
时钟节拍是特定的周期性中断,这个中断可以看做是系统心跳。中断之间的时间间隔取决于不同的应用,一般是1ms
–
100ms。时钟的节拍中断使得内核可以将任务延迟若干个时钟节拍,以及当任务等待事件发生时,提供等待超时等依据。时钟节拍率越快,系统的额外开销就越大。
对于Cortex-M3内核的STM32F103和Cortex-M4内核的STM32F407以及F429,教程配套的例子都是用滴答定时器来实现系统时钟节拍的。
l
滴答定时器Systick
SysTick定时器被捆绑在NVIC中,用于产生SysTick异常(异常号:15),滴答定时器是一个24位
的递减计数器,支持中断。使用比较简单,专门用于给操作系统提供时钟节拍。
FreeRTOS的系统时钟节拍可以在配置文件FreeRTOSConfig.h里面设置:
#define
configTICK_RATE_HZ ( ( TickType_t ) 1000 )
如上所示的宏定义配置表示系统时钟节拍是1KHz,即1ms。
17.2FreeRTOS的时间管理
时间管理功能是FreeRTOS操作系统里面最基本的功能,同时也是必须要掌握好的。
17.2.1时间延迟
FreeRTOS中的时间延迟函数主要有以下两个作用:
u
为周期性执行的任务提供延迟。
u
对于抢占式调度器,让高优先级任务可以通过时间延迟函数释放CPU使用权,从而让低优先级任务可以得到执行。
下面我们通过如下的框图来说明一下延迟函数对任务运行状态的影响,让大家有一个形象的认识。
运行条件:
u
仅对任务Task1的运行状态做说明。
u
调度器支持时间片调度和抢占式调度。
运行过程描述如下:
u
起初任务Task1处于运行态,调用vTaskDelay函数后进入到阻塞状态,也就是blocked状态。
u
vTaskDelay函数设置的延迟时间到,由于任务Task1不是当前就绪的最高优先级任务,所以不能进入到运行状态,只能进入到就绪状态,也就是ready状态。
u
一段时间后,调度器发现任务Task1是当前就绪的最高优先级任务,从而任务从就绪态切换到运行态。
u
由于时间片调度,任务Task1由运行态切换到就绪态。
上面就是一个简单的任务运行状态的切换过程。
17.2.2FreeRTOS的时间相关函数
FreeRTOS时间相关的函数主要有以下4个:
u
vTaskDelay
()
u
vTaskDelayUntil
()
u
xTaskGetTickCount()
u
xTaskGetTickCountFromISR()
下面我们对这4个函数依次进行说明:
17.2.3函数vTaskDelay
关于这个函数的讲解及其使用方法可以看FreeRTOS在线版手册:
这里也对此函数进行下介绍。
函数原型:
void
vTaskDelay(
const TickType_t xTicksToDelay );
函数描述:
函数vTaskDelay用于任务的延迟。
u
参数xTicksToDelay用于设置延迟的时钟节拍个数,范围1-
0xFFFFFFFF。延迟时间的最大值在portmacro.h文件里面有定义:
typedef uint32_t
TickType_t;
#define
portMAX_DELAY ( TickType_t )0xffffffffUL
即延迟时间的范围是:1-
0xFFFFFFFF
使用举例:
static
void vTaskLED(void *pvParameters)
{
while(1)
{
bsp_LedToggle(2);
vTaskDelay(200);
}
}
17.2.4函数vTaskDelayUntil
关于这个函数的讲解及其使用方法可以看FreeRTOS在线版手册:
这里也对此函数进行下介绍。
函数原型:
void
vTaskDelayUntil( TickType_t
*pxPreviousWakeTime,
const TickType_t xTimeIncrement );
函数描述:
函数vTaskDelayUntil用于周期性延迟。
u
第1个参数,存储任务上次处于非阻塞状态时刻的变量地址。
u
第2个参数,周期性延迟时间。
使用这个函数要注意以下问题:
1.
使用此函数需要在FreeRTOSConfig.h配置文件中配置如下宏定义为1
#define
INCLUDE_vTaskDelayUntil 1
2.
用户要注意此函数跟vTaskDelay的区别,本章17.2.7小节详细讲解。
使用举例:
static
void vTaskLED(void *pvParameters)
{
TickType_t xLastWakeTime;
const TickType_t xFrequency = 200;
xLastWakeTime = xTaskGetTickCount();
while(1)
{
bsp_LedToggle(2);
vTaskDelayUntil(&xLastWakeTime, xFrequency);
}
}
17.2.5函数xTaskGetTickCount
关于这个函数的讲解及其使用方法可以看FreeRTOS在线版手册:
这里也对此函数进行下介绍。
函数原型:
volatile
TickType_t xTaskGetTickCount( void );
函数描述:
函数xTaskGetTickCount用于获取系统当前运行的时钟节拍数。
使用这个函数要注意以下问题:
1. 此函数用于在任务代码里面调用,如果在中断服务程序里面调用的话,需要使用函数xTaskGetTickCountFromISR,这两个函数切不可混用。
使用举例:
static
void vTaskTaskUserIF(void *pvParameters)
{
uint8_t ucKeyCode;
uint8_t pcWriteBuffer[500];
while(1)
{
ucKeyCode = bsp_GetKey();
if (ucKeyCode != KEY_NONE)
{
switch (ucKeyCode)
{
case
KEY_DOWN_K1:
printf("当前的系统时钟节拍数
= %d\r\n", xTaskGetTickCount());
break;
default:
break;
}
}
vTaskDelay(20);
}
}
17.2.6函数xTaskGetTickCountFromISR
关于这个函数的讲解及其使用方法可以看FreeRTOS在线版手册:
这里也对此函数进行下介绍。
函数原型:
volatile
TickType_t xTaskGetTickCountFromISR( void );
函数描述:
函数xTaskGetTickCountFromISR用于获取系统当前运行的时钟节拍数。
使用这个函数要注意以下问题:
1. 此函数用于在中断服务程序里面调用,如果在任务里面调用的话,需要使用函数xTaskGetTickCount,这两个函数切不可混用。
使用举例:
void
TIM6_IRQHandler( void )
{
TickType_t xTickCount;
xTickCount = xTaskGetTickCountFromISR;
}
17.2.7函数vTaskDelay和vTaskDelayUntil的区别
函数vTaskDelayUntil实现的是周期性延迟,而函数vTaskDelay实现的是相对性延迟,反映到实际应用上有什么区别呢,下面就给大家举一个简单的例子。
运行条件:
u
有一个bsp_KeyScan函数,这个函数处理时间大概耗时2ms。
u
有两个任务,一个任务Task1是用的vTaskDelay延迟,延迟10ms,另一个任务Task2是用的vTaskDelayUntil延迟,延迟10ms。
u
不考虑任务被抢占而造成的影响。
实际运行过程效果:
Task1:
bsp_KeyScan+ vTaskDelay
(10) ---> bsp_KeyScan
+ vTaskDelay
(10)
|----2ms + 10ms
为一个周期------||----2ms + 10ms 为一个周期----|
这个就是相对性的含义
Task2:
bsp_KeyScan + vTaskDelayUntil --------->
bsp_KeyScan + vTaskDelayUntil
|----10ms为一个周期(2ms包含在10ms内)---||----10ms
为一个周期------|
这就是周期性的含义。
下面我们通过函数vTaskDelay来实现vTaskDelayUntil,大家会有一个更加全面的认识:
static
void vTaskMsgPro(void *pvParameters)
{
TickType_t xDelay, xNextTime;
const TickType_t xFrequency = 200;
xNextTime = xTaskGetTickCount() + xFrequency;
while(1)
{
bsp_LedToggle(3);
xDelay = xNextTime - xTaskGetTickCount();
xNextTime += xFrequency;
if(xDelay <&#61; xFrequency)
{
vTaskDelay(xDelay);
}
}
}
17.3实验例程说明
17.3.1STM32F103开发板实验
配套例子&#xff1a;
V4-311_FreeRTOS实验_周期性延迟和相对性延迟函数
实验目的&#xff1a;
1.
学习FreeRTOS的周期性延迟和相对性延迟函数。
2.
注意相对性延迟函数vTaskDelay和周期性延迟函数vTaskDelayUntil的区别。
实验内容&#xff1a;
1.
K1按键按下&#xff0c;串口打印任务执行情况(波特率115200&#xff0c;数据位8&#xff0c;奇偶校验位无&#xff0c;停止位1)。
2.
K2键按下&#xff0c;串口打印系统时钟节拍数。
3.
各个任务实现的功能如下&#xff1a;
vTaskUserIF任务
&#xff1a;按键消息处理。
vTaskLED任务&#xff1a;LED闪烁。
vTaskMsgPro任务
&#xff1a;消息处理&#xff0c;这里是用作LED闪烁。
vTaskStart任务&#xff1a;启动任务&#xff0c;也是最高优先级任务&#xff0c;这里实现按键扫描。
FreeRTOS的配置&#xff1a;
FreeRTOSConfig.h文件中的配置如下&#xff1a;
#if
defined(__ICCARM__) || defined(__CC_ARM) ||
defined(__GNUC__)
#include
extern
volatile uint32_t ulHighFrequencyTimerTicks;
#endif
#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 )
#define
configMAX_PRIORITIES ( 5 )
#define
configMINIMAL_STACK_SIZE ( ( unsigned short ) 128
)
#define
configTOTAL_HEAP_SIZE ( ( size_t ) ( 17 * 1024 ) )
#define
configMAX_TASK_NAME_LEN ( 16 )
#define
configUSE_TRACE_FACILITY
1
#define
configUSE_16_BIT_TICKS 0
#define
configIDLE_SHOULD_YIELD 1
#define
configGENERATE_RUN_TIME_STATS 1
#define
configUSE_STATS_FORMATTING_FUNCTIONS 1
#define
portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() (ulHighFrequencyTimerTicks &#61; 0ul)
#define
portGET_RUN_TIME_COUNTER_VALUE() ulHighFrequencyTimerTicks
//#define
portALT_GET_RUN_TIME_COUNTER_VALUE 1
#define
configUSE_CO_ROUTINES
0
#define
configMAX_CO_ROUTINE_PRIORITIES ( 2 )
#define
INCLUDE_vTaskPrioritySet 1
#define
INCLUDE_uxTaskPriorityGet 1
#define
INCLUDE_vTaskDelete 1
#define
INCLUDE_vTaskCleanUpResources
0
#define
INCLUDE_vTaskSuspend 1
#define
INCLUDE_vTaskDelayUntil 1
#define
INCLUDE_vTaskDelay 1
#ifdef
__NVIC_PRIO_BITS
#define
configPRIO_BITS __NVIC_PRIO_BITS
#else
#define
configPRIO_BITS 4
#endif
#define
configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0x0f
#define
configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 0x01
几个重要选项说明&#xff1a;
u
#define
configUSE_PREEMPTION 1
使能抢占式调度器
u
#define
configCPU_CLOCK_HZ ( ( unsigned long ) 72000000
)
系统主频72MHz。
u
#define
configTICK_RATE_HZ ( ( TickType_t ) 1000 )
系统时钟节拍1KHz&#xff0c;即1ms。
u
#define
configMAX_PRIORITIES ( 5 )
定义可供用户使用的最大优先级数&#xff0c;如果这个定义的是5&#xff0c;那么用户可以使用的优先级号是0,1,2,3,4&#xff0c;不包含5&#xff0c;对于这一点&#xff0c;初学者要特别的注意。
u
#define
configTOTAL_HEAP_SIZE ( ( size_t ) ( 17 * 1024 ) )
定义堆大小&#xff0c;FreeRTOS内核&#xff0c;用户动态内存申请&#xff0c;任务栈等都需要用这个空间。
u
configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 0x01
定义受FreeRTOS管理的最高优先级中断。简单的说就是允许用户在这个中断服务程序里面调用FreeRTOS的API的最高优先级。为了进一步说明这个宏定义的的作用&#xff0c;解释如下&#xff1a;
l
使用CM内核的MCU&#xff0c;官方强烈建议将NVIC的优先级分组配置为全抢占式优先级&#xff0c;全部配置为抢占式优先级的好处就是方便管理。
l
对于STM32来说&#xff0c;设置NVIC的优先级分组为4时&#xff0c;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4)就是全部配置为抢占式优先级。又因为STM32的优先级设置仅使用CM内核8bit中的高4bit&#xff0c;即只能区分2^4
&#61;
16种优先级。因此当优先级分组设置为4的时候可供用户选择抢占式优先级为0到15&#xff0c;共16个优先级&#xff0c;配置为0表示最高优先级&#xff0c;配置为15表示最低优先级&#xff0c;不存在子优先级。
l
这里配置configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY为0x01表示用户可以在抢占式优先级为1到15的中断里面调用FreeRTOS的API函数&#xff0c;抢占式优先级为0的中断里面是不允许调用的。
更多关于这个参数说明请参看第12章。
FreeRTOS任务调试信息(按K1按键&#xff0c;串口打印)&#xff1a;
上面截图中打印出来的任务状态字母B,
R, D, S对应如下含义&#xff1a;
#define
tskBLOCKED_CHAR ( &#39;B&#39; ) 任务阻塞
#define
tskREADY_CHAR ( &#39;R&#39;
) 任务就绪
#define
tskDELETED_CHAR ( &#39;D&#39; ) 任务删除
#define
tskSUSPENDED_CHAR ( &#39;S&#39;
) 任务挂起
程序设计&#xff1a;
u
任务栈大小分配&#xff1a;
vTaskUserIF任务
&#xff1a;2048字节
vTaskLED任务&#xff1a;2048字节
vTaskMsgPro任务 &#xff1a;2048字节
vTaskStart任务&#xff1a;2048字节
任务栈空间是在任务创建的时候从FreeRTOSConfig.h文件中定义的heap空间中申请的
#define
configTOTAL_HEAP_SIZE ( ( size_t ) ( 17 * 1024 ) )
u
系统栈大小分配&#xff1a;
u
FreeROTS初始化&#xff1a;
int
main(void)
{
__set_PRIMASK(1);
bsp_Init();
vSetupSysInfoTest();
AppTaskCreate();
vTaskStartScheduler();
while(1);
}
u
硬件外设初始化
硬件外设的初始化是在bsp.c文件实现&#xff1a;
void
bsp_Init(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
bsp_InitUart();
bsp_InitLed();
bsp_InitKey();
}
u
FreeRTOS任务创建&#xff1a;
static
void AppTaskCreate (void)
{
xTaskCreate(
vTaskTaskUserIF,
"vTaskUserIF",
512,
NULL,
1,
&xHandleTaskUserIF ); /* 任务句柄*/
xTaskCreate(
vTaskLED,
"vTaskLED",
512,
NULL,
2,
&xHandleTaskLED );
xTaskCreate(
vTaskMsgPro,
"vTaskMsgPro",
512,
NULL,
3,
&xHandleTaskMsgPro ); /* 任务句柄*/
xTaskCreate(
vTaskStart,
"vTaskStart",
512,
NULL,
4,
&xHandleTaskStart );
}
u
四个FreeRTOS任务的实现&#xff1a;
static
void vTaskTaskUserIF(void *pvParameters)
{
uint8_t ucKeyCode;
uint8_t pcWriteBuffer[500];
while(1)
{
ucKeyCode &#61; bsp_GetKey();
if (ucKeyCode !&#61; KEY_NONE)
{
switch (ucKeyCode)
{
case
KEY_DOWN_K1:
printf("&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;\r\n");
printf("任务名
任务状态 优先级 剩余栈
任务序号\r\n");
vTaskList((char *)&pcWriteBuffer);
printf("%s\r\n", pcWriteBuffer);
printf("\r\n任务名
运行计数
使用率\r\n");
vTaskGetRunTimeStats((char *)&pcWriteBuffer);
printf("%s\r\n", pcWriteBuffer);
break;
case
KEY_DOWN_K2:
printf("当前的系统时钟节拍数
&#61; %d\r\n", xTaskGetTickCount());
break;
default:
break;
}
}
vTaskDelay(20);
}
}
static
void vTaskLED(void *pvParameters)
{
TickType_t xLastWakeTime;
const TickType_t xFrequency &#61; 200;
xLastWakeTime &#61; xTaskGetTickCount();
while(1)
{
bsp_LedToggle(2);
vTaskDelayUntil(&xLastWakeTime, xFrequency);
}
}
static
void vTaskMsgPro(void *pvParameters)
{
TickType_t xDelay, xNextTime;
const TickType_t xFrequency &#61; 200;
xNextTime &#61; xTaskGetTickCount() &#43; xFrequency;
while(1)
{
bsp_LedToggle(3);
xDelay &#61; xNextTime - xTaskGetTickCount();
xNextTime &#43;&#61; xFrequency;
if(xDelay <&#61; xFrequency)
{
vTaskDelay(xDelay);
}
}
}
static
void vTaskStart(void *pvParameters)
{
while(1)
{
bsp_KeyScan();
vTaskDelay(10);
}
}
17.3.2STM32F407开发板实验
配套例子&#xff1a;
V5-311_FreeRTOS实验_周期性延迟和相对性延迟函数
实验目的&#xff1a;
1.
学习FreeRTOS的周期性延迟和相对性延迟函数。
2.
注意相对性延迟函数vTaskDelay和周期性延迟函数vTaskDelayUntil的区别。
实验内容&#xff1a;
1.
K1按键按下&#xff0c;串口打印任务执行情况(波特率115200&#xff0c;数据位8&#xff0c;奇偶校验位无&#xff0c;停止位1)。
2.
K2键按下&#xff0c;串口打印系统时钟节拍数。
3.
各个任务实现的功能如下&#xff1a;
vTaskUserIF任务
&#xff1a;按键消息处理。
vTaskLED任务&#xff1a;LED闪烁。
vTaskMsgPro任务
&#xff1a;消息处理&#xff0c;这里是用作LED闪烁。
vTaskStart任务&#xff1a;启动任务&#xff0c;也是最高优先级任务&#xff0c;这里实现按键扫描。
FreeRTOS的配置&#xff1a;
FreeRTOSConfig.h文件中的配置如下&#xff1a;
#if
defined(__ICCARM__) || defined(__CC_ARM) ||
defined(__GNUC__)
#include
extern
volatile uint32_t ulHighFrequencyTimerTicks;
#if
defined(__ICCARM__) || defined(__CC_ARM) ||
defined(__GNUC__)
#include
extern
volatile uint32_t ulHighFrequencyTimerTicks;
#endif
#define
configUSE_PREEMPTION 1
#define
configUSE_IDLE_HOOK 0
#define
configUSE_TICK_HOOK 0
#define
configCPU_CLOCK_HZ ( ( unsigned long ) 168000000 )
#define
configTICK_RATE_HZ ( ( TickType_t ) 1000 )
#define
configMAX_PRIORITIES ( 5 )
#define
configMINIMAL_STACK_SIZE
( ( unsigned
short ) 128 )
#define
configTOTAL_HEAP_SIZE ( ( size_t ) ( 30 * 1024 ) )
#define
configMAX_TASK_NAME_LEN ( 16 )
#define
configUSE_TRACE_FACILITY
1
#define
configUSE_16_BIT_TICKS 0
#define
configIDLE_SHOULD_YIELD 1
#define
configGENERATE_RUN_TIME_STATS 1
#define
configUSE_STATS_FORMATTING_FUNCTIONS 1
#define
portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() (ulHighFrequencyTimerTicks &#61; 0ul)
#define
portGET_RUN_TIME_COUNTER_VALUE() ulHighFrequencyTimerTicks
//#define
portALT_GET_RUN_TIME_COUNTER_VALUE 1
#define
configUSE_CO_ROUTINES
0
#define
configMAX_CO_ROUTINE_PRIORITIES ( 2 )
#define
INCLUDE_vTaskPrioritySet 1
#define
INCLUDE_uxTaskPriorityGet 1
#define
INCLUDE_vTaskDelete 1
#define
INCLUDE_vTaskCleanUpResources 0
#define
INCLUDE_vTaskSuspend 1
#define
INCLUDE_vTaskDelayUntil 1
#define
INCLUDE_vTaskDelay 1
#ifdef
__NVIC_PRIO_BITS
#define
configPRIO_BITS __NVIC_PRIO_BITS
#else
#define
configPRIO_BITS 4
#endif
#define
configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0x0f
#define
configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 0x01
几个重要选项说明&#xff1a;
u
#define
configUSE_PREEMPTION 1
使能抢占式调度器
u
#define
configCPU_CLOCK_HZ ( ( unsigned long ) 168000000 )
系统主频168MHz。
u
#define
configTICK_RATE_HZ ( ( TickType_t ) 1000 )
系统时钟节拍1KHz&#xff0c;即1ms。
u
#define
configMAX_PRIORITIES ( 5 )
定义可供用户使用的最大优先级数&#xff0c;如果这个定义的是5&#xff0c;那么用户可以使用的优先级号是0,1,2,3,4&#xff0c;不包含5&#xff0c;对于这一点&#xff0c;初学者要特别的注意。
u
#define
configTOTAL_HEAP_SIZE ( ( size_t ) ( 30 * 1024 ) )
定义堆大小&#xff0c;FreeRTOS内核&#xff0c;用户动态内存申请&#xff0c;任务栈等都需要用这个空间。
u
configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 0x01
定义受FreeRTOS管理的最高优先级中断。简单的说就是允许用户在这个中断服务程序里面调用FreeRTOS的API的最高优先级。为了进一步说明这个宏定义的的作用&#xff0c;解释如下&#xff1a;
l
使用CM内核的MCU&#xff0c;官方强烈建议将NVIC的优先级分组配置为全抢占式优先级&#xff0c;全部配置为抢占式优先级的好处就是方便管理。
l
对于STM32来说&#xff0c;设置NVIC的优先级分组为4时&#xff0c;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4)就是全部配置为抢占式优先级。又因为STM32的优先级设置仅使用CM内核8bit中的高4bit&#xff0c;即只能区分2^4
&#61;
16种优先级。因此当优先级分组设置为4的时候可供用户选择抢占式优先级为0到15&#xff0c;共16个优先级&#xff0c;配置为0表示最高优先级&#xff0c;配置为15表示最低优先级&#xff0c;不存在子优先级。
l
这里配置configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY为0x01表示用户可以在抢占式优先级为1到15的中断里面调用FreeRTOS的API函数&#xff0c;抢占式优先级为0的中断里面是不允许调用的。
更多关于这个参数说明请参看第12章。
FreeRTOS任务调试信息(按K1按键&#xff0c;串口打印)&#xff1a;
上面截图中打印出来的任务状态字母B,
R, D, S对应如下含义&#xff1a;
#define
tskBLOCKED_CHAR ( &#39;B&#39; ) 任务阻塞
#define
tskREADY_CHAR ( &#39;R&#39;
) 任务就绪
#define
tskDELETED_CHAR ( &#39;D&#39; ) 任务删除
#define
tskSUSPENDED_CHAR ( &#39;S&#39;
) 任务挂起
程序设计&#xff1a;
u
任务栈大小分配&#xff1a;
vTaskUserIF任务
&#xff1a;2048字节
vTaskLED任务&#xff1a;2048字节
vTaskMsgPro任务 &#xff1a;2048字节
vTaskStart任务&#xff1a;2048字节
任务栈空间是在任务创建的时候从FreeRTOSConfig.h文件中定义的heap空间中申请的
#define
configTOTAL_HEAP_SIZE ( ( size_t ) ( 30 * 1024 ) )
u
系统栈大小分配&#xff1a;
u
FreeROTS初始化&#xff1a;
int
main(void)
{
__set_PRIMASK(1);
bsp_Init();
vSetupSysInfoTest();
AppTaskCreate();
vTaskStartScheduler();
while(1);
}
u
硬件外设初始化
硬件外设的初始化是在bsp.c文件实现&#xff1a;
void
bsp_Init(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
bsp_InitUart();
bsp_InitKey();
bsp_InitLed();
}
u
FreeRTOS任务创建&#xff1a;
static
void AppTaskCreate (void)
{
xTaskCreate(
vTaskTaskUserIF,
"vTaskUserIF",
512,
NULL,
1,
&xHandleTaskUserIF ); /* 任务句柄*/
xTaskCreate(
vTaskLED,
"vTaskLED",
512,
NULL,
2,
&xHandleTaskLED
);
xTaskCreate(
vTaskMsgPro,
"vTaskMsgPro",
512,
NULL,
3,
&xHandleTaskMsgPro ); /* 任务句柄*/
xTaskCreate(
vTaskStart,
"vTaskStart",
512,
NULL,
4,
&xHandleTaskStart );
}
u
四个FreeRTOS任务的实现&#xff1a;
static
void vTaskTaskUserIF(void *pvParameters)
{
uint8_t ucKeyCode;
uint8_t pcWriteBuffer[500];
while(1)
{
ucKeyCode &#61; bsp_GetKey();
if (ucKeyCode !&#61; KEY_NONE)
{
switch (ucKeyCode)
{
case
KEY_DOWN_K1:
printf("&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;\r\n");
printf("任务名
任务状态 优先级 剩余栈
任务序号\r\n");
vTaskList((char *)&pcWriteBuffer);
printf("%s\r\n", pcWriteBuffer);
printf("\r\n任务名
运行计数
使用率\r\n");
vTaskGetRunTimeStats((char *)&pcWriteBuffer);
printf("%s\r\n", pcWriteBuffer);
break;
case
KEY_DOWN_K2:
printf("当前的系统时钟节拍数
&#61; %d\r\n", xTaskGetTickCount());
break;
default:
break;
}
}
vTaskDelay(20);
}
}
static
void vTaskLED(void *pvParameters)
{
TickType_t xLastWakeTime;
const TickType_t xFrequency &#61; 200;
xLastWakeTime &#61; xTaskGetTickCount();
while(1)
{
bsp_LedToggle(2);
vTaskDelayUntil(&xLastWakeTime, xFrequency);
}
}
static
void vTaskMsgPro(void *pvParameters)
{
TickType_t xDelay, xNextTime;
const TickType_t xFrequency &#61; 200;
xNextTime &#61; xTaskGetTickCount() &#43; xFrequency;
while(1)
{
bsp_LedToggle(3);
xDelay &#61; xNextTime - xTaskGetTickCount();
xNextTime &#43;&#61; xFrequency;
if(xDelay <&#61; xFrequency)
{
vTaskDelay(xDelay);
}
}
}
static
void vTaskStart(void *pvParameters)
{
while(1)
{
bsp_KeyScan();
vTaskDelay(10);
}
}
17.4总结
本章节主要为大家讲解了FreeRTOS操作系统的时钟节拍和时间管理函数&#xff0c;其中时间管理函数是FreeRTOS的基本函数&#xff0c;初学者务必要掌握。