① 單片機 紅外解碼
紅外線遙控是目前使用最廣泛的一種通信和遙控手段。由於紅外線遙控裝置具有體積小、功耗低、功能強、
成本低等特點,因而,繼彩電、錄像機之後,在錄音機、音響設備、空凋機以及玩具等其它小型電器裝置上也紛
紛採用紅外線遙控。工業設備中,在高壓、輻射、有毒氣體、粉塵等環境下,採用紅外線遙控不僅完全可靠而且
能有效地隔離電氣干擾。
1 紅外遙控系統
通用紅外遙控系統由發射和接收兩大部分組成。應用編/解碼專用集成電路晶元來進行控制操作,如圖1 所示。
發射部分包括鍵盤矩陣、編碼調制、LED 紅外發送器;接收部分包括光、電轉換放大器、解調、解碼電路。
遙控發射器及其編碼
遙控發射器專用晶元很多,根據編碼格式可以分成兩大類,這里我們以運用比較廣泛,解碼比較容易的一類
來加以說明,現以日本NEC 的uPD6121G 組成發射電路為例說明編碼原理(一般家庭用的DVD、VCD、音響都使用
這種編碼方式)。當發射器按鍵按下後,即有遙控碼發出,所按的鍵不同遙控編碼也不同。這種遙控碼具有以下
特徵:
採用脈寬調制的串列碼,以脈寬為0.565ms、間隔0.56ms、周期為1.125ms 的組合表示二進制的「0」;以脈
寬為0.565ms、間隔1.685ms、周期為2.25ms 的組合表示二進制的「1」.
上述「0」和「1」組成的32 位二進制碼經38kHz 的載頻進行二次調制以提高發射效率,達到降低電源功耗的
目的。然後再通過紅外發射二極體產生紅外線向空間發射
UPD6121G 產生的遙控編碼是連續的32 位二進制碼組,其中前16 位為用戶識別碼,能區別不同的電器設備,
防止不同機種遙控碼互相干擾。該晶元的用戶識別碼固定為十六進制01H;後16 位為8 位操作碼(功能碼)及其
反碼。UPD6121G 最多額128 種不同組合的編碼。
遙控器在按鍵按下後,周期性地發出同一種32 位二進制碼,周期約為108ms。一組碼本身的持續時間隨它包
含的二進制「0」和「1」的個數不同而不同,大約在45~63ms 之間.
2 遙控發射器及其編碼
遙控發射器專用晶元很多,根據編碼格式可以分成兩大類,這里我們以運用比較廣泛,解碼比較容易的一類
來加以說明,現以日本NEC 的uPD6121G 組成發射電路為例說明編碼原理(一般家庭用的DVD、VCD、音響都使用
這種編碼方式)。當發射器按鍵按下後,即有遙控碼發出,所按的鍵不同遙控編碼也不同。這種遙控碼具有以下
特徵:
採用脈寬調制的串列碼,以脈寬為0.565ms、間隔0.56ms、周期為1.125ms 的組合表示二進制的「0」;以脈
寬為0.565ms、間隔1.685ms、周期為2.25ms 的組合表示二進制的「1」
上述「0」和「1」組成的32 位二進制碼經38kHz 的載頻進行二次調制以提高發射效率,達到降低電源功耗的
目的。然後再通過紅外發射二極體產生紅外線向空間發射。
UPD6121G 產生的遙控編碼是連續的32 位二進制碼組,其中前16 位為用戶識別碼,能區別不同的電器設備,
防止不同機種遙控碼互相干擾。該晶元的用戶識別碼固定為十六進制01H;後16 位為8 位操作碼(功能碼)及其
反碼。UPD6121G 最多額128 種不同組合的編碼。
遙控器在按鍵按下後,周期性地發出同一種32 位二進制碼,周期約為108ms。一組碼本身的持續時間隨它包
含的二進制「0」和「1」的個數不同而不同,大約在45~63ms 之間。
遙控信號接收
接收電路可以使用一種集紅外線接收和放大於一體的一體化紅外線接收器,不需要任何外接元件,就能完成
從紅外線接收到輸出與TTL 電平信號兼容的所有工作,而體積和普通的塑封三極體大小一樣,它適合於各種紅外
線遙控和紅外線數據傳輸。
接收器對外只有3 個引腳:Out、GND、Vcc 與單片機介面非常方便
① 脈沖信號輸出接,直接接單片機的IO 口。
② GND 接系統的地線(0V);
③ Vcc 接系統的電源正極(+5V);
② 單片機如何紅外遙控解碼
用單片機的中斷 測試低電平,載波是0.14ms,判斷低電平時幾個0.14ms,就能測出紅外線的碼值
③ 51單片機紅外解碼C程序
單片機採用外部中斷P3.3管腳和紅外接收頭的信號線相連,中斷方式為邊沿觸發方式。並用定時器0計算中斷的間隔時間,來區分前導碼、二進制的「1」、「0」碼。並將8位操作碼提取出來在數碼管上顯示。
// 解碼值在Im[2]中,當IrOK=1時解碼有效。
/* 51單片機紅外遙控解碼程序 */
//用遙控器對准紅外接收頭,按下遙控器按鍵,在數碼管前兩位上就會顯示對應按鍵的編碼
#include <reg52.h>
#define uchar unsigned char
sbit la=P2^6;
sbit wela=P2^7;
uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
uchar f;
#define Imax 14000 //此處為晶振為11.0592時的取值,
#define Imin 8000 //如用其它頻率的晶振時,
#define Inum1 1450 //要改變相應的取值。
#define Inum2 700
#define Inum3 3000
unsigned char Im[4]={0x00,0x00,0x00,0x00};
uchar show[2]={0,0};
unsigned long m,Tc;
unsigned char IrOK;
void delay(uchar i)
{
uchar j,k;
for(j=i;j>0;j--)
for(k=125;k>0;k--);
}
void display()
{
la=0;
P0=table[show[0]];
la=1;
la=0;
wela=0;
P0=0xfe;
wela=1;
wela=0;
delay(5);
P0=table[show[1]];
la=1;
la=0;
P0=0xfd;
wela=1;
wela=0;
delay(5);
} //外部中斷解碼程序
void intersvr1(void) interrupt 2 using 1
{
Tc=TH0*256+TL0; //提取中斷時間間隔時長
TH0=0;
TL0=0; //定時中斷重新置零
if((Tc>Imin)&&(Tc<Imax))
{
m=0;
f=1;
return;
} //找到啟始碼
if(f==1)
{
if(Tc>Inum1&&Tc<Inum3)
{
Im[m/8]=Im[m/8]>>1|0x80; m++;
}
if(Tc>Inum2&&Tc<Inum1)
{
Im[m/8]=Im[m/8]>>1; m++; //取碼
}
if(m==32)
{
m=0;
f=0;
if(Im[2]==~Im[3])
{
IrOK=1;
}
else IrOK=0; //取碼完成後判斷讀碼是否正確
}
//准備讀下一碼
}
}
/*演示主程序*/
void main(void)
{
unsigned int a;
m=0;
f=0;
EA=1;
IT1=1;EX1=1;
TMOD=0x11;
TH0=0;TL0=0;
TR0=1;//ET0=1;
while(1)
{
if(IrOK==1)
{
show[1]=Im[2] & 0x0F; //取鍵碼的低四位
show[0]=Im[2] >> 4;
IrOK=0;
}
for(a=100;a>0;a--)
{
display();
}
}
}
解碼程序這個就能實現
④ 單片機控制紅外遙控編碼解碼中定時器和外部中斷的作用是什麼紅外遙控編碼解碼的大致步驟是什麼
同時使用上定時器 跟 外中斷 的紅外程序,只有解碼程序。而且該方式,只能解析 使用不同時間長度代表數據「0」、「1」 的波形(如數據『1』的時間長度 2倍於數據『0』的時間)。
解析原理:外部中斷接 紅外輸入,當有 紅外信號的時候,該引腳會有波形輸入(N多下降沿),觸發外部中斷,通過記錄 每2次中斷的時間間隔,可以判斷此段時間對應的數據(0/1)。一般「數據」長度為32位數據
注意點:
①初次產生外中斷的時候,並無 時間記錄,不需要進行時間判斷;
②第二次中斷與第一次中斷 之間 的時間,是 紅外的引導碼,該時間一般多倍於數據時間(一般為ms級時間);
③第三次中斷與第二次中斷的時間,即為 第一個數據 的時間;
④第34次中斷與第33次中斷的時間間隔,即為 第32個數據的時間;
⑤後面 可能存在 停止位,是否存在,由遙控器決定;不過,一般都直接忽略該位,除非該位是由自己製作的遙控器 發出 的校驗位;
⑥後面 可能存在 連發碼,是否存在,由遙控器決定;
另外:一般紅外數據的每個位元組都是LSB在前,MSB在後的( 低位先發,高位後發)
軟體要處理以下情況:
①干擾的處理,有些紅外接收頭不僅僅對38KHz頻率光有反應,可能對人體紅外、日光燈紅外一樣有反應,那就存在干擾。如果它只產生一次干擾,就會使系統卡在引導碼接收階段;
②引導碼時間過短、過長 的處理;
③接收數據位數不足的處理;
④完成32位數據接收後,處理接收爛尾:後面不會有中斷(如果需接收停止位、連發碼,就增加對應數據長度),需要停止計時。
⑤進行數據校對,一般第一位元組跟第二位元組互為反碼,第三位元組跟第四位元組互為反碼,而且第一位元組 代表 一個地址、一個密碼,只有地址、密碼正確,才能算合法的操作。
⑤ 關於51單片機紅外解碼程序,哪位大俠幫我看下
我以前做的一個項目,紅外遙控開關,解碼部分的code,供參考
6121碼,外部中斷0,at89s52
void int0() interrupt 0 //外部中斷1服務函數,紅外解碼程序
{
static uchar wei; //定義靜態變數
static uchar pp; //定義靜態變數
if(tt<56&&tt>50) {d2=0; tt=0;pp=0;wei=0;}//起始信號符合,將d2標記為0,各變數清零
if(tt>11)tt=0;
if(d2==0&&tt>=4)
{
buf[pp]>>=1;
if(tt>5) buf[pp]|=0x80; //如果時間大於780us ,則視為收到數據1
wei++;
if(wei==8)
{
pp++;
wei=0;
if(pp==4) { pp=0; d2=1;} //接收滿4個位元組,標志位清除
} //在 d2為0期間進入中斷8次,說明已經收到一個位元組數據,位元組號加1
}
tt=0;//每次進入中斷都清零
}
void timer1() interrupt 3 //紅外解碼計時
{
tt++;
}
⑥ 單片機紅外解碼
紅外解碼程序!
/*-----------------------------------------------
名稱:遙控器紅外解碼液晶顯示
------------------------------------------------*/
#include<reg52.h> //包含頭文件,一般情況不需要改動,頭文件包含特殊功能寄存器的定義
#include<stdio.h>
#include<intrins.h>
#define TURE 1
#define FALSE 0
sbit IR=P3^2; //紅外介面標志
sbit RS = P2^4;//Pin4
sbit RW = P2^5;//Pin5
sbit E = P2^6;//Pin6
#define Data P0//數據埠
unsigned int hour,minute,second,count;
char code Tab[16]="0123456789ABCDEF";
char data TimeNum[]=" ";
char data Test1[]=" ";
/******************************************************************/
/* 變數聲明 */
/******************************************************************/
unsigned char irtime;//紅外用全局變數
bit irpro_ok,irok;
unsigned char IRcord[4]; //處理後的紅外碼,分別是 客戶碼,客戶碼,數據碼,數據碼反碼
unsigned char irdata[33]; //33個高低電平的時間數據
/******************************************************************/
/* 函數聲明 */
/******************************************************************/
void Ir_work(void);
void Ircordpro(void);
void ShowString (unsigned char line,char *ptr);
/******************************************************************/
/* 定時器0中斷服務函數 */
/******************************************************************/
void tim0_isr (void) interrupt 1 using 1//定時器0中斷服務函數
{
irtime++; //用於計數2個下降沿之間的時間
}
/******************************************************************/
/* 外部中斷0函數 */
/******************************************************************/
void ex0_isr (void) interrupt 0 using 0//外部中斷0服務函數
{
static unsigned char i; //接收紅外信號處理
static bit startflag; //是否開始處理標志位
if(startflag)
{
if(irtime<63&&irtime>=33)//引導碼 TC9012的頭碼,9ms+4.5ms
i=0;
irdata[i]=irtime;//存儲每個電平的持續時間,用於以後判斷是0還是1
irtime=0;
i++;
if(i==33)
{
irok=1;
i=0;
}
}
else
{irtime=0;startflag=1;}
}
/******************************************************************/
/* 定時器0初始化 */
/******************************************************************/
void TIM0init(void)//定時器0初始化
{
TMOD=0x02;//定時器0工作方式2,TH0是重裝值,TL0是初值
TH0=0x00; //重載值
TL0=0x00; //初始化值
ET0=1; //開中斷
TR0=1;
}
/******************************************************************/
/* 外部中斷初始化 */
/******************************************************************/
void EX0init(void)
{
IT0 = 1; //指定外部中斷0下降沿觸發,INT0 (P3.2)
EX0 = 1; //使能外部中斷
EA = 1; //開總中斷
}
/******************************************************************/
/* 紅外鍵值處理 */
/******************************************************************/
void Ir_work(void) //紅外鍵值散轉程序
{
TimeNum[5] = Tab[IRcord[0]/16]; //處理客戶碼並顯示
TimeNum[6] = Tab[IRcord[0]%16];
TimeNum[8] = Tab[IRcord[1]/16]; //處理客戶碼並顯示
TimeNum[9] = Tab[IRcord[1]%16];
TimeNum[11] = Tab[IRcord[2]/16]; //處理數據碼並顯示
TimeNum[12] = Tab[IRcord[2]%16];
TimeNum[14] = Tab[IRcord[3]/16]; //處理數據反碼並顯示
TimeNum[15] = Tab[IRcord[3]%16];
ShowString(1,TimeNum);//顯示處理過後的碼值
irpro_ok=0; //處理完成後清楚標志位
}
/******************************************************************/
/* 紅外解碼函數處理 */
/******************************************************************/
void Ircordpro(void)//紅外碼值處理函數
{
unsigned char i, j, k;
unsigned char cord,value;
k=1;
for(i=0;i<4;i++) //處理4個位元組
{
for(j=1;j<=8;j++) //處理1個位元組8位
{
cord=irdata[k];
if(cord>7)//大於某值為1,這個和晶振有絕對關系,這里使用12M計算,此值可以有一定誤差
{
value=value|0x80;
}
else
{
value=value;
}
if(j<8)
{
value=value>>1;
}
k++;
}
IRcord[i]=value;
value=0;
} irpro_ok=1;//處理完畢標志位置1
}
/******************************************************************/
/* 微秒延時函數 */
/******************************************************************/
void DelayUs(unsigned char us)//delay us
{
unsigned char uscnt;
uscnt=us>>1;/* Crystal frequency in 12MHz*/
while(--uscnt);
}
/******************************************************************/
/* 毫秒函數聲明 */
/******************************************************************/
void DelayMs(unsigned char ms)//delay Ms
{
while(--ms)
{
DelayUs(250);
DelayUs(250);
DelayUs(250);
DelayUs(250);
}
}
/******************************************************************/
/* 寫入命令函數 */
/******************************************************************/
void WriteCommand(unsigned char c)
{
DelayMs(5);//操作前短暫延時,保證信號穩定
E=0;
RS=0;
RW=0;
_nop_();
E=1;
Data=c;
E=0;
}
/******************************************************************/
/* 寫入數據函數 */
/******************************************************************/
void WriteData(unsigned char c)
{
DelayMs(5); //操作前短暫延時,保證信號穩定
E=0;
RS=1;
RW=0;
_nop_();
E=1;
Data=c;
E=0;
RS=0;
}
/******************************************************************/
/* 寫入位元組函數 */
/******************************************************************/
void ShowChar(unsigned char pos,unsigned char c)
{
unsigned char p;
if (pos>=0x10)
p=pos+0xb0; //是第二行則命令代碼高4位為0xc
else
p=pos+0x80; //是第二行則命令代碼高4位為0x8
WriteCommand (p);//寫命令
WriteData (c); //寫數據
}
/******************************************************************/
/* 寫入字元串函數 */
/******************************************************************/
void ShowString (unsigned char line,char *ptr)
{
unsigned char l,i;
l=line<<4;
for (i=0;i<16;i++)
ShowChar (l++,*(ptr+i));//循環顯示16個字元
}
/******************************************************************/
/* 初始化函數 */
/******************************************************************/
void InitLcd()
{
DelayMs(15);
WriteCommand(0x38); //display mode
WriteCommand(0x38); //display mode
WriteCommand(0x38); //display mode
WriteCommand(0x06); //顯示游標移動位置
WriteCommand(0x0c); //顯示開及游標設置
WriteCommand(0x01); //顯示清屏
}
/******************************************************************/
/* 主函數 */
/******************************************************************/
void main(void)
{
EX0init(); //初始化外部中斷
TIM0init();//初始化定時器
InitLcd(); //初始化液晶
DelayMs(15);
sprintf(Test1," haixiang MCU "); //顯示第一行固定信息
ShowString(0,Test1);
sprintf(TimeNum,"Code ");//顯示第二行固定信息
ShowString(1,TimeNum);
while(1)//主循環
{
if(irok) //如果接收好了進行紅外處理
{
Ircordpro();
irok=0;
}
if(irpro_ok) //如果處理好後進行工作處理,如按對應的按鍵後顯示對應的數字等
{
Ir_work();
}
}
}
⑦ 單片機如何實現紅外遙控
以下文件是51單片機實現遙控解碼,通過數碼管顯示鍵碼的程序,P0口驅動數碼管段選,p2.6和p2.7為數碼管位選,接收頭連到P3.2口。此程序以通過驗證,可以直接編譯使用,另外還有一個繼電器和蜂鳴器的控制,不用可以屏蔽掉。
;********************************************************************************
;* 描述: *
;* 遙控鍵值讀取器 *
;* 數碼管顯示, P0口為數碼管的數據口 *
;* *
;********************************************************************************
;遙控鍵值解碼-數碼管顯示 *
;********************************************************************************/
#include <reg51.h>
#include <intrins.h>
void IR_SHOW();
void delay(unsigned char x);//x*0.14MS
void delay1(unsigned char ms);
void beep();
sbit IRIN = P3^2;
sbit BEEP = P3^7;
sbit RELAY= P1^3;
sbit GEWEI= P2^7;
sbit SHIWEI= P2^6;
unsigned char IRCOM[8];
unsigned char code table[16] =
{0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};
main()
{
IE = 0x81; //允許總中斷中斷,使能 INT0 外部中斷
TCON = 0x1; //觸發方式為脈沖負邊沿觸發
delay(1);
IRIN=1;
BEEP=1;
RELAY=1;
for(;;)
{
IR_SHOW();
}
} //end main
void IR_IN() interrupt 0 using 0
{
unsigned char i,j,k,N=0;
EA = 0;
I1:
for (i=0;i<4;i++)
{
if (IRIN==0) break;
if (i==3) {EA =1;return;}
}
delay(20);
if (IRIN==1) goto I1; //確認IR信號出現
while (!IRIN) //等 IR 變為高電平
{delay(1);}
for (j=0;j<4;j++)
{
for (k=0;k<8;k++)
{
while (IRIN) //等 IR 變為低電平
{delay(1);}
while (!IRIN) //等 IR 變為高電平
{delay(1);}
while (IRIN) //計算IR高電平時長
{
delay(1);
N++;
if (N>=30) {EA=1;return;}
}
IRCOM[j]=IRCOM[j] >> 1;
if (N>=8) {IRCOM[j] = IRCOM[j] | 0x80;}
N=0;
}//end for k
}//end for j
if (IRCOM[2]!=~IRCOM[3]) {EA=1;return;}
IRCOM[5]=IRCOM[2] & 0x0F;
IRCOM[6]=IRCOM[2] & 0xF0;
IRCOM[6]=IRCOM[6] >> 4;
beep();
EA = 1;
}
void IR_SHOW()
{
P0 = table[IRCOM[5]];
GEWEI = 0;
SHIWEI = 1;
delay1(4);
P0 = table[IRCOM[6]];
SHIWEI = 0;
GEWEI = 1;
delay1(4);
}
void beep()
{
unsigned char i;
for (i=0;i<100;i++)
{
delay(5);
BEEP=!BEEP;
}
BEEP=1;
}
void delay(unsigned char x)//x*0.14MS
{
unsigned char i;
while(x--)
{
for (i = 0; i<13; i++) {}
}
}
void delay1(unsigned char ms)
{
unsigned char i;
while(ms--)
{
for(i = 0; i<120; i++)
{
_nop_();
_nop_();
_nop_();
_nop_();
}
}
}