RT-Thread入门(三) 定时器

RT-Thread入门之定时器

        上一篇文章我们学习了RT-Thread建立线程相关函数,这次我们将学习系统中一个很重要的功能:定时器。系统提供的软件定时器可以为我们提供无限个定时器使用,但定时时间必须是系统节拍的整数倍。RT-Thread 中,时钟节拍的长度可以根据 RT_TICK_PER_SECOND 的定义来调整,我们使用的工程设置的为100,这里我们就使用他的默认设置,所以我们可以设置的定时时间只能为10ms的整数倍。

一、HARD/SOFT_TIMER区别

        HARD_TIMER 模式的定时器超时函数在中断上下文环境中执行,在中断上下文环境中执行时,对于超时函数的要求与中断服务例程的要求相同:执行时间应该尽量短,
执行时不应导致当前上下文挂起、等待。
        SOFT_TIMER 模 式 可 配 置, 通 过 宏 定 义RT_USING_TIMER_SOFT 来 决 定 是 否 启 用 该 模式,该宏定义在rtconfigs.h中定义,默认为不使用。该模式被启用后,系统会在初始化时创建一个 timer 线程,然后SOFT_TIMER 模式的定时器超时函数在都会在 timer 线程的上下文环境中执行。
       总结起来就是:hard_timer中断服务程序不能被打断,soft_timer中断服务程序和线程一样参与任务的调度。
       除此之外,定时器也有两种创建方式:动态方式和静态方式。额我认为大多数时间使用动态方式就可以了,他们的区别和进程类似,代码空间的分配方式不同,这篇文章主要使用动态方式进行实验。

二、相关函数介绍

1.rt_timer_create 通过这个函数可以设置定时器的定时时间,超时函数入口和定时器模式等一些参数。

rt_timer_t rt_timer_create(const char* name,
							void (*timeout)(void* parameter),
							void* parameter,
							rt_tick_t time,
							rt_uint8_t flag);

2.rt_timer_start 设置完成定时器的参数之后定时器不会立即启动,只有调用rt_timer_start函数之后定时器才开始计时。

rt_err_t rt_timer_start(rt_timer_t timer);

3.rt_timer_stop 启动定时器以后,若想使它停止,可以使用下面的函数接口:

rt_err_t rt_timer_stop(rt_timer_t timer);

4.rt_timer_control 除了上述提供的一些编程接口, RT-Thread 也额外提供了定时器控制函数接口,以获取或设置更多定时器的信息。控制定时器函数接口如下:

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 <rtthread.h>
#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");
}

四、总结

       刚开始不知道哪里出现的问题,程序不会执行,串口连版本信息都没有,后来不知道改了那里竟然好了,呃呃呃呃呃呃呃呃呃神奇。
       看到编程手册有说软件定时器的超时函数可以在上下文执行,就想在超时函数中下入延时和任务调度函数的,后来发现好像也不行,谔谔谔谔,然后试了一下在超时函数中执行一个很长的任务,发现这个函数一直在执行没有发生任务的切换,设置的小灯不会闪。后来查了一下,有些人说虽然是软件超时函数也不能执行太长时间或者阻塞、挂起任务的事情。有没有大神指点一下啊。

猜你喜欢

转载自blog.csdn.net/qq_39552181/article/details/86648825