上一篇文章我们学习了RT-Thread建立线程相关函数,这次我们将学习系统中一个很重要的功能:定时器。系统提供的软件定时器可以为我们提供无限个定时器使用,但定时时间必须是系统节拍的整数倍。RT-Thread 中,时钟节拍的长度可以根据 RT_TICK_PER_SECOND 的定义来调整,我们使用的工程设置的为100,这里我们就使用他的默认设置,所以我们可以设置的定时时间只能为10ms的整数倍。
HARD_TIMER 模式的定时器超时函数在中断上下文环境中执行,在中断上下文环境中执行时,对于超时函数的要求与中断服务例程的要求相同:执行时间应该尽量短,
执行时不应导致当前上下文挂起、等待。
SOFT_TIMER 模 式 可 配 置, 通 过 宏 定 义RT_USING_TIMER_SOFT 来 决 定 是 否 启 用 该 模式,该宏定义在rtconfigs.h中定义,默认为不使用。该模式被启用后,系统会在初始化时创建一个 timer 线程,然后SOFT_TIMER 模式的定时器超时函数在都会在 timer 线程的上下文环境中执行。
总结起来就是:hard_timer中断服务程序不能被打断,soft_timer中断服务程序和线程一样参与任务的调度。
除此之外,定时器也有两种创建方式:动态方式和静态方式。额我认为大多数时间使用动态方式就可以了,他们的区别和进程类似,代码空间的分配方式不同,这篇文章主要使用动态方式进行实验。
rt_timer_t rt_timer_create(const char* name,
void (*timeout)(void* parameter),
void* parameter,
rt_tick_t time,
rt_uint8_t flag);
rt_err_t rt_timer_start(rt_timer_t timer);
rt_err_t rt_timer_stop(rt_timer_t timer);
rt_err_t rt_timer_control(rt_timer_t timer, rt_uint8_t cmd, void* arg);
其中cmd用于控制定时器的命令,当前支持四个命令,分别是设置定时时间,查看定时时间,设置单次触发,设置周期触发;arg用于控制定时器的命令,当前支持四个命令,分别是设置定时时间,查看定时时间,设置单次触发,设置周期触发。函数参数 cmd 支持的命令如下:
#define RT_TIMER_CTRL_SET_TIME 0x0 /* 设 置 定 时 器 超 时 时 间 */
#define RT_TIMER_CTRL_GET_TIME 0x1 /* 获 得 定 时 器 超 时 时 间 */
#define RT_TIMER_CTRL_SET_ONESHOT 0x2 /* 设 置 定 时 器 为 单 次 定 时 器 */
#define RT_TIMER_CTRL_SET_PERIODIC 0x3 /* 设 置 定 时 器 为 周 期 型 定 时 器 */
这里我们要实现以下功能:
1.创建两个定时器timer1和timer2,timer1为周期软甲定时器,设定定时时间为500ms,每次时间到了以后通过串口输出timer1执行次数;timer2为单次硬件定时器,设定定时时间为5s,定时达到之后停止定时器1。
2.定时器1执行5次之后,改变自身定时长度为250ms。
程序代码如下:
因为我们使用到了软件定时器,首先在rtconfig.h中定义#define RT_USING_TIMER_SOFT。(但我发现这个好像定不定义程序都能执行,不过编程指南中说要定义一下就定义好了。)
编程手册中还说要在初始化中加入 rt_system_timer_init(void);或者rt_system_timer_thread_init(void),不过看了网上的一些教程,这两个函数在系统初始化的时候就已经初始化了,所以我们就不加这两个函数了。
#include
#include "LED.h"
//LED_thread
#define LED_priority 5
#define LED_timeslices 5
#define LED_SIZE 1024
static rt_thread_t LED_thread = RT_NULL;
static void LED_enter(void *parameter);
//timer1_thread
static rt_timer_t timer1;
static void timeout1(void *parameter);
//timer2_thread
static rt_timer_t timer2;
static void timeout2(void *parameter);
int main(void)
{
//创建USART线程
LED_thread=rt_thread_create("LED_thread",
LED_enter,
RT_NULL,
LED_SIZE,
LED_priority,
LED_timeslices);
if(LED_thread != RT_NULL) rt_thread_startup(LED_thread);
timer1 = rt_timer_create("timer1",timeout1,RT_NULL,50,RT_TIMER_FLAG_PERIODIC|RT_TIMER_FLAG_SOFT_TIMER);
/* 启 动 定 时 器 1 */
if (timer1 != RT_NULL) rt_timer_start(timer1);
timer2 = rt_timer_create("timer2",timeout2,RT_NULL,500,RT_TIMER_FLAG_ONE_SHOT);
/* 启 动 定 时 器 2 */
if (timer2 != RT_NULL) rt_timer_start(timer2);
}
static void LED_enter(void *parameter)
{
while (1)
{
rt_thread_mdelay(500);
LED0=~LED0;
}
}
rt_uint16_t count = 0;
static void timeout1(void *parameter)
{
int arg=25;
if(count==4) rt_timer_control(timer1 , RT_TIMER_CTRL_SET_TIME ,&arg);
rt_kprintf("thread timer1 count: %d\r\n", count++);
}
static void timeout2(void *parameter)
{
rt_timer_stop(timer1);
rt_kprintf("timer1 was stopped! \n");
}
刚开始不知道哪里出现的问题,程序不会执行,串口连版本信息都没有,后来不知道改了那里竟然好了,呃呃呃呃呃呃呃呃呃神奇。
看到编程手册有说软件定时器的超时函数可以在上下文执行,就想在超时函数中下入延时和任务调度函数的,后来发现好像也不行,谔谔谔谔,然后试了一下在超时函数中执行一个很长的任务,发现这个函数一直在执行没有发生任务的切换,设置的小灯不会闪。后来查了一下,有些人说虽然是软件超时函数也不能执行太长时间或者阻塞、挂起任务的事情。有没有大神指点一下啊。