新聞中心

單片機(jī)分時(shí)思想

作者: 時(shí)間:2016-11-17 來(lái)源:網(wǎng)絡(luò) 收藏
下面說(shuō)的單片機(jī)應(yīng)用也主要是家電控制方面,也就是現(xiàn)在的工作。其它應(yīng)用不在討論范圍。才識(shí)有限,也敬請(qǐng)前輩們勘誤,指教。

本文引用地址:http://m.butianyuan.cn/article/201611/315477.htm

先用一個(gè)小例子引出今天的主題,想象一下,一個(gè)基本的家電控制板,肯定或多或少的會(huì)包含 : LED 或者 數(shù)碼管顯示, 按鍵, 繼電器或者可控硅的輸出 這3部分。數(shù)碼管需要 10ms到20ms的動(dòng)態(tài)掃描,按鍵也需要 20ms左右的延時(shí)消抖,有沒(méi)有意識(shí)到,其實(shí)這些時(shí)間是同時(shí)在進(jìn)行的?;叵胍幌略蹅兊慕炭茣?shū)怎么教 按鍵 的延時(shí)消抖的?沒(méi)錯(cuò),死循環(huán),絕對(duì)是原地踏步死循環(huán),用指令來(lái)計(jì)時(shí)。這樣很自然的引發(fā)一個(gè)問(wèn)題,單片機(jī)在原地踏步死循環(huán)的話,那么其它的工作怎么辦?如數(shù)碼管的動(dòng)態(tài)掃描怎么辦?唯有等按鍵掃描之后再進(jìn)行了,這樣出來(lái)的效果,數(shù)碼管肯定會(huì)閃爍的,掃描時(shí)間過(guò)長(zhǎng)了,縮短按鍵消抖時(shí)間也不是解決辦法,想象如果咱們還有其它很多工作也是同時(shí)做的呢?解決辦法之一,就是今天的主題,分時(shí)掃描的思想。當(dāng)然不會(huì)是唯一的辦法,只不過(guò)俺一直在用,覺(jué)得這個(gè)是非常不錯(cuò)的思想,可以解決很多實(shí)際問(wèn)題。大膽妄言一下,分時(shí)掃描的思想也是單片機(jī)編程最核心的思想了,信不信就由你自己判斷了。

程序的執(zhí)行環(huán)境

用的是純匯編,因?yàn)橛昧?xí)慣的匯編,以致于整個(gè)腦袋都是匯編的思想,某種程度上說(shuō),C的廢碼確實(shí)是多了一點(diǎn),對(duì)于實(shí)際工業(yè)用的單片機(jī)ROM和RAM都不是很充足的情況下,代碼還是要求盡量精簡(jiǎn)的。所以俺一直都在匯編的苦海中沉浮著……說(shuō)明一點(diǎn),俺用的是EMC的單片機(jī)(Elan公司的),傳聞中最爛的單片機(jī),所以代碼不值的去學(xué),也正是這個(gè)原因,但愿我想表達(dá)的思想能表達(dá)清楚, 阿門(mén)!

核心思想的實(shí)現(xiàn)

其實(shí)是幾個(gè)步驟,

第一, 用TCC中斷來(lái)計(jì)時(shí),TCC的中斷時(shí)間斷一點(diǎn),我習(xí)慣是 125us ,為了解紅外遙控的碼,這個(gè)時(shí)間是需要的。TCC計(jì)時(shí)是相當(dāng)準(zhǔn)的,盡量利用。

第二, 在TCC的中斷服務(wù)程序里面放3個(gè)(數(shù)量自定)記時(shí)器(說(shuō)白了就是計(jì)數(shù)器),我的習(xí)慣是 2ms 5ms 500ms 這3個(gè)是作為基準(zhǔn)時(shí)間,提供給整個(gè)系統(tǒng)來(lái)調(diào)用的,所以必須準(zhǔn)確一點(diǎn),實(shí)際用示波器調(diào)一下就OK了,不難。

