單片機練習(xí)-RC-5紅外遙控器程序及簡單制造DIY PC遙控器
本程序采用的芯片為SAA3010, 參考資料有:
1.常用紅外遙控接收頭引腳圖解
2.紅外遙控編碼資料
3.RC-5紅外遙控程序
4.GIRDER中文教程與電腦遙控器制作資料
5.Girder網(wǎng)站(一個需要錢買的遙控)
6.再度出擊,20元打造經(jīng)典PC遙控器!
7.SAA3010 DataSheet
這次主要是完成單片機接收紅外搖控器發(fā)出的數(shù)據(jù). 在此基礎(chǔ)上, 我們可DIY出自己的PC搖控器, 也可自行發(fā)揮一些, 做出類似于很多Club里的點歌系統(tǒng)的硬件外紅信號轉(zhuǎn)換裝置....
本次實驗依舊采用TX-1B實驗板, 只需增加一個一體化紅外接收頭, 如下圖:
本程序中, DataOut引腳接到P3.2口. 在接收頭的電源和地端接上濾波電容會使誤碼率更加低....
SAA3010芯片:
(圖中位時間1.688ms, 而根據(jù)DataSheet里描述的位時間為1.788ms, 但實際中我使用的時間為1.651ms)
我使用的鍵盤編碼如下:
鍵盤外觀:
編碼:
一體化紅外接收頭的數(shù)據(jù)輸出的判斷思路: (手畫, 太難看也別見怪:) )
Tb = 1.778ms = 1.780ms (實際中測試為1.651ms)
T1/4b = 445us (實際中413ms)
T3/4b = 1.335ms (實際1.239ms)
在等待第一次低電平到來后, 定時器開始第一次定時T1/4b時間, 然后到達第一次數(shù)據(jù)的T3/4b時刻, 讀取該位電平狀態(tài);
以后定時器每次定時Tb時間, 這樣到達對應(yīng)每位的T3/4時刻, 并可讀取該位電平狀態(tài).
具體邏輯請看代碼中的詳細注釋:
采用程序查詢方式:
SAA3010_RC5
//接收紅外遙控器(Infraredremotecontroltransmitter)發(fā)出的數(shù)據(jù)
//芯片型號:SAA3010,它采用RC-5協(xié)議
//芯片資料:http://www.alldatasheet.com/datasheet-pdf/pdf/18953/PHILIPS/SAA3010.html
//利用與P1口相連的發(fā)光二極管輸出接收到的按鍵對應(yīng)碼,并將它輸出到串口,用于遙控
//PC使用了Girder來觸發(fā)自定義的功能
#include"reg51.h"
#include"intrins.h"
#defineucharunsignedchar
/*********************IRCRC-5****************************************/
ucharYKDatas[3];//遙控碼(一幀14位),YKDatas[0]:0,1為startbits,2為controlbit,YKtype=0
//YKDatas[1]:3~7為systembits,YKtype=1
//YKDatas[2]:8~13為commandbits,YKtype=2
sbitYKIn=P3^2;//數(shù)據(jù)輸入位
ucharYKcount,YKtype;//遙控已接收位數(shù),一幀的各段標(biāo)志
bitYKend;//接收結(jié)束標(biāo)志
//延時a*1ms
voiddelayMs(unsignedinta)
{
unsignedinti,j;
for(i=a;i>0;i--)
for(j=100;j>0;j--);
}
voidYKInit()//遙控接收初始化
{
YKDatas[0]=YKDatas[1]=YKDatas[2]=0;
YKcount=0;
YKtype=0;
YKend=0;
}
voidtime0()interrupt1
{
//第一次進入中斷前,定時1/4位的時間:445us,以后則定時一位時間1.778ms
//即在3/4位時間時,判斷該位是1還是0
//實際測試中,位時間只在1.651ms(+-1ms),定時1/4位的時間:413us
bitin=~YKIn;//一體化解碼后,有載頻部分變?yōu)榈碗娖?即低電平實際為1,高電平實際為0
//設(shè)置定時器初值
//模式1:TH0=(2^16-(1651/1.085))/2^8=(65536-1651/1.085)/256=250;
//TL0=(65536-1651/1.085)%256=14
TH0=250;
TL0=14;
YKDatas[YKtype]=YKDatas[YKtype]"in;//將數(shù)據(jù)放入最低位
YKcount++;
if(YKcount==3)//獲取完Startbits和controlbit,共3位
{
YKtype=1;
}
elseif(YKcount==8)//獲取完systembits,共5位
{
YKtype=2;
}
elseif(YKcount==14)//獲取完commondbits,共6位
{
YKtype=3;
}
elseif(YKtype==3)//等待最后1/4位時間結(jié)束,實際延時1位時間
{
YKend=1;
YKcount=0;
YKtype=0;
TR0=0;//接收結(jié)束,停止定時器0
return;
}
else//將數(shù)據(jù)左移一位,以便將一下位數(shù)據(jù)并于最低位
{
YKDatas[YKtype]=YKDatas[YKtype]<<1;
}
}
/*********************IRCRC-5****************************************/
/*********************RS232****************************************/
//初始化串口
voidRSInit()
{
TMOD|=0x20;//T1工作方式2
TH1=TL1=0xfd;//裝入初值,以后是自動重載的8位計數(shù)器
TR1=1;//啟動T1
SM0=0;
SM1=1;//方式1
REN=1;//允許接收
EA=1;//開中斷
ES=1;//允許串口中斷
PCON=0x00;//串口波特率不加倍.即設(shè)置SMOD=0;
}
//寫一字節(jié)數(shù)據(jù)到串口,使用程序查詢方式檢測發(fā)送情況
voidRsWriteByte(unsignedcharbyte)
{
ES=0;//關(guān)中斷
SBUF=byte;
while(!TI);//檢測是否發(fā)送完
TI=0;//清0發(fā)送中斷標(biāo)志
ES=1;//開中斷,以允許接收數(shù)據(jù)時使用中斷方式
}
voidserial()interrupt4//串口中斷是4
{
P1=SBUF;
RI=0;//清0接收中斷標(biāo)志
}
/*********************RS232****************************************/
voiddisplay()//顯示接收的數(shù)據(jù)
{
P1=~YKDatas[2];
/*switch(YKDatas[2])
{
case0x3f:
case0x0c:RsWriteByte(YKDatas[0]);break;
default:break;
}*/
//RsWriteByte(YKDatas[1]);
RsWriteByte(YKDatas[2]);
}
voidmain(void)
{
TMOD=0x01;//T0選用方式1(16位定時)
IE=0x82;//開總中斷,開定時器0中斷
YKIn=1;
RSInit();
while(1)
{
YKInit();
//模式1:TH0=(2^16-(413/1.085))/2^8=(65536-381)/256=255;
//TL0=(65536-381)%256=131
TH0=255;
TL0=131;
while(YKIn);//等待低電平,一幀開始
TR0=1;//啟動定時器0,接收紅外遙控器發(fā)來的數(shù)據(jù)
while(!YKend);//等待接收結(jié)束
display();
delayMs(200);
}
}
改進代碼: 由原來的程序查詢方式, 換成