PIC單片機的紅外遙控與解碼
先了解紅外接收的原理:
本文引用地址:http://www.ex-cimer.com/article/201611/317656.htm遙控器使用方便,功能多.目前已廣泛應(yīng)用在電視機、VCD、DVD、空調(diào)等各種家用電器中,且價格便宜,市場上非常容易買到。如果能將遙控器上許多的按鍵解碼出來.用作單片機系統(tǒng)的輸入.則解決了常規(guī)矩陣鍵盤線路板過大、布線復(fù)雜、占用I/O口過多的弊病。而且通過使用遙控器,操作時可實現(xiàn)人與設(shè)備的分離,從而更加方便使用。
一、編碼格式
1、0和1的編碼
遙控器發(fā)射的信號由一串O和1的二進(jìn)制代碼組成.不同的芯片對0和1的編碼有所不同。通常有曼徹斯特編碼和脈沖寬度編碼。TC9012的O和1采用PWM方法編碼,即脈沖寬度調(diào)制,其O碼和1碼如圖1所示(以遙控接收輸出的波形為例)。O碼由O.56ms低電平和0.56ms高電平組合而成.脈沖寬度為1.12ms.1碼由0.56ms低電平和1.69ms高電平組合而成.脈沖寬度為2.25ms。在編寫解碼程序時.通過判斷脈沖的寬度,即可得到0或1。
2、按鍵的編碼
當(dāng)一個鍵按下超過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.5ms)組成。
當(dāng)我們按下遙控器的按鍵時,遙控器將發(fā)出如圖2的一串二進(jìn)制代碼,我們稱它為一幀數(shù)據(jù)。根據(jù)各部分的功能??蓪⑺鼈兎譃?部分,分別為引導(dǎo)碼、地址碼、地址碼、數(shù)據(jù)碼、數(shù)據(jù)反碼。遙控器發(fā)射代碼時.均是低位在前。高位在后。由圖2分析可以得到.引導(dǎo)碼高電平為4.5ms,低電平為4.5ms。當(dāng)
接收到此碼時.表示一幀數(shù)據(jù)的開始。單片機可以準(zhǔn)備接收下面的數(shù)據(jù)。地址碼由8位二進(jìn)制組成,共256種.圖中地址碼重發(fā)了一次。主要是加強遙控器的可靠性.如果兩次地址碼不相同.則說明本幀數(shù)據(jù)有錯.應(yīng)丟棄。不同的設(shè)備可以擁有不同的地址碼.因此。同種編碼的遙控器只要設(shè)置地址碼不同,也不會相互干擾。圖中的地址碼為十六進(jìn)制的0EH(注意低位在前)。在同一個遙控器中.所有按鍵發(fā)出的地址碼都是相同的。數(shù)據(jù)碼為8位,可編碼256種狀態(tài),代表實際所按下的鍵。數(shù)據(jù)反碼是數(shù)據(jù)碼的各位求反,通過比較數(shù)據(jù)碼與數(shù)據(jù)反碼.可判斷接收到的數(shù)據(jù)是否正確。如果數(shù)據(jù)碼與數(shù)據(jù)反碼之間的關(guān)系不滿足相反的關(guān)系.則本次遙控接收有誤.?dāng)?shù)據(jù)應(yīng)丟棄。在同一個遙控器上.所有按鍵的數(shù)據(jù)碼均不相同。在圖2中,數(shù)據(jù)碼為十六進(jìn)制的0CH,數(shù)據(jù)反碼為十六進(jìn)制的0F3H(注意低位在前).兩者之和應(yīng)為0FFH。
連續(xù)碼
二、單片機遙控接收電路
紅外遙控接收可采用較早的紅外接收二極管加專用的紅外處理電路的方法。如CXA20106,此種方法電路復(fù)雜,現(xiàn)在一般不采用。較好的接收方法是用一體化紅外接收頭,它將紅外接收二極管、放大、解調(diào)、整形等電路做在一起,只有三個引腳.分別是+5V電源、地、信號輸出。常用的一體化接收頭的外形及引腳見圖3和圖4。紅外接收頭的信號輸
出接單片機的INTO或INTl腳.典型電路如圖5所示.圖中增加了一只PNP型三極管對輸出信號進(jìn)行放大。
針對遙控器端(解碼端,接收端對對此取反即可)
引導(dǎo)碼:9ms高+4.5ms低
系統(tǒng)碼:系統(tǒng)碼1+系統(tǒng)碼2(由定義高低電平的"0"和"1"組成)
數(shù)據(jù)碼:數(shù)據(jù)碼1+數(shù)據(jù)反碼(由定義高低電平的"0"和"1"組成)
剩余碼:108ms-引導(dǎo)碼占用時間-系統(tǒng)碼占用時間-數(shù)據(jù)碼占用時間.
如果按"鍵"的時間超過108ms,遙控器還會發(fā)射重發(fā)碼:
重發(fā)碼(108ms)的格式如下:
9ms高+2.25ms低+0.56ms高+96.19ms低
連接電路圖:
下面開始寫程序:
#ifndef MAIN_H
#define MAIN_H
#include
#define bitset(var,bitno)(var |=1< //定義接受幀狀態(tài) #endif typedef struct frame1 void int_delay(uint count) void interrupt main_int() if(INTF&INTEDG) switch(frame.ir_state) } } frame.temp=frame.temp<<1 ; init_all() ; if(frame.ready==1) }
#define uint unsigned int
#define uchar unsigned char
#define IR_IDLE 0x01
#define IR_START 0x02
#define IR_ADD 0x03
#define IR_ADDINV 0x04
#define IR_DATA 0x05
#define IR_DATAINV 0x06
#define ms_168 0x0600
#define ms_th 0x08CA
#define ms_9 0x0800
#define ms_306 0x0B00
#define ms_125 0x1300
#define ms_15 0x15F9
//void DelayMS(uint ms);//毫秒級延時函數(shù)
//void Delay10US(uint us);//10微秒級延時函數(shù)
void init_all() ;
#include "main.h"
#include "t232.h"
{
uint add ;
uint addinv ;
uchar data ;
uchar datainv ;
uchar ir_state ;
uint count ;
uint temp ;
uchar ready ;
} ir_frame ;
{
while(count--) ;
}
//define global variable
ir_frame frame ;
{
{
GIE=0 ;
INTF=0 ;
TMR1ON=0;
frame.count=TMR1H*256+TMR1L;
TMR1H=0;
TMR1L=0;
TMR1ON=1;
{
case IR_IDLE :
if(frame.count>0x2000)//防止干擾
frame.ir_state=IR_START ;
break ;
case IR_START :
if(frame.ready==1)//沒有處理,等待
{
frame.ir_state=IR_IDLE ;
return ;
}
if((frame.count>ms_125)&&(frame.count
frame.add=0 ;
frame.addinv=0 ;
frame.data=0 ;
frame.datainv=0 ;
frame.ir_state=IR_ADD ;
frame.temp=1 ;
frame.ready=0 ;
else if((frame.count>ms_9)&&(frame.count
frame.ready=1 ;
frame.ir_state = IR_IDLE ;
else//噪聲?
{
frame.ir_state = IR_IDLE ;
}
break ;
case IR_ADD :
if(frame.count<0x280)//噪聲?
return ;
if((frame.count>ms_168))//高電平?
frame.add|=frame.temp ;
frame.temp=frame.temp<<1 ;
if(frame.temp==0x2000)//13位OK?
{
frame.ir_state=IR_ADDINV ;
frame.temp=1 ;
}
break ;
case IR_ADDINV :
//int_delay(75) ;
//if(RB0)
if(frame.count<0x280)
return ;
if((frame.count>ms_168))
frame.addinv|=frame.temp ;
frame.temp=frame.temp<<1 ;
if(frame.temp==0x2000)//13位OK?
{
frame.ir_state=IR_DATA ;
frame.temp=1 ;
}
break ;
case IR_DATA :
if(frame.count<0x280)//噪聲
return ;
if((frame.count>ms_168))//高電平
frame.data|=frame.temp ;
if(frame.temp==0x0100)//8位 finished ?
{
frame.ir_state=IR_DATAINV ;
frame.temp=1 ;
}
break ;
case IR_DATAINV :
if(frame.count<0x280)
return ;
if((frame.count>ms_168))
frame.datainv|=frame.temp ;
frame.temp=frame.temp<<1 ;
if(frame.temp==0x0080)//7 位 finished?
{
frame.temp=frame.temp<<1 ;
int_delay(75) ;//延時等待最后一位的電平
if(RB0)
frame.datainv|=frame.temp ;
if((frame.data|frame.datainv==0xff)&&(frame.add==0x011F))
{
frame.ready=1 ;
}
frame.ir_state=IR_IDLE ;
}
break ;
default :
break ;
}
GIE=1 ;
}
}
void init_all()
{
init_232() ;
//init_hongwai() ;
INTCON=0 ;
INTE=1;//開RB電平中斷
PEIE=1;
INTEDG=1 ;
TRISB0=1;//RB4為輸入
T1CON=0 ;
TMR1H=0xAA ;
TMR1L=0xBB ;
frame.ir_state=IR_IDLE ;
GIE=1 ;
ADCON0=0x06 ;
TRISA0=0 ;
}
void main()
{
const char str[]= "hello world !" ;
send_str(str) ;//測試串口
while(1)
{
{
put_char(frame.data) ;
frame.ready=0 ;
}
}
評論