单片机学习小组
直播中

高欢

7年用户 153经验值
私信 关注

DIY单片机红外线按键解码程序分享


1.紅外光按波長範圍分為近紅外、中紅外、遠紅外、極紅外4類。
2.紅外線遙控是利用近紅外光傳送遙控指令的,波長為0.76um~1.5um。
3.用近紅外作為遙控光源,是因為目前紅外發射器件與紅外接收器件的發光與受光峰值波長一般為0.8um~0.94um,這樣可以獲得較高的傳輸效率及較高的可靠性。

1.紅外遙控系統主要由紅外遙控發射裝置、紅外接收設備、遙控微處理機等組成。
2.紅外遙控發射裝置,其主要元件為紅外發光二極體。单只红外发光二极管的发射功率约 100mW。
3.接收電路的紅外接收管是一種光敏二極體,使用時要給紅外接收二極體加反向偏壓,它才能正常工作而獲得高的靈敏度。

1.常用的红外线信号传输协议有 ITT 协议、 NEC 协议、 Nokia NRC 协议、 Sharp 协议、 Philips RC-5 协议、Philips RC-6协议,
Philips RECS-80协议,以及 Sony SIRC 协议等。
2.協議組成 :一般由引導碼 ,用戶碼,資料碼,重複碼或資料碼的反碼和結束碼構成。
3.載波:常用的有33K,36K,36.6K,38K,40K,56K,無載波
4.占空比:常用的有1/3,1/2,不常用1/4
5.調製方式:脈寬調製,相位調製,脈衝位置調製

在東亞地區比較常用的紅外線傳輸協議是NEC協議,故我們主要介紹NEC協議即6122協議。

红外线遥控的解码程序

#include
#define u8 unsigned char
#define u16  unsigned int
u8 irtime = 0;
u8 startflag = 0;
u8 irdata[33] = {0};
u8 bitnum = 0;
u8 irreceive = 0;
u8 ircore[4] = {0};
u8 irpros = 0;
u8 display[8] = {0};
u8 code smg_du[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x6f,0x77,0x39,0x5e,0x79,0x71,0x00};
u8 code smg_we[] = {0x08,0x18,0x28,0x38,0x48,0x58,0x68,0x78};
//************************************************
//延时函数  在12MHZ的晶振下
//大约延时 50us
//***********************************************
void delay_time(u16 t)
{
u8 j;
for(;t > 0;t --)
for(j = 19;j > 0;j --);
}
//************************************************
//延时函数  在12MHZ的晶振下
//大约延时 50ms
//***********************************************
void delay_time(u16 t)
{
u8 j;
for(;t > 0;t --)
for(j = 6245;j > 0;j --);
}
//************************************************
//外部中断 0
//***********************************************
void int0init(void )
{
IT0 = 1;
EX0 = 1;
EA = 1;
}
//************************************************
//开启中断定时器0  工作在 2 模式下
//***********************************************
void timer0init(void)
{
TMOD = 0x02;
TH = 0;
TL = 0;
ET0 = 1;
EA = 1;
TR = 1;
}
void irwork()//每个字节用2个数码管显示出来
{
diaplay[0] = ircode[0]/16;
diaplay[1] = ircode[0]%16;
diaplay[2] = ircode[1]/16;
diaplay[3] = ircode[1]%16;
diaplay[4] = ircode[2]/16;
diaplay[5] = ircode[2]%16;
diaplay[6] = ircode[3]/16;
diaplay[7] = ircode[3]%16;
}
void displayir()                            //显示程序
{
    u8 i = 0;
    for(i = 0;i < 8;i++)
    {
    P1 = smg_du[disp];
P2 = smg_we;
delay_50us(20);
    }
}
void irpros()                //处理红外线按键的信息
{
u8 k = 1, v = 0;
u8 value = 0;
u8 j = 0;
for(j = 0 ; j < 4; j++)
{
     for(i = 0 ; i < 8; i++)
{
value = value >> 0;
if(irdata[k] > 6)                  //判断每一位到底是 0  还是  1 0的时间大约是4.4ms  1的时间大约是 8.8ms
{
value = value |0x80;//查看每一个位是否为  1
}
k++;
}
ircode[j] = value;        //将四个字节的红外线代码存到数组中
}
irpros = 1;
}
void main()  
{
timer0init();                    //定时器初始化
int0init();                    //外部中断初始化
while(1)
{
if(irreceive)
{
irpros();
irreceive = 0;
}
if(irpros)
{
irwork();
irpros = 0;
}  
display();
}
}
void  timer0 interrupt 1            //定时器  0   工作在  2   模式下
{
irtime++;   //255
}
void int0init interrupt 0            //外部中断 0
{
if(startflag)
{
    if(irtime > 32)                     //大约是引导码得时间
    {
    bitnum = 0;
    }
    irdata[bitnmu] = irtime;            //开始提取引导码第一个位
    irtime = 0;
    bitnum++;
    if(bitnum == 33)            //引导码  客户码  数据码   数据反码 总共33 个位
    {
       bitnum = 0;
    irreceive = 1;                 //红外线接受完毕
    }

}
else
{
   sartflag = 1;                //接受到红外线的标志
   irtime = 0;
}
}




