技术热线: 4007-888-234
设计开发

专注差异化嵌入式产品解决方案 给智能产品定制注入灵魂给予生命

开发工具

提供开发工具、应用测试 完善的开发代码案例库分享

技术支持

从全面的产品导入到强大技术支援服务 全程贴心伴随服务,创造无限潜能!

新品推广

提供新的芯片及解决方案,提升客户产品竞争力

新闻中心

提供最新的单片机资讯,行业消息以及公司新闻动态

关于红外遥控的编码与解码的问题

更新时间: 2019-03-23
阅读量:2708

十年专注单片机方案开发的方案公司英锐恩,分享关于红外遥控的编码与解码的问题。英锐恩现提供服务产品涉及主控芯片:8位单片机、16位单片机、32位单片机及各类运算放大器等。

关于红外遥控的编码与解码的问题
一般常用的红外遥控器编码规则都差不多,基本上都同6221原理一样(本站网上有)
1先谈接收:
如果用54,57这类片子做的话有一定的难度(假如要做成实时控制的;比如说你还要驱动显示,驱动步进电机,在加上几个按键)原因就是这类片子没有中断
例程如下(用来解6221;分频比为256)
RF:
      BTFSC PORTB,2;;B2口用做接收口
      GOTO RF1
      BTFSS DOWNBIT;;检测下降沿标制
      CLRF RTCCOUNT
      BSF DOWNBIT;制下降沿标制
      BTFSS UPBIT;;检测上升沿标制
      RETLW 0
      BTFSC IDBIT;;检测码头标制
      GOTO RF3
      MOVLW 2AH
      SUBWF RTCCOUNT,0
      BTFSS STATUS,0
      GOTO RF2
      MOVLW 36H

SUBWF RTCCOUNT,0
      BTFSC STATUS,0
      GOTO RF2
      BTFSC IDBIT
      GOTO RF3
      MOVLW .8
      MOVWF LOOP
      MOVLW .3
      MOVWF LOOPCOUNT
      CLRF DATACOUNT
      BSF IDBIT
      BSF DOWNBIT
      BCF UPBIT
      CLRF RTCCOUNT
      RETLW 0
RF1:
      BTFSS DOWNBIT
      RETLW 0
      BSF UPBIT
      RETLW 0

RF2:
      BCF DOWNBIT
      BCF UPBIT
      BCF IDBIT
      CLRF RTCCOUNT
      RETLW 0     ;遥控接收
RF3:
      MOVLW 02H
      SUBWF RTCCOUNT,0
      BTFSS STATUS,0
      GOTO RF4
      MOVLW 0CH
      SUBWF RTCCOUNT,0
      BTFSS STATUS,0
      GOTO RF4
      GOTO RF2
RF4:
      MOVLW 08H
      SUBWF RTCCOUNT,0
      BTFSC STATUS,0
      BSF 3H,0
      MOVLW 07H
      SUBWF RTCCOUNT,0
      BTFSS STATUS,0
      BCF 3H,0
      RLF DATACOUNT,1
      BSF DOWNBIT
      BCF UPBIT
      CLRF RTCCOUNT
      DECFSZ LOOP,1
      RETLW 0
      MOVLW .8

  MOVWF LOOP
      DECFSZ LOOPCOUNT
      RETLW 0
      BSF RFBIT;;制接收完标制
      BCF DOWNBIT
      BCF UPBIT
      BCF IDBIT
      CLRF RTCCOUNT
      RETLW 0
