如何DIY一個屬于你的超聲波測距傳感器三:程序的構(gòu)思和設(shè)計(jì)
2009-02-09 20:35:43| 分類:
單片機(jī)
|字號 訂閱
前文:
圖1 將被賦予“智慧”的東東 二、需求分析 測距傳感器的核心功能是測量距離,但當(dāng)其用于不同場合時(shí),會有許多不同的需求。 如果是傳統(tǒng)的傳感器概念,只需將“非電量轉(zhuǎn)換為便于測量的電量”即可,這是一個比較通俗也基本正確的定義,“便于測量的電量”通常為:直流小電流、小電壓以及方波等。 這類傳統(tǒng)傳感器給系統(tǒng)帶來了不少“麻煩”,因?yàn)槠漭敵龅乃^“便于測量的電量”只是物理上的,充其量達(dá)到“可測”而已,由于其輸出的不統(tǒng)一、不靈活,甚至有些“粗糙”,使得系統(tǒng)不得不付出一些開銷去彌補(bǔ)之。 就拿GP2D12來說,其輸出是直流電壓,可與距離的關(guān)系是非線性的,且是反比例,輸出還是非連續(xù)的,就這三個特征就足以讓系統(tǒng)耗費(fèi)不少周折才能得到想要的距離值。 還有很多類似的例子,如熱電偶溫度測量傳感器、光敏傳感器等,在此就不一一枚舉了。 從系統(tǒng)設(shè)計(jì)的角度考慮,最好是傳感器將所測量的量轉(zhuǎn)換成數(shù)字信息,系統(tǒng)不必再去理會這些“底層”的處理,專心于功能的實(shí)現(xiàn)。如同現(xiàn)在的PC操作系統(tǒng),有統(tǒng)一的設(shè)備接口,系統(tǒng)級應(yīng)用是“與硬件無關(guān)”的,設(shè)備的差異由各設(shè)備廠家通過驅(qū)動程序?qū)崿F(xiàn)統(tǒng)一。 以往由于技術(shù)和成本的限制,為了節(jié)省開支,將很多功能都交給了主控系統(tǒng)完成,形成所謂“樹形”架構(gòu),只有“主干”是有智能的,其余都是“末梢神經(jīng)”,只具備最低級的信號采集能力,也就是傳統(tǒng)傳感器的角色。 隨著單片機(jī)的功能提升、價(jià)格下降,新的構(gòu)架方式逐漸顯現(xiàn):一個系統(tǒng)中,每個部分都自成體系,主控只是負(fù)責(zé)策略、協(xié)調(diào),各個獨(dú)立的功能模塊“自行其事”。這就是“分布式”系統(tǒng)。 分布式系統(tǒng)概念的普及,催生了智能傳感器的需求。 所謂“智能傳感器”,至少有以下特征: 1) 能夠?qū)⒈粶y量轉(zhuǎn)換為數(shù)字值,而非簡單的模擬量; 2) 能夠根據(jù)要求獨(dú)立完成測量; 3) 能夠通過數(shù)字通訊接口接受命令、輸出數(shù)據(jù)。 具備此特征的傳感器已有很多,有些已制成IC,如常見的溫度傳感器 18B20。 智能傳感器除了降低了系統(tǒng)的軟硬件開銷外,附帶的一個好處就是便于傳送,傳統(tǒng)傳感器的輸出信號傳輸時(shí)的“干擾”和“衰減”是最令設(shè)計(jì)者頭痛的! 因此,智能傳感器是未來的方向。實(shí)際也是如此,讀者可搜索一下新興的MESM(微機(jī)電系統(tǒng))傳感器,不論是兩軸、三軸加速度,還是陀螺儀等,新產(chǎn)品幾乎都是I2C、SPI等數(shù)字總線接口。 所以,我們這個超聲波測距傳感器也是按智能傳感器理念設(shè)計(jì)的。 因本篇只是示范性軟件設(shè)計(jì),沒有特定的應(yīng)用場合,所以只好就測量本身來定義需求: 在性能上,測量關(guān)注兩方面:一是得到數(shù)據(jù)的速度,二是數(shù)據(jù)的可靠度。 在功能上,測量有兩類:一是不斷的測量并輸出結(jié)果,二是觸發(fā)后開始測量。 所以至少應(yīng)滿足上述需求: 1) 可設(shè)置為快速測量模式,讓系統(tǒng)最快得到測量數(shù)據(jù); 2) 可設(shè)置為精確測量模式,返回給系統(tǒng)比較可靠的數(shù)據(jù); 3) 可以設(shè)置為連續(xù)測量模式,不斷提供給系統(tǒng)測量數(shù)據(jù); 4) 可以按照系統(tǒng)請求開始測量,返回即時(shí)數(shù)據(jù)。
三、功能設(shè)計(jì) 按上述需求,傳感器的功能設(shè)計(jì)如下: 傳感器上電處于待命狀態(tài),等待系統(tǒng)命令做以下操作: 1) 可以支持連續(xù)測量,并存放最近8次數(shù)據(jù),測量周期可以由系統(tǒng)設(shè)置。在此狀態(tài)下,系統(tǒng)根據(jù)需要讀取數(shù)據(jù)。 2) 可以支持連續(xù)測量,并且將每次的數(shù)據(jù)返回給系統(tǒng),由系統(tǒng)進(jìn)行需要的后處理。 3) 可以接受系統(tǒng)命令,返回待命狀態(tài)。 4) 可以支持單輪測量,即系統(tǒng)發(fā)出命令通知傳感器,采集幾次數(shù)據(jù),傳感器可做基本的數(shù)據(jù)處理,如取平均、剔除最大最小值,完成后返回這組數(shù)據(jù)后,恢復(fù)到待命狀態(tài)。
此外,為了便于調(diào)試,增加讀、寫單片機(jī)內(nèi)存的功能。
四、詳細(xì)設(shè)計(jì) 4.1 題外話 看懂別人軟件是件相當(dāng)困難的事,即使那些較正規(guī)的、有完善文檔的項(xiàng)目,也不是十分輕松,因?yàn)橛涗浵聛淼闹皇墙Y(jié)果,思維的過程無法再現(xiàn),而讀者有時(shí)更多關(guān)注的是如何“想到的”,特別是初學(xué)者! 但描述軟件的構(gòu)思過程也并非易事! 前
期我寫過的“圓夢小車StepbyStep”系列文章中,嘗試通過一步步“搭建”的方式來引導(dǎo)讀者理解思考過程,并在程序中特別注釋了每一步所增加的內(nèi)
容,程序中排版順序都放棄了邏輯關(guān)系而“屈從”于“搭建”的順序,可似乎收效甚微?。坎聹y是沒有交代最基本的思路所致,因?yàn)榧词故敲恳徊蕉己芫唧w,讀者仍
會問:怎么來的?為何? 本文不是技術(shù)論文,其目的是幫助有意學(xué)習(xí)者實(shí)現(xiàn)自己的愿望,所以本篇嘗試簡述一下思考方式,看是否對學(xué)習(xí)者有幫助,但聲明一點(diǎn):此乃個人觀點(diǎn),并非“寶典”,不保證正確,僅供參考!
4.2 程序構(gòu)建思考過程 我開始涉足單片機(jī)編程時(shí),由于只有匯編語言可用,且編譯環(huán)境較弱,變量名、標(biāo)號限制較多,所以那時(shí)很講究使用流程圖來表達(dá)程序的構(gòu)思,因?yàn)閺膮R編代碼上看懂程序?qū)嵲诶щy,畢竟那是為機(jī)器思維服務(wù)的邏輯順序,與人理解所需的表述相差甚遠(yuǎn)。 當(dāng)
我轉(zhuǎn)換到C語言編程時(shí),開始還保持著畫流程圖的習(xí)慣,但逐漸覺得有些多余,因?yàn)镃語言的自注釋性(即語句和變量名的組合表達(dá)方式已接近人的理解需要)以及
編譯環(huán)境的提升,配合各類幾乎無限制的定義手段,使程序本身就可以方便的為人所理解。如今編輯器也在優(yōu)化,讀者可以嘗試一下
UltraEdit,其“折疊”、“展開”功能十分有助于理解程序的思路。所以漸漸的放棄了流程圖。但還維持著按實(shí)現(xiàn)過程來構(gòu)建程序的習(xí)慣。 自從我嘗試編寫PC環(huán)境下的VC程序后,逐漸構(gòu)思習(xí)慣有了很大變化,讀者如果沒有嘗試過,可以參照“圓夢小車StepbyStep之二”做一次,然后再用類似的方式構(gòu)建幾個自己想象的題目,一定會有所感受!
在VC中構(gòu)建一個程序,其過程大致如下: 1) 設(shè)計(jì)功能 —— 這是機(jī)器所不能代替的,靠你的創(chuàng)造力實(shí)現(xiàn)之,需要用文本記錄之; 2) 構(gòu)思界面 —— 這就是VC為你提供的方便了,根據(jù)功能和工具可以實(shí)現(xiàn)你所要的界面 3) 變量定義 —— 構(gòu)建界面時(shí)VC會自動生成變量,根據(jù)功能對這些變量進(jìn)行類型定義; 4) 編寫處理程序 —— 基于界面所產(chǎn)生的操作(按鈕等)編寫對上述變量進(jìn)行處理的程序,這是你的智慧展示的空間。
在PC上編程(默認(rèn)是Windows下),由于很多事情都由Windows操作系統(tǒng)幫助做了,所以在VC環(huán)境下編程確實(shí)比較輕松,只需關(guān)注和功能相關(guān)的事,無創(chuàng)意的瑣碎事務(wù)都由系統(tǒng)和VC處理了。 單片機(jī)中雖沒有這么“美”的事,但是這種構(gòu)建過程倒是改變了我,我現(xiàn)在基本也是按此思路去構(gòu)建一個程序,只不過一些VC幫助自動生成的過程由自己完成了。
首先,是確定所做的東西要完成哪些功能,這是基礎(chǔ)。在需求分析和概要設(shè)計(jì)階段基本搞定,在詳細(xì)設(shè)計(jì)的開始處將其具體化,用技術(shù)術(shù)語表達(dá)之。 之后根據(jù)這些功能定義相應(yīng)的變量。如需要記錄 8 次測量數(shù)據(jù),就需要有一個 8元的數(shù)組,同時(shí)要有存放指針和取數(shù)指針(注意:此處所述“指針”,非C語言的指針,是指數(shù)組的下標(biāo),只是個人表達(dá)習(xí)慣而已,下同),以便于對數(shù)組操作。 根
據(jù)硬件的性能和需求確定數(shù)組的類型,是用整型還是字節(jié)型等;因?yàn)槲叶x的測量范圍為5米,即使用cm為單位字節(jié)型也不夠,所以用整型。因?yàn)椴豢赡苡胸?fù)數(shù),
所以用無符號整型。數(shù)值表達(dá)范圍大了,將單位提高到mm,雖然不一定需要,但不增加工作量,感覺卻好多了 : P 何樂而不為? 在定義變量的同
時(shí),定義一些與變量處理相關(guān)的常量,一方面為了程序的可讀性,同時(shí)也是為了日后便于修改。如現(xiàn)在設(shè)計(jì)是保留最近8次數(shù)據(jù),但日后也許需要更多或較少,將數(shù)
組的單元數(shù)聲明為符號常量 ——
DATA_SAVE_NUM,定義為8,需要時(shí)只需修改此處定義即可,不用在程序中“遍地”去找,遺漏一個就形成一個bug! 在構(gòu)思服務(wù)于功能的
變量時(shí)順便考慮如何處理之,還是拿測量數(shù)據(jù)存放為例。既然需要存放最近N次的數(shù)據(jù),可以這樣處理:存滿8個之后依次向前移,覆蓋序號最小的單元,騰出序號
最大的存放新數(shù)據(jù)。這樣處理效率太低,常用的方式是環(huán)形緩沖區(qū)的概念,即將數(shù)據(jù)存放區(qū)看成是個首尾相接的環(huán),存放數(shù)據(jù)時(shí)指針不斷“加”,到尾時(shí)自動環(huán)到
首,不用任何數(shù)據(jù)搬家操作,而取數(shù)也是同樣,只是從存數(shù)指針向回“減”,到首時(shí)自動環(huán)到尾。 基于這個思路,自然2個指針變量的需求就產(chǎn)生了。這兩
個指針據(jù)需要能夠“加”到尾環(huán)頭,或“減”到頭環(huán)尾。如憑直覺,就用比較的方式判斷,每次運(yùn)算都作一次檢測,雖能完成,但似乎有些繁瑣??紤]一下有無更好
的方式?如果還記得二進(jìn)制的基本運(yùn)算,就可以理解我為何在程序中設(shè)計(jì)環(huán)形數(shù)據(jù)存放區(qū)的時(shí)候均要求單元數(shù)是2的冪,即4、8、16……
按上述方式,可以依次定義出功能用的變量。之后就要結(jié)合運(yùn)行定義一些處理用的變量,這就是VC和操作系統(tǒng)可以幫你完成的那部分。
嵌入式系統(tǒng)(或俗稱“單片機(jī)系統(tǒng)”)有以下幾個概念: 1)死循環(huán) 嵌入式系統(tǒng)是連續(xù)不斷運(yùn)行的,所以必然有一個“死循環(huán)”,一般用以下程序?qū)崿F(xiàn): While(1) { …… } 2)標(biāo)志驅(qū)動 對于嵌入式系統(tǒng),小的應(yīng)用一般沒有操作系統(tǒng),內(nèi)存不夠,開銷也大,所以需要自己設(shè)置一些標(biāo)志,以實(shí)現(xiàn)類似于PC上的“消息驅(qū)動”。 在上述循環(huán)中,程序順序檢測各個標(biāo)志,根據(jù)標(biāo)志做相應(yīng)的處理。標(biāo)志的建立一般由中斷完成,或者是中斷處理后產(chǎn)生。 3)時(shí)基 多數(shù)程序都有按時(shí)間處理的需求,如延時(shí)、定時(shí)查詢、周期測量等等,所以一定有一個時(shí)基,由定時(shí)器中斷產(chǎn)生,建立標(biāo)志。在PC中也有類似的機(jī)制,DOS時(shí)代的PC我知道系統(tǒng)有一個18.2ms的時(shí)鐘信號,現(xiàn)在的PC不太清楚了 : ( 我設(shè)計(jì)系統(tǒng)通常使用1ms時(shí)基,因?yàn)槎鄶?shù)處理不會小于這個間隔。由此,要設(shè)計(jì)一個1ms中斷標(biāo)志。所有與時(shí)間相關(guān)的處理都安排在1ms中斷標(biāo)志建立后的處理中。 4)狀態(tài) 一個功能的實(shí)現(xiàn),往往不能“一蹴而就”。 就拿超聲波測距來說:首先得發(fā)出超聲波,之后等待回波,等待過程中要根據(jù)時(shí)間控制增益,逐漸增大,以彌補(bǔ)聲波隨距離增加的衰減。收到后再計(jì)算,至此才能得到一個測量結(jié)果。 按照聲波速度,2m距離約需要12ms(來回4m)。如果程序設(shè)計(jì)成順序依次處理模式,直到完成后再處理其它的任務(wù),則大概通訊成功率只有一半了,因?yàn)镸CU的處理給測距過程獨(dú)占了。 也許有人說:可以用中斷來處理。 在
此,順便說一下:在成熟的程序中,中斷處理中盡量少安排操作。因?yàn)橐皇菚捎谥袛鄡?nèi)、外同時(shí)處理相同變量產(chǎn)生錯誤,除非你設(shè)計(jì)了嚴(yán)格的“閉鎖”機(jī)制;二是
降低了其它中斷的響應(yīng)速度,也許會導(dǎo)致程序性能下降;如需要精確捕捉脈沖,則會由于延時(shí)響應(yīng)而降低精度。優(yōu)先級機(jī)制雖可彌補(bǔ),但那更容易導(dǎo)致數(shù)據(jù)錯誤,而
且需要更多的堆??臻g。 為了避免上述問題,通常使用狀態(tài)來標(biāo)注一個功能做到了哪一步?設(shè)置一個狀態(tài)變量,記錄功能實(shí)現(xiàn)的進(jìn)程,每次輪回時(shí)根據(jù)狀態(tài)做相應(yīng)的事,把能做的做完后立刻退出,把MCU的處理能力交給別的任務(wù)。 這就是“分時(shí)”處理的概念,只不過分時(shí)是由自己寫的程序所調(diào)度,而非“操作系統(tǒng)”,隨著所做的項(xiàng)目復(fù)雜度加大,你會感到“操作系統(tǒng)”的重要! 而利用狀態(tài)控制大概就是所謂的“有限狀態(tài)機(jī)”,這在嵌入式系統(tǒng)中是常見的。 具體實(shí)施時(shí),采用螺旋式步驟完成程序。 先構(gòu)建一個最基本的程序框架:(這一步在VC中,建立MFC工程時(shí)就自動完成了,可在單片機(jī)上,得自己為之 ? )
圖 1 程序主框架 (使用圖片表示并非想阻礙拷貝,只是想借用編輯器的彩色表示方式,更直觀,下同) 從上圖可以看出,程序基本上由初始化和死循環(huán)組成,死循環(huán)中設(shè)計(jì)了三個處理:時(shí)基、通訊、測量(工作),這三件事因?yàn)樾枰瑫r(shí)處理,所以設(shè)計(jì)在循環(huán)中依次得到MCU的處理時(shí)間。讀者可回憶一下流程圖格式,有了這個還需要嗎? 然后逐步充實(shí),每構(gòu)思一個功能: 1) 定義相關(guān)變量 2) 在init_var()中初始化; 3) 根據(jù)需要定義相關(guān)常數(shù); 4) 涉及硬件,在init_hardware()中初始化硬件; 5) 構(gòu)建處理方法,也就是函數(shù),完成功能; 6) 如完成需要等待外部條件,則定義狀態(tài)變量,并定義狀態(tài),轉(zhuǎn)換條件; 7) 處理時(shí)如涉及定時(shí),則設(shè)置計(jì)時(shí)器,建立相應(yīng)標(biāo)志,在時(shí)基處理中添加處理; 不一定要一個螺旋就上到“頂”,可以逐步添加,首先是實(shí)現(xiàn)功能必備的處理,其次是防護(hù)出錯的保護(hù)性處理。程序?qū)⒅鸩阶兊猛晟?、可靠。最終得到的程序自然比較復(fù)雜,而讀程序者通??吹降氖沁@個版本,所以自然費(fèi)解! 讀
者如果接觸過編程,一定知道“面向?qū)ο蟆?,這個概念開始時(shí)我很不理解,匯編程序?qū)懚嗔?,思維更“接近”機(jī)器。在編寫幾次VC程序后,覺得“面向?qū)ο蟆钡故?
一個不錯的思維方式,即從你要做的事情開始思考,它要完成什么?它有什么特征?它怎么去做?可以類比一下,上述功能定義說明了它要完成什么?變量定義說明
了特征,而處理方法指明它如何去做。也許不太貼切,但是自我感覺有不小的幫助。
|