一、簡介
? ? ? ? 軟件定時器,是基于系統(tǒng)Tick時鐘中斷且由軟件來模擬的定時器。當經(jīng)過設(shè)定的Tick時鐘計數(shù)值后,會觸發(fā)用戶定義的回調(diào)函數(shù)。定時精度與系統(tǒng)Tick時鐘周期有關(guān)。
? ? ? ? 硬件定時器受硬件的限制,數(shù)量上不足以滿足用戶的實際需求。因此,為了滿足用戶需求,提供更多的定時器,LiteOS提供軟件定時器功能。
? ? ? ? 軟件定時器擴展了定時器的數(shù)量,允許創(chuàng)建更多的定時業(yè)務(wù)。
? ? ? ? 軟件定時器功能上支持:
- 靜態(tài)裁剪:能通過宏關(guān)閉軟件定時器功能。
- 軟件定時器創(chuàng)建。
- 軟件定時器啟動。
- 軟件定時器停止。
- 軟件定時器刪除。
- 軟件定時器剩余Tick數(shù)獲取。
? ? ? ? 更多概念可以參考:FreeRTOS學習六(軟件定時器)_freertos 執(zhí)行定時器回調(diào)函數(shù)的內(nèi)存消耗將是在定時器任務(wù)堆棧上動態(tài)分配_t_guest的博客-CSDN博客
????????Timer Management
二、運作機制
? ? ? ? 軟件定時器使用了系統(tǒng)的一個隊列和一個任務(wù)資源,軟件定時器的觸發(fā)遵循隊列規(guī)則,先進先出。定時時間短的定時器總是比定時時間長的靠近隊列頭,滿足優(yōu)先被觸發(fā)的準則。
? ? ? ? 軟件定時器以Tick為基本計時單位,當用戶創(chuàng)建并啟動一個軟件定時器時,LiteOS會根據(jù)當前系統(tǒng)Tick時間寄用戶設(shè)置的定時間隔確定該定時器的到期Tick時間,并將該定時器控制結(jié)構(gòu)掛入計時全局鏈表。
? ? ? ? 當Tick中斷到來時,在Tick中斷處理函數(shù)中掃描軟件定時器的計時全局鏈表,看是否有定時器超時,若有則將超時的定時器記錄下來。
? ? ? ? Tick中斷處理函數(shù)結(jié)束后,軟件定時器任務(wù)(優(yōu)先級最高)被喚醒,在該任務(wù)中調(diào)傭之前記錄下來的定時器的超時回調(diào)函數(shù)。
三、API介紹
??????osTimerNew
????????函數(shù)功能:
? ? ? ? 創(chuàng)建一個軟件定時器
? ? ? ??函數(shù)原型:
osTimerId_t osTimerNew(osTimerFunc_t func, osTimerType_t type, void *argument, const osTimerAttr_t *attr)
? ? ? ??參數(shù):
? ? ? ? func:超時回調(diào)函數(shù)
? ? ? ? type:運行模式
osTimerOnce | 0,單次 |
osTimerPeriodic | 1,周期 |
? ? ? ? argument:傳給定時器的參數(shù)。沒有填NULL
? ? ? ? attr:定時器相關(guān)屬性。自定義地址的時候會用到。大部分情況用不到,填NULL。
? ? ? ??返回值:
? ? ? ? NULL:失敗
? ? ? ? 其他值:osTimerId_t類型的定時器ID。該ID給其他函數(shù)使用
? ? ? ??實例:
osTimerPeriodic
char timer1_param[] = "timer1 param";
g_timer1_id = osTimerNew(Timer1_Callback, osTimerPeriodic, timer1_param, NULL);
??????osTimerStart
????????函數(shù)功能:
? ? ? ? 軟件定時器啟動
? ? ? ??函數(shù)原型:
osStatus_t osTimerStart(osTimerId_t timer_id, uint32_t ticks)
? ? ? ??參數(shù):
? ? ? ? timer_id:軟件定時器ID,創(chuàng)建時osTimerNew獲得。
? ? ? ? ticks:軟件定時器的定時周期。對于Hi3861,定時器單位為10ms。
? ? ? ??返回值:
? ? ? ? osOK:成功
? ? ? ? 其他值:失敗
typedef enum {
/** Operation completed successfully */
osOK = 0,
/** Unspecified error */
osError = -1,
/** Timeout */
osErrorTimeout = -2,
/** Resource error */
osErrorResource = -3,
/** Incorrect parameter */
osErrorParameter = -4,
/** Insufficient memory */
osErrorNoMemory = -5,
/** Service interruption */
osErrorISR = -6,
/** Reserved. It is used to prevent the compiler from optimizing enumerations. */
osStatusReserved = 0x7FFFFFFF
} osStatus_t;
? ? ? ??實例:
osTimerId_t g_timer1_id;
timerDelay = 100U;
status = osTimerStart(g_timer1_id, timerDelay);
??????osTimerStop
????????函數(shù)功能:
? ? ? ? 軟件定時器停止
? ? ? ??函數(shù)原型:
osStatus_t osTimerStop(osTimerId_t timer_id)
? ? ? ??參數(shù):
? ? ? ? timer_id 定時器ID
? ? ? ??返回值
????????osOK:成功
? ? ? ? 其他值:失敗
? ? ? ??實例:
osTimerId_t g_timer1_id;
osTimerStop(g_timer1_id);
??????osTimerDelete
????????函數(shù)功能:
? ? ? ? 軟件定時器刪除
? ? ? ??函數(shù)原型:
osStatus_t osTimerDelete(osTimerId_t timer_id)
? ? ? ??參數(shù):
????????timer_id 定時器ID
? ? ? ??返回值:
????????osOK:成功
? ? ? ? 其他值:失敗
? ? ? ??實例:
osTimerId_t g_timer1_id;
osTimerDelete(g_timer1_id);
四、代碼實例
? ? ? ? 此代碼創(chuàng)建兩個軟件定時器,定時器1為循環(huán)定時器,定時器2為單次定時器。
#define LOG_I(fmt, args...) printf("<%8ld> - [TIMER]:"fmt"\r\n",osKernelGetTickCount(),##args);
#define LOG_E(fmt, args...) printf("<%8ld>-[TIMER_ERR]>>>>>>>>>>>>:"fmt"\r\n",osKernelGetTickCount(), ##args);
osTimerId_t g_timer1_id;
osTimerId_t g_timer2_id;
/***** 定時器1 回調(diào)函數(shù) *****/
void Timer1_Callback(void *arg)
{
static uint8_t cnt = 0;
LOG_I("timer1 callback,cnt:%d,param:%s",cnt,arg);
if(cnt++ > 10)
{
osTimerDelete(g_timer1_id);
LOG_I("timer1 delete");
}
else if(cnt == 3)
{
osTimerStop(g_timer1_id);
LOG_I("timer1 stop and restart timer2");
osTimerStart(g_timer2_id, 500);
}
}
/***** 定時器2 回調(diào)函數(shù) *****/
void Timer2_Callback(void *arg)
{
LOG_I("timer2 callback,param:%d",*(uint32_t *)arg);
osTimerStart(g_timer1_id, 100);
LOG_I("start timer1");
}
char timer1_param[] = "timer1 param";
uint32_t timer2_param = 1024;
void Hello_World(void)
{
LOG_I("Test software Timer");
uint32_t timerDelay;
osStatus_t status;
/*timer 1*/
g_timer1_id = osTimerNew(Timer1_Callback, osTimerPeriodic, timer1_param, NULL);
if (g_timer1_id != NULL)
{
// Hi3861 1U=10ms,100U=1S
timerDelay = 100U;
status = osTimerStart(g_timer1_id, timerDelay);
if (status != osOK)
{
LOG_E("timer1 start error");
}
else
{
LOG_I("timer1 start success,cycle:%dms",timerDelay * 10);
}
}
else
{
LOG_E("timer1 create fail!!!");
}
/*timer 2*/
g_timer2_id = osTimerNew(Timer2_Callback, osTimerOnce, (void *)&timer2_param, NULL);
if (g_timer2_id != NULL)
{
// Hi3861 1U=10ms,100U=1S
timerDelay = 500U;
status = osTimerStart(g_timer2_id, timerDelay);
if (status != osOK)
{
LOG_E("timer2 start error");
}
else
{
LOG_I("timer2 start success,cycle:%dms",timerDelay * 10);
}
}
else
{
LOG_E("timer2 create fail!!!");
}
}
? ? ? ? 定時器1為循環(huán)定時器,循環(huán)周期為1秒,定時器2為單次定時器,超時時間為5秒。兩個定時器同時啟動。在定時器1第三秒的時候,會停止自己,并且重新啟動定時器2。定時器2超時后會重新啟動定時器1。定時器1在第10次時會刪除自己。
? ? ? ? 看運行結(jié)果:
? ? ? ? ?可以看到,雖然定時器2在運行,但是如果此時再次調(diào)用osTimerStart來啟動定時器2,會刷新定時器的超時時間。
? ? ? ? 這里我們用軟件打印當前的時間戳,來看一下1秒的定時周期是否準確。
文章來源:http://www.zghlxwxcb.cn/news/detail-445682.html
? ? ? ? ?可以看到1秒的定時還是很準的。文章來源地址http://www.zghlxwxcb.cn/news/detail-445682.html
到了這里,關(guān)于鴻蒙Hi3861學習六-Huawei LiteOS-M(軟件定時器)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!