總述
紅外遙控由發送和接收兩個組成部分。發送端采用單片機將待發送的二進制信號編碼調制為一系列的脈沖串信號,通過紅外發射管發射紅外信號。紅外接收完成對紅外信號的接收、放大、檢波、整形,並解調出遙控編碼脈沖。為了減少干擾,采用的是價格便宜性能可靠的一體化紅外接收頭(
HS0038,它接收紅外信號頻率為 38kHz,周期約 26μs,采用NEC紅外編碼) 接收紅外信號,它同時對信號進行放大、檢波、整形得到 TTL 電平的編碼信號,再送給單片機,經單片機解碼並執行去控制相關對象。如圖 1 所示:

紅外發射和接收組成電路

發射電路

接收電路
調制與發射
紅外遙控發射芯片采用PPM 編碼方式,當發射器按鍵按下后,將發射一組 110ms 的編碼脈沖。
遙控編碼脈沖由前導碼、16 位用戶碼(8 位用戶碼、8 位用戶碼的反碼)和 16 位操作碼(8 位操作碼、8 位操作碼的反碼)組成。
前導碼的作用:
前導碼是一個遙控碼的起始部分,由一個 9ms 的高電平 (起始碼) 和一個 4.5ms 的低電平 (結果碼) 組成。
用戶碼的作用:
16 位用戶碼(8 位用戶碼、8 位用戶碼的反碼),
通過對用戶碼的檢驗,每個遙控器只能控制一個設備動作,這樣可以有效地防止多個設備之間的干擾。編碼后面還要有編碼的反碼,用來檢驗編碼接收的正確性,防止誤操作,增強系統的可靠性。
0和1的表示:
0和1均以0.56ms的高電平開始(實際測量是500us的樣子),不同的是后面出現的低電平,
如果低電平是0.56ms(實際測量是500us的樣子),則表示0,如果低電平是1.68ms(0.56*3=1.68)則表示1。

二進制信號的調制由單片機來完成,它把編碼后的二進制信號調制成頻率為38kHz 的間斷脈沖串(周期約26us的脈沖),相當於用二進制信號的編碼乘以頻率為 38kHz 的脈沖信號得到的間斷脈沖串,即是調制后用於紅外發射二極管發送的信號,如圖 4 二進制碼的調制所示。


待發射的二進制編碼(注意是未調制的)
注意上面的一組二進制編碼並非完整的NEC編碼!完整的NEC協議編碼長度為110ms,即剩余的是低電平,大約40ms左右,怎么算的呢?9+4.5+16*2.24+16*1.12 = 67.26,110 -
67.26 = 42.74(有的是108 - 67.26 =
40.74
)。
如果我們一直按着鍵不放,會產生什么效果呢?如下圖:


上面這一些稱為重復碼,
以110ms為周期的重復碼,如下圖:

就是說,發了一次命令碼之后,不會再發送命令碼,而是每隔110ms時間,發送一段重復碼。
重復碼由9ms高電平和2.25ms的低電平以及560us的高電平組成。如下圖:

因為HS0038B接收頻率是38KHz,約26us,
記住這個不是高電平的時間長度,這個是一個脈沖的時間長度也就是一個周期,例如我們利用一個中斷產生38K脈沖,占空比是1/2,我們的中斷時間就要設置為 1/38000/2 S中斷一次,然后通過相隔一次中斷電平翻轉一次就形成了一個頻率為38K占空比1/2的脈沖。
所以在編程時,每兩次中斷的間隔時間為26/2us即13us。由上面可以知道,要發射9ms高電平+4.5ms低電平的前導碼,由於高電平的發射要產生的是38KHz的脈沖,所以在每次中斷中反轉輸出形成38KHz的脈沖,而低電平的發射只需要將引腳電平拉低即可,這樣接收端接收到38KHz的信號則可知接收到的是高電平,而沒有接收到38KHz則認為接收到的是低電平。
紅外接收頭只接受38K信號(誤差范圍內),我們把接收頭看出一個轉換器。遇到38K就輸出低電平,沒有遇到38K就被上拉成高電平。
於是所謂的“編碼”的概念就這樣產生了,我們利用有38K信號 跟 沒有38K信號 這兩種狀態,利用紅外接收頭就翻譯成低電平、高電平的信號。這就是最主要的東西。
-
/***********************定時器0中斷處理 **********************/ void timeint(void) interrupt 1 { TH0=0xFF; TL0=0xF3; //設定時值為38K*2 也就是每隔13us中斷一次 count++; if (flag==1) //如果是發射“1”,則產生38K信號 { OP=~OP; } else //如果是發射“0”,則單純拉低電平,不產生38K信號 { OP = 0; } ir_in= OP; } //發送9ms的起始碼 endcount=692; flag=1; count=0; do{}while(count<endcount); /**********************發送4.5ms的結果碼***********************/ endcount=346; flag=0; count=0; do{}while(count<endcount);
解調
紅外接收需先進行解調,解調的過程是通過紅外接收管進行接收的。其基本工作過程為:當接收到調制信號時,輸出低電平,否則輸出為高電平, 是調制的逆過程(圖 5 解調)。HS0038 是一體化集成的紅外接收器件,直接就可以輸出解調后的高低電平信號;紅外接收器 HS0038 的應用電路(圖6)。

發送方的電平跟接收方解調出來的電平是反向的。
紅外接收頭接收到遙控器的信號后,解碼出后的數據格式如下:
寫程序即根據這個信號的格式來寫。

接收到的信號經過HS0038B解調后得到一系列的高低電平,即遙控碼,分為3部分:
前導碼:9ms的低電平+4.5ms的高電平(和發射的時候相反)
用戶碼:區別不同的紅外設備
操作碼:8bit操作碼和8bit的操作反碼組成
0和1均以0.56ms的低電平開始(實際測量是500us的樣子),不同的是后面出現的高電平,
如果高電平是0.56ms(實際測量是500us的樣子),則表示0,如果高電平是1.68ms(0.56*3=1.68)則表示1
寫代碼的時候只需要檢測高電平的時間即可。
以下時間都是通過示波器實際測量所得。
引導碼的高電平:4.5ms
0的高電平 :0.56ms(實測0.5ms的樣子)
1的高電平 :1.68ms
重復碼的高電平:2.1ms
重復碼前的高電平:40ms
//獲取高電平時間函數偽代碼,返回幾微妙 Get_Pulse_Time() begin time = 0 while HS0038B數據引腳的電平為高電平 time = time + 1 延時20微妙 //time等於250,即延時了5ms if time == 250 return time*20 return time*20 end
紅外接收函數采用中斷函數,通過邊沿觸發啟動高電平時間檢測,比較即時准確。
//紅外中斷函數偽代碼,frame_data、frame_cnt、frame_flag為全局變量 EXTI15_10_IRQHandler() begin pulse_time = 0 leader_code_flag = 0 /* 引導碼標志位,當引導碼出現時,表示一幀數據開始 */ irda_data = 0 /* 數據暫存位 */ while 1 if 紅外接收頭數據引腳的電平 == 高電平 //獲取高電平時間 pulse_time = Get_Pulse_Time() //>=50ms 不是有用信號 當出現干擾或者連發碼時,也會break跳出while(1)循環 if( pulse_time >= 50ms break; //0.56ms:低電平0 if pulse_time > 0.2ms and pulse_time < 1ms irda_data = 0 //1.68ms:高電平1 else if pulse_time > 1ms and pulse_time < 2ms irda_data = 1 //4.5ms:前導位 else if pulse_time > 4ms and pulse_time < 4.5ms leader_code_flag = 1 //2.1ms:連發碼,在第二次中斷出現,40ms:16位操作碼后的高電平時間,位於重復碼之前 else if (pulse_time > 2ms and pulse_time < 4ms) or (pulse_time > 36ms and pulse_time < 44ms) frame_flag = 1; /* 一幀數據接收完成 */ frame_cnt++; /* 按鍵次數加1 */ break //在第一次中斷中完成 if leader_code_flag == 1 frame_data <<= 1 frame_data += irda_data frame_cnt = 0 清除中斷標志 end
-
//獲取操作碼函數偽代碼 IrDa_Process() begin first_byte = frame_data >> 24 sec_byte = (frame_data>>16) & 0xff tir_byte = frame_data >> 8 fou_byte = frame_data // 清標志位 frame_flag = 0; if (first_byte==~sec_byte) && (first_byte== 用戶碼) if tir_byte ==~fou_byte ) return tir_byte return 0; /* 錯誤返回 */ end
-
//main函數里使用紅外偽代碼 while 1 if( frame_flag == 1 ) /* frame_flag為全局變量,一幀紅外數據接收完成 */ key_val = IrDa_Process()



參考鏈接: