【STM32H7】第15章 ThreadX系统时钟节拍和时间管理(绝对延迟和相对延迟)
论坛原始地址(持续更新):http://www.armbbs.cn/forum.php?mod=viewthread&tid=99514
第15章 ThreadX系统时钟节拍和时间管理(绝对延迟和相对延迟)
本章节为大家讲解ThreadX操作系统的系统时钟节拍和时间管理函数,其中时间管理函数是ThreadX的基本函数,初学者务必要掌握。
15.1 ThreadX的时钟节拍
15.2 ThreadX的时间管理
15.3 实验例程说明
15.4 总结
15.1 ThreadX的时钟节拍
任何操作系统都需要提供一个时钟节拍,以供系统处理诸如延时、超时等与时间相关的事件。
时钟节拍是特定的周期性中断,这个中断可以看做是系统心跳。中断之间的时间间隔取决于不同的应用,一般是1ms – 100ms。时钟的节拍中断使得内核可以将任务延迟若干个时钟节拍,以及当任务等待事件发生时,提供等待超时等依据。时钟节拍率越快,系统的额外开销就越大。
对于Cortex-M3内核的STM32F103和,Cortex-M4内核的STM32F407以及F429和Cortex-M内核的STM32H7,做的例子都是用滴答定时器来实现系统时钟节拍的。
- 滴答定时器Systick
SysTick定时器被捆绑在NVIC中,用于产生SysTick异常(异常号:15),滴答定时器是一个24位的递减计数器,支持中断。使用比较简单,专门用于给操作系统提供时钟节拍。
ThreadX的系统时钟节拍可以在配置文件tx_initialize_low_level.s里面设置:
SYSTEM_CLOCK EQU 400000000
SYSTICK_CYCLES EQU ((SYSTEM_CLOCK / 1000) -1)
如上所示的配置表示系统时钟节拍是1KHz,即1ms。
15.2 ThreadX的时间管理
时间管理功能是ThreadX操作系统里面最基本的功能,同时也是必须要掌握好的。
15.2.1 时间延迟介绍
ThreadX中的时间延迟函数主要有以下两个作用:
- 为周期性执行的任务提供延迟。
- 对于抢占式调度器,让高优先级任务可以通过时间延迟函数释放CPU使用权,从而让低优先级任务可以得到执行。
下面我们通过如下的框图来说明一下延迟函数对任务运行状态的影响,让大家有一个形象的认识。
运行条件:
- 仅对任务Task1的运行状态做说明。
- 调度器支持时间片调度和抢占式调度。
运行过程描述如下:
- 起初任务Task1处于运行态,调用tx_thread_sleep函数后进入到阻塞状态,也就是blocked状态。
- tx_thread_sleep函数设置的延迟时间到,由于任务Task1不是当前就绪的最高优先级任务,所以不能进入到运行状态,只能进入到就绪状态,也就是ready状态。
- 一段时间后,调度器发现任务Task1是当前就绪的最高优先级任务,从而任务从就绪态切换到运行态。
- 由于时间片调度,任务Task1由运行态切换到就绪态。
上面就是一个简单的任务运行状态的切换过程。
15.2.2 函数tx_thread_sleep
函数原型:
UINT tx_thread_sleep(ULONG timer_ticks)
函数描述:
函数tx_thread_sleep用于任务的延迟。
1、 参数timer_ticks用于设置延迟的时钟节拍个数,范围1- 0xFFFFFFFF。
2、 返回值:
- TX_SUCCESS (0x00) ,调用成功。
- TX_WAIT_ABORTED (0x1A) ,被其它中断,定时器组或者任务终止运行。
- TX_CALLER_ERROR (0x13) ,不是在任务中调用。
注意事项:
- 不允许在中断中调用,仅可以在任务中调用。
使用举例:
/* ********************************************************************************************************* * 函 数 名: AppTaskCom * 功能说明: 这里用作LED闪烁 * 形 参: thread_input 创建该任务时传递的形参 * 返 回 值: 无 优 先 级: 5 ********************************************************************************************************* */ static void AppTaskCOM(ULONG thread_input) { (void)thread_input; while(1) { bsp_LedToggle(2); tx_thread_sleep(100); } }
15.2.3 函数tx_time_get
函数原型:
ULONG tx_time_get(VOID);
函数描述:
函数tx_time_get用于获取系统当前运行的时钟节拍数。
注意事项:
- 可以在任务,定时器组合中断服务程序里面调用。
使用举例:
ULONG current_time;
current_time = tx_time_get();
15.2.4 绝对延迟函数实现方法
注:这里绝对延迟和周期性延迟是一个意思。
ThreadX内核只有相对延迟函数tx_thread_sleep,没有绝对延迟函数,这里简单实现一个tx_thread_sleepuntil。
条件:
1、有一个bsp_KeyScan函数,这个函数处理时间大概耗时2ms。
2、有两个任务,一个任务Task1是用的tx_thread_sleep延迟,延迟10ms,另一个任务Task2是用的tx_thread_sleepuntil(ThreadX没有这个函数,要自己封装)延迟,延迟10ms。不考虑任务被抢占而造成的影响。
相对性的含义:
bsp_KeyScan+ tx_thread_sleep(10) ---> bsp_KeyScan + tx_thread_sleep (10)
|----2ms + 10ms 为一个周期------| |----2ms + 10ms 为一个周期----|
周期性延迟含义:
bsp_KeyScan + tx_thread_sleepunti ------> bsp_KeyScan + tx_thread_sleepunti
|----10ms为一个周期(2ms包含在10ms内)---| |------10ms 为一个周期---------------|
这里我们通过tx_thread_sleep来实现一个tx_thread_sleepuntil
static void AppTaskMsgPro(ULONG thread_input) { UINT Delay, NextTime; const UINT Frequency = 200; /* 获取Frequency个时钟节拍后的时间 */ NextTime = tx_time_get() + Frequency; while(1) { bsp_LedToggle(3); Delay = NextTime - tx_time_get(); NextTime += Frequency; if(Delay <= Frequency) { tx_thread_sleep(Delay); } } }
15.3 实验例程
配套例子:
V7-3010_ThreadX Sleep Until
实验目的:
- 学习ThreadX绝对延迟和相对延迟的实现。
实验内容:
1、共创建了如下几个任务,通过按下按键K1可以通过串口或者RTT打印任务堆栈使用情况
========================================================
OS CPU Usage = 1.05%
========================================================
任务优先级 任务栈大小 当前使用栈 最大栈使用 任务名
Prio StackSize CurStack MaxStack Taskname
2 4092 303 459 App Task Start
30 1020 303 303 App Task STAT
31 1020 87 71 App Task IDLE
5 4092 167 167 App Msp Pro
4 4092 167 167 App Task UserIF
5 4092 167 167 App Task COM
0 1020 191 191 System Timer Thread
串口软件可以使用SecureCRT或者H7-TOOL RTT查看打印信息。
App Task Start任务 :启动任务,这里用作BSP驱动包处理。
App Task MspPro任务 :消息处理,这里用作LED闪烁。
App Task UserIF任务 :按键消息处理。
App Task COM任务 :这里用作LED闪烁。
App Task STAT任务 :统计任务
App Task IDLE任务 :空闲任务
System Timer Thread任务:系统定时器任务
2、(1) 凡是用到printf函数的全部通过函数App_Printf实现。
(2) App_Printf函数做了信号量的互斥操作,解决资源共享问题。
3、默认上电是通过串口打印信息,如果使用RTT打印信息
(1) MDK AC5,MDK AC6或IAR通过使能bsp.h文件中的宏定义为1即可
#define Enable_RTTViewer 1
(2) Embedded Studio继续使用此宏定义为0, 因为Embedded Studio仅制作了调试状态RTT方式查看。
串口打印信息方式(AC5,AC6和IAR):
波特率 115200,数据位 8,奇偶校验位无,停止位 1
RTT打印信息方式(AC5,AC6和IAR):
Embedded Studio仅支持调试状态RTT打印:
由于Embedded Studio不支持中文,所以中文部分显示乱码,不用管。
程序执行框图:
15.4 总结
本章节主要为大家讲解了ThreadX节拍和时间管理函数,其中时间管理函数是ThreadX学者务必要掌握。