STM32紅外NEC協(xié)議解碼實(shí)戰(zhàn):從原理到穩(wěn)定實(shí)現(xiàn)的避坑指南
1. 項(xiàng)目緣起從一次“失控”的空調(diào)說起去年夏天我手頭一個(gè)基于STM32的智能家居中控項(xiàng)目遇到了一個(gè)不大不小的麻煩。項(xiàng)目需要集成紅外遙控學(xué)習(xí)功能用來控制客廳里的一臺(tái)老式美的空調(diào)。我信心滿滿地接好了紅外接收頭用邏輯分析儀抓取了原裝遙控器的波形然后開始對(duì)著NEC協(xié)議的數(shù)據(jù)手冊(cè)寫解碼程序。本以為是個(gè)標(biāo)準(zhǔn)操作結(jié)果卻讓人哭笑不得中控發(fā)出的指令十次里有八次空調(diào)沒反應(yīng)剩下兩次要么是開了制冷卻調(diào)到30度要么是打開了掃風(fēng)模式。項(xiàng)目眼看要延期我開始從頭排查這才發(fā)現(xiàn)紅外NEC協(xié)議解碼這個(gè)看似簡(jiǎn)單的任務(wù)里面藏著不少?gòu)臄?shù)據(jù)手冊(cè)上看不到的“坑”。紅外遙控幾乎是每個(gè)嵌入式開發(fā)者都會(huì)接觸到的技術(shù)。它成本低廉、技術(shù)成熟廣泛應(yīng)用于家電、玩具等領(lǐng)域。而NEC協(xié)議則是紅外遙控領(lǐng)域事實(shí)上的“普通話”絕大多數(shù)消費(fèi)電子產(chǎn)品的紅外遙控都兼容或基于此協(xié)議。對(duì)于STM32這類單片機(jī)來說實(shí)現(xiàn)NEC協(xié)議解碼是檢驗(yàn)其定時(shí)器、外部中斷和GPIO應(yīng)用能力的經(jīng)典課題。但很多人包括當(dāng)時(shí)的我容易把它想得太簡(jiǎn)單以為就是按照協(xié)議規(guī)定的時(shí)序去判斷0和1結(jié)果在實(shí)際環(huán)境中卻要面對(duì)信號(hào)畸變、環(huán)境光干擾、不同廠商的協(xié)議變種等一系列問題。今天我就結(jié)合那次踩坑和后續(xù)多個(gè)項(xiàng)目的實(shí)戰(zhàn)經(jīng)驗(yàn)為你徹底拆解如何在STM32上穩(wěn)定、可靠地實(shí)現(xiàn)紅外NEC協(xié)議解碼。我們不止于讀懂協(xié)議更要搞定從硬件連接到軟件濾波從基礎(chǔ)解碼到處理“非標(biāo)”信號(hào)的完整方案。無論你是正在做課程設(shè)計(jì)的學(xué)生還是需要為產(chǎn)品添加紅外控制功能的工程師這篇內(nèi)容都能讓你避開我走過的彎路。2. NEC協(xié)議核心不止于0和1的時(shí)序邏輯在動(dòng)手寫代碼之前我們必須吃透NEC協(xié)議的本質(zhì)。很多教程只告訴你“引導(dǎo)碼是9ms低電平4.5ms高電平”但這遠(yuǎn)遠(yuǎn)不夠。理解其設(shè)計(jì)哲學(xué)才能寫出健壯的代碼。2.1 協(xié)議幀結(jié)構(gòu)為何如此設(shè)計(jì)一幀完整的NEC協(xié)議數(shù)據(jù)通常由以下幾部分組成引導(dǎo)碼Start Code一個(gè)9ms的載波脈沖低電平緊接著一個(gè)4.5ms的空閑高電平。這個(gè)超長(zhǎng)的、獨(dú)特的信號(hào)就像廣播里的報(bào)時(shí)音用于喚醒接收端并告訴它“注意下面要開始傳數(shù)據(jù)了” 它的長(zhǎng)度遠(yuǎn)大于數(shù)據(jù)位這為接收端的自動(dòng)增益控制和噪聲過濾提供了時(shí)間窗口。用戶碼Customer Code8位地址碼用于區(qū)分不同廠家的設(shè)備。例如索尼的電視和松下的空調(diào)就有不同的用戶碼防止互相干擾。通常還會(huì)發(fā)送這8位的反碼邏輯取反作為校驗(yàn)所以實(shí)際傳輸16位。接收端會(huì)同時(shí)檢查原碼和反碼是否匹配這是第一道簡(jiǎn)單的容錯(cuò)機(jī)制。數(shù)據(jù)碼Data Code8位命令碼即具體的按鍵指令如“音量加”、“開機(jī)”。同樣其后也跟隨8位命令反碼。結(jié)束位Stop Bit一個(gè)560μs的脈沖后跟隨一段空閑。有時(shí)在連按按鍵時(shí)它會(huì)被簡(jiǎn)化為一個(gè)單獨(dú)的560μs脈沖后面直接跟下一幀的引導(dǎo)碼稱為“重復(fù)碼”。這個(gè)“原碼反碼”的雙重傳輸機(jī)制是NEC協(xié)議在無線環(huán)境下的一個(gè)巧妙設(shè)計(jì)。它用極小的開銷多傳8位實(shí)現(xiàn)了單比特錯(cuò)誤的檢測(cè)在早期單片機(jī)處理能力有限、無線環(huán)境干擾大的背景下大大提升了可靠性。2.2 數(shù)據(jù)位的編碼脈寬調(diào)制的奧秘NEC協(xié)議采用脈沖位置調(diào)制PPM的一種變體具體來說是脈沖寬度編碼。邏輯‘0’由一個(gè)560μs的載波脈沖低電平和560μs的空閑高電平組成總周期為1.125ms。邏輯‘1’由一個(gè)560μs的載波脈沖低電平和1.69ms的空閑高電平組成總周期為2.25ms。這里有一個(gè)至關(guān)重要的細(xì)節(jié)無論是‘0’還是‘1’其起始部分都是一個(gè)560μs的脈沖。這個(gè)脈沖是載波信號(hào)通常為38kHz調(diào)制產(chǎn)生的。區(qū)別僅在于脈沖之后的高電平持續(xù)時(shí)間不同。這意味著接收端硬件一體化紅外接收頭在收到信號(hào)時(shí)會(huì)先解調(diào)掉38kHz的載波輸出一個(gè)反向的電平信號(hào)。我們單片機(jī)檢測(cè)的是這個(gè)解調(diào)后的波形。所以我們?cè)谑静ㄆ骰蜻壿嫹治鰞x上看到的“低電平”實(shí)際上對(duì)應(yīng)著紅外發(fā)射管正在發(fā)射光脈沖。理解這一點(diǎn)就能明白為什么我們的解碼程序核心是測(cè)量?jī)蓚€(gè)下降沿之間的時(shí)間間隔。因?yàn)槊總€(gè)數(shù)據(jù)位都以一個(gè)下降沿脈沖開始為起點(diǎn)我們測(cè)量從這個(gè)下降到下一個(gè)下降沿的時(shí)間如果接近1.125ms則是‘0’如果接近2.25ms則是‘1’。2.3 示波器下的真實(shí)世界協(xié)議變種與噪聲如果你用示波器去實(shí)測(cè)一個(gè)美的空調(diào)遙控器可能會(huì)發(fā)現(xiàn)它的引導(dǎo)碼不是嚴(yán)格的9ms4.5ms可能是8.8ms4.4ms。數(shù)據(jù)位的脈寬也可能有微小的偏差。這就是“協(xié)議變種”。NEC協(xié)議是一個(gè)事實(shí)標(biāo)準(zhǔn)不同廠商在具體參數(shù)上會(huì)有細(xì)微調(diào)整但只要編碼規(guī)則一致通常都能兼容。更麻煩的是環(huán)境噪聲。日光燈、白熾燈、甚至陽光中都含有紅外成分會(huì)被接收頭拾取產(chǎn)生隨機(jī)的低電平毛刺。這些毛刺如果被誤判為數(shù)據(jù)位的起始下降沿就會(huì)導(dǎo)致解碼完全錯(cuò)誤。這就是我項(xiàng)目初期失敗的主要原因——沒有做有效的軟件濾波。3. 硬件連接與信號(hào)調(diào)理給STM32一雙“好耳朵”穩(wěn)定的解碼始于干凈的信號(hào)。紅外接收頭如VS1838B、HS0038的選擇和電路設(shè)計(jì)是第一步。3.1 一體化紅外接收頭不只是接三根線常用的一體化接收頭有三個(gè)引腳VCC3.3V/5V、GND、OUT信號(hào)輸出。它內(nèi)部已經(jīng)集成了紅外接收管、前置放大器、帶通濾波器中心頻率38kHz和解調(diào)電路。你只需要給它供電它就能輸出解調(diào)后的數(shù)字信號(hào)。注意務(wù)必在VCC和GND之間就近放置一個(gè)10uF~100uF的電解電容和一個(gè)0.1uF的瓷片電容用于電源去耦。紅外接收頭在工作時(shí)電流會(huì)有瞬間變化不穩(wěn)定的電源會(huì)導(dǎo)致輸出信號(hào)抖動(dòng)產(chǎn)生誤觸發(fā)。這是我早期用面包板調(diào)試時(shí)踩過的坑加上電容后解碼穩(wěn)定性立竿見影。接收頭的OUT引腳需要連接到STM32的GPIO。這里有一個(gè)關(guān)鍵決策點(diǎn)使用外部中斷模式還是定時(shí)器輸入捕獲模式外部中斷模式將GPIO配置為下降沿觸發(fā)的外部中斷。每個(gè)下降沿脈沖開始進(jìn)入中斷在中斷服務(wù)函數(shù)中記錄時(shí)間戳通過SysTick或通用定時(shí)器并計(jì)算時(shí)間間隔來判斷是引導(dǎo)碼、數(shù)據(jù)‘0’還是數(shù)據(jù)‘1’。這種方法直觀對(duì)初學(xué)者友好但中斷頻繁一幀數(shù)據(jù)多達(dá)68個(gè)邊沿在系統(tǒng)繁忙時(shí)可能丟失中斷。定時(shí)器輸入捕獲模式將一個(gè)定時(shí)器的輸入捕獲通道配置為捕獲該GPIO的下降沿。硬件會(huì)自動(dòng)在邊沿發(fā)生時(shí)記錄定時(shí)器計(jì)數(shù)器的值并產(chǎn)生中斷。你只需要在中斷中讀取兩次捕獲值的差值即可得到高電平或低電平的持續(xù)時(shí)間。這種方法更精確對(duì)CPU占用率更低是更專業(yè)的選擇。對(duì)于追求穩(wěn)定性和低功耗的產(chǎn)品我強(qiáng)烈推薦使用定時(shí)器輸入捕獲模式。下面我們以STM32F103C8T6的TIM2_CH1PA0引腳為例進(jìn)行配置。3.2 定時(shí)器輸入捕獲配置詳解我們目標(biāo)是測(cè)量高電平的持續(xù)時(shí)間。NEC協(xié)議中無論是引導(dǎo)碼還是數(shù)據(jù)位有用的信息都編碼在高電平的寬度里。GPIO初始化將PA0配置為浮空輸入或上拉輸入因?yàn)榻邮疹^輸出默認(rèn)高電平。定時(shí)器初始化以TIM2為例。時(shí)鐘源內(nèi)部時(shí)鐘APB1總線通常72MHz。預(yù)分頻器PSC設(shè)置為71。這樣定時(shí)器時(shí)鐘 72MHz / (711) 1MHz即計(jì)數(shù)器每1微秒計(jì)數(shù)一次。這個(gè)精度足夠測(cè)量毫秒和微秒級(jí)的紅外信號(hào)。自動(dòng)重裝載值A(chǔ)RR設(shè)置為最大值0xFFFF65535。因?yàn)槲覀冎魂P(guān)心兩次捕獲之間的差值A(chǔ)RR設(shè)大一些避免溢出65.535ms內(nèi)必須處理完一次捕獲對(duì)NEC協(xié)議綽綽有余。捕獲/比較通道1配置為輸入捕獲模式捕獲下降沿。開啟捕獲中斷。中斷服務(wù)函數(shù)邏輯這是解碼的核心。第一次下降沿引導(dǎo)碼開始記錄捕獲值IC1Value1然后將捕獲邊沿改為上升沿。第一次上升沿引導(dǎo)碼低電平結(jié)束記錄捕獲值IC1Value2。計(jì)算差值IC1Value2 - IC1Value1這個(gè)值應(yīng)該在9000左右對(duì)應(yīng)9ms允許一定誤差如±500。如果符合說明檢測(cè)到引導(dǎo)碼準(zhǔn)備接收數(shù)據(jù)。然后將捕獲邊沿改回下降沿并清空數(shù)據(jù)緩沖區(qū)。后續(xù)的下降沿?cái)?shù)據(jù)位開始對(duì)于數(shù)據(jù)位我們關(guān)心的是前一個(gè)上升沿到當(dāng)前下降沿之間的時(shí)間即高電平持續(xù)時(shí)間。所以需要在每次上升沿時(shí)記錄時(shí)間戳LastRiseTime。在下降沿中斷中用當(dāng)前捕獲值減去LastRiseTime得到高電平持續(xù)時(shí)間HighLevelTime。如果HighLevelTime在1000~1350微秒之間理論1125μs則判定為邏輯‘0’。如果HighLevelTime在1600~2000微秒之間理論1690μs則判定為邏輯‘1’。將判斷出的位存入緩沖區(qū)。重復(fù)上述過程直到收齊32位數(shù)據(jù)用戶碼16位數(shù)據(jù)碼16位或超時(shí)。這種利用輸入捕獲自動(dòng)測(cè)量脈寬的方式比在外部中斷里手動(dòng)開定時(shí)器要精準(zhǔn)和可靠得多。4. 軟件解碼實(shí)戰(zhàn)狀態(tài)機(jī)與魯棒性設(shè)計(jì)直接寫一堆if-else來判斷各種狀態(tài)會(huì)讓代碼難以維護(hù)且容易出錯(cuò)。更好的方法是使用有限狀態(tài)機(jī)FSM。對(duì)于NEC解碼我們可以定義以下幾個(gè)狀態(tài)typedef enum { IR_IDLE, // 空閑狀態(tài)等待引導(dǎo)碼 IR_LEADER_CODE, // 已收到引導(dǎo)碼等待用戶碼/數(shù)據(jù)碼 IR_REPEAT_CODE, // 處理重復(fù)碼連按 IR_ERROR // 錯(cuò)誤狀態(tài) } IR_DecodeState_t;在定時(shí)器輸入捕獲的中斷服務(wù)函數(shù)或由它觸發(fā)的回調(diào)函數(shù)中我們根據(jù)當(dāng)前狀態(tài)和測(cè)量到的時(shí)間值進(jìn)行狀態(tài)轉(zhuǎn)移和數(shù)據(jù)收集。4.1 解碼狀態(tài)機(jī)流程IR_IDLE狀態(tài)當(dāng)捕獲到下降沿并測(cè)得低電平持續(xù)時(shí)間在8ms~10ms范圍內(nèi)且緊隨其后的高電平持續(xù)時(shí)間在4ms~5ms范圍內(nèi)則判定為有效的引導(dǎo)碼。狀態(tài)轉(zhuǎn)移到IR_LEADER_CODE復(fù)位位計(jì)數(shù)器bit_cnt 0清空數(shù)據(jù)緩沖區(qū)ir_data 0。IR_LEADER_CODE狀態(tài)在此狀態(tài)下我們開始按位接收數(shù)據(jù)。每次進(jìn)入下降沿中斷就根據(jù)前一個(gè)高電平的持續(xù)時(shí)間判斷位值。將判斷出的位值0或1移位存入ir_data。例如ir_data (ir_data 1) | bit_value。位計(jì)數(shù)器bit_cnt加1。當(dāng)bit_cnt 32時(shí)表示一幀數(shù)據(jù)接收完成。接下來進(jìn)行數(shù)據(jù)校驗(yàn)將收到的32位數(shù)據(jù)拆分為address高8位、~address次8位、command次次8位、~command低8位。檢查address與~address是否互為反碼command與~command是否互為反碼。如果兩者都通過則認(rèn)為解碼成功將address和command存入結(jié)果變量并設(shè)置一個(gè)標(biāo)志位如ir_ok 1通知主循環(huán)。如果校驗(yàn)失敗則轉(zhuǎn)入IR_ERROR狀態(tài)。無論成功與否解碼完成后狀態(tài)都回到IR_IDLE等待下一幀。重復(fù)碼的處理當(dāng)按鍵被長(zhǎng)時(shí)間按住時(shí)遙控器不會(huì)發(fā)送完整幀而是先發(fā)一幀完整數(shù)據(jù)之后每隔約110ms發(fā)送一個(gè)特殊的“重復(fù)碼”。重復(fù)碼由9ms低電平和2.25ms高電平再加一個(gè)560μs的脈沖組成。在IR_IDLE狀態(tài)如果捕獲到一個(gè)下降沿且測(cè)得的前一個(gè)高電平持續(xù)時(shí)間在2.0ms~2.5ms之間對(duì)應(yīng)重復(fù)碼的2.25ms高電平則可以判定為重復(fù)碼。此時(shí)狀態(tài)轉(zhuǎn)移到IR_REPEAT_CODE我們可以直接復(fù)用上一次成功解碼的command并設(shè)置ir_repeat 1標(biāo)志通知主循環(huán)“同一個(gè)鍵被持續(xù)按下”。處理完后狀態(tài)回到IR_IDLE。IR_ERROR狀態(tài)發(fā)生任何不符合預(yù)期的時(shí)序如位間隔超時(shí)、校驗(yàn)失敗都進(jìn)入此狀態(tài)。在此狀態(tài)可以記錄錯(cuò)誤類型或簡(jiǎn)單地復(fù)位所有變量然后無條件跳轉(zhuǎn)回IR_IDLE狀態(tài)。使用狀態(tài)機(jī)后代碼邏輯清晰易于調(diào)試和擴(kuò)展。主循環(huán)只需要輪詢ir_ok和ir_repeat標(biāo)志即可。4.2 超時(shí)處理與軟件濾波對(duì)抗干擾的盾牌這是保證解碼魯棒性的關(guān)鍵也是很多簡(jiǎn)單示例代碼缺失的部分。位超時(shí)Bit Timeout在IR_LEADER_CODE狀態(tài)每收到一個(gè)位都應(yīng)該啟動(dòng)一個(gè)超時(shí)計(jì)時(shí)器可以用SysTick或另一個(gè)定時(shí)器。超時(shí)時(shí)間應(yīng)略大于一個(gè)邏輯‘1’的周期2.5ms比較安全。如果在超時(shí)時(shí)間內(nèi)沒有收到下一個(gè)下降沿則認(rèn)為本幀數(shù)據(jù)傳輸出錯(cuò)可能被噪聲打斷應(yīng)強(qiáng)制跳轉(zhuǎn)到IR_ERROR狀態(tài)。這能有效防止因丟失一個(gè)邊沿而導(dǎo)致程序永遠(yuǎn)卡在等待狀態(tài)。幀間靜默Inter-frame Gap在成功解碼一幀或處理完重復(fù)碼后可以故意讓解碼器進(jìn)入一個(gè)短暫的“沉默期”例如10-20ms在此期間忽略所有外部中斷或捕獲事件。因?yàn)榧t外接收頭在信號(hào)結(jié)束后可能還會(huì)輸出一些雜波這個(gè)沉默期可以過濾掉它們防止誤觸發(fā)。數(shù)字濾波Digital Filtering對(duì)于GPIO輸入STM32的硬件有可配置的消抖濾波功能但對(duì)于高速的紅外信號(hào)微秒級(jí)通常不適用。更有效的軟件濾波是“多次采樣判決”。例如在判斷下降沿時(shí)可以在中斷中連續(xù)快速讀取幾次GPIO電平如果都是低電平才認(rèn)為是真正的下降沿。這可以濾除極窄的噪聲毛刺。但要注意這會(huì)增加中斷處理時(shí)間需要權(quán)衡。動(dòng)態(tài)閾值調(diào)整不要使用絕對(duì)固定的時(shí)間閾值如1125μs來判斷‘0’和‘1’??梢栽谝粠瑪?shù)據(jù)開始時(shí)用測(cè)量到的引導(dǎo)碼高低電平時(shí)間作為基準(zhǔn)進(jìn)行比例計(jì)算。例如測(cè)得引導(dǎo)碼高電平為T_leader_high那么數(shù)據(jù)位高電平的判斷閾值可以設(shè)為(T_leader_high / 4.5) * 1.125和(T_leader_high / 4.5) * 1.69附近的一個(gè)范圍。這樣能更好地適應(yīng)不同遙控器的微小差異。5. 調(diào)試與驗(yàn)證讓問題無處遁形寫好了代碼怎么知道它能不能用除了直接對(duì)著設(shè)備測(cè)試我們還需要更科學(xué)的調(diào)試手段。5.1 邏輯分析儀解碼過程的“X光機(jī)”邏輯分析儀是調(diào)試數(shù)字通信協(xié)議的利器。將探頭連接到紅外接收頭的OUT引腳和STM32的某個(gè)調(diào)試GPIO用于在代碼中打點(diǎn)。抓取原始波形按下遙控器抓取完整的波形。驗(yàn)證引導(dǎo)碼、數(shù)據(jù)位的波形是否符合預(yù)期。測(cè)量具體的時(shí)間參數(shù)用于校準(zhǔn)你代碼中的判斷閾值。驗(yàn)證解碼邏輯在STM32代碼中每當(dāng)成功解碼一幀就讓一個(gè)調(diào)試GPIO引腳翻轉(zhuǎn)一次。在邏輯分析儀上同時(shí)觀察這個(gè)引腳和紅外信號(hào)。你可以清晰地看到每次紅外信號(hào)結(jié)束后是否立即有一次翻轉(zhuǎn)從而確認(rèn)解碼是否成功觸發(fā)。你甚至可以把這個(gè)調(diào)試引腳當(dāng)成一個(gè)簡(jiǎn)單的“解碼成功”指示燈。5.2 串口打印內(nèi)部狀態(tài)的“監(jiān)視器”通過串口將解碼過程中的關(guān)鍵信息打印出來是最直接的調(diào)試方法。在收到引導(dǎo)碼時(shí)打印“Leader Code Detected”。每收到一個(gè)位打印其值0/1和測(cè)量到的高電平時(shí)間。在完成一幀接收時(shí)打印出原始的32位數(shù)據(jù)以及解析出的地址碼和命令碼。在遇到錯(cuò)誤時(shí)打印錯(cuò)誤類型如“Timeout Error”, “Check Sum Error”。這樣當(dāng)解碼失敗時(shí)你可以通過串口日志一步步回溯看是在哪個(gè)環(huán)節(jié)出了錯(cuò)是時(shí)間測(cè)量不準(zhǔn)還是狀態(tài)機(jī)邏輯有漏洞。5.3 示波器實(shí)測(cè)深入信號(hào)的微觀世界當(dāng)遇到特別棘手的干擾問題時(shí)示波器比邏輯分析儀更能看清信號(hào)的細(xì)節(jié)。你可以觀察到接收頭輸出的信號(hào)基線是否平穩(wěn)有沒有上下漂移低電平的底部有沒有毛刺或振鈴環(huán)境光干擾如快速開關(guān)日光燈在信號(hào)線上產(chǎn)生了什么樣的噪聲根據(jù)觀察到的現(xiàn)象回頭調(diào)整你的硬件如加強(qiáng)電源濾波、在接收頭OUT引腳對(duì)地加一個(gè)小電容吸收尖峰或軟件如調(diào)整濾波算法、超時(shí)時(shí)間。6. 進(jìn)階與擴(kuò)展從解碼到應(yīng)用當(dāng)你能夠穩(wěn)定解碼NEC信號(hào)后就可以在此基礎(chǔ)上構(gòu)建更復(fù)雜的功能。6.1 構(gòu)建紅外信號(hào)數(shù)據(jù)庫(kù)碼庫(kù)一個(gè)實(shí)用的紅外學(xué)習(xí)型遙控器需要存儲(chǔ)不同設(shè)備的編碼。你可以設(shè)計(jì)一個(gè)簡(jiǎn)單的數(shù)據(jù)結(jié)構(gòu)來管理typedef struct { uint16_t vendor_id; // 廠商ID用戶碼 uint8_t func_code; // 功能碼命令碼 char func_name[20]; // 功能描述如“Power”, “Vol” // 如果需要學(xué)習(xí)重復(fù)碼間隔也可以存儲(chǔ) } IR_Command_t;通過“學(xué)習(xí)模式”將遙控器對(duì)準(zhǔn)你的設(shè)備按鍵程序解碼后把a(bǔ)ddress和command存入Flash或EEPROM。在“發(fā)射模式”下根據(jù)存儲(chǔ)的碼值控制一個(gè)紅外發(fā)射管需連接三極管驅(qū)動(dòng)按照NEC協(xié)議格式發(fā)送出去。注意發(fā)射時(shí)需要用一個(gè)定時(shí)器如PWM模式產(chǎn)生38kHz的載波來調(diào)制信號(hào)。6.2 處理非標(biāo)準(zhǔn)NEC協(xié)議正如前文所述很多設(shè)備如我遇到的那臺(tái)美的空調(diào)使用的是NEC協(xié)議的變種。它們的差異可能在于引導(dǎo)碼長(zhǎng)度不同。邏輯‘0’和‘1’的脈寬比例不同但‘1’總是‘0’的兩倍左右。數(shù)據(jù)格式不同可能只有16位8位地址8位命令沒有反碼或者地址碼是16位。應(yīng)對(duì)策略就是讓你的解碼程序可配置化。不要將時(shí)間閾值寫成死代碼而是定義成變量typedef struct { uint16_t leader_low_min; uint16_t leader_low_max; uint16_t leader_high_min; uint16_t leader_high_max; uint16_t bit0_high_min; uint16_t bit0_high_max; uint16_t bit1_high_min; uint16_t bit1_high_max; uint8_t data_bits; // 總位數(shù)32或16 uint8_t with_inverse; // 是否包含反碼 } IR_ProtocolConfig_t;為不同的設(shè)備預(yù)定義不同的配置結(jié)構(gòu)體。在解碼前先嘗試用幾種常見的配置去匹配引導(dǎo)碼匹配成功后再用該配置進(jìn)行后續(xù)數(shù)據(jù)位的解碼。這就實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的“自動(dòng)協(xié)議識(shí)別”功能。6.3 低功耗設(shè)計(jì)考量如果設(shè)備是電池供電需要時(shí)刻監(jiān)聽紅外信號(hào)那么功耗就很重要。一體化接收頭本身在工作時(shí)就有一定電流約0.5-1mA。一種常見的優(yōu)化是周期性喚醒讓STM32和接收頭大部分時(shí)間處于睡眠模式每隔幾十毫秒喚醒一次快速檢查一下是否有紅外信號(hào)可以通過檢查GPIO電平簡(jiǎn)單判斷如果沒有立即再次休眠。雖然可能丟失信號(hào)頭部的幾個(gè)毫秒但NEC協(xié)議的引導(dǎo)碼很長(zhǎng)有很大概率能捕捉到。這需要結(jié)合STM32的低功耗模式Stop模式來設(shè)計(jì)。從一次失敗的空調(diào)控制開始到最終實(shí)現(xiàn)一個(gè)穩(wěn)定可靠、能適應(yīng)多種設(shè)備的紅外解碼模塊這個(gè)過程讓我對(duì)嵌入式開發(fā)中的“細(xì)節(jié)魔鬼”有了更深的認(rèn)識(shí)。紅外NEC解碼就像一門基礎(chǔ)內(nèi)功它考驗(yàn)的是你對(duì)硬件定時(shí)器的掌握、對(duì)中斷服務(wù)的理解、對(duì)狀態(tài)機(jī)編程的熟練度以及最重要的——在充滿噪聲的真實(shí)世界中設(shè)計(jì)魯棒性系統(tǒng)的能力。代碼不僅僅要在實(shí)驗(yàn)室里跑通更要在客廳的日光燈下、在午后的陽光下穩(wěn)定工作。當(dāng)你按下遙控器設(shè)備應(yīng)聲而動(dòng)的那一刻你會(huì)覺得所有這些關(guān)于時(shí)序、濾波、狀態(tài)轉(zhuǎn)移的思考都是值得的。

相關(guān)新聞

Vuforia AR開發(fā)實(shí)戰(zhàn):從圖像識(shí)別到空間錨定,打造企業(yè)級(jí)增強(qiáng)現(xiàn)實(shí)應(yīng)用

Vuforia AR開發(fā)實(shí)戰(zhàn):從圖像識(shí)別到空間錨定,打造企業(yè)級(jí)增強(qiáng)現(xiàn)實(shí)應(yīng)用

1. 從零認(rèn)識(shí)Vuforia:它到底是什么,又能做什么?如果你對(duì)AR(增強(qiáng)現(xiàn)實(shí))開發(fā)感興趣,或者你的項(xiàng)目需要將虛擬內(nèi)容“釘”在現(xiàn)實(shí)世界里,那么“Vuforia”這個(gè)名字你肯定繞不過去。它不是什么新潮的玩具&…

2026/7/29 7:46:08 閱讀更多
嵌入式Linux網(wǎng)關(guān)實(shí)戰(zhàn):EC20 SGMII網(wǎng)口與FC20 Wi-Fi 6 AP配置全解析

嵌入式Linux網(wǎng)關(guān)實(shí)戰(zhàn):EC20 SGMII網(wǎng)口與FC20 Wi-Fi 6 AP配置全解析

1. 項(xiàng)目概述:當(dāng)4G模組遇上高速網(wǎng)口與Wi-Fi最近在搞一個(gè)工業(yè)網(wǎng)關(guān)項(xiàng)目,核心需求是把現(xiàn)場(chǎng)的各種傳感器數(shù)據(jù)通過4G網(wǎng)絡(luò)穩(wěn)定地傳到云端,同時(shí)設(shè)備本地還得有個(gè)Wi-Fi熱點(diǎn),方便現(xiàn)場(chǎng)工程師用筆記本或手機(jī)快速連接進(jìn)去做配置和調(diào)試。這個(gè)需求…

2026/7/29 7:46:08 閱讀更多
STM32 CAN總線通信從原理到實(shí)踐:核心協(xié)議、驅(qū)動(dòng)實(shí)現(xiàn)與調(diào)試指南

STM32 CAN總線通信從原理到實(shí)踐:核心協(xié)議、驅(qū)動(dòng)實(shí)現(xiàn)與調(diào)試指南

1. 項(xiàng)目概述:從零開始理解CAN通信最近在做一個(gè)車載設(shè)備相關(guān)的項(xiàng)目,不可避免地要和CAN總線打交道。說實(shí)話,第一次接觸CAN(Controller Area Network,控制器局域網(wǎng))時(shí),看著那一堆縮寫和協(xié)議幀格式&…

2026/7/29 7:46:08 閱讀更多
HarmonyOS應(yīng)用開發(fā)實(shí)戰(zhàn):貓貓大作戰(zhàn)-FormExtensionAbility 的實(shí)現(xiàn)

HarmonyOS應(yīng)用開發(fā)實(shí)戰(zhàn):貓貓大作戰(zhàn)-FormExtensionAbility 的實(shí)現(xiàn)

前言 FormExtensionAbility 是服務(wù)卡片的生命周期管理器,負(fù)責(zé)卡片的創(chuàng)建、更新、刪除等操作。每個(gè)卡片類型都需要一個(gè)對(duì)應(yīng)的 FormExtensionAbility。 本文以「貓貓大作戰(zhàn)」的戰(zhàn)績(jī)卡片管理為錨點(diǎn),講解 FormExtensionAbility 的實(shí)現(xiàn)。 提示:本…

2026/7/29 13:46:45 閱讀更多
TI TLV8544評(píng)估板:超低功耗PIR運(yùn)動(dòng)傳感器AFE設(shè)計(jì)全解析

TI TLV8544評(píng)估板:超低功耗PIR運(yùn)動(dòng)傳感器AFE設(shè)計(jì)全解析

1. 項(xiàng)目概述與核心價(jià)值如果你正在設(shè)計(jì)一個(gè)需要電池供電、且能持續(xù)工作數(shù)年的無線運(yùn)動(dòng)傳感器,那么功耗和信號(hào)調(diào)理精度就是你繞不開的兩座大山。傳統(tǒng)的方案往往需要在多級(jí)放大、濾波和比較器之間做取舍,不僅電路復(fù)雜,靜態(tài)電流也容易失控。德州儀…

2026/7/29 13:46:45 閱讀更多
深入解析 MySQL InnoDB 存儲(chǔ)引擎:架構(gòu)、事務(wù)與并發(fā)控制

深入解析 MySQL InnoDB 存儲(chǔ)引擎:架構(gòu)、事務(wù)與并發(fā)控制

目錄 一、InnoDB引擎-邏輯存儲(chǔ)結(jié)構(gòu)二、InnoDB引擎-架構(gòu) 1. 內(nèi)存結(jié)構(gòu)2. 磁盤結(jié)構(gòu)3. 后臺(tái)線程 三、InnoDB引擎-事務(wù)原理 1. redo log2. undo log 四、InnoDB引擎-MVCC(多版本并發(fā)控制) 1. 基本概念2. MVCC_隱藏字段3. MVCC_undo log4. MVCC_readview提取規(guī)…

2026/7/29 13:46:45 閱讀更多
力扣22-括號(hào)生成

力扣22-括號(hào)生成

22. 括號(hào)生成 - 力扣(LeetCode) 數(shù)字 n 代表生成括號(hào)的對(duì)數(shù),請(qǐng)你設(shè)計(jì)一個(gè)函數(shù),用于能夠生成所有可能的并且 有效的 括號(hào)組合。 示例 1: 輸入:n 3 輸出:["((()))","(()())&qu…

2026/7/29 13:46:45 閱讀更多
數(shù)據(jù)資產(chǎn)盤點(diǎn):用資源血緣讓BI從‘黑盒‘變成‘透明工廠‘

數(shù)據(jù)資產(chǎn)盤點(diǎn):用資源血緣讓BI從‘黑盒‘變成‘透明工廠‘

導(dǎo)語 在與客戶交流BI選型時(shí),常常被問到的一個(gè)高頻問題不再是"圖表好不好看"“性能夠不夠快”,而是——“這個(gè)平臺(tái)能不能讓我說清楚,每一個(gè)指標(biāo)是怎么來的、動(dòng)一下會(huì)影響誰?” 這個(gè)問題的出現(xiàn),標(biāo)志著企業(yè)選型…

2026/7/29 13:46:45 閱讀更多
沒API的老系統(tǒng)數(shù)據(jù)怎么取——異構(gòu)對(duì)接的數(shù)據(jù)庫(kù)只讀路線

沒API的老系統(tǒng)數(shù)據(jù)怎么取——異構(gòu)對(duì)接的數(shù)據(jù)庫(kù)只讀路線

# 沒API的老系統(tǒng)數(shù)據(jù)怎么取——異構(gòu)對(duì)接的數(shù)據(jù)庫(kù)只讀路線## 引言企業(yè)做數(shù)據(jù)集成,碰到的第一個(gè)攔路虎往往不是技術(shù)多復(fù)雜,而是手里壓根沒有像樣的接口。一套ERP是十幾年前上的,原廠早就停維,接口文檔跟著離職的開發(fā)一起沒了&#x…

2026/7/29 13:36:44 閱讀更多
面試官大笑:“一個(gè)任務(wù)拆給 5 個(gè) Subagent 并行跑,不比 1 個(gè)快 5 倍?“我搖頭:“快不了,還可能更慢“

面試官大笑:“一個(gè)任務(wù)拆給 5 個(gè) Subagent 并行跑,不比 1 個(gè)快 5 倍?“我搖頭:“快不了,還可能更慢“

前兩個(gè)月,我在重構(gòu) AlgoMooc 網(wǎng)站過程中,發(fā)現(xiàn)一個(gè)問題:在 Claude Code 里把一個(gè)任務(wù)拆給 5 個(gè) Subagent 并行跑,結(jié)果可能比 1 個(gè) agent 從頭干到尾還慢? 大多數(shù)人的第一反應(yīng)是反過來的:活是并行干的&#…

2026/7/29 0:15:24 閱讀更多
# 鴻蒙 HarmonyOS 應(yīng)用開發(fā)實(shí)戰(zhàn)(第25期)|骰子(Dice Roller)— Unicode 符號(hào)與動(dòng)畫渲染精講

# 鴻蒙 HarmonyOS 應(yīng)用開發(fā)實(shí)戰(zhàn)(第25期)|骰子(Dice Roller)— Unicode 符號(hào)與動(dòng)畫渲染精講

一、應(yīng)用概述 骰子(Dice Roller) 是一款經(jīng)典的休閑娛樂應(yīng)用,模擬了真實(shí)擲骰子的過程。應(yīng)用投擲兩個(gè)骰子(六面標(biāo)準(zhǔn)骰),使用 Unicode 骰面符號(hào)直觀展示每個(gè)骰子的點(diǎn)數(shù),并伴有快速滾動(dòng)的動(dòng)畫效果。…

2026/7/29 0:15:24 閱讀更多