第三, 在主程序的循環(huán)里面放一個(gè)專(zhuān)門(mén)處理時(shí)間的子程序。(注:?jiǎn)纹瑱C(jī)是不會(huì)停的,永遠(yuǎn)在不斷循環(huán)的跑,這個(gè)跟學(xué)校學(xué)的貌似有點(diǎn)不同,俺面試的時(shí)候被問(wèn)過(guò)這個(gè)問(wèn)題 ….) 將所有的時(shí)間處理都放在時(shí)間處理子程序里面做,這樣是非常方便的,一個(gè)單片機(jī)系統(tǒng)最起碼需要處理 10~20個(gè)不同的時(shí)間,也需要10~20個(gè)計(jì)時(shí)器了,而且相當(dāng)多要求同時(shí)不同步工作的,如果每個(gè)都單獨(dú)的話是相當(dāng)?shù)穆闊?/p>

第四, “程序是跑著來(lái)等,而不是站著來(lái)等”,這話看來(lái)有點(diǎn)玄,一個(gè)跟俺一起進(jìn)去公司的工程師討論的時(shí)候提到的這個(gè)問(wèn)題,俺覺(jué)得這個(gè)也是分時(shí)系統(tǒng)的一個(gè)比較重要的思想,所以也這樣叫,下面有細(xì)說(shuō)。

第五, 下面用程序來(lái)說(shuō)話,注釋盡量詳細(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)過(guò)的時(shí)間是 125us × 16 = 2ms,這個(gè)就是所謂的計(jì)時(shí)/計(jì)數(shù)器 了。這樣就可以靠一個(gè)系統(tǒng)的TCC中斷,來(lái)實(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)志,后面的程序可以通過(guò)讀這個(gè)標(biāo)志,就知道 2ms 是否已經(jīng)計(jì)時(shí)到了

這程序還用了一個(gè)塊的框架,比較方便的,不過(guò)跟今天的主題無(wú)關(guān),以后郁悶的時(shí)候再上來(lái)寫(xiě)寫(xiě)這個(gè)。上面的程序就是中斷服務(wù)程序里面的計(jì)時(shí)器,分別定時(shí) 2ms 5ms 500ms,計(jì)時(shí)完畢溢出是flag_time 標(biāo)志來(lái)記錄的,程序通過(guò)讀這個(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 沒(méi)有的話判斷500ms

time_5ms_proc:

bc flag_time,flag_5ms 5ms已經(jīng)到了,進(jìn)入服務(wù)程序,先清掉那個(gè)標(biāo)志,這樣下次再過(guò)5ms才允許進(jìn)來(lái)這里。

;------------------ 按鍵延時(shí)部分--------------------- ;這里用這個(gè)做例子

key_delay_proc:

jbs flag_delay,key_start ; 按鍵延時(shí)開(kāi)始標(biāo)志,這個(gè)用來(lái)控制是否進(jìn)入計(jì)時(shí),允許計(jì)時(shí)標(biāo)志

jmp key_delay_end

djz reg_key ; 預(yù)先設(shè)置的延時(shí)時(shí)間,每5秒減一次,這里預(yù)設(shè)的值是4,也就是說(shuō) 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)來(lái)一下,每個(gè)計(jì)時(shí)器都同時(shí)在計(jì)數(shù)了,誰(shuí)先計(jì)算完畢就先關(guān)掉自己,置相應(yīng)的標(biāo)志給其它程序調(diào)用,而對(duì)其它計(jì)時(shí)器完全沒(méi)有影響!這樣,我們可以在這里放很多個(gè)計(jì)時(shí)器了,一般來(lái)說(shuō),十來(lái)二十個(gè)是沒(méi)有問(wèn)題的,完全滿足一個(gè)單片機(jī)系統(tǒng)對(duì)多個(gè)時(shí)間的需求了。

單個(gè)計(jì)時(shí)器的結(jié)構(gòu)很簡(jiǎn)單,先判斷允許計(jì)時(shí)標(biāo)志是否進(jìn)入計(jì)時(shí),然后一個(gè)專(zhuān)用的寄存器在加1或者減1,加/減購(gòu)相應(yīng)的數(shù)值之后也就是相應(yīng)的時(shí)間到了,關(guān)掉計(jì)時(shí)器,置相應(yīng)需要用到的標(biāo)志。

到這里差不多了,俺們需要的時(shí)間都可以出來(lái)了,這樣做是不是非常方便?咱們?cè)賮?lái)看看在這段時(shí)間里面單片機(jī)在做了什么東西?只有中斷計(jì)時(shí)夠 5ms 或者 500ms ,那個(gè)溢出標(biāo)志才有效,才能進(jìn)入上面的計(jì)時(shí)程序,其它時(shí)間都是在做其它事情。而且進(jìn)入上面的計(jì)時(shí)器的時(shí)候,可以看出,并不是在那里死循環(huán),只是單純的加減一下寄存器就退出了,整個(gè)過(guò)程耗時(shí)極其短,看代碼不同吧,5us到 20us左右吧,對(duì)主程序的執(zhí)行沒(méi)有什么影響。

