1 引 言
這里的倒計時就是計算出從當(dāng)前時間點(diǎn)需要經(jīng)過多長時間才能到達(dá)目標(biāo)時間點(diǎn),。從另一個角度講,, 就是計算出兩個時間點(diǎn)之間的時間差,。
目前, 倒計時系統(tǒng)正得到越來越廣泛的應(yīng)用,。
在體育比賽、公交系統(tǒng)乃至鐵路系統(tǒng)中出現(xiàn)了很多倒計時的時間顯示。就在前不久,, 關(guān)于上海世博會的倒計時正式啟動,, 其精度精確到天。
在類似的應(yīng)用中,, 大多數(shù)情況下,, 倒計時功能(包括顯示功能)是由微控制器實(shí)現(xiàn)的。微控制器不同于桌面電腦或筆記本電腦,, 其系統(tǒng)資源非常有限,, 也不能安裝復(fù)雜的操作系統(tǒng), 沒有現(xiàn)成的倒計時系統(tǒng)可以應(yīng)用,。下面將討論適合在微控制器中運(yùn)行的倒計時算法,。
2 倒計時算法的兩種常用思路
關(guān)于倒計時的計算主要有兩種思路: 一是針對時間段倒計時, 二是針對目標(biāo)時間倒計時,。
●針對時間段倒計時
時間段的含義就是兩個時間點(diǎn)的時間差,。對時間段倒計時就是先獲取兩個時間點(diǎn)之間的時間差,然后隨著運(yùn)行時間的增加對該時間差按運(yùn)行時間遞減,, 直至遞減為0,, 表示倒計時結(jié)束。
例如,, 微處理器對100天倒計時或者對100秒倒計時,, 都屬于對時間段倒計時, 時間段分別是100天和100秒,。當(dāng)然,, 在實(shí)際計算時, 最好先把天換算為秒,, 再按運(yùn)行時間遞減,。
●針對目標(biāo)時間倒計時
該種思路與第一種思路最大的不同就是它獲取的不是時間差, 而是目標(biāo)時間,, 微控制器須自行計算出當(dāng)前時間與目標(biāo)時間的時間差,。在這種情況下,隨著當(dāng)前時間的改變,, 微控制器必須反復(fù)計算與目標(biāo)時間的時間差,, 直至差值為0。
例如,, 當(dāng)前時間是2009年5月10 日11點(diǎn)27分0秒,, 微控制器獲取到目標(biāo)時間是2009年5月12日11點(diǎn)27分0秒, 則計算出當(dāng)前的時間差為2天,。
然后,, 當(dāng)前時間一旦改變,, 微控制器就必須重新計算時間差, 直到當(dāng)前時間到達(dá)或超過2009年5月12日11點(diǎn)27分0秒,。
●兩種思路的比較
( 1)獲取的時間參數(shù)不同
如前所述,, 第一種思路獲取的是時間差, 第二種思路獲取的是目標(biāo)時間點(diǎn),。
( 2)采取的算法不同
第一種思路的主要算法是按運(yùn)行時間對獲取的時間差進(jìn)行遞減運(yùn)算,, 這實(shí)際是時間計時的逆運(yùn)算。
該算法牽涉到減法運(yùn)算與天,、小時,、分鐘、秒的時間規(guī)則運(yùn)算,。
第二種思路的主要算法就是計算出兩個時間點(diǎn)之間的時間差,。該算法不僅牽涉到時間規(guī)則運(yùn)算,還牽涉到閏年的概念與多種算術(shù)運(yùn)算,, 比第一種思路的算法復(fù)雜許多,。此外, 由于該算法需要微控制器能夠隨時獲取當(dāng)前的準(zhǔn)確時間,, 因此要求微處理器必須具備實(shí)時時鐘功能,。
( 3)應(yīng)用范圍與靈活性不同
第一種思路的實(shí)現(xiàn)依靠對運(yùn)行時間的準(zhǔn)確把握。如果微控制器斷電或由于其它原因產(chǎn)生復(fù)位導(dǎo)致運(yùn)行中斷,, 則從此刻起到下一次穩(wěn)定運(yùn)行時所經(jīng)過的時間無法掌控,, 進(jìn)而導(dǎo)致倒計時運(yùn)算無法繼續(xù)運(yùn)行。因此,, 該思路只適用于極短時間段的倒計時計算,, 其可靠性與靈活性欠佳。
第二種思路的實(shí)現(xiàn)需要兩點(diǎn): 一是斷電保護(hù)的實(shí)時時鐘功能,, 這是為了微控制器能夠隨時讀取準(zhǔn)確時間; 二是非易失數(shù)據(jù)的存儲功能,, 這是為了微控制器可以長時間保存目標(biāo)時間。滿足了這兩點(diǎn)要求,, 微控制器就能夠可靠地實(shí)現(xiàn)倒計時計算,, 即使突然斷電或復(fù)位也不會受到影響。對于第一點(diǎn)要求,,不管使用外置時鐘還是內(nèi)置時鐘,, 只要配置電池就可以實(shí)現(xiàn)。對于第二點(diǎn)要求,, 當(dāng)前的主流微控制器大都配置FLASH存儲功能,, 也可以輕松滿足。
可見,, 針對目標(biāo)時間的倒計時算法在可靠性與靈活性上極具優(yōu)勢,, 對微控制器的要求也不苛刻,。
下面就闡述該算法的實(shí)現(xiàn)環(huán)節(jié)。
3 針對目標(biāo)時間點(diǎn)的倒計時算法實(shí)現(xiàn)
如前所述,, 該算法主要是計算當(dāng)前時間點(diǎn)與目標(biāo)時間點(diǎn)的時間差,。具體思路就是先選擇一個參考時間點(diǎn), 然后分別計算出這兩個時間點(diǎn)與參考時間點(diǎn)之間的時間差,, 再把這兩個時間差相減就得到這兩個時間點(diǎn)之間的時間差。
下面分三部分描述該算法: 時間格式的建立; 計算時間點(diǎn)到參考時間點(diǎn)的時間差; 時間差相減算法,。
( 1)時間格式的建立
有兩種時間格式,, 一是時間點(diǎn)的格式; 一是時間差的格式。時間點(diǎn)的格式按年月日時分秒排列,, 其中年份為16位無符號整數(shù),, 其余為8 位無符號整數(shù)。時間差格式按天時分秒排列,, 天數(shù)為16位無符號整數(shù),, 其余為8位無符號整數(shù)。
( 2)到參考時間點(diǎn)的時間差算法
該算法有兩個重點(diǎn),, 一是參考時間點(diǎn)的選取,, 二是根據(jù)閏年規(guī)則對時間差中的天數(shù)進(jìn)行補(bǔ)償。
關(guān)于參考時間點(diǎn)的選取,, 應(yīng)符合兩個原則: 一是方便閏年的計算,, 二是方便時間差的計算。在這里,,選取2001年1月1日0時0分0秒為參考時間點(diǎn),。
圖1是時間點(diǎn)到該參考時間點(diǎn)算法的示例代碼,pT mi e是指向時間點(diǎn)的數(shù)據(jù)結(jié)構(gòu)指針,, pResult是指向時間差的數(shù)據(jù)結(jié)構(gòu)指針,。下面對該段代碼逐條說明。
圖1 天數(shù)時間差參考代碼
圖1- 1定義了一個數(shù)組,, 它的12個元素對應(yīng)1月份到12月份所累積的天數(shù),。請注意兩點(diǎn), 一是該天數(shù)不包括本月份的天數(shù),, 二是二月份的天數(shù)按28天計,。
圖1- 2是計算時間點(diǎn)與參考時間點(diǎn)的年份、月份與日期的差值,。
圖1- 3 是初步計算天數(shù)差,。在這里應(yīng)用到了圖1- 1定義的數(shù)組與圖1- 2的計算結(jié)果。首先,,按照每年365天來計算天數(shù),, 再按照閏年個數(shù)補(bǔ)償天數(shù),, 最后按月份日期的差值計算本年度過的天數(shù)。
代碼中的( Y earId /4) 就是初步的閏年補(bǔ)償計算,, 補(bǔ)償規(guī)則就是把年份差被4整除的值視為經(jīng)過的閏年個數(shù),, 也就是要補(bǔ)償?shù)奶鞌?shù)。
圖1- 4是根據(jù)世紀(jì)年(也就是能被100整除的年份)的閏年判斷規(guī)則對圖1- 3的計算結(jié)果進(jìn)行校正,。這是因為圖1- 3 進(jìn)行的閏年補(bǔ)償計算所依據(jù)的是非世紀(jì)年的閏年判斷規(guī)則,, 這一規(guī)則在判斷世紀(jì)年是否為閏年時可能會產(chǎn)生誤差。在這里,, 對該步驟算法采用了條件編譯,, 這是考慮到該計算牽涉到真正的多字節(jié)除法, 比較耗時,, 設(shè)計者可以根據(jù)實(shí)際需要決定是否運(yùn)行該計算,。
圖1- 5是判斷時間點(diǎn)的年份是否閏年, 進(jìn)而進(jìn)行最后的天數(shù)調(diào)整,。請注意,, 在圖1- 3與圖1- 4的計算中, 只計算了度過的年份中包含了多少個閏年,, 這其中不包含時間點(diǎn)本身的年份,。在本計算中,先調(diào)用函數(shù)判斷時間點(diǎn)年份是否閏年,, 再根據(jù)時間點(diǎn)的月份是否超過2月決定是否對天數(shù)進(jìn)行補(bǔ)償,。
圖1 - 6是記錄時間差結(jié)果。因為參考時間點(diǎn)的時分秒選擇的是0時0分0秒,, 所以時間差的時分秒也就是時間點(diǎn)的時分秒,。
圖2是閏年判斷函數(shù)的參考代碼。該函數(shù)提供了兩種判斷計算,, 一種是關(guān)于閏年規(guī)則的完整判斷,,即當(dāng)年份不能被100整除時, 能被4整除的是閏年;當(dāng)年份能被100整除時,, 必須能被400 整除才是閏年,。另一種是簡易判斷, 即把能被4整除的年份視為閏年(當(dāng)然,, 該判斷只在年份不能被100整除時才正確),。這兩種計算的復(fù)雜程度與應(yīng)用條件不同, 設(shè)計者應(yīng)根據(jù)實(shí)際需要自行選擇,。
圖2 閏年檢測函數(shù)參考代碼
請注意,, 如果參考時間點(diǎn)選擇的不是2001年1月1日0時0分0秒, 則上述算法需要進(jìn)行適當(dāng)調(diào)整,。
( 3)時間差相減算法時間差相減算法的主要處理方法是按時間規(guī)則進(jìn)行借位相減,。
圖3 是完整的時間差借位相減的參考代碼,, 其前提是時間差中的天數(shù)差不為0。代碼中pT im e0是指向目標(biāo)時間點(diǎn)與參考時間點(diǎn)的時間差數(shù)據(jù)結(jié)構(gòu)的指針,, pT ime1是指向當(dāng)前時間點(diǎn)與參考時間點(diǎn)的時間差數(shù)據(jù)結(jié)構(gòu)的指針,。
下面對圖3的代碼逐條分析。
圖3- 1 就是按時間規(guī)則進(jìn)行時間借位,。其實(shí)質(zhì)是小時單位向天數(shù)單位借1天,, 增加24小時; 分鐘單位向小時單位借1小時, 增加60分鐘; 秒單位向分鐘單位借1分鐘,, 增加60秒,。
圖3- 2是時間差相減。注意,, 因為天數(shù)差被借走一天, 所以要減1,。
圖3- 3 是根據(jù)計算結(jié)果進(jìn)行進(jìn)位補(bǔ)償,。因為經(jīng)過借位, 相減的結(jié)果有可能超過時間單位的上限,,此時就要按時間規(guī)則進(jìn)位,。
請注意, 圖3代碼是以天數(shù)為最高時間單位的借位計算,, 可以根據(jù)實(shí)際需要把最大的時間單位設(shè)為小時或分鐘,。
在實(shí)際的時間差相減計算中, 為了避免負(fù)值的出現(xiàn),, 應(yīng)先從天數(shù)開始對兩個時間差的時間單位比較數(shù)值大小,, 其結(jié)果按三種情況處理。
( 1)若當(dāng)前時間點(diǎn)的時間單位超過目標(biāo)時間點(diǎn)的時間單位,, 表明倒計時結(jié)束,。
( 2)若兩個時間單位相同, 當(dāng)時間單位為秒時,,表明倒計時結(jié)束,, 否則進(jìn)入次一級時間單位的判斷。
( 3)若當(dāng)前時間點(diǎn)的時間單位小于目標(biāo)時間點(diǎn)的時間單位,, 則視此時間單位為最高時間單位,, 進(jìn)行借位相減計算。
由此,, 即可計算出兩個時間點(diǎn)的精確時間差,。
圖3 時間差借位相減參考代碼。
4 結(jié)束語
在上面的介紹中,, 先討論了倒計時的兩種算法,,再擇優(yōu)對其中一種算法進(jìn)行了詳細(xì)的闡述,。該算法已在實(shí)際項目中獲得應(yīng)用, 其計時準(zhǔn)確,, 工作穩(wěn)定,。