热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

read.phptid3307995,【FreeRTOS操作系统教程】第17章 FreeRTOS系统时钟节拍和时间管理...

第17章FreeRTOS系统时钟节拍和时间管理本文完整版地址:http:bbs.armfly.comread.php?tid21196本章节为大家讲解FreeRTOS

第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使用权,从而让低优先级任务可以得到执行。

下面我们通过如下的框图来说明一下延迟函数对任务运行状态的影响,让大家有一个形象的认识。

a4c26d1e5885305701be709a3d33442f.png

运行条件:

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在线版手册:

a4c26d1e5885305701be709a3d33442f.png

这里也对此函数进行下介绍。

函数原型:

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在线版手册:

a4c26d1e5885305701be709a3d33442f.png

这里也对此函数进行下介绍。

函数原型:

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在线版手册:

a4c26d1e5885305701be709a3d33442f.png

这里也对此函数进行下介绍。

函数原型:

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在线版手册:

a4c26d1e5885305701be709a3d33442f.png

这里也对此函数进行下介绍。

函数原型:

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;

a4c26d1e5885305701be709a3d33442f.png

上面截图中打印出来的任务状态字母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;

a4c26d1e5885305701be709a3d33442f.png

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;

a4c26d1e5885305701be709a3d33442f.png

上面截图中打印出来的任务状态字母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;

a4c26d1e5885305701be709a3d33442f.png

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;初学者务必要掌握。



推荐阅读
  • 深入解析零拷贝技术(Zerocopy)及其应用优势
    零拷贝技术(Zero-copy)是Netty框架中的一个关键特性,其核心在于减少数据在操作系统内核与用户空间之间的传输次数。通过避免不必要的内存复制操作,零拷贝显著提高了数据传输的效率和性能。本文将深入探讨零拷贝的工作原理及其在实际应用中的优势,包括降低CPU负载、减少内存带宽消耗以及提高系统吞吐量等方面。 ... [详细]
  • Unity与MySQL连接过程中出现的新挑战及解决方案探析 ... [详细]
  • Spring Boot 中配置全局文件上传路径并实现文件上传功能
    本文介绍如何在 Spring Boot 项目中配置全局文件上传路径,并通过读取配置项实现文件上传功能。通过这种方式,可以更好地管理和维护文件路径。 ... [详细]
  • 单片微机原理P3:80C51外部拓展系统
      外部拓展其实是个相对来说很好玩的章节,可以真正开始用单片机写程序了,比较重要的是外部存储器拓展,81C55拓展,矩阵键盘,动态显示,DAC和ADC。0.IO接口电路概念与存 ... [详细]
  • 本文详细介绍了 PHP 中对象的生命周期、内存管理和魔术方法的使用,包括对象的自动销毁、析构函数的作用以及各种魔术方法的具体应用场景。 ... [详细]
  • 在Delphi7下要制作系统托盘,只能制作一个比较简单的系统托盘,因为ShellAPI文件定义的TNotifyIconData结构体是比较早的版本。定义如下:1234 ... [详细]
  • 开机自启动的几种方式
    0x01快速自启动目录快速启动目录自启动方式源于Windows中的一个目录,这个目录一般叫启动或者Startup。位于该目录下的PE文件会在开机后进行自启动 ... [详细]
  • 本文介绍了如何利用 `matplotlib` 库中的 `FuncAnimation` 类将 Python 中的动态图像保存为视频文件。通过详细解释 `FuncAnimation` 类的参数和方法,文章提供了多种实用技巧,帮助用户高效地生成高质量的动态图像视频。此外,还探讨了不同视频编码器的选择及其对输出文件质量的影响,为读者提供了全面的技术指导。 ... [详细]
  • 技术分享:使用 Flask、AngularJS 和 Jinja2 构建高效前后端交互系统
    技术分享:使用 Flask、AngularJS 和 Jinja2 构建高效前后端交互系统 ... [详细]
  • Java能否直接通过HTTP将字节流绕过HEAP写入SD卡? ... [详细]
  • Presto:高效即席查询引擎的深度解析与应用
    本文深入解析了Presto这一高效的即席查询引擎,详细探讨了其架构设计及其优缺点。Presto通过内存到内存的数据处理方式,显著提升了查询性能,相比传统的MapReduce查询,不仅减少了数据传输的延迟,还提高了查询的准确性和效率。然而,Presto在大规模数据处理和容错机制方面仍存在一定的局限性。本文还介绍了Presto在实际应用中的多种场景,展示了其在大数据分析领域的强大潜力。 ... [详细]
  • MySQL性能优化与调参指南【数据库管理】
    本文详细探讨了MySQL数据库的性能优化与参数调整技巧,旨在帮助数据库管理员和开发人员提升系统的运行效率。内容涵盖索引优化、查询优化、配置参数调整等方面,结合实际案例进行深入分析,提供实用的操作建议。此外,还介绍了常见的性能监控工具和方法,助力读者全面掌握MySQL性能优化的核心技能。 ... [详细]
  • JVM参数设置与命令行工具详解
    JVM参数配置与命令行工具的深入解析旨在优化系统性能,通过合理设置JVM参数,确保在高吞吐量的前提下,有效减少垃圾回收(GC)的频率,进而降低系统停顿时间,提升服务的稳定性和响应速度。此外,本文还将详细介绍常用的JVM命令行工具,帮助开发者更好地监控和调优JVM运行状态。 ... [详细]
  • 本文介绍如何在 Android 中自定义加载对话框 CustomProgressDialog,包括自定义 View 类和 XML 布局文件的详细步骤。 ... [详细]
  • 本文探讨了在Linux 2.6内核中实现进程隐藏的技术方法与实践。通过分析系统调用 `sys_getdents` 的工作原理,提出了一种有效的方法来隐藏指定的进程。该方法通过对内核模块进行修改,拦截并过滤掉目标进程的相关信息,从而在常用的进程查看命令(如 `ps` 和 `top`)中无法显示这些隐藏的进程。实验结果表明,该方法在实际应用中具有较高的隐蔽性和稳定性。 ... [详细]
author-avatar
手机用户2602937435
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有