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");
}

四、總結

       剛開始不知道哪裏出現的問題,程序不會執行,串口連版本信息都沒有,後來不知道改了那裏竟然好了,呃呃呃呃呃呃呃呃呃神奇。
       看到編程手冊有說軟件定時器的超時函數可以在上下文執行,就想在超時函數中下入延時和任務調度函數的,後來發現好像也不行,諤諤諤諤,然後試了一下在超時函數中執行一個很長的任務,發現這個函數一直在執行沒有發生任務的切換,設置的小燈不會閃。後來查了一下,有些人說雖然是軟件超時函數也不能執行太長時間或者阻塞、掛起任務的事情。有沒有大神指點一下啊。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章