一、紅外遙控簡介
紅外遙控是一種無線、非接觸控制技術,具有抗干擾能力強,信息傳輸可靠,功耗低,成本低,易實現等顯著優點,被諸多電子設備特別是家用電器廣泛采用,并越來越多的應用到計算機系統中。由于紅外線遙控不具有像無線電遙控那樣穿過障礙物去控制被控對象的能力,所以,在設計紅外線遙控器時,不必要像無線電遙控器那樣,每套(發射器和接收器)要有不同的遙控頻率或編碼(否則就會隔墻控制或干擾鄰居的家用電器),所以同類產品的紅外線遙控器,可以有相同的遙控頻率或編碼,而不會出現遙控信號“串門”的情況。這對于大批量生產以及在家用電器上普及紅外線遙控提供了極大的方便。由于紅外線為不可見光,因此對環境影響很小,再由紅外光波動波長遠小于無線電波的波長,所以紅外線遙控不會影響其他家用電器,也不會影響臨近的無線電設備。

二、紅外遙控特性
紅外遙控的情景中,必定會有一個紅外發射端和紅外接收端。要使兩者通信成功,收/發紅外波長與載波頻率需一致,在這里波長就是940nm,載波頻率就是38kHz。
紅外發射管也是屬于二極管類,紅外發射電路通常使用三極管控制紅外發射器的導通或者截至,在導通的時候,紅外發射管會發射出紅外光,反之,就不會發射出紅外光。雖然用肉眼看不到紅外光,但是可以借助手機攝像頭就能看到紅外光。但是紅外接收管的特性是當接收到紅外載波信號時,OUT引腳輸出低電平;假如沒有接收到紅外載波信號時,OUT引腳輸出高電平。
紅外載波信號其實就是由一個個紅外載波周期組成。在頻率為38KHz下,紅外載波周期約等于26.3us(1s/38KHz≈26.3us)。在一個紅外載波發射周期里,發射紅外光時間8.77us和不發射紅外光17.53us,發射紅外光的占空比一般為1/3。相對的,整個周期內不發射紅外光,就是載波不發射周期。在紅外遙控器內已經把載波和不載波信號處理好,只需要做的就是識別遙控器按鍵發射出的信號,信號也是遵循某種協議的。
三、紅外編解碼協議介紹
紅外遙控的編碼方式目前廣泛使用的是:PWM(脈沖寬度調制)的NEC協議和PhilipsPPM(脈沖位置調制)的RC-5協議的。以NEC協議為例,其特征如下:
1、8位地址和8位指令長度;
2、地址和命令2次傳輸(確??煽啃?;
3、PWM脈沖位置調制,以發射紅外載波的占空比代表“0”和“1”;
4、載波頻率為38Khz;
5、位時間為1.125ms或2.25ms;
在NEC協議中,如何為協議中的數據‘0’或者‘1’?這里分開紅外接收器和紅外發射器。
紅外發射器:
發送協議數據‘0’=發射載波信號560us+不發射載波信號560us
發送協議數據‘1’=發射載波信號560us+不發射載波信號1680us
紅外發射器的位定義如下圖所示:
紅外接收器:
接收到協議數據‘0’=560us低電平+560us高電平
接收到協議數據‘1’=560us低電平+1680us高電平
紅外接收器的位定義如下圖所示:
NEC遙控指令的數據格式為:同步碼頭、地址碼、地址反碼、控制碼、控制反碼。同步碼由一個9ms的低電平和一個4.5ms的高電平組成,地址碼、地址反碼、控制碼、控制反碼均是8位數據格式。按照低位在前,高位在后的順序發送。采用反碼是為了增加傳輸的可靠性 (可用于校驗)。除了上面的數據格式,NEC還規定了一個連發碼(由9ms低電平+2.5ms高電平+0.56ms低電平+97.94ms高電平組成),如果在一幀數據發送完畢之后,按鍵仍然沒有放開,則發射重復碼,即連發碼可以通過統計連發碼的次數來標記按鍵按下的長短/次數。紅外NEC協議編碼如圖所示:

當遙控器的按鍵按下時,從紅外接收頭端收到的波形如圖所示,從圖中可以看到,其地址碼為0,控制碼為21(正確解碼后00010101)。

四、STM32F103解碼接收紅外信號
準備工作
STM32F103C8T6開發板,940nm波長 38kHz載波頻率的紅外遙控器,HX1838接收頭,OLED屏幕
接線說明
| STM32F103C8T6 | HX1838接收頭 |
|---|---|
| 3.3V | 接收頭的+ 和 OLED的VCC |
| GND | 共地 |
| PA0 | S |
| PB8 | OLED->SCL |
| PB9 | OLED->SDA |

代碼示例
HX1838.c
#include "IR.h"
#include "timer.h"
// 遙控器接收狀態
//[7]:收到了引導碼標志
//[6]:得到了一個按鍵的所有信息
//[5]:保留
//[4]:標記上升沿是否已經被捕獲
//[3:0]:溢出計時器
uint8_t RmtSta = 0;
uint16_t Dval; // 下降沿時計數器的值
uint32_t RmtRec = 0; // 紅外接收到的數據
uint8_t RmtCnt = 0; // 按鍵按下的次數
void IR_Init(void)
{
Timer_Init();
}
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
if (RmtSta & 0x80) // 上次有數據被接收到了
{
RmtSta &= ~0X10; // 取消上升沿已經被捕獲標記
if ((RmtSta & 0X0F) == 0X00)
RmtSta |= 1 < < 6; // 標記已經完成一次按鍵的鍵值信息采集
if ((RmtSta & 0X0F) < 14)
RmtSta++;
else
{
RmtSta &= ~(1 < < 7); // 清空引導標識
RmtSta &= 0XF0; // 清空計數器
}
}
}
if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)
{
if (RDATA) // 上升沿捕獲
{
TIM_OC1PolarityConfig(TIM2, TIM_ICPolarity_Falling); // CC4P=1 設置為下降沿捕獲
TIM_SetCounter(TIM2, 0); // 清空定時器值
RmtSta |= 0X10; // 標記上升沿已經被捕獲
}
else // 下降沿捕獲
{
Dval = TIM_GetCapture1(TIM2); // 讀取CCR4也可以清CC4IF標志位
TIM_OC1PolarityConfig(TIM2, TIM_ICPolarity_Rising); // CC4P=0 設置為上升沿捕獲
if (RmtSta & 0X10) // 完成一次高電平捕獲
{
if (RmtSta & 0X80) // 接收到了引導碼
{
if (Dval > 300 && Dval < 800) // 560為標準值,560us
{
RmtRec < <= 1; // 左移一位.
RmtRec |= 0; // 接收到0
}
else if (Dval > 1400 && Dval < 1800) // 1680為標準值,1680us
{
RmtRec < <= 1; // 左移一位.
RmtRec |= 1; // 接收到1
}
else if (Dval > 2200 && Dval < 2600) // 得到按鍵鍵值增加的信息 2500為標準值2.5ms
{
RmtCnt++; // 按鍵次數增加1次
RmtSta &= 0XF0; // 清空計時器
}
}
else if (Dval > 4200 && Dval < 4700) // 4500為標準值4.5ms
{
RmtSta |= 1 < < 7; // 標記成功接收到了引導碼
RmtCnt = 0; // 清除按鍵次數計數器
}
}
RmtSta &= ~(1 < < 4);
}
}
TIM_ClearITPendingBit(TIM2, TIM_IT_Update | TIM_IT_CC1);
}
// 處理紅外鍵盤
// 返回值:
// 0,沒有任何按鍵按下
// 其他,按下的按鍵鍵值.
uint8_t Remote_Scan(void)
{
uint8_t sta = 0;
uint8_t t1, t2;
if (RmtSta & (1 < < 6)) // 得到一個按鍵的所有信息了
{
t1 = RmtRec > > 24; // 得到地址碼
t2 = (RmtRec > > 16) & 0xff; // 得到地址反碼
if ((t1 == (uint8_t)~t2) && t1 == REMOTE_ID) // 檢驗遙控識別碼(ID)及地址
{
t1 = RmtRec > > 8;
t2 = RmtRec;
if (t1 == (uint8_t)~t2)
sta = t1; // 鍵值正確
}
RmtSta &= ~(1 < < 6); // 清除接收到有效按鍵標識
RmtCnt = 0; // 清除按鍵次數計數器
}
return sta;
}
main.c
#include "stm32f10x.h" // Device header
#include "oled.h"
#include "delay.h"
#include "IR.h"
uint8_t IR_Address;
uint8_t IR_Command;
uint8_t IR_Count;
uint8_t *str = 0;
uint8_t key;
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
OLED_Init();
IR_Init();
OLED_ShowString(1,1,"ADDR HEX CMD NUM");
OLED_ShowString(2,1,"00 00 0 000");
while(1)
{
IR_Address = (RmtRec > > 24) & 0xFF;
IR_Command = (RmtRec > > 8) & 0xFF;
key = Remote_Scan();
if (key) {
switch (key) {
case IR_1:
str = "1";
break;
case IR_2:
str = "2";
break;
case IR_3:
str = "3";
break;
case IR_4:
str = "4";
break;
case IR_5:
str = "5";
break;
case IR_6:
str = "6";
break;
case IR_7:
str = "7";
break;
case IR_8:
str = "8";
break;
case IR_9:
str = "9";
break;
case IR_0:
str = "0";
break;
case IR_SP1:
str = "*";
break;
case IR_SP2:
str = "#";
break;
case IR_UP: //"↑"
IR_Count++;
break;
case IR_LEFT: //"←"
//
break;
case IR_DOWN: //"↓"
IR_Count--;
break;
case IR_RIGHT: //"→"
//
break;
case IR_CONFIRM:
str = "OK ";
break;
default:
str = "EMOURE";
break;
}
OLED_ShowHexNum(2, 1, IR_Address, 2);
OLED_ShowHexNum(2, 6, IR_Command, 2);
OLED_ShowString(2,12," ");
OLED_ShowString(2,11,str);
OLED_ShowNum(2, 14, IR_Count, 3);
}
Delay_ms(10);
}
}
效果展示

審核編輯 黃宇
-
紅外遙控
+關注
關注
22文章
351瀏覽量
47602 -
STM32F103C8T6
+關注
關注
113文章
166瀏覽量
88727
發布評論請先 登錄
STM32驅動串口屏,STM32F103C8T6串口發送指令控制HMI串口屏
基于STM32F103C8T6對紅外遙控信號解碼 實現HX1838接收頭接收數據
評論