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