一个遥控解码程序说明实际NEC码过程

2019-04-15 15:58发布

 #define WD_END           (5u+1u)  //    5ms
 #define RM_OFTM          60u   //   20ms
 #define RM_OFTM_R     100u  //   100ms
  /*以下的时序值都经过特殊处理*/
 #define RC_HEADER0           (13300000ul/RC_CLK) //13.3MS
 #define RC_HEADER1           (13700000ul/RC_CLK) //13.7MS
 #define RC_REPEAT0            (11050000ul/RC_CLK) //11.05MS
 #define RC_REPEAT1            (11450000ul/RC_CLK) //11.45MS
 #define RC_CODE1                (2250000ul/RC_CLK) //2.25MS 
 #define RC_CODE1_GOSA   ( 200000ul/RC_CLK) //0.2MS
 #define RC_CODE0                (1125000ul/RC_CLK) //1.125MS 
 #define RC_CODE0_GOSA    ( 100000ul/RC_CLK) //0.1MS 
 #define RC_CODE_0_1        (2000000ul/RC_CLK) //2 MS 
         对以上定义补充说明:程序中RC_CLK是 1185ul,这是因为分频运算后1/27M×32=1.185(周期乘以MCU位数,注意单位跟M对应的是US)。这是表示一个CLK是对应1.185微秒,由于遥控计时器是对RCLK进行计数,所以要有一个转换,M×RCLK(对应的时间)=13.3MS,即M=13.3M/RCLK=13.3×1000US/1.185US得对应的参考值。
 /*定义解码所需的标志*/
 static U32 InputData;                            //转储数据
 static U8 rcv_header = WRONG;        //解出头码标志
 static U8 rcv_repeat = WRONG;        //解出重发标志
static U8 BitCount;                                //位计数器
static U8 RcOffTimer;                          //遥控发码的剩余时间
 U8 OneCodeTime; 
void remocon_initial (void)  
{
 /*初始化IR相应的寄存器*/
        BitCount = 0; 
}
#pragma  INTERRUPT remocon_edge         //边沿中断触发函数,由电平跳变即执行
void remocon_edge (void)
{
 /*在IR寄存器检测正常的情况下,继续执行*/
         U16 pls_cnt   = IR_MFTCMPRLD;
         if( (RC_HEADER0 <= pls_cnt) && (pls_cnt <= RC_HEADER1) )
         {                     //Header Pulse,判断头脉冲,由于反向后IR PIN默认是高电平,该寄存器主要用来
                   rcv_header = TRUE;            //获得一次由低到高的跳变时间,NEC默认是13.5MS,13.3<13.7
                  //由于接下来就是数据码,所以不需要时延RcOffTimer。
         }
         Else if( (RC_REPEAT0 <= pls_cnt) && (pls_cnt <= RC_REPEAT1) )
         {                   //Repeat Pulse,同理用来检测重发码,NEC标准为11.5MS,必须处于RC_REPEAT0
                 rcv_repeat = TRUE;           //与RC_REPEAT1之间,即视为识别
                 RcOffTimer = RM_OFTM_R;         //由于重发后相邻的一次脉冲在100MS之后,所以有//必要延时,避免重复检测。
          }
          Else if( rcv_header == TRUE ) //头码判断出来之后
          {
                 if( BitCount < 32 )           //位长32位是标准,如果未到,继续检测完。
                 {
                          if((pls_cnt>=(RC_CODE0-RC_CODE0_GOSA))&&((RC_CODE1+RC_CODE1_GOSA) >= pls_cnt))                            {
                                    InputData >>= 1;            //需处理新的一位,将以前的数据右移,注意发送顺序//和存储过程是反向的。
                                    if ( pls_cnt >= RC_CODE_0_1 )             //如果时延大于2MS,足可以判定该次接//收的是1
                                    {
                                             InputData |= 0x80000000;//将最高接收位置1,说明该次读出的是1
                                    }
                                    BitCount++;             //位计数器加1     
                                    RcOffTimer = RM_OFTM;             // RcOffTimer的作用很奇特,其实在每解出一//个位后,该值被重置。当解出最后一个BIT后,该值才不再改变,被后//面的                                //1MS处理函数处理消耗完剩下的时间,再集中判断处理。该值不一//定很准,因为跟之前的01数目有关系,所以只能提供大概值。
                          }
                 }
                 OneCodeTime = WD_END; //一次解码过程完成,做个标记值,供后面消耗时间再//判断    
         }
}
 Void remocon_1ms (void)               //该函数处在一个1MS的控制台中,循环执行。其中的两个子///////过程一个用来处理单发,一个处理重发。
{
         if( OneCodeTime != 0 ) //在一次所有的码发完之后,OneCodeTime值固定下来,
         {          
                  OneCodeTime- -; //延迟稳定6MS之后开始解数据
                  if( OneCodeTime == 0 )
                  {
                          if( BitCount >= 32 ) //在完整接收和正确发码的情况下,最后一次边沿触发//完后,BitCount是32,当然有多32位的情况下,会忽略掉后面的(偶尔)
                          { 
                                  RcOffTimer = RM_OFTM; //进入该判断,表示正确接收开始解码,其后// RcOffTimer是为了消耗掉一次发码后剩余的时间
                                  if( (InputData & 0x0000FFFFu) == CUSTOMER_CODE )//如果客户码是//匹配的,注意顺序我们从示波器上读的值是从右往左存,所以客户码转//成16进制时从高位往低位组合。
                                  {    
                                           if( (U8)((((InputData & 0xFF000000) ^ ((InputData & 0x00FF0000u) << 8)) >> 24) ) == 0xFF ) //如果数据码和数据码的反码相匹配,满足异或为1
                                           {
                                                    RcData = (U16)((InputData & 0x00FF0000u) >> 16); //真正////解出了一个码值 
                                                    InputData = 0; //清空转储变量
                                           }
                                  }
                        } 
                        BitCount  = 0;   //不管有没有正确解出数据,在一次完整的发出数据后,要//清空BitCount和rcv_header,表示当前该次解码结束,如果<32,无效忽略,//是一种容错机制
                        rcv_header = WRONG;
                }                 if( RcOffTimer != 0 ) //用于消耗掉剩余时间
                {
                        RcOffTimer--; 
                        if( RcOffTimer == 0 )
                        {
                                if( rcv_repeat == TRUE ) //如果在耗时这段时间内(显然比重发间隔要//长),重发键仍然按着,RcData仍然有效。
                                {
                                        rcv_repeat = WRONG; //rcv_repeat清空,判断下一个重发耗时间隔//是否有效
                                        RcOffTimer = RM_OFTM_R;
                                }
                                Else  //如果时间耗完后,rcv_repeat仍然0,说明没有连按,清RcData
                                {
                                         RcData   = NP; 
                                }
                        }
              }
}//此处有误
         需要注意的是,NEC的大体过程是上面,但在时延上(不一定是那些时间表示01),数据位个数上(不一定是32位)。需要作些特殊处理。If•••else•••和if •••else if•••的差别,一般情况下两者是可以通用的,但后者有个缺点是没有出口,一旦出现两个都不符合的值出现,将没有任何子程序段处理,在编译时会警告某些后面用到的参数在子程序段中没有初始化。