红外发送方:


#include
static bit OP;                                                                                                 // 红外发射管的亮灭
static unsigned int count;                                                                         // 延时计数器
static unsigned int endcount;                                                                         // 终止延时计数
static unsigned int temp;                                                                                 // 按键
static unsigned char flag;                                                                         // 红外发送标志
static unsigned char num;
***it ir_in=P3^4;
char iraddr1;                                                                                                 //十六位地址的第一个字节
char iraddr2;                                                                                                 //十六位地址的第二个字节
unsigned char code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,    //红外数据传输
0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};                                                 // 共阳数码管 0~~f

void SendIRdata(char p_irdata);
void delay(unsigned int);

void keyscan();
/****************** 主函数**************************/
void main(void)
{
         num=0;
         P2=0x3f;
         count = 0;
         flag = 0;
         OP = 0;
         ir_in= 0;
         EA = 1;                                                                                         //允许CPU中断
         TMOD = 0x11;                                                                                 //设定时器0和1为16位模式1
         ET0 = 1;                                                                                         //定时器0中断允许
         TH0 = 0xFF;
         TL0 = 0xE6;                                                                                 //设定时值0为38K 也就是每隔26us中断一次
         TR0 = 1;                                                                                        //开始计数
         iraddr1=3;                                                                                        //00000011
         iraddr2=252;                                                                                //11111100
         do{
                 keyscan();
         }while(1);
}
/*********************** 定时器0中断处理 **********************/
void timeint(void) interrupt 1
{
         TH0=0xFF;
         TL0=0xE6;                                                                                 //设定时值为38K 也就是每隔26us中断一次
         count++;
         if (flag==1)
         {
                 OP=~OP;
         }
         else
         {
                 OP = 0;
         }
         ir_in= OP;
}
void SendIRdata(char p_irdata)
{

         //红外数据传输
         int i;
         char irdata=p_irdata;
         //发送9ms的起始码
         endcount=223;
         flag=1;
         count=0;
         do{}while(count          /********************** 发送4.5ms的结果码***********************/
         endcount=117;
         flag=0;
         count=0;
         do{}while(count          /******************** 发送十六位地址的前八位*******************/
         irdata=iraddr1;
         for(i=0;i<8;i++)
         {
                 /*****先发送0.56ms的38KHZ红外波(即编码中0.56ms的低电平)*****/
                 endcount=10;
                 flag=1;
                 count=0;
                 do{}while(count                  /***********停止发送红外信号(即编码中的高电平)*************/
                 if(irdata-(irdata/2)*2) //判断二进制数个位为1还是0
                 {
                         endcount=41; //1 为宽的高电平
                 }
                 else
                 {
                         endcount=15; //0 为窄的高电平
                 }
                 flag=0;
                 count=0;
                 do{}while(count                  irdata=irdata>>1;
         }
         /********************** 发送十六位地址的后八位******************/
         irdata=iraddr2;
         for(i=0;i<8;i++)
         {
                 endcount=10;
                 flag=1;
                 count=0;
                 do{}while(count                  if(irdata-(irdata/2)*2)
                 {
                         endcount=41;
                 }
                 else
                 {

                         红外数据传输
                         endcount=15;
                 }
                 flag=0;
                 count=0;
                 do{}while(count                  irdata=irdata>>1;
         }
         /****************** 发送八位数据********************************/
         irdata=p_irdata;
         for(i=0;i<8;i++)
         {
                 endcount=10;
                 flag=1;
                 count=0;
                 do{}while(count                  if(irdata-(irdata/2)*2)
                 {
                         endcount=41;
                 }
                 else
                 {
                         endcount=15;
                 }
                 flag=0;
                 count=0;
                 do{}while(count                  irdata=irdata>>1;
         }
         /*********************** 发送八位数据的反码**********************/
         irdata=~p_irdata;
         for(i=0;i<8;i++)
         {
                 endcount=10;
                 flag=1;
                 count=0;
                 do{}while(count                  if(irdata-(irdata/2)*2)
                 {
                         endcount=41;
                 }
                 else
                 {
                         endcount=15;
                 }
                 flag=0;
                 count=0;
                 do{}while(count                  irdata=irdata>>1;
         }

         //红外数据传输
         endcount=10;
         flag=1;
         count=0;
         do{}while(count          flag=0;
}

void delay(unsigned int z)
{
         unsigned char x,y;
         for(x=z;x>0;x--)
         for(y=110;y>0;y --);
}
/*********************4 ×4键盘扫描按下按键发射数据************************/
void keyscan()
{
         P1=0xfe;
         temp=P1;
         temp=temp&0xf0;
         while(temp!=0xf0)
         {
                 temp=P1;
                 switch(temp)
                 {
                         case 0xee:num=1;
                         break;
                         case 0xde:num=2;
                         break;
                         case 0xbe:num=3;
                         break;
                         case 0x7e:num=4;
                         break;
             }
                 while(temp!=0xf0)
                 {
                         temp=P1;
                         temp=temp&0xf0;
                 }
                 P2=table[num-1];
                 SendIRdata(table[num -1]);
         }
         P1=0xfd;
         temp=P1;
         temp=temp&0xf0;
         while(temp!=0xf0)
         {
                 temp=P1;
                 switch(temp)
                 {
                 case 0xed:num=5;
                 break;
                 case 0xdd:num=6;
                 break;
                 case 0xbd:num=7;
                 break;
                 case 0x7d:num=8;
                 //                红外数据传输
                 break;
                 }
                 
                 while(temp!=0xf0)
                 {
                         temp=P1;
                         temp=temp&0xf0;
                 }
                 P2=table[num-1];
                 SendIRdata(table[num -1]);
         }
         P1=0xfb;
         temp=P1;
         temp=temp&0xf0;
         while(temp!=0xf0)
         {
                 temp=P1;
                 switch(temp)
                 {
                         case 0xeb:num=9;
                         break;
                         case 0xdb:num=10;
                         break;
                         case 0xbb:num=11;
                         break;
                         case 0x7b:num=12;
                         break;
                 }
                 while(temp!=0xf0)
                 {
                         temp=P1;
                         temp=temp&0xf0;
                 }
                 P2=table[num-1];
                 SendIRdata(table[num -1]);
         }
         P1=0xf7;
         temp=P1;
         temp=temp&0xf0;
         while(temp!=0xf0)
         {
                 temp=P1;
                 switch(temp)
                 {
                         case 0xe7:num=13;
                         break;
                         case 0xd7:num=14;
                         break;
                         case 0xb7:num=15;
                         break;
                         case 0x77:num=16;
                         break;
                 }
                 while(temp!=0xf0)
                 {
                         temp=P1;
                         temp=temp&0xf0;
                 }
         
                 //红外数据传输
                 P2=table[num-1];
                 SendIRdata(table[num -1]);
         }
}


红外的接受方:


#include"reg52.h"   
#define uchar unsigned char   
#define uint unsigned int
uchar dis_num,num,num1,num2,num3;
***it led=P1^0;
unsigned char code table[]={
0xc0,0xf9,0xa4,0xb0,
0x99,0x92,0x82,0xf8,
0x80,0x90,0x88,0x83,
0xc6,0xa1,0x86,0x8e};                                                                         // 共阳数码管 0~~f
***it prem =P3^2;                                                                            //定义遥控头的接收脚
uchar ram[4]={0,0,0,0};                                                                        // 存放接受到的4个数据  地址码16位+按键码8位+按键码取反的8位
void delaytime(uint time)                                                                 //延迟90uS
{
         uchar a,b;
         for(a=time;a>0;a--)
         {
                 for(b=40;b>0;b--);
         }
}
void rem()interrupt 0                                                                    //中断函数
{
         uchar ramc=0;                                                                      //定义接收了4个字节的变量
         uchar count=0;                                                                      //定义现在接收第几位变量
         uint i=0;                                                                                //此处变量用来在下面配合连续监测9MS 内是否有高电平
         prem=1;
         for(i=0;i<1100;i++)                                                                   //以下FOR语句执行时间为8MS左右
         {
                 if(prem)                                                                   //进入遥控接收程序首先进入引导码的前半部判断,即:是否有9MS左右的低电平
                 return;                                                                       //引导码错误则退出
         }
         while(prem!=1);                                                                   //等待引导码的后半部 4.5 MS 高电平开始的到来。
         delaytime(50);                                                                  //延时大于4.5MS时间,跨过引导码的后半部分,来到真正遥控数据32位中
                                                                                                 //第一位数据的0.56MS开始脉冲
         for(ramc=0;ramc<4;ramc++)                                                // 循环4次接收4个字节
         {   
                 for(count=0;count<8;count++)                                  //循环8次接收8位(一个字节)
                 {
                         while(prem!=1);                                                   //开始判断现在接收到的数据是0或者1 ,首先在这行本句话时,
                                                                                                 //保已经进入数据的0.56MS 低电平阶段
                                                                                                 //等待本次接受数据的高电平的到来。
                         delaytime(9);                                                //高电平到来后,数据0 高电平最多延续0.56MS,而数据1,高电平可

                                                                                                 // 红外数据传输
                                                                                                 //延续1.66MS大于0.8MS 后我们可以再判断遥控接收脚的电平,
                         if(prem)                                                            //如果这时高电平仍然在继续那么接收到的数据是1的编码
                         {
                         ram[ramc]=(ram[ramc]<<1)+1;                                // 将目前接收到的数据位1放到对应的字节中
                         delaytime(11);                                                         //如果本次接受到的数据是1,那么要继续延迟1MS,这样才能跨入
                                                                                                 //下个位编码的低电平中(即是开始的0.56MS中)
                         }
                         else                                                                    //否则目前接收到的是数据0的编码
                         ram[ramc]=ram[ramc]<<1;                                 // 将目前接收到的数据位0放到对应的字节中
                 }                                                                  //本次接收结束,进行下次位接收,此接收动作进行32次,正好完成4个字节的接收
         }
         if(ram[2]!=(~(ram[3]&0x7f)))                                             //本次接收码的判断
         {
         for(i=0;i<4;i++)                                                                    //没有此对应关系则表明接收失败,清除接受到的数据
         ram=0;
         return ;
         }
         dis_num=ram[2];                                                                  //将接收到的按键数据赋给显示变量
}
main()
{
         IT0=1;                                                                                 // 设定INT0为边沿触发
         EX0=1;                                                                                    //打开外部中断0
         EA=1;                                                                                 // 全局中断开关打开
         while(1)
         {
                 switch(dis_num)
                 {
                         case 0x81: num=0; break;
                         case 0xcf: num=1; break;
                         case 0x92: num=2; break;
                         case 0x86: num=3; break;
                         case 0xcc: num=4; break;
                         case 0xa4: num=5; break;
                         case 0xa0: num=6; break;
                         case 0x8f: num=7; break;
                         case 0x80: num=8; break;
                         case 0x84: num=9; break;
                         case 0x88: num=10;break;
                         case 0xe0: num=11;break;
                         case 0xb1: num=12;break;
                         case 0xc2: num=13;break;
                         case 0xb0: num=14;break;
                         case 0xb8: num=15;break;
                 }
                 P2=table[num];
                 P1=0x01;
                 delaytime(5);
         }
}  


更多回帖

发帖
×
20
完善资料,
赚取积分