日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

OSAL之时间管理,软件定时器链表管理

發布時間:2024/3/24 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 OSAL之时间管理,软件定时器链表管理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

讀源碼寫作,尊重原創;

本博文根據藍牙4.0, 協議族版本是1.3.2
本博文分兩大塊。一部分是時間管理,另一部分是軟件定時器管理。


OSAL的時鐘實現在OSAL_CockBLE.c與OSAL_Clock.h兩個文件中。OSAL支持完整的UTC(世界統一時間),以2000年1月1日00:00:00為時間起點,可以精確到年、月、日、時、分、秒的時間值。

背景知識

// number of seconds since 0 hrs, 0 minutes, 0 seconds, on the 1st of January 2000 UTC存儲自2000年1月1日開始的**秒數**,uint32可存儲大約135年的數據,就是到2135年左右。 typedef uint32 UTCTime; UTCTime OSAL_timeSeconds = 0;//定義一個存儲秒數的變量// To be used with typedef struct {uint8 seconds; // 0-59uint8 minutes; // 0-59uint8 hour; // 0-23uint8 day; // 0-30uint8 month; // 0-11uint16 year; // 2000+ } UTCTimeStruct;//這是將UTCTime轉化為UTCTimeStruct的結構//幾個宏定義,判斷閏年 #define IsLeapYear(yr) (!((yr) % 400) || (((yr) % 100) && !((yr) % 4))) //每年多少天 #define YearLength(yr) (IsLeapYear(yr) ? 366 : 365) // (MAXCALCTICKS * 5) + (max remainder) must be <= (uint16 max), // so: (13105 * 5) + 7 <= 65535這是防止微妙轉化為毫秒是uint16溢出 #define MAXCALCTICKS ((uint16)(13105))#define BEGYEAR 2000 // UTC started at 00:00:00 January 1, 2000 UTC時間是自2000年1月1日開始#define DAY 86400UL // 24 hours * 60 minutes * 60 seconds一天的秒數//全局變量 static uint16 previousLLTimerTick = 0; //存儲的是上次調用osalTimeUpdate獲得的625us反轉次數,也即上次調用的節拍數量 static uint16 remUsTicks = 0; //存儲的是每次更新us轉ms *5/8的余數 static uint16 timeMSec = 0; //存儲的是ms轉s 的余數

osalTimeUpdata

OSAL里面所有時間的根源都來自于硬件層一個定時器的更新,它是625us自動反轉重新計時的定時器,只要計算前后兩次獲得它反轉的次數想減那么就可以計算出之間花費了多少時間。
這個定時器由osalTimeUpdata調用。