//////////////////////////////////////////////////////////
TIME:
      BTFSC TIMEPD1
      GOTO TIME1
      MOVF RTCC,0;;(
      MOVWF TIMEONE
      BSF TIMEPD1
      RETLW 0                     ;定时查寻
TIME1:
      MOVF RTCC,0
      SUBWF TIMEONE,0
      BTFSC STATUS,2
      RETLW 0

BCF TIMEPD1
INCF RTCCOUNT,1
RETLW 0
////////////////////////////////////////////////
在这里我是用查询的方式来定时的(RTCCOUNT)只是在解码时不需要去追求时间精度;我是去查RTCC有没有发生跳变如有则表示时间过了256US---RTCCOUNT加一;这样做有一个好处---你不必去管RTCC具体的值是多少,(RTCC去做精确的时钟定时;在这个查询的子程序中你可以去判断键扫,显示刷新,驱动步进电机等等)
相应的C代码如下:
unsigned char   rfcount,
         loop,
         rftime,//查询定时器
         k;
  bit    rfbit, //接收完标制
   lowbit1,
         lowbit2,
  downbit,
  rfgobit;
unsigned char dispcount[5];//结果
#define rfin RC6
////////////////////////////////////////////////////////////////////////////////
rf( )//遥控接收
{
        if(rfbit==0)
        {
        if((lowbit1==0)&&(rfin==0))

 {
        downbit=1;
        rftime=0;
        lowbit1=1;
        return;
}
        if((lowbit1==1)&&(rfin==1))
        {
        lowbit2=1;
        return;
}
        if((lowbit1==1)&&(lowbit2==1)&&(RC6==0))
        {
        lowbit1=0;
        lowbit2=0;
        if((rftime>=40)&&(downbit==1))//遥控接收;
        {
        rfgobit=1;

   loop=0;
        rfcount=0;
        k=1;
        rftime=0;
        return;
        }
        rfcount=rfcount+1;
        loop=loop+1;
        if(rfcount>=31)
        {
        rfgobit=0;
        downbit=0;
        rfcount=0;
        rfbit=1;
        loop=0;
        return;
        }
        if((rftime>=7)&&(rfgobit==1))
        {
        dispcount[k]=dispcount[k]|0x80;
        rftime=0;
        if(loop==8)
        {
        k=k+1;
        loop=0;
        return;
        }
        dispcount[k]=dispcount[k]>>1;

 return;
        }
        if((rftime<5)&&(rfgobit==1))
        {
        dispcount[k]=dispcount[k]&0x7f;
        rftime=0;
        if(loop==8)
        {
        k=k+1;
        loop=0;
        return;
        }
        dispcount[k]=dispcount[k]>>1;
        return;
        }
        }
}
}
(查询子程序同汇编)

假如用中断的话也可用时间查询的方法,只是接收口改用带中断的口线;RB4--RB7,CCP1,CCP2,都可以。建议不要用RB0(他当按键输入最好用);
还有就是解码时的容陷和误码处理(有一种写法是在解码移位时利用进位标制C同时移位;我个人认为不太好,因为只要差一位没接收到,整个接收到的都是误码且浪费时间)
2在谈发送
原理是接收的逆过程
例程如下(用来发6221;分频比为256)
;///////////////////////////////////////////////////////////////////////////////////////////////
READDIGT:
   MOVF SENDLOOP,0
   ADDWF PC,1
   GOTO SENDC4
   GOTO SENDC3
   GOTO SENDC2
   GOTO SENDC1
   GOTO SENDC0
;///////////////////////////////////
SENDC0:
   MOVF C4COUNT,0;;读要发的数据(假设要发5个字)
   RETURN
SENDC1:
   MOVF C3COUNT,0
   RETURN
SENDC2:
   MOVF C2COUNT,0
   RETURN
SENDC3:

  MOVF C1COUNT,0
   RETURN
SENDC4:
   MOVF C0COUNT,0
   RETURN
;///////////////////////////////////
SENDBIT:
   CLRF TIME
   BCF PORTB,1
SENDBIT1:
   CLRWDT
   MOVLW .35
   SUBWF TIME,0
   BTFSS STATUS,2
   GOTO SENDBIT1
   CLRF TIME
   BSF PORTB,1
SENDBIT2:
   CLRWDT
   MOVLW .18
   SUBWF TIME,0

   BTFSS STATUS,2
   GOTO SENDBIT2
   CLRF  SENDLOOP                          ;码头数据发送
//////////////////////////////////////////////
SENDBIT3:
    CLRWDT
   BCF INTCON,7
   CALL READDIGT
   MOVWF SENDCOUNT
   BSF INTCON,7
   CALL SENDDIGT
   INCF SENDLOOP,1
   MOVLW .5
   SUBWF SENDLOOP,0
   BTFSS STATUS,2
   GOTO SENDBIT3
   CLRF TIME
   BCF PORTB,1
SENDDIGT5:
   CLRWDT
   MOVLW .2;;加发一个结束位
   SUBWF TIME,0
   BTFSS STATUS,2
   GOTO SENDDIGT5

   BSF PORTB,1
   BSF STARTBIT
   RETURN
;/////////////////////////////////////////////////////////////////////////////////////////
SENDDIGT:;;实现0和1的发送
   MOVLW .8
   MOVWF LOOPSENDCOUNT
SENDDIGTGO:
   BTFSS SENDCOUNT,7
   GOTO ZERSEND
   CLRF TIME
SENDDIGT1:
   CLRWDT
   BCF PORTB,1
   MOVLW .2
   SUBWF TIME,0
   BTFSS STATUS,2
   GOTO SENDDIGT1
   CLRF TIME
SENDDIGT2:
   CLRWDT
   BSF PORTB,1
   MOVLW .6
   SUBWF TIME,0
   BTFSS STATUS,2
   GOTO SENDDIGT2
   GOTO SENDOVER
ZERSEND:
   CLRF TIME

SENDDIGT3:
   CLRWDT
   BCF PORTB,1
   MOVLW .2
   SUBWF TIME,0
   BTFSS STATUS,2
   GOTO SENDDIGT3
   CLRF TIME
SENDDIGT4:
   CLRWDT
   BSF PORTB,1
   MOVLW .2
   SUBWF TIME,0
   BTFSS STATUS,2
   GOTO SENDDIGT4
SENDOVER:
   RLF SENDCOUNT,1
   DECFSZ  LOOPSENDCOUNT
   GOTO SENDDIGTGO

 RETURN
相应的C代码如下:(C5口是发送口)
#include
#include
#include
unsigned char dispcount[5];//要发送的码值
unsigned char i,k,data,rfbit,zbit,rfgobit;
#pragma interrupt_level 1
interrupt adint(void)
        {
        if(TMR1IF==1)
        {
        TMR1IF=0;
        TMR1H=0b11111100;
        TMR1L=0b00010111;
        rfbit=rfbit+1;//发送指针加一
       send( );
        }
        }
//////////////////////////////////////////
send( )
      {
       if(rfgobit==0)
       {
switch(rfbit)
      {
        case 1 :

   RC5=0;
        break;
        case 6 :
        RC5=1;
        break;
        case 7 :
        RC5=0;
        rfgobit=1;//制发送完标制
        rfbit=0;
        break;
        default :
        break;
}
}
       if(rfgobit==1)
       {
       zbit=dispcount[i]&0b00000001;
       switch(rfbit)
       {
       case 1:
       RC5=1;
       break;
       case 2 :
       if(zbit==0)
       {
       RC5=0;

 rfbit=0;
       rf( );
       }
       break;
       case 3 :
       if(zbit==1)
       {
        RC5=0;
        rfbit=0;
        rf( );
}
       break;
       default :
       break;
}
}
}
//////////////////////////////////////////////
rf( )
       {
        k=k+1;
       if(k==8)
       {
        i=i+1;
        k=0;
        if(i==6)
        {
        i=1;
        rfgobit=0;
        TMR1H=0;

     TMR1L=0;
        RC5=1;
        dispcount[1]=0xaa;
        dispcount[2]=0xbb;
        dispcount[3]=0xcc;
        dispcount[4]=0xdd;
        dispcount[5]=0xee;
        }
        return;
        }
       dispcount[i]=dispcount[i]>>1;
}
//////////////////////////////////////
main( )
        {
        di( );
        TRISC=0b11011111;
        TRISA=0b111111;
        TRISB=0b11111111;
        i=1;
        k=0;
         TMR1H=0b11111100;
        TMR1L=0b00010111;
         T1CON=1;
        TMR1IE=1;
        RC5=1;
        PEIE=1;
        ei( );
        dispcount[1]=0xaa;
        dispcount[2]=0xbb;

 dispcount[3]=0xcc;
        dispcount[4]=0xdd;
        dispcount[5]=0xee;
        while( 1 )
        {
        ;
}
}
这两个程序只是一个演示例程
在实际运用中可变通的把这种发送与接受用于两机之间的通讯(好处是移植性好,抗干扰好且一发一收只要两根线或一根线)另外如要产生载波(38KHZ)的话可用其输出口去调制38KHZ发生源(比如555电路,PWM)来得到,或干脆用软件来实现(不过难度较大;不如用带38KHZ的单片机来做)