(三)下面看看具體怎么調(diào)用

最開(kāi)始談過(guò)的按鍵的消抖時(shí)間處理問(wèn)題,現(xiàn)在就用上面介紹的辦法來(lái)看具體怎么解決問(wèn)題。按鍵的處理也是重要的基礎(chǔ)學(xué)問(wèn),不過(guò)不在本次的討論范圍,所以只是單單的討論怎么解決時(shí)間問(wèn)題,而對(duì)于按鍵的一些問(wèn)題,下次有機(jī)會(huì)繼續(xù)討論吧,hoho~~~

scan_key:

jbc flag_key,first_on ; 用來(lái)控制跳轉(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í)器開(kāi)始定時(shí)20ms消抖

have_key:

jbs flag_delay,key_flow 等待定時(shí)結(jié)束溢出

jmp key_end

大概是這樣的:判斷時(shí)候有健,沒(méi)有的話跳出,有的話開(kāi)始延時(shí)消抖的計(jì)時(shí),第二次進(jìn)來(lái)的時(shí)候直接由標(biāo)志位控制過(guò)去判斷時(shí)間時(shí)候夠。

同樣是等待,這里就是最后一點(diǎn)所說(shuō)的,咱這是跑著來(lái)等,不是站著來(lái)等。跟死循環(huán)定時(shí)比較,在沒(méi)有定時(shí)到20ms 的這段時(shí)間里面單片機(jī)在做什么? 死循環(huán)的話,肯定就是在原地等,什么都不做,而看看上面的程序,他只是判斷是否定時(shí)夠,具體的定時(shí)在統(tǒng)一的時(shí)間子程序里面做,判斷沒(méi)有到時(shí)間的話就跳出了,繼續(xù)跑其它的程序,直到當(dāng)時(shí)間到了,單片機(jī)判斷出flag_delay,key_flow 符合條件,開(kāi)始進(jìn)入按鍵處理程序了,在這個(gè)期間,單片機(jī)都在做其它事情,只是一個(gè)主循環(huán)跑回來(lái)判斷一次,所以單片機(jī)完全有空跑其它的程序,而沒(méi)有將時(shí)間都耗在消抖上面。

(四)看看我的主程序循環(huán)體

start:

call clear_all_ram 清空RAM

call initialize 初始化

loop:

eni 開(kāi)中斷

wdtc 清看門(mén)狗

call scan_proc 調(diào)用掃描LED和按鍵程序

call ir_data_proc 調(diào)用紅外處理程序

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è)程序都采用上面說(shuō)的分時(shí)掃的思想的話,一周循環(huán)回來(lái)的時(shí)間是相當(dāng)短的,其實(shí)是不是跟電腦的思想有點(diǎn)像呢?電腦再快也并不是同時(shí)處理多個(gè)任務(wù),而且每次處理一個(gè),然后非??斓乃俣葋?lái)循環(huán)處理,讓我們感覺(jué)上他是在同時(shí)處理多個(gè)程序那樣,我想,我最終想表達(dá)的思想也就是這個(gè)而已。

啰啰唆唆的說(shuō)了一堆,也不知道是否能看懂,或者是否去看。不知道我對(duì)分時(shí)掃描這個(gè)概念是否理解錯(cuò)了呢?在我看來(lái),有這個(gè)思想支撐下,單片機(jī)的程序變得比較容易上手了,剩下的只是集中精力去用程序來(lái)實(shí)現(xiàn)我們的思想而已,當(dāng)然,這里只是說(shuō)一種可行的辦法而已,不是說(shuō)只有這種辦法,如果大家有好的思想也分享一下哦,編寫(xiě)程序是一門(mén)藝術(shù),寫(xiě)出來(lái)很容易,但是寫(xiě)得好,寫(xiě)得精巧,那就很難了。



關(guān)鍵詞: 單片機(jī)分時(shí)思

評(píng)論


技術(shù)專(zhuān)區(qū)

關(guān)閉