void osalTimeUpdate( void ) {uint16 tmp; //記錄這次獲得625us逝去的次數uint16 ticks625us; //記錄前后兩次625us逝去的次數uint16 elapsedMSec = 0; //記錄前后兩次625 us逝去的毫秒數// Get the free-running count of 625us timer tickstmp = ll_McuPrecisionCount(); //計算當前過去了多少個625us次數if ( tmp != previousLLTimerTick ){// Calculate the elapsed ticks of the free-running timer.ticks625us = tmp - previousLLTimerTick;// Store the LL Timer tick count for the next time through this function.存儲這次過去的625us的次數previousLLTimerTick = tmp;/* It is necessary to loop to convert the usecs to msecs in increments so as* not to overflow the 16-bit variables.*/while ( ticks625us > MAXCALCTICKS ) //主要為了數據過大轉換為ms是溢出了。MAXCALCTICKS >13105就會溢出從零開始,對時間來說是不行的{ticks625us -= MAXCALCTICKS;elapsedMSec += MAXCALCTICKS * 5 / 8; //計算逝去的毫秒;整除,MAXCALCTICKS =13105個節拍轉換為ms是8190msremUsTicks += MAXCALCTICKS * 5 % 8; //計算當前循環的余數,余數為5,時間0.625ms;5除8 =0.625}}// update converted number with remaining ticks from loop and the// accumulated remainder from loop把余數加進去,組合成剩余的滴答數*5;這里限制了必須使得((ticks625us *5) + 7 < = 65535)tmp = (ticks625us * 5) + remUsTicks;// Convert the 625 us ticks into milliseconds and a remainderelapsedMSec += tmp / 8; //將剩余的滴答數轉化成msremUsTicks = tmp % 8; //將余數留到下次使用// Update OSAL Clock and Timers更新時鐘和軟件定時器if ( elapsedMSec )//{osalClockUpdate( elapsedMSec );//更新整個系統的時間,UTCTime以秒為單位記錄 osalTimerUpdate( elapsedMSec );//傳入過去流逝的時間值,進一步更新每個軟件定時器,減去一定的時間 }} }

個人覺得上面對MAXCALCTICKS處理有點問題,詳情可以看下面OSAL時鐘優化

osalClockUpdate( elapsedMSec );

用于更新系統時鐘時間,保存到一個全局變量OSAL_timeSeconds中。參數是毫秒數據,

static void osalClockUpdate( uint16 elapsedMSec ) {// Add elapsed milliseconds to the saved millisecond portion of timetimeMSec += elapsedMSec;// Roll up milliseconds to the number of secondsif ( timeMSec >= 1000 ){OSAL_timeSeconds += timeMSec / 1000;timeMSec = timeMSec % 1000; //存儲ms轉s余數} }

時間管理的其他API

void osal_setClock函數是更新系統時間,以UTCTime為參數,秒級別

void osal_setClock( UTCTime newTime ) {OSAL_timeSeconds = newTime; }

osal_getClock函數用于獲得當前的系統時鐘時間

UTCTime osal_getClock( void ) {return ( OSAL_timeSeconds ); }

osal_ConvertUTCTime函數是將時間從UTCTime轉化成UTCTimeStruct

void osal_ConvertUTCTime( UTCTimeStruct *tm, UTCTime secTime ) {// calculate the time less than a day - hours, minutes, seconds計算時間不足一天{uint32 day = secTime % DAY;//不足一天的秒數tm->seconds = day % 60UL; //秒tm->minutes = (day % 3600UL) / 60UL; //分tm->hour = day / 3600UL; //小時}// Fill in the calendar - day, month, year填充日,月,年{uint16 numDays = secTime / DAY;//總的天數tm->year = BEGYEAR;while ( numDays >= YearLength( tm->year ) ){numDays -= YearLength( tm->year );//根據YearLength判定是否是閏年?返回366/365tm->year++;}tm->month = 0;while ( numDays >= monthLength( IsLeapYear( tm->year ), tm->month ) )//這里判定月份天數的算法比較獨特{numDays -= monthLength( IsLeapYear( tm->year ), tm->month );tm->month++;}tm->day = numDays;} } //下面是對月份判斷的代碼 static uint8 monthLength( uint8 lpyr, uint8 mon ) {uint8 days = 31;if ( mon == 1 ) // feb{days = ( 28 + lpyr );}else{if ( mon > 6 ) // aug-dec{mon--;}if ( mon & 1 ){days = 30;}}return ( days ); }

月份的計算小算法

osal_ConvertUTCSecs 函數
//下面這里是將UTCStruct時間轉化為uint32的秒數

UTCTime osal_ConvertUTCSecs( UTCTimeStruct *tm ) {uint32 seconds;/* Seconds for the partial day */seconds = (((tm->hour * 60UL) + tm->minutes) * 60UL) + tm->seconds;//計算不足一天的秒數/* Account for previous complete days計算當前月已過去的天數 ,比如20,就等于20天*/{/* Start with complete days in current month計算已當前月過去的月份 */uint16 days = tm->day;/* Next, complete months in current year計算當年已過去的月,比如month = 2,三月,過了兩月了,執行兩次循環 */{int8 month = tm->month;while ( --month >= 0 ){days += monthLength( IsLeapYear( tm->year ), month );}}/* Next, complete years before current year計算自2000年到當前多了多少年 */{uint16 year = tm->year;while ( --year >= BEGYEAR ){days += YearLength( year );}}/* Add total seconds before partial day */seconds += (days * DAY);}return ( seconds ); }

//下面這個函數根據上面osalTimeUpdate函數更新系統時間osal_systemClock,更新軟件定時器里面定時值。OSAL的定時器的相關代碼實現OSAL_Timers.c與OSAL_Timers.h

osalTimerUpdate( elapsedMSec );

函數功能是用過去的毫秒值去更新軟件定時器的值,減去時間;

軟件定時器相關的背景知識

typedef union {uint32 time32;uint16 time16[2];uint8 time8[4]; } osalTime_t;typedef struct {void *next;osalTime_t timeout;uint16 event_flag;uint8 task_id;uint32 reloadTimeout; } osalTimerRec_t; //上面是一個軟件定時器的結構體,OSAL的定時器主要為任務提供定時服務,所以定時器的結構需要包括任務的ID(task_id)以及它承載的事件ID(event_flag),以便告訴OSAL讓哪個任務做什么事情;除此之外定時器還需要記錄的定時時間(timeout)以及超時后需要重載的定時值(reloadTimeout)。 //一個用來記錄系統上電的運行時間 static uint32 osal_systemClock; osalTimerRec_t *timerHead; //定義一個頭指針,指向軟件定時器鏈表

例程講解

void osalTimerUpdate( uint32 updateTime ) {halIntState_t intState;osalTimerRec_t *srchTimer; //遍歷軟件定時器鏈表osalTimerRec_t *prevTimer;osalTime_t timeUnion;timeUnion.time32 = updateTime;//共用體,下面可以看到這個共用體是為了可以字節操作timeout而設置的。這是共用體的好處吧HAL_ENTER_CRITICAL_SECTION( intState ); // Hold off interrupts.// Update the system timeosal_systemClock += updateTime;//將逝去的時間更新到系統時鐘,以毫秒級別HAL_EXIT_CRITICAL_SECTION( intState ); // Re-enable interrupts.// Look for open timer slotif ( timerHead != NULL ){// Add it to the end of the timer listsrchTimer = timerHead;//指向定時器鏈表頭prevTimer = (void *)NULL;//初始化為空// Look for open timer slotwhile ( srchTimer ){osalTimerRec_t *freeTimer = NULL;//記錄待釋放的軟件定時器HAL_ENTER_CRITICAL_SECTION( intState ); // Hold off interrupts.// To minimize time in this critical section, avoid 32-bit math為了避免32位匹配,計算最小時間if ((timeUnion.time16[1] == 0) && (timeUnion.time8[1] == 0)){// If upper 24 bits are zero, check lower 8 bits for roll over逝去的時間只有 1 byteif (srchTimer->timeout.time8[0] >= timeUnion.time8[0]){// 8-bit math減去逝去的時間srchTimer->timeout.time8[0] -= timeUnion.time8[0];}else{// 32-bit mathif (srchTimer->timeout.time32 > timeUnion.time32){srchTimer->timeout.time32 -= timeUnion.time32;}else{srchTimer->timeout.time32 = 0;}}}else{// 32-bit mathif (srchTimer->timeout.time32 > timeUnion.time32){srchTimer->timeout.time32 -= timeUnion.time32;//減去逝去的時間}else{srchTimer->timeout.time32 = 0;//定時時間到}}// Check for reloading對于自動重載的軟件定時器處理if ( (srchTimer->timeout.time16[0] == 0) && (srchTimer->timeout.time16[1] == 0) &&(srchTimer->reloadTimeout) && (srchTimer->event_flag) ){// Notify the task of a timeout時間到,設定事件osal_set_event( srchTimer->task_id, srchTimer->event_flag );// Reload the timer timeout value重新設定時間srchTimer->timeout.time32 = srchTimer->reloadTimeout;}// When timeout or delete (event_flag == 0)對于只定時一次的軟件定時器處理和要刪除的軟件定時器處理if ( ((srchTimer->timeout.time16[0] == 0) && (srchTimer->timeout.time16[1] == 0)) ||(srchTimer->event_flag == 0) ){// Take out of listif ( prevTimer == NULL ){timerHead = srchTimer->next;}else{prevTimer->next = srchTimer->next;}// Setup to free memoryfreeTimer = srchTimer;//記錄當前待釋放的定時器// NextsrchTimer = srchTimer->next;}else{// Get next如果沒有軟件定時器到時,則遍歷下一個軟件定時器prevTimer = srchTimer;srchTimer = srchTimer->next;}HAL_EXIT_CRITICAL_SECTION( intState ); // Re-enable interrupts.if ( freeTimer ){if ( (freeTimer->timeout.time16[0] == 0) && (freeTimer->timeout.time16[1] == 0) ){osal_set_event( freeTimer->task_id, freeTimer->event_flag );}osal_mem_free( freeTimer );//釋放軟件定時器}}} }

上面這個函數是對軟件定時器鏈表的所有定時器時間進行更新。

OSAL維護著一個定時器全局鏈表timerHead,每當調用osal_start_timerEx或者osal_start_reload_timer實際再調用osalAddTimer,來創建一個新的軟件Timer。

osalTimerRec_t * osalAddTimer( uint8 task_id, uint16 event_flag, uint32 timeout ) {osalTimerRec_t *newTimer;osalTimerRec_t *srchTimer;// Look for an existing timer firstnewTimer = osalFindTimer( task_id, event_flag );查找是否已存在這個任務對應事件的的定時器;if ( newTimer ){// Timer is found - update it.如果存在更新超時時間newTimer->timeout.time32 = timeout;return ( newTimer );}else{// New Timer若沒有,只要創建新的軟件定時器newTimer = osal_mem_alloc( sizeof( osalTimerRec_t ) );if ( newTimer ){// Fill in new timernewTimer->task_id = task_id;newTimer->event_flag = event_flag;newTimer->timeout.time32 = timeout;newTimer->next = (void *)NULL;newTimer->reloadTimeout = 0;// Does the timer list already existif ( timerHead == NULL ){// Start task list如果軟件定時器為空,那么指向第一個軟件定時器timerHead = newTimer;}else{// Add it to the end of the timer list不然加到線性表末尾srchTimer = timerHead;// Stop at the last recordwhile ( srchTimer->next )srchTimer = srchTimer->next;// Add to the listsrchTimer->next = newTimer;}return ( newTimer );}else{return ( (osalTimerRec_t *)NULL );}} }

總結

以上是生活随笔為你收集整理的OSAL之时间管理,软件定时器链表管理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 涩涩综合 | 久福利| 麻豆中文字幕 | 亚洲欧美激情小说另类 | 精品国产人妻一区二区三区 | 午夜激情免费 | 国产精品黑丝 | 91精品国产91久久久久久黑人 | 精品国产美女 | 久久精品2 | 日本不卡一 | 男人女人拔萝卜视频 | 美女a视频| 姐姐你真棒插曲快来救救我电影 | 91av免费看 | 欧美激情视频一区二区 | 日日麻批 | 91成人午夜| 亚洲自拍成人 | 国产精品一线天 | 亚洲另类一区二区 | 亚洲精品午夜国产va久久成人 | 日日爽夜夜爽 | 情侣自拍av | 欧美瑟瑟 | 成人av在线影院 | 爱情岛亚洲论坛入口 | 亚洲欧美综合一区 | 一区视频免费观看 | 日韩三级在线观看 | 正在播放国产一区 | 国产精品久久久一区 | sese久久| 日韩精品一区二区亚洲av性色 | 黄色免费网站在线看 | 欧美一区二区在线播放 | 亚洲色图国产视频 | 欧美日韩中文字幕在线视频 | 国产精品亚洲欧美 | 老熟女高潮一区二区三区 | 欧美人与动牲交a欧美精品 欧美三级在线看 | 一区二区三区美女视频 | 一区二区精品区 | 精品一区视频 | 黄色视屏在线看 | 综合视频| xx性欧美肥妇精品久久久久久 | 亚洲精品视频导航 | 欧美日韩欧美 | 欧洲一区二区三区在线 | 精品久久久精品 | www.黄在线观看 | 久久精品在线 | 国产综合无码一区二区色蜜蜜 | 情侣av| 91精品久久人妻一区二区夜夜夜 | 亚洲一线在线观看 | 欧美天堂网站 | 大尺度网站在线观看 | 91精品国产91久久久久 | 国产一区二区三区四区五区在线 | 日本专区在线 | 欧美成人精品一区二区男人看 | 成人免费高清在线观看 | 色片免费看 | 国产aⅴ精品一区二区三区久久 | 五月天一区二区三区 | 在线观看日本一区二区 | 性色av免费 | 黑人一区二区三区四区五区 | 国产又大又硬又粗 | 久久久99精品国产一区二区三区 | 久久靖品| 欧美片一区二区 | 337p亚洲欧洲色噜噜噜 | 国产免费久久 | 亚洲国产精品视频在线 | 欧美亚州 | 一区二区视频免费在线观看 | 黑人极品ⅴideos精品欧美棵 | 欧美日在线观看 | 成人动漫在线播放 | 国产av 一区二区三区 | 欧美一区二区三区婷婷 | 午夜激情视频在线观看 | 91精品国产欧美一区二区成人 | 涩涩视屏 | 自拍欧美亚洲 | 国内精品国产三级国产aⅴ久 | 99福利影院 | www成人在线观看 | 青青草原成人 | 成人在线视频免费看 | 黄色在线播放 | 男女av在线| 日韩成人中文字幕 | 91网站在线播放 | 亚洲性片| 成人www.|