橋杯國(guó)賽超聲波測(cè)距機(jī):從單片機(jī)原理到嵌入式系統(tǒng)實(shí)戰(zhàn))
1. 項(xiàng)目緣起從賽題到超聲波測(cè)距機(jī)的誕生第八屆藍(lán)橋杯單片機(jī)設(shè)計(jì)與開(kāi)發(fā)國(guó)賽的題目我至今記憶猶新。它沒(méi)有直接給出一個(gè)花哨的名字而是用“超聲波測(cè)距機(jī)”這個(gè)樸實(shí)無(wú)華的功能描述精準(zhǔn)地勾勒出了考核的核心。對(duì)于當(dāng)時(shí)備賽的我而言這不僅僅是一道題目更像是一個(gè)從零到一、從原理到實(shí)物的完整工程項(xiàng)目挑戰(zhàn)。它要求我們綜合運(yùn)用單片機(jī)、傳感器、人機(jī)交互和數(shù)據(jù)處理等多方面知識(shí)最終制作出一個(gè)能夠穩(wěn)定、精確測(cè)量距離并直觀顯示的設(shè)備。超聲波測(cè)距聽(tīng)起來(lái)原理簡(jiǎn)單——發(fā)射聲波接收回波計(jì)算時(shí)間差再乘以聲速的一半。但真正動(dòng)手做起來(lái)從電路設(shè)計(jì)、程序時(shí)序控制、到數(shù)據(jù)處理和抗干擾每一步都藏著“坑”。這個(gè)學(xué)習(xí)記錄就是我一步步把這些“坑”填平最終讓一個(gè)冰冷的單片機(jī)開(kāi)發(fā)板變成一個(gè)能“看見(jiàn)”距離的智能設(shè)備的過(guò)程。它適合所有正在學(xué)習(xí)單片機(jī)、準(zhǔn)備參加電子類(lèi)競(jìng)賽或者對(duì)嵌入式系統(tǒng)如何與現(xiàn)實(shí)世界交互感興趣的朋友。無(wú)論你是剛?cè)腴T(mén)的新手還是有一定基礎(chǔ)的愛(ài)好者相信這個(gè)從賽題出發(fā)的完整實(shí)現(xiàn)過(guò)程都能給你帶來(lái)一些實(shí)實(shí)在在的啟發(fā)和可以直接“抄作業(yè)”的代碼思路。2. 核心需求拆解與系統(tǒng)架構(gòu)設(shè)計(jì)拿到“超聲波測(cè)距機(jī)”這個(gè)題目第一步不是急著寫(xiě)代碼或焊電路而是靜下心來(lái)把題目中或明或暗的需求全部梳理出來(lái)。這是保證后續(xù)開(kāi)發(fā)不跑偏、功能完整的關(guān)鍵。根據(jù)國(guó)賽一貫的命題風(fēng)格和“測(cè)距機(jī)”這個(gè)應(yīng)用場(chǎng)景我們可以分解出以下幾個(gè)核心需求點(diǎn)2.1 基本功能需求測(cè)距與顯示這是最核心、最基礎(chǔ)的需求。系統(tǒng)必須能夠驅(qū)動(dòng)超聲波傳感器通常是HC-SR04模塊完成一次完整的測(cè)距過(guò)程并將計(jì)算出的距離值通過(guò)某種方式顯示出來(lái)。在藍(lán)橋杯官方指定的CT107D開(kāi)發(fā)板上顯示設(shè)備通常是LCD1602液晶屏或8位數(shù)碼管。這里就涉及到第一個(gè)設(shè)計(jì)決策顯示設(shè)備選型。我選擇了LCD1602。原因有三其一LCD可以顯示字符和數(shù)字能更友好地展示“距離XX.XX cm”這樣的信息用戶(hù)體驗(yàn)更好其二避免了數(shù)碼管動(dòng)態(tài)掃描可能帶來(lái)的程序時(shí)序復(fù)雜度和潛在的顯示閃爍問(wèn)題其三LCD的驅(qū)動(dòng)雖然初始化稍復(fù)雜但一旦寫(xiě)好驅(qū)動(dòng)函數(shù)后續(xù)顯示固定格式的內(nèi)容非常方便。這個(gè)選擇直接影響了后續(xù)的軟件架構(gòu)我們需要編寫(xiě)或移植一個(gè)穩(wěn)定的LCD1602驅(qū)動(dòng)層。2.2 性能與精度需求作為“測(cè)距機(jī)”精度和穩(wěn)定性是衡量其好壞的核心指標(biāo)。題目不會(huì)明確要求精度達(dá)到毫米級(jí)但一個(gè)能穩(wěn)定工作在2cm到400cmHC-SR04的典型量程范圍內(nèi)誤差在合理范圍例如±1cm的系統(tǒng)是基本要求。這引出了幾個(gè)關(guān)鍵技術(shù)點(diǎn)高精度定時(shí)器超聲波測(cè)距的基石是時(shí)間測(cè)量。聲波在空氣中的速度約為340m/s測(cè)量1cm距離對(duì)應(yīng)的時(shí)間差約為58.8微秒。因此我們需要一個(gè)精度在微秒級(jí)別的定時(shí)器來(lái)捕獲回波的高電平持續(xù)時(shí)間。通常我們會(huì)使用單片機(jī)的定時(shí)器中斷功能。溫度補(bǔ)償聲速受溫度影響顯著。公式v 331.4 0.606 * TT為攝氏溫度描述了這種關(guān)系。如果要求高精度尤其是測(cè)量范圍較大時(shí)引入溫度傳感器如DS18B20進(jìn)行聲速修正是必要的。雖然基礎(chǔ)功能可以不考慮但這體現(xiàn)了系統(tǒng)的完備性。濾波算法超聲波傳感器容易受到環(huán)境噪聲、多次反射等干擾導(dǎo)致單次測(cè)量值跳變。因此必須對(duì)連續(xù)多次的測(cè)量結(jié)果進(jìn)行軟件濾波例如取中值、取平均值或卡爾曼濾波以輸出一個(gè)穩(wěn)定的距離值。2.3 人機(jī)交互與擴(kuò)展需求一個(gè)完整的設(shè)備不能只有測(cè)量和顯示。良好的人機(jī)交互能極大提升實(shí)用性。這包括按鍵控制至少需要設(shè)置一個(gè)“測(cè)量觸發(fā)”鍵。更進(jìn)一步可以設(shè)計(jì)“模式切換”鍵如切換顯示單位cm/inch、”報(bào)警閾值設(shè)置“鍵等。聲光報(bào)警當(dāng)測(cè)量距離低于某個(gè)預(yù)設(shè)的安全閾值時(shí)系統(tǒng)應(yīng)能通過(guò)蜂鳴器報(bào)警和LED指示燈閃爍來(lái)提醒用戶(hù)。這是測(cè)距機(jī)常見(jiàn)的安防應(yīng)用場(chǎng)景。數(shù)據(jù)輸出是否需要通過(guò)串口將距離數(shù)據(jù)發(fā)送到上位機(jī)電腦進(jìn)行記錄或分析雖然賽題可能不要求但加上這個(gè)功能能讓系統(tǒng)更具擴(kuò)展性。基于以上需求我設(shè)計(jì)了如下的系統(tǒng)軟件架構(gòu)它遵循了分層和模塊化的思想便于調(diào)試和代碼復(fù)用應(yīng)用層 (main.c) |-- 調(diào)用各個(gè)模塊接口組織業(yè)務(wù)流程初始化、按鍵掃描、顯示刷新、報(bào)警判斷 | 驅(qū)動(dòng)層/服務(wù)層 |-- 超聲波測(cè)距模塊 (ultrasonic.c/h)封裝發(fā)射、接收、定時(shí)器計(jì)時(shí)邏輯。 |-- 顯示模塊 (lcd1602.c/h)封裝LCD初始化、清屏、寫(xiě)字符串/數(shù)字函數(shù)。 |-- 按鍵模塊 (key.c/h)封裝獨(dú)立按鍵或矩陣鍵盤(pán)的掃描函數(shù)。 |-- 報(bào)警模塊 (buzzer_led.c/h)封裝蜂鳴器鳴叫、LED閃爍模式控制。 |-- 延時(shí)模塊 (delay.c/h)提供微秒級(jí)和毫秒級(jí)精準(zhǔn)延時(shí)用于超聲波觸發(fā)信號(hào)。 | 硬件抽象層 |-- 對(duì)單片機(jī)IO口、定時(shí)器、中斷的直接操作通常包含在驅(qū)動(dòng)模塊中。這樣的架構(gòu)使得main函數(shù)中的邏輯非常清晰初始化所有外設(shè) - 進(jìn)入主循環(huán) - 檢測(cè)按鍵是否觸發(fā)測(cè)量 - 調(diào)用超聲波模塊函數(shù)獲取距離 - 調(diào)用顯示模塊刷新屏幕 - 判斷距離是否超限并控制報(bào)警。3. 硬件連接與關(guān)鍵電路解析藍(lán)橋杯CT107D開(kāi)發(fā)板已經(jīng)集成了大部分電路我們的主要工作是根據(jù)原理圖正確連接超聲波模塊HC-SR04和相關(guān)的外設(shè)。理解這些連接背后的原因比單純照著連線更重要。3.1 HC-SR04模塊接口與單片機(jī)連接HC-SR04有四個(gè)引腳VCC, GND, Trig觸發(fā), Echo回波。VCC和GND接開(kāi)發(fā)板的5V和GND。務(wù)必確保供電穩(wěn)定不穩(wěn)定的電源是測(cè)量值亂跳的常見(jiàn)原因之一。Trig觸發(fā)端接單片機(jī)任意一個(gè)IO口如P1^0。這個(gè)引腳用于接收單片機(jī)發(fā)出的一個(gè)至少10微秒的高電平脈沖信號(hào)模塊收到此信號(hào)后會(huì)自動(dòng)發(fā)射8個(gè)40kHz的超聲波脈沖。Echo回波端這是連接的關(guān)鍵和易錯(cuò)點(diǎn)。該引腳在模塊內(nèi)部是開(kāi)漏輸出需要外接上拉電阻通常模塊板上已集成。它輸出一個(gè)高電平脈沖其寬度與測(cè)得的距離成正比。這個(gè)引腳必須連接到單片機(jī)的外部中斷引腳或支持輸入捕獲的定時(shí)器引腳上因?yàn)槲覀儫o(wú)法用簡(jiǎn)單的延時(shí)循環(huán)來(lái)精確測(cè)量這個(gè)高電平的寬度微秒級(jí)。在STC15系列單片機(jī)中我通常將其連接到P3^2INT0或P3^3INT1利用外部中斷的上升沿/下降沿來(lái)精準(zhǔn)計(jì)時(shí)。注意有些教程為了簡(jiǎn)單用普通IO口配合查詢(xún)Echo電平并軟件計(jì)數(shù)的方式。這種方法在單片機(jī)沒(méi)有其他任務(wù)時(shí)勉強(qiáng)可用但極不精確且會(huì)阻塞CPU。在國(guó)賽級(jí)別的應(yīng)用中使用外部中斷定時(shí)器是標(biāo)準(zhǔn)且必須的做法。3.2 顯示、按鍵與報(bào)警設(shè)備連接LCD1602按照開(kāi)發(fā)板原理圖連接數(shù)據(jù)口P0和控制口RS, RW, E到指定的P2口高三位。一個(gè)關(guān)鍵細(xì)節(jié)P0口作為數(shù)據(jù)口時(shí)必須接上拉電阻CT107D板子上通常有排阻提供上拉。程序里不需要特別設(shè)置但硬件上一定要有否則數(shù)據(jù)無(wú)法正確寫(xiě)入LCD。按鍵開(kāi)發(fā)板上有獨(dú)立按鍵和矩陣鍵盤(pán)。對(duì)于簡(jiǎn)單的“開(kāi)始測(cè)量”鍵使用一個(gè)獨(dú)立按鍵如S7連接到某個(gè)IO口如P3^0設(shè)置為輸入模式程序內(nèi)做消抖處理即可。蜂鳴器與LED蜂鳴器通常通過(guò)一個(gè)三極管驅(qū)動(dòng)連接到一個(gè)IO口如P1^5輸出高電平響低電平停。LED則連接到LED蜂鳴器模塊的接口通過(guò)鎖存器如74HC573控制。這里容易踩坑CT107D板子的LED和數(shù)碼管、蜂鳴器是共用部分IO口的通過(guò)鎖存器選擇。操作LED前必須先打開(kāi)控制LED的鎖存器Y4C操作完后如果后續(xù)還要用同一個(gè)IO口控制其他設(shè)備如數(shù)碼管必須記得關(guān)閉或切換鎖存器否則會(huì)造成顯示混亂。3.3 電源與抗干擾考慮如果系統(tǒng)同時(shí)驅(qū)動(dòng)LCD、超聲波模塊、蜂鳴器瞬間電流可能較大。確保你的5V電源適配器能提供足夠的電流建議1A以上。超聲波模塊的VCC和GND引腳附近可以并聯(lián)一個(gè)10uF和一個(gè)0.1uF的電容到地用于濾除電源噪聲。Trig和Echo的信號(hào)線應(yīng)盡量短如果必須延長(zhǎng)建議使用屏蔽線或雙絞線減少干擾。4. 軟件核心超聲波測(cè)距的驅(qū)動(dòng)實(shí)現(xiàn)這是整個(gè)項(xiàng)目的靈魂。其核心思想是單片機(jī)給Trig一個(gè)脈沖啟動(dòng)超聲波發(fā)射然后等待Echo引腳變高同時(shí)開(kāi)啟定時(shí)器計(jì)數(shù)當(dāng)Echo變低時(shí)停止定時(shí)器根據(jù)計(jì)數(shù)值計(jì)算時(shí)間進(jìn)而算出距離。4.1 定時(shí)器與中斷的配置我們使用定時(shí)器0Timer0工作在16位自動(dòng)重裝模式為系統(tǒng)提供精準(zhǔn)的計(jì)時(shí)基準(zhǔn)。假設(shè)單片機(jī)晶振為12MHz傳統(tǒng)51常用或11.0592MHz串口通信常用這里以11.0592MHz為例它每個(gè)機(jī)器周期約1.085微秒。// Timer0 初始化用于微秒級(jí)延時(shí)和距離計(jì)算的時(shí)間基準(zhǔn) void Timer0_Init(void) //11.0592MHz { AUXR 0x7F; // 定時(shí)器時(shí)鐘12T模式 TMOD 0xF0; // 設(shè)置定時(shí)器模式 TMOD | 0x01; // 定時(shí)器0模式116位非自動(dòng)重裝 TL0 0x00; // 初始化計(jì)時(shí)值 TH0 0x00; TF0 0; // 清除溢出標(biāo)志 TR0 0; // 先不啟動(dòng)定時(shí)器 }注意這里我們沒(méi)有開(kāi)啟定時(shí)器中斷因?yàn)槲覀兪前裈imer0當(dāng)作一個(gè)精準(zhǔn)的“秒表”來(lái)用通過(guò)讀取TH0和TL0的值來(lái)計(jì)算時(shí)間間隔而不是依賴(lài)中斷來(lái)累加時(shí)間。這種方式精度更高。4.2 超聲波觸發(fā)與回波捕獲我們使用外部中斷0INT0來(lái)捕獲Echo引腳上的跳變沿。// 外部中斷0初始化用于捕獲Echo上升沿和下降沿 void INT0_Init(void) { IT0 1; // 設(shè)置外部中斷0為下降沿觸發(fā) EX0 1; // 使能外部中斷0 EA 1; // 開(kāi)啟總中斷 }但是我們需要同時(shí)捕獲上升沿回波開(kāi)始和下降沿回波結(jié)束。一種更靈活的方法是將Echo引腳配置為雙邊沿觸發(fā)或者結(jié)合軟件判斷。在STC15單片機(jī)中可以設(shè)置INT0為上升沿和下降沿都觸發(fā)。為了清晰我們采用另一種常見(jiàn)方法在發(fā)送Trig脈沖后先將INT0設(shè)置為上升沿觸發(fā)在上升沿中斷服務(wù)程序ISR中開(kāi)啟Timer0并改為下降沿觸發(fā)在下降沿ISR中關(guān)閉Timer0并讀取時(shí)間值。4.3 距離計(jì)算與濾波在下降沿中斷中我們獲得了Timer0的計(jì)數(shù)值time_us單位是機(jī)器周期。距離計(jì)算公式為距離cm time_us * 機(jī)器周期時(shí)間 * 聲速 / 2將聲速近似為34000 cm/s機(jī)器周期時(shí)間 12 / 11.0592 us ≈ 1.085 us。 代入公式距離 time_us * 1.085e-6 * 34000 / 2 ≈ time_us * 0.01845為了在整數(shù)運(yùn)算中保持精度我們通常將公式變換為距離 time_us * 17 / 921。這個(gè)系數(shù)是通過(guò)0.01845 * 1000將cm轉(zhuǎn)換為mm保留一位小數(shù)并找到合適的整數(shù)近似比得到的最終顯示時(shí)再除以10.0得到以cm為單位的帶一位小數(shù)的值。單次測(cè)量極易受干擾必須濾波。我采用的方法是連續(xù)測(cè)量5次去掉一個(gè)最大值和一個(gè)最小值對(duì)剩下的3個(gè)值取平均。unsigned int GetDistance(void) { unsigned int distances[5]; unsigned int temp, sum 0; char i, j; for(i0; i5; i) { distances[i] SingleMeasure(); // 單次測(cè)量函數(shù) DelayMs(60); // 兩次測(cè)量間稍作延時(shí)避免余波干擾 } // 簡(jiǎn)單冒泡排序去掉首尾 for(i0; i4; i) for(j0; j4-i; j) if(distances[j] distances[j1]) { temp distances[j]; distances[j] distances[j1]; distances[j1] temp; } // 取中間三個(gè)值的平均 for(i1; i4; i) sum distances[i]; return sum / 3; }5. 系統(tǒng)集成與主程序邏輯流當(dāng)各個(gè)模塊超聲波、LCD、按鍵、報(bào)警的驅(qū)動(dòng)函數(shù)都準(zhǔn)備好后最后的拼圖就是在main函數(shù)中將它們有機(jī)地組合起來(lái)形成一個(gè)穩(wěn)定運(yùn)行的嵌入式系統(tǒng)。5.1 系統(tǒng)初始化這是程序運(yùn)行的起點(diǎn)必須嚴(yán)謹(jǐn)。初始化的順序有時(shí)也有講究。void main() { Sys_Init(); // 系統(tǒng)初始化關(guān)閉無(wú)關(guān)外設(shè)如蜂鳴器、繼電器、LED Timer0_Init(); // 初始化定時(shí)器0作為計(jì)時(shí)基準(zhǔn) INT0_Init(); // 初始化外部中斷0用于Echo捕獲 LCD_Init(); // 初始化LCD1602顯示歡迎界面或標(biāo)題 Key_Init(); // 按鍵IO口初始化設(shè)置為準(zhǔn)雙向或輸入模式 Buzzer_LED_Init(); // 初始化報(bào)警設(shè)備IO口輸出模式 LCD_ShowString(0, 0, UltraSonic Ranging); LCD_ShowString(1, 0, Dist: ---.-- cm); // ... 其他初始化顯示 }Sys_Init()是一個(gè)好習(xí)慣它確保單片機(jī)從上電的隨機(jī)狀態(tài)進(jìn)入一個(gè)已知的、安全的狀態(tài)。對(duì)于CT107D板這個(gè)函數(shù)里通常會(huì)關(guān)閉蜂鳴器、繼電器關(guān)閉所有LED將用到的鎖存器置于一個(gè)確定的狀態(tài)。5.2 主循環(huán)設(shè)計(jì)嵌入式系統(tǒng)的主程序幾乎都是一個(gè)無(wú)限循環(huán)while(1)。在這個(gè)循環(huán)里我們需要以合理的頻率和順序執(zhí)行各項(xiàng)任務(wù)檢測(cè)用戶(hù)輸入、執(zhí)行測(cè)量、更新顯示、判斷報(bào)警條件。這里的關(guān)鍵是非阻塞和實(shí)時(shí)性平衡。while(1) { // 1. 按鍵掃描與處理非阻塞式每隔10-20ms掃描一次即可 key Key_Scan(); // 返回按下的鍵值無(wú)按鍵返回0 if(key KEY_MEASURE) // 假設(shè)定義了測(cè)量鍵 { Buzzer_Beep(1); // 短鳴一聲提示開(kāi)始測(cè)量 distance_mm GetDistance(); // 獲取距離單位毫米*10即0.1mm distance_cm distance_mm / 10.0; // 轉(zhuǎn)換為厘米浮點(diǎn)數(shù) // 2. 更新顯示 LCD_ShowFloat(1, 6, distance_cm, 4, 1); // 在第1行第6列顯示總寬4字符1位小數(shù) // 3. 報(bào)警判斷與處理 if(distance_cm ALARM_THRESHOLD) { Buzzer_Beep(3); // 報(bào)警模式鳴叫3次 LED_Flash(500); // LED以500ms間隔閃爍 } else { Buzzer_Off(); LED_Off(); } } // 4. 可以加入其他任務(wù)如自動(dòng)循環(huán)測(cè)量模式、串口發(fā)送數(shù)據(jù)等 // DelayMs(10); // 主循環(huán)延時(shí)降低CPU占用率但會(huì)影響響應(yīng)速度 }我在這里采用了事件驅(qū)動(dòng)的方式只有當(dāng)測(cè)量鍵被按下時(shí)才執(zhí)行一次完整的測(cè)量、顯示和報(bào)警判斷流程。這比在循環(huán)里不斷自動(dòng)測(cè)量更省電也更符合“按需測(cè)量”的交互邏輯。Key_Scan()函數(shù)內(nèi)部實(shí)現(xiàn)了軟件消抖確保一次按鍵只觸發(fā)一次。5.3 中斷服務(wù)程序與全局變量中斷服務(wù)程序ISR要盡可能短小精悍只做最必要的事情記錄時(shí)間戳、改變狀態(tài)標(biāo)志。unsigned int echo_start_time, echo_end_time; bit echo_flag 0; // 回波標(biāo)志0-未開(kāi)始1-正在測(cè)量 void exint0() interrupt 0 // 外部中斷0服務(wù)函數(shù) { if(echo_flag 0) // 捕獲到上升沿回波開(kāi)始 { echo_flag 1; TR0 1; // 啟動(dòng)定時(shí)器0 TL0 0; TH0 0; // 定時(shí)器清零 } else // 捕獲到下降沿回波結(jié)束 { echo_flag 0; TR0 0; // 停止定時(shí)器0 echo_end_time (TH0 8) | TL0; // 獲取計(jì)時(shí)值 } }在SingleMeasure()函數(shù)里先給Trig一個(gè)10us以上的高脈沖然后等待echo_flag被置1再清0并讀取echo_end_time進(jìn)行計(jì)算。這里使用了一個(gè)bit類(lèi)型的全局變量echo_flag在ISR和主程序間通信是單片機(jī)編程中常見(jiàn)的技巧。需要注意的是對(duì)于可能在中斷和主程序中被同時(shí)訪問(wèn)的全局變量雖然這里echo_flag只是簡(jiǎn)單的置1/清0如果單片機(jī)架構(gòu)支持需要考慮簡(jiǎn)單的原子操作或關(guān)中斷保護(hù)但對(duì)于51內(nèi)核的單片機(jī)這種簡(jiǎn)單操作通常是安全的。6. 調(diào)試、優(yōu)化與常見(jiàn)問(wèn)題排查即使代碼邏輯完全正確第一次上電也大概率不會(huì)成功。系統(tǒng)的調(diào)試過(guò)程就是與各種硬件特性、時(shí)序問(wèn)題和環(huán)境干擾斗爭(zhēng)的過(guò)程。6.1 調(diào)試第一步模塊隔離測(cè)試不要一開(kāi)始就把所有代碼都集成進(jìn)去。應(yīng)該分模塊調(diào)試LCD測(cè)試寫(xiě)一個(gè)簡(jiǎn)單的測(cè)試程序讓LCD顯示固定的字符串“Hello World”。確保硬件連接、對(duì)比度調(diào)節(jié)通過(guò)電位器和驅(qū)動(dòng)代碼正確。按鍵測(cè)試寫(xiě)一個(gè)程序按下不同的鍵在LCD或通過(guò)串口打印出鍵值。確保消抖邏輯有效。超聲波模塊單獨(dú)測(cè)試這是最復(fù)雜的一步??梢韵炔挥弥袛嘤檬静ㄆ魅绻械脑?huà)觀察Trig腳和Echo腳的波形。給Trig一個(gè)脈沖看Echo是否有一個(gè)高電平脈沖輸出。如果沒(méi)有檢查模塊供電、接線。如果有再用一個(gè)簡(jiǎn)單的延時(shí)循環(huán)粗略測(cè)量高電平寬度看是否隨距離變化。這一步能排除大部分硬件問(wèn)題。定時(shí)器測(cè)試寫(xiě)一個(gè)程序用定時(shí)器精確延時(shí)1秒讓一個(gè)LED閃爍。驗(yàn)證定時(shí)器配置和中斷是否正常工作。6.2 超聲波測(cè)距不準(zhǔn)的排查這是最常見(jiàn)的問(wèn)題現(xiàn)象包括數(shù)值亂跳、始終為0、始終為一個(gè)極大值如65535。數(shù)值亂跳首先懷疑電源噪聲和軟件濾波。確保電源質(zhì)量在模塊VCC和GND間加濾波電容。務(wù)必啟用軟件濾波如前面提到的去極值平均法。其次檢查測(cè)量間隔兩次測(cè)量之間必須留有足夠時(shí)間建議60ms以上讓上一次發(fā)射的聲波完全衰減避免余波干擾。始終為0通常是Echo信號(hào)沒(méi)有被正確捕獲。檢查Echo腳是否接到了外部中斷引腳P3^2或P3^3。檢查外部中斷的配置觸發(fā)方式、中斷使能、總中斷使能是否正確。用示波器看Echo腳是否有高電平脈沖輸出。如果沒(méi)有可能是模塊損壞或Trig觸發(fā)信號(hào)太短確保10us。始終為極大值如65535這通常是Echo高電平持續(xù)時(shí)間過(guò)長(zhǎng)導(dǎo)致定時(shí)器溢出或者根本沒(méi)有捕獲到下降沿。檢查物體是否在量程內(nèi)HC-SR04通常2cm-400cm太近或太遠(yuǎn)都可能無(wú)回波。檢查中斷服務(wù)程序邏輯是否在上升沿和下降沿處理中正確切換了echo_flag和定時(shí)器TR0。一個(gè)關(guān)鍵點(diǎn)在SingleMeasure()函數(shù)中發(fā)送Trig脈沖后應(yīng)有一個(gè)等待回波超時(shí)的機(jī)制。例如等待echo_flag變?yōu)?如果超過(guò)30ms對(duì)應(yīng)約5米還沒(méi)等到就認(rèn)為測(cè)量超時(shí)返回一個(gè)錯(cuò)誤值如0xFFFF而不是死等。否則當(dāng)沒(méi)有回波時(shí)程序會(huì)卡死在這里。6.3 顯示刷新與系統(tǒng)響應(yīng)優(yōu)化在集成測(cè)試時(shí)你可能會(huì)發(fā)現(xiàn)按下按鍵后LCD顯示更新有遲滯或者蜂鳴器響的時(shí)候LED控制不靈。顯示遲滯檢查GetDistance()函數(shù)中的濾波部分。連續(xù)測(cè)5次每次間隔60ms這就意味著一次測(cè)量要花費(fèi)至少300ms。這是為了精度必要的犧牲。如果覺(jué)得太慢可以改為測(cè)3次或者減少單次測(cè)量間隔但不要低于40ms。另一種思路是將測(cè)量和顯示異步按下按鍵后立即在LCD上顯示“Measuring...”然后啟動(dòng)測(cè)量測(cè)量完成后在中斷或主循環(huán)中更新結(jié)果。這樣用戶(hù)體驗(yàn)更好。外設(shè)控制沖突回顧前面硬件連接提到的鎖存器問(wèn)題。如果你在控制LED后沒(méi)有正確關(guān)閉或切換鎖存器緊接著去操作數(shù)碼管就會(huì)導(dǎo)致數(shù)碼管顯示異?;蛘週ED亂亮。確保每個(gè)外設(shè)操作函數(shù)LED_Control(),Seg_Display()在操作前后都嚴(yán)格遵循“打開(kāi)對(duì)應(yīng)鎖存器 - 輸出數(shù)據(jù) - 關(guān)閉/切換鎖存器”的步驟。將這些步驟封裝成函數(shù)是避免錯(cuò)誤的好方法。6.4 增加魯棒性與功能擴(kuò)展基礎(chǔ)功能穩(wěn)定后可以考慮增加一些提升體驗(yàn)和魯棒性的功能上電自檢程序開(kāi)始時(shí)讓蜂鳴器響一聲所有LED流水燈一次LCD顯示版本號(hào)給用戶(hù)一個(gè)明確的“系統(tǒng)就緒”信號(hào)。測(cè)量超時(shí)處理如前所述在等待Echo上升沿和下降沿時(shí)加入超時(shí)判斷防止程序因無(wú)回波而卡死。報(bào)警閾值設(shè)置與存儲(chǔ)增加兩個(gè)按鍵加/減允許用戶(hù)設(shè)置報(bào)警距離閾值并使用單片機(jī)的EEPROM或外置24C02保存設(shè)置掉電不丟失。串口調(diào)試與數(shù)據(jù)輸出利用單片機(jī)的串口將實(shí)時(shí)距離數(shù)據(jù)發(fā)送到電腦串口助手便于在電腦上繪制距離-時(shí)間曲線進(jìn)行更深入的分析和調(diào)試。