紅外遙控器的接收實驗
遙控發(fā)射器專用 芯片 很多,根據(jù)編碼格式可以分成兩大類,這里我們以運用比較廣泛,解碼比較容易的一類來加以說明,現(xiàn)以日本NEC的uPD6121G組成發(fā)射電路為例說明編碼 原理 (一般家庭用的DVD、VCD、音響都使用這種編碼方式)。當發(fā)射器按鍵按下后,即有遙控碼發(fā)出,所按的鍵不同遙控編碼也不同。
一、電路實現(xiàn)
紅外發(fā)射器很容易找到,我們平時家用的電視、DVD遙控器都可以用來進行實驗。下面的 電路圖 是紅外接收部分的電路圖,
二、紅外接收原理
關于紅外發(fā)射部分,由于我們采用的是現(xiàn)成的遙控器,而不同的遙控器其實現(xiàn)電路各不相同,這里我們就不詳細介紹。我們只需要知道遙控器發(fā)射出來的 數(shù)據(jù) 格式,然后通過紅外接收器接收數(shù)據(jù),并根據(jù)數(shù)據(jù)格式將其進行分解,得到相應鍵值即可。
遙控器在按鍵按下后,周期性地發(fā)出同一種32位二進制碼,周期約為108ms。一組碼本身的持續(xù)時間隨它包含的二進制“0”和“1”的個數(shù)不同而不同,大約在45~63ms之間,發(fā)射波形圖如下:
當一個鍵按下超過36ms,振蕩器使芯片激活,將發(fā)射一組108ms的編碼脈沖,這108ms發(fā)射 代碼 由一個引導碼(9ms),一個結(jié)果碼(4.5ms),低8位地址碼(9ms~18ms),高8位地址碼(9ms~18ms),8位數(shù)據(jù)碼(9ms~18ms)和這8位數(shù)據(jù)的反碼(9ms~18ms)組成。如果鍵按下超過108ms仍未松開,接下來發(fā)射的代碼(連發(fā)碼)將僅由起始碼(9ms)和結(jié)束碼(2.25ms)組成。其中32位數(shù)據(jù)格式如下:
這種遙控碼具有以下特征:
采用脈寬調(diào)制的 串行 碼,以脈寬為0.565ms、間隔0.56ms、周期為1.125ms的組合表示二進制的“0”;以脈寬為0.565ms、間隔1.685ms、周期為2.25ms的組合表示二進制的“1”,波形如下圖:
三、 程序 實現(xiàn)
在本 實例 中,我們利用 串口 將單片機從一體化紅外接收器接收到的紅外遙控鍵值發(fā)送到計算機上,通過計算機的串口助手觀察接收到的數(shù)據(jù)。
紅外遙控的數(shù)據(jù)接收主要在外部中斷函數(shù)中進行處理:處理過程為:當有遙控鍵值發(fā)送的時候,紅外一體化接收器的脈沖信號輸出腳發(fā)生一個下降沿的電平變化,外部中斷采用下降沿出發(fā)的方式接收到由外部中斷事件發(fā)生,程序進入外部中斷處理函數(shù),首先關閉外部中斷,然后根據(jù)一體化接收器脈沖信號輸出引腳的高低電平變化時間判斷紅外遙控發(fā)送的數(shù)據(jù),共有4個字節(jié)的數(shù)據(jù),處理完這4個字節(jié)數(shù)據(jù)后,利用 單片機 的串口將數(shù)據(jù)發(fā)送到計算機。
下面是完整代碼:其中串口數(shù)據(jù)發(fā)送部分的程序請查看前面關于串口的實現(xiàn)部分
#include
#include
#include //中斷函數(shù)頭文件
#include "usart.h"
void INT_Init(void); //外部中斷初始化
void Delayus(unsigned int lus); //us延時函數(shù)
void Delayms(unsigned int lms); //ms延時函數(shù)
int main(void)
{
Port1_Init();
Usart1_Init();
INT_Init();
sei(); //使能全局中斷
while(1)
{
}
}
//外部中斷初始化
void INT_Init(void)
{
EICRB |= (1 << ISC41); //選擇外部中斷4,下降沿觸發(fā)中斷
EIMSK |= (1 << INT4); //使能外部中斷4
}
//
ISR(INT4_vect)
{
unsigned char i,j,k = 0,addr[4] = {0};
EIMSK = 0x00; //禁止外部中斷4 關閉外部中斷,開始接受數(shù)據(jù)
for(i = 0;i < 14;i++)
{
Delayus(400);
if(PINE & (1 << PE4)) //9MS內(nèi)有高電平,則判斷為干擾,退出處理程序
{
EIMSK |= (1 << INT4); //使能外部中斷4
return;
}
}
while(!(PINE & (1 << PE4)));//等待9ms低電平過去
for(i = 0;i < 4;i++) //
{
for(j = 0;j < 8;j++) //
{
while(PINE & (1 << PE4)); //等待4.5ms高電平過去
while(!(PINE & (1 << PE4))); //等待變高電平
while(PINE & (1 << PE4))//計算高電平時間
{
Delayus(100);
k++;
if(k >= 30) //高電平時間過長,則退出處理程序
{
EIMSK |= (1 << INT4); //使能外部中斷4
return; //
}
}
addr= addr>> 1; //接受一位數(shù)據(jù)
if(k >= 8)
{
addr= addr| 0x80; //高電平時間大于0.56,則為數(shù)據(jù)1
}
k = 0; //計時清零
}
}
Usart1_PutChar(addr[0]); //通過串口發(fā)送接收到的4個字節(jié)
Usart1_PutChar(addr[1]);
Usart1_PutChar(addr[2]);
Usart1_PutChar(addr[3]);
EIMSK |= (1 << INT4); //使能外部中斷4
}
//
//us級別的延時函數(shù)
void Delayus(unsigned int lus)
{
while(lus--)
{
_delay_loop_2(4); //_delay_loop_2(1)是延時4個 時鐘 周期,參數(shù)為4則延時16
//個時鐘周期,本實驗用16M晶體,則16個時鐘周期為16/16=1us
}
}
//ms級別的延時函數(shù)
void Delayms(unsigned int lms)
{
while(lms--)
{
_delay_loop_2(4000); //延時1ms
}
}