單片機(jī)分時(shí)思想
先用一個(gè)小例子引出今天的主題,想象一下,一個(gè)基本的家電控制板,肯定或多或少的會(huì)包含 : LED 或者 數(shù)碼管顯示, 按鍵, 繼電器或者可控硅的輸出 這3部分。數(shù)碼管需要 10ms到20ms的動(dòng)態(tài)掃描,按鍵也需要 20ms左右的延時(shí)消抖,有沒有意識(shí)到,其實(shí)這些時(shí)間是同時(shí)在進(jìn)行的?;叵胍幌略蹅兊慕炭茣趺唇?按鍵 的延時(shí)消抖的?沒錯(cuò),死循環(huán),絕對(duì)是原地踏步死循環(huán),用指令來計(jì)時(shí)。這樣很自然的引發(fā)一個(gè)問題,單片機(jī)在原地踏步死循環(huán)的話,那么其它的工作怎么辦?如數(shù)碼管的動(dòng)態(tài)掃描怎么辦?唯有等按鍵掃描之后再進(jìn)行了,這樣出來的效果,數(shù)碼管肯定會(huì)閃爍的,掃描時(shí)間過長(zhǎng)了,縮短按鍵消抖時(shí)間也不是解決辦法,想象如果咱們還有其它很多工作也是同時(shí)做的呢?解決辦法之一,就是今天的主題,分時(shí)掃描的思想。當(dāng)然不會(huì)是唯一的辦法,只不過俺一直在用,覺得這個(gè)是非常不錯(cuò)的思想,可以解決很多實(shí)際問題。大膽妄言一下,分時(shí)掃描的思想也是單片機(jī)編程最核心的思想了,信不信就由你自己判斷了。
程序的執(zhí)行環(huán)境
用的是純匯編,因?yàn)橛昧?xí)慣的匯編,以致于整個(gè)腦袋都是匯編的思想,某種程度上說,C的廢碼確實(shí)是多了一點(diǎn),對(duì)于實(shí)際工業(yè)用的單片機(jī)ROM和RAM都不是很充足的情況下,代碼還是要求盡量精簡(jiǎn)的。所以俺一直都在匯編的苦海中沉浮著……說明一點(diǎn),俺用的是EMC的單片機(jī)(Elan公司的),傳聞中最爛的單片機(jī),所以代碼不值的去學(xué),也正是這個(gè)原因,但愿我想表達(dá)的思想能表達(dá)清楚, 阿門!
核心思想的實(shí)現(xiàn)
其實(shí)是幾個(gè)步驟,
第一, 用TCC中斷來計(jì)時(shí),TCC的中斷時(shí)間斷一點(diǎn),我習(xí)慣是 125us ,為了解紅外遙控的碼,這個(gè)時(shí)間是需要的。TCC計(jì)時(shí)是相當(dāng)準(zhǔn)的,盡量利用。
第二, 在TCC的中斷服務(wù)程序里面放3個(gè)(數(shù)量自定)記時(shí)器(說白了就是計(jì)數(shù)器),我的習(xí)慣是 2ms 5ms 500ms 這3個(gè)是作為基準(zhǔn)時(shí)間,提供給整個(gè)系統(tǒng)來調(diào)用的,所以必須準(zhǔn)確一點(diǎn),實(shí)際用示波器調(diào)一下就OK了,不難。
第三, 在主程序的循環(huán)里面放一個(gè)專門處理時(shí)間的子程序。(注:?jiǎn)纹瑱C(jī)是不會(huì)停的,永遠(yuǎn)在不斷循環(huán)的跑,這個(gè)跟學(xué)校學(xué)的貌似有點(diǎn)不同,俺面試的時(shí)候被問過這個(gè)問題 ….) 將所有的時(shí)間處理都放在時(shí)間處理子程序里面做,這樣是非常方便的,一個(gè)單片機(jī)系統(tǒng)最起碼需要處理 10~20個(gè)不同的時(shí)間,也需要10~20個(gè)計(jì)時(shí)器了,而且相當(dāng)多要求同時(shí)不同步工作的,如果每個(gè)都單獨(dú)的話是相當(dāng)?shù)穆闊?/p>
第四, “程序是跑著來等,而不是站著來等”,這話看來有點(diǎn)玄,一個(gè)跟俺一起進(jìn)去公司的工程師討論的時(shí)候提到的這個(gè)問題,俺覺得這個(gè)也是分時(shí)系統(tǒng)的一個(gè)比較重要的思想,所以也這樣叫,下面有細(xì)說。
第五, 下面用程序來說話,注釋盡量詳細(xì),可以不用看代碼,直接看注釋就可以了。
(一)先中斷服務(wù)程序部分:
每 125us 中斷一次
;-------------------產(chǎn)生幾個(gè)基準(zhǔn)時(shí)間---------------------------
int_2ms:
djz ref_2ms (1)
jmp int_5ms
mov a,@16 ; 恢復(fù)原始數(shù)據(jù)
mov ref_2ms,a
bs flag_time,flag_2ms (2)
int_5ms:
djz ref_5ms
jmp ref_time_end
mov a,@40 125us×40=5ms
mov ref_5ms,a
bs flag_time,flag_5ms
int_500ms:
djz ref_500ms
jmp ref_time_end
mov a,@100
mov ref_500ms,a
bs flag_time,flag_500ms
ref_time_end:
nop
(1) ef_2ms寄存器不斷的減1,每次中斷減1,一共減 16次,所以這里經(jīng)過的時(shí)間是 125us × 16 = 2ms,這個(gè)就是所謂的計(jì)時(shí)/計(jì)數(shù)器 了。這樣就可以靠一個(gè)系統(tǒng)的TCC中斷,來實(shí)現(xiàn)我們需要的很多個(gè)定時(shí)時(shí)間。
(2)置 2ms 計(jì)時(shí)結(jié)束標(biāo)志,這個(gè)是提供給時(shí)間處理程序用的,這是一個(gè)計(jì)時(shí)器的框架,下面的5ms計(jì)時(shí)完全相同。
這里解釋一下:bs flag_time,flag_2ms,其中bs是將某一位置1的指令,該指令的意思是,將 flag_timg寄存器里面第flag_2ms位置1,設(shè)立一個(gè)溢出標(biāo)志,后面的程序可以通過讀這個(gè)標(biāo)志,就知道 2ms 是否已經(jīng)計(jì)時(shí)到了
這程序還用了一個(gè)塊的框架,比較方便的,不過跟今天的主題無關(guān),以后郁悶的時(shí)候再上來寫寫這個(gè)。上面的程序就是中斷服務(wù)程序里面的計(jì)時(shí)器,分別定時(shí) 2ms 5ms 500ms,計(jì)時(shí)完畢溢出是flag_time 標(biāo)志來記錄的,程序通過讀這個(gè)標(biāo)志就可以知道定時(shí)的時(shí)間是否已經(jīng)到了。
(二)下面看那個(gè)統(tǒng)一的時(shí)間服務(wù)子程序
;-------------------時(shí)間處理子程序-----------------------------
time_proc:
jbs flag_time,flag_5ms 判斷5ms是否到
jmp time_500ms_proc 沒有的話判斷500ms
time_5ms_proc:
bc flag_time,flag_5ms 5ms已經(jīng)到了,進(jìn)入服務(wù)程序,先清掉那個(gè)標(biāo)志,這樣下次再過5ms才允許進(jìn)來這里。
;------------------ 按鍵延時(shí)部分--------------------- ;這里用這個(gè)做例子
key_delay_proc:
jbs flag_delay,key_start ; 按鍵延時(shí)開始標(biāo)志,這個(gè)用來控制是否進(jìn)入計(jì)時(shí),允許計(jì)時(shí)標(biāo)志
jmp key_delay_end
djz reg_key ; 預(yù)先設(shè)置的延時(shí)時(shí)間,每5秒減一次,這里預(yù)設(shè)的值是4,也就是說 5ms * 4 = 20ms
jmp key_delay_end 有減到0的話直接跳出
bs flag_delay,key_flow 時(shí)間到,置需要用的標(biāo)志
mov a,@4 ; 重新置數(shù)據(jù)下次用。
mov reg_key,a
key_delay_end:
nop
;---------------------500ms處理部分------------------------
time_500ms_proc:
jbs flag_time,flag_500ms
ret
bc flag_time,flag_500ms
這里放需要的計(jì)時(shí)器
Ret
上面用了按鍵20ms消抖的計(jì)時(shí)器作為例子,如果理解之后就可以發(fā)現(xiàn),我們可以完全模仿那個(gè)計(jì)時(shí)器而在下面放很多很多的計(jì)時(shí)器,則每5ms 進(jìn)來一下,每個(gè)計(jì)時(shí)器都同時(shí)在計(jì)數(shù)了,誰先計(jì)算完畢就先關(guān)掉自己,置相應(yīng)的標(biāo)志給其它程序調(diào)用,而對(duì)其它計(jì)時(shí)器完全沒有影響!這樣,我們可以在這里放很多個(gè)計(jì)時(shí)器了,一般來說,十來二十個(gè)是沒有問題的,完全滿足一個(gè)單片機(jī)系統(tǒng)對(duì)多個(gè)時(shí)間的需求了。
單個(gè)計(jì)時(shí)器的結(jié)構(gòu)很簡(jiǎn)單,先判斷允許計(jì)時(shí)標(biāo)志是否進(jìn)入計(jì)時(shí),然后一個(gè)專用的寄存器在加1或者減1,加/減購相應(yīng)的數(shù)值之后也就是相應(yīng)的時(shí)間到了,關(guān)掉計(jì)時(shí)器,置相應(yīng)需要用到的標(biāo)志。
到這里差不多了,俺們需要的時(shí)間都可以出來了,這樣做是不是非常方便?咱們?cè)賮砜纯丛谶@段時(shí)間里面單片機(jī)在做了什么東西?只有中斷計(jì)時(shí)夠 5ms 或者 500ms ,那個(gè)溢出標(biāo)志才有效,才能進(jìn)入上面的計(jì)時(shí)程序,其它時(shí)間都是在做其它事情。而且進(jìn)入上面的計(jì)時(shí)器的時(shí)候,可以看出,并不是在那里死循環(huán),只是單純的加減一下寄存器就退出了,整個(gè)過程耗時(shí)極其短,看代碼不同吧,5us到 20us左右吧,對(duì)主程序的執(zhí)行沒有什么影響。
(三)下面看看具體怎么調(diào)用
最開始談過的按鍵的消抖時(shí)間處理問題,現(xiàn)在就用上面介紹的辦法來看具體怎么解決問題。按鍵的處理也是重要的基礎(chǔ)學(xué)問,不過不在本次的討論范圍,所以只是單單的討論怎么解決時(shí)間問題,而對(duì)于按鍵的一些問題,下次有機(jī)會(huì)繼續(xù)討論吧,hoho~~~
scan_key:
jbc flag_key,first_on ; 用來控制跳轉(zhuǎn)的
jmp have_key
jbs port6,1 假設(shè)P61高電平是有鍵
jmp key_end
;-------------------------------------
bs flag_key,first_on 第一次按鍵的標(biāo)志
bs flag_delay,key_start 啟動(dòng)計(jì)時(shí)器開始定時(shí)20ms消抖
have_key:
jbs flag_delay,key_flow 等待定時(shí)結(jié)束溢出
jmp key_end
大概是這樣的:判斷時(shí)候有健,沒有的話跳出,有的話開始延時(shí)消抖的計(jì)時(shí),第二次進(jìn)來的時(shí)候直接由標(biāo)志位控制過去判斷時(shí)間時(shí)候夠。
同樣是等待,這里就是最后一點(diǎn)所說的,咱這是跑著來等,不是站著來等。跟死循環(huán)定時(shí)比較,在沒有定時(shí)到20ms 的這段時(shí)間里面單片機(jī)在做什么? 死循環(huán)的話,肯定就是在原地等,什么都不做,而看看上面的程序,他只是判斷是否定時(shí)夠,具體的定時(shí)在統(tǒng)一的時(shí)間子程序里面做,判斷沒有到時(shí)間的話就跳出了,繼續(xù)跑其它的程序,直到當(dāng)時(shí)間到了,單片機(jī)判斷出flag_delay,key_flow 符合條件,開始進(jìn)入按鍵處理程序了,在這個(gè)期間,單片機(jī)都在做其它事情,只是一個(gè)主循環(huán)跑回來判斷一次,所以單片機(jī)完全有空跑其它的程序,而沒有將時(shí)間都耗在消抖上面。
(四)看看我的主程序循環(huán)體
start:
call clear_all_ram 清空RAM
call initialize 初始化
loop:
eni 開中斷
wdtc 清看門狗
call scan_proc 調(diào)用掃描LED和按鍵程序
call ir_da
call time_proc 調(diào)用時(shí)間統(tǒng)一處理程序
call output_proc 調(diào)用輸出處理程序
jmp loop
這個(gè)就是我用的循環(huán)體了,所有功能都做成子程序形式了,需要就掛上去就可以了,比較方便,這樣一個(gè)總的循環(huán)體,單片機(jī)就是在不斷的執(zhí)行這個(gè)循環(huán)體,如果整個(gè)程序都采用上面說的分時(shí)掃的思想的話,一周循環(huán)回來的時(shí)間是相當(dāng)短的,其實(shí)是不是跟電腦的思想有點(diǎn)像呢?電腦再快也并不是同時(shí)處理多個(gè)任務(wù),而且每次處理一個(gè),然后非??斓乃俣葋硌h(huán)處理,讓我們感覺上他是在同時(shí)處理多個(gè)程序那樣,我想,我最終想表達(dá)的思想也就是這個(gè)而已。
啰啰唆唆的說了一堆,也不知道是否能看懂,或者是否去看。不知道我對(duì)分時(shí)掃描這個(gè)概念是否理解錯(cuò)了呢?在我看來,有這個(gè)思想支撐下,單片機(jī)的程序變得比較容易上手了,剩下的只是集中精力去用程序來實(shí)現(xiàn)我們的思想而已,當(dāng)然,這里只是說一種可行的辦法而已,不是說只有這種辦法,如果大家有好的思想也分享一下哦,編寫程序是一門藝術(shù),寫出來很容易,但是寫得好,寫得精巧,那就很難了。
評(píng)論