51微控制器NEC紅外遙控器解碼

【前言】
紅外遙控器常用的調製制式主要分為兩種,這裡主要講解以NEC調製方式的遙控器解碼過程。

廢話不多說,直接上時序圖!( 更多詳細資料自行查詢)

總時序圖:

前導碼:

‘ 0 ‘ 和 ‘ 1 ‘ 編碼表示:

【解碼思路】
—–1、 使用定時器計算高低電平的時間
—–2、 使用陣列存放一組完整的電平時間編碼
—–3、 計算電平的時長
—–4、 組合資料,獲得編碼值,存放於陣列
—–5、 LCD1602管顯示

【編寫程式】

/*--------------------------------------------------------
程式功能: 51紅外遙控器解碼程式
功能詳情: 遙控解碼後送數碼管依次顯示,共4位元組	.( 12MHz晶振 )
編寫時間: 2017/9/7
編寫人:	吳**
--------------------------------------------------------*/
#include<reg52.h>
#include<string.h>
#define uchar unsigned char
#define uint unsigned int
#define display_data P0
sbit LCD_RS=P1^0;
sbit LCD_RW=P1^1;
sbit LCD_EN=P1^2;					   
uchar irtime = 0;
uchar startflag = 0;	// 起始標誌位
uchar ir_rc_ok = 0;		// 紅外高/低電平時間接收完成標誌位 
uchar bitnum = 0;
uchar ir_change_ok = 0;		// 轉碼完成標誌位
uchar irdata[33];		// 電平時間陣列
uchar ircode[4];	// 遙控解碼陣列
// 字元編碼
uchar str[17]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F',' '};
/********* 延時函式 **********/
void delayms(uint xms)
{
uint i,j;
for(i=xms;i>0;i--)
for(j=110;j>0;j--);
}	  
/********** 系統初始化 ********/
void sysinit()
{
// 初始化定時器
TMOD = 0x02;	// 設定定時器0為工作方式2 (0~255)
TH0 = 0x00;		// 賦初值
TL0 = 0x00;
TR0 = 1;	// 啟動定時器0
ET0 = 1;	// 使能定時器0
// 初始換外部中斷1
IT1 = 1;	//	下降沿觸發
EX1 = 1;		// 開外部中斷0
EA = 1;		// 開總中斷
}
/************ 轉換編碼 *************/
void changecode()
{
uchar k = 1;
uchar i,j;
uchar value;
if(ir_rc_ok ==1)		// 如果ir接收完成就進行轉碼
{
for(i=0;i<4;i  )	// 獲取前導碼後的4個位元組資料
{
for(j=0;j<8;j  )
{
value = value>>1;	// 因低位在前,所以需右移 
if(irdata[k]>6&&irdata[k]<10)		// 判斷資料是否為" 1 ",從第2位開始接收
{
value |= 0x80;
}
k  ;
}
ircode[i] = value;		// 儲存1個位元組資料 
}
ir_change_ok = 1;		// 編碼轉換完成標誌位
ir_rc_ok = 0;		// ir接收標誌復位	
}
}
/********** 1602寫指令 ***********/
void write_com(uchar com)	  
{
LCD_RS=0;		   //RS =‘low’為寫指令
LCD_RW=0;
display_data=com;
delayms(5);
LCD_EN=1;
delayms(5);
LCD_EN=0;			
}
/*********** 1602寫資料 ***********/
void write_data(uchar wdata)	
{
LCD_RS=1;			//RS ='high'為寫資料
LCD_RW=0;
display_data=wdata;
delayms(3);
LCD_EN=1;
delayms(5);
LCD_EN=0;			
}
/*********** 1602顯示屏初始化 ***********/
void disinit()
{
LCD_EN=0;			 		 //初始化使能
write_com(0x38);	 		 //設定顯示模式
write_com(0x0f);	 		 //設定顯示開/關及游標
write_com(0x06);	  		//設定指標位置及移屏
write_com(0x80); 	  //資料指標初始化(  0x10 指標移至顯示區外)
}
/************* 1602顯示解碼結果 *****************/
void display()
{
uchar num,high,low;
if(ir_change_ok == 1)		// 判斷編碼是否轉換完畢
{
ir_change_ok = 0;
write_com(0x80);		// 重複呼叫時,顯示指標復位
for(num=0;num<4;num  )
{
high = ircode[num]/16;
low = ircode[num]%16;
write_data(str[high]);
write_data(str[low]);
write_data(str[16]);	// 顯示空格
}
}
}
/********** 主函式 *************/
void main()
{
sysinit();		// 初始化
disinit();		// 顯示屏初始化
while(1)
{
changecode();	// 獲取編碼
display();		// 顯示解碼後的編碼
}
}
/********* 定時器0中斷服務函式 ***********/
void t0()interrupt 1
{
irtime  ;
}
/********* 外部中斷1服務函式 ***********/
void exint1() interrupt 2
{
if(startflag)	
{
if(irtime>32) 		// 檢測前導碼	
{
bitnum=0;			
}			
irdata[bitnum]=irtime;		// 從前導碼開始接收資料
irtime=0;
bitnum  ;
if(bitnum==33)		// 前導碼 4位元組資料,共 33 位元 
{
bitnum=0;
ir_rc_ok = 1;
}		
}
else
{
startflag = 1;
irtime = 0;
}
}