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