?? 文章作者:二土電子
?? 關(guān)注文末公眾號獲取其他資料和工程文件!
?? 期待大家一起學(xué)習交流!
一、紅外遙控簡介
紅外遙控,顧名思義,就是利用紅外線實現(xiàn)遙控。這里就不單獨對紅外線做介紹了,紅外線的波長再可見光范圍外,所以人眼是看不到的。紅外遙控的原理就是利用紅外線進行通訊,比如生活中常用的電視遙控器,空調(diào)遙控器等,大多都是紅外通訊實現(xiàn)的遙控功能。
二、紅外遙控的原理
紅外遙控是一種非接觸,無線控制技術(shù)。具有抗干擾能力強,信息傳輸可靠,功耗低,成本低,易實現(xiàn)等特點。紅外遙控系統(tǒng)一般有紅外發(fā)射裝置和紅外接收設(shè)備兩大部分組成。
- 紅外發(fā)射裝置就是我們常見的遙控器,由鍵盤電路,紅外編碼電路,電源電路和紅外發(fā)射電路組成。
- 紅外接收設(shè)備是由紅外接收電路,紅外解碼,電源和應(yīng)用電路組成。紅外接收裝置有三個引腳,VDD,GND和數(shù)據(jù)輸出VOUT。通常正對接收頭凸起處看,從左到右引腳順序為VOUT,GND,VDD
通常紅外遙控為了提高抗干擾性能和降低電源消耗,紅外遙控器常用載波的方式傳送二進制編碼,常用的載波頻率為38kHz,這是由發(fā)射端所使用的455kHz晶振來決定的。在發(fā)射端要對晶振進行整數(shù)分頻,分頻系數(shù)一般取12,所以為38kHz。也有一些遙控系統(tǒng)采用36kHz、40 kHz、56 kHz等,一般由發(fā)射端晶振的振蕩頻率來決定。所以,通常的紅外遙控器是將遙控信號(二進制脈沖碼) 調(diào)制在38KHz的載波上,經(jīng)緩沖放大后送至紅外發(fā)光二極管,轉(zhuǎn)化為紅外信號發(fā)射出去的。
三、二進制脈沖編碼
二進制脈沖碼的形式有多種,其中最為常用的是NEC Protocol 的PWM碼(脈沖寬度調(diào)制)和 Philips RC-5 Protoco 的 PPM碼(脈沖位置調(diào)制碼,脈沖串之間的時間間隔來實現(xiàn)信號調(diào)制)。如果要開發(fā)紅外接收設(shè)備,一定要知道紅外遙控器的編碼方式和載波頻率,才可以選取一體化紅外接收頭和制定解碼方案。這里針對NEC編碼形式做一個詳細介紹。NEC編碼形式有以下特點
- 8 位地址和 8 位指令長度
- 地址和命令 2次傳輸(確??煽啃?
- PWM 脈沖位置調(diào)制,以發(fā)射紅外載波的占空比代表“ 0”和“1”
- 載波頻率為 38Khz
- 位時間為 1.125ms 或 2.25ms
3.1 NEC碼的位定義
一個脈沖對應(yīng) 560us 的連續(xù)載波,一個邏輯1傳輸需要 2.25ms(560us脈沖+1680us 低電平) ,一個邏輯 0的傳輸需要 1.125ms (560us脈沖+560us 低電平)。而紅外接收頭在收到脈沖的時候為低電平,在沒有脈沖的時候為高電平,這樣,我們在接收頭端收到的信號為: 邏輯 1應(yīng)該是 560us 低+1680us 高,邏輯 0 應(yīng)該是 560us 低+560us 高。所以可以通過計算高電平時間判斷接收到的數(shù)據(jù)是0還是1。NEC碼位定義時序圖如下
特別標注一下,上圖邏輯0和邏輯1的時序圖對應(yīng)的是接收端的時序圖。
3.2 NEC遙控指令的數(shù)據(jù)格式
NEC遙控指令的數(shù)據(jù)格式為:引導(dǎo)碼、地址碼、地址反碼、控制碼控制反碼。引導(dǎo)碼由一個 9ms 的低電平和一個 4.5ms 的高電平組成地址碼、地址反碼、控制碼、控制反碼均是8 位數(shù)據(jù)格式。按照低位在前,高位在后的順序發(fā)送。采用反碼是為了增加傳輸?shù)目煽啃?(可用于校驗)。數(shù)據(jù)格式如下
特別標注一下,上圖為發(fā)送端的時序圖。
NEC碼還規(guī)定了連發(fā)碼(由 9ms 低電平+2.5m 高電平+0.5ms 低電平+97.94ms 高電平組成),如果在一幀數(shù)據(jù)發(fā)送完畢之后,紅外遙控器按鍵仍然沒有放開,則發(fā)射連發(fā)碼,可以通過統(tǒng)計連發(fā)碼的次數(shù)來標記按鍵按下的長短或次數(shù)。
四、紅外遙控程序設(shè)計思路
紅外發(fā)射裝置只需要按鍵按下即可產(chǎn)生紅外信號,我們只需要針對紅外接收設(shè)備編寫程序即可。上面介紹了,紅外接收設(shè)備在收到脈沖的時候為低電平,在沒有脈沖的時候為高電平。根據(jù)“0”和“1”的時序圖可知,我們只需要監(jiān)測紅外接收設(shè)備的數(shù)據(jù)輸出引腳的高電平持續(xù)時間就可以判斷接收到的是“0”還是“1”。
另外,沒有按鍵按下時,也就是沒有發(fā)紅外信號,沒有脈沖,紅外接收設(shè)備的數(shù)據(jù)輸出引腳一直為高電平。只有接收到脈沖時,說明有按鍵按下,此時紅外接收設(shè)備的數(shù)據(jù)輸出引腳為低電平。因此,可以利用外部中斷的下降沿出發(fā)來判斷是否有按鍵按下,在中斷中測量高電平持續(xù)時間來判斷接收到的是“0”還是“1”。
五、紅外遙控程序設(shè)計
5.1 紅外遙控初始化程序
需要初始化GPIO和外部中斷,GPIO配置為上拉輸入模式
/*
*==============================================================================
*函數(shù)名稱:Drv_Hw_Init
*函數(shù)功能:初始化紅外遙控模塊
*輸入?yún)?shù):無
*返回值:無
*備 注:紅外端口初始化函數(shù),時鐘端口及外部中斷初始化
*==============================================================================
*/
void Drv_Hw_Init (void)
{
// 結(jié)構(gòu)體定義
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
// 開啟時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE);
// 配置GPIO結(jié)構(gòu)體
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_11; // 紅外接收
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; // 上拉輸入模式
GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource11); // 選擇GPIO管腳用作外部中斷線路
EXTI_ClearITPendingBit(EXTI_Line11);
// 配置外部中斷
EXTI_InitStructure.EXTI_Line=EXTI_Line11;
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd=ENABLE;
EXTI_Init(&EXTI_InitStructure);
// 配置NVIC結(jié)構(gòu)體
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 搶占優(yōu)先級為0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 響應(yīng)優(yōu)先級為1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能
NVIC_Init(&NVIC_InitStructure);
}
5.2 記錄高電平持續(xù)時間函數(shù)
利用記錄延時次數(shù)的方法測量高電平持續(xù)時間
/*
*==============================================================================
*函數(shù)名稱:Drv_Hw_RecordHightTime
*函數(shù)功能:記錄高電平持續(xù)時間并返回
*輸入?yún)?shù):無
*返回值:t:高電平持續(xù)時間
*備 注:無
*==============================================================================
*/
u8 Drv_Hw_RecordHightTime (void)
{
u8 t = 0;
while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11) == 1) // 高電平
{
t ++;
delay_us(20);
if(t >= 250)
{
return t; // 超時溢出
}
}
return t;
}
5.3 中斷服務(wù)函數(shù)
中斷服務(wù)函數(shù)中接收數(shù)據(jù),接收完成后對應(yīng)的接收完成標志位置1
/*
*==============================================================================
*函數(shù)名稱:EXTI15_10_IRQHandler
*函數(shù)功能:外部中斷服務(wù)函數(shù)
*輸入?yún)?shù):無
*返回值:無
*備 注:無
*==============================================================================
*/
void EXTI15_10_IRQHandler(void) // 紅外遙控外部中斷
{
u8 Tim = 0,Ok = 0,Data,Num = 0;
while(1)
{
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11) == 1)
{
Tim = Drv_Hw_RecordHightTime(); //獲得此次高電平時間
if(Tim>=250)
{
break; // 不是有用的信號
}
if(Tim >= 200 && Tim < 250)
{
Ok = 1; // 收到起始信號
}
else if(Tim >= 60 && Tim < 90)
{
Data = 1; // 收到數(shù)據(jù) 1
}
else if(Tim >= 10 && Tim < 50)
{
Data = 0; // 收到數(shù)據(jù) 0
}
if(Ok == 1)
{
hw_jsm <<= 1;
hw_jsm += Data;
// 接收完成
if(Num >= 32)
{
hw_jsbz = 1;
break;
}
}
Num ++;
}
}
// 清除中斷標志位
EXTI_ClearITPendingBit(EXTI_Line11);
}
5.4 讀取鍵值
判斷鍵盤上按下的是哪個按鍵。不同的遙控器,按鍵對應(yīng)的紅外編碼可能不同,可以通過串口打印接收到的鍵值的方法來讀出每一個按鍵的鍵值。
/*
*==============================================================================
*函數(shù)名稱:Med_Hw_ReadKeyValue
*函數(shù)功能:讀取鍵值
*輸入?yún)?shù):無
*返回值:紅外鍵值
*備 注:每一個鍵值是測試出來的,不同遙控器鍵值可能不同
*==============================================================================
*/
u8 Med_Hw_ReadKeyValue (void)
{
if(hw_jsm == 0x00FF9867)
{
return 0;
}
else if(hw_jsm == 0x00FFA25D)
{
return 1;
}
else if(hw_jsm == 0x00FF629D)
{
return 2;
}
else if(hw_jsm == 0x00FFE21D)
{
return 3;
}
else if(hw_jsm == 0x00FF22DD)
{
return 4;
}
else if(hw_jsm == 0x00FF02FD)
{
return 5;
}
else if(hw_jsm == 0x00FFC23D)
{
return 6;
}
else if(hw_jsm == 0x00FFE01F)
{
return 7;
}
else if(hw_jsm == 0x00FFA857)
{
return 8;
}
else if(hw_jsm == 0x00FF906F)
{
return 9;
}
else if(hw_jsm == 0x00FF6897) // 按鍵*按下
{
return 10;
}
else if(hw_jsm == 0x00FFB04F) // 按鍵#按下
{
return 11;
}
else if(hw_jsm == 0x00FF38C7) // 按鍵OK按下
{
return 12;
}
else if(hw_jsm == 0x00FF18E7) // 按鍵"上"按下
{
return 13;
}
else if(hw_jsm == 0x00FF4AB5) // 按鍵"下"按下
{
return 14;
}
else if(hw_jsm == 0x00FF10EF) // 按鍵"左"按下
{
return 15;
}
else if(hw_jsm == 0x00FF5AA5) // 按鍵"右"按下
{
return 16;
}
return 17;
}
5.5 參數(shù)定義
定義了以下兩個參數(shù)文章來源:http://www.zghlxwxcb.cn/news/detail-619964.html
u32 hw_jsm; // 定義一個32位數(shù)據(jù)變量,保存接收碼
u8 hw_jsbz; // 定義一個8位數(shù)據(jù)的變量,用于指示接收標志
六、應(yīng)用實例
利用紅外遙控控制LED的亮滅,按下“1”點亮,按下“0”熄滅。每次執(zhí)行完對應(yīng)按鍵的內(nèi)容后,需要清除接收完成標志位和接收碼。main函數(shù)如下文章來源地址http://www.zghlxwxcb.cn/news/detail-619964.html
u8 gHwKeyValue = 0; // 紅外鍵值
int main(void)
{
Med_Mcu_Iint(); // 系統(tǒng)初始化
while(1)
{
if (hw_jsbz == 1)
{
// 獲取紅外鍵值
gHwKeyValue = Med_Hw_ReadKeyValue();
// 按下按鍵“1”
if (gHwKeyValue == 1)
{
// 點亮LED
Med_Led_StateCtrl(LED1,LED_ON);
}
// 按下按鍵“0”
if (gHwKeyValue == 0)
{
// 熄滅LED
Med_Led_StateCtrl(LED1,LED_OFF);
}
hw_jsbz = 0; // 清除接收完成標志位
hw_jsm = 0; // 清零接收碼
}
}
}
到了這里,關(guān)于STM32外設(shè)系列—紅外遙控的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!