【原创+整理】红外通信原理

   
 提示:看这篇文章前,先看这篇基础扫盲贴  http://www.geek-workshop.com/thread-2322-1-1.html

总述    

    红外遥控由发送和接收两个组成部分。发送端采用单片机将待发送的二进制信号编码调制为一系列的脉冲串信号,通过红外发射管发射红外信号。红外接收完成对红外信号的接收、放大、检波、整形,并解调出遥控编码脉冲。为了减少干扰,采用的是价格便宜性能可靠的一体化红外接收头(HS0038,它接收红外信号频率为 38kHz,周期约 26μs,采用NEC红外编码)  接收红外信号,它同时对信号进行放大、检波、整形得到 TTL 电平的编码信号,再送给单片机,经单片机解码并执行去控制相关对象。如图 1  所示:
 
 
红外发射和接收组成电路
    
发射电路
 
 
接收电路
 
调制与发射
 
    红外遥控发射芯片采用PPM 编码方式,当发射器按键按下后,将发射一组 110ms 的编码脉冲。遥控编码脉冲由前导码、16 位用户码(8 位用户码、8 位用户码的反码)和 16 位操作码(8 位操作码、8 位操作码的反码)组成。
    前导码的作用前导码是一个遥控码的起始部分,由一个 9ms 的高电平 (起始码)  和一个 4.5ms 的低电平 (结果码) 组成。
    用户码的作用16 位用户码(8 位用户码、8 位用户码的反码),通过对用户码的检验,每个遥控器只能控制一个设备动作,这样可以有效地防止多个设备之间的干扰。编码后面还要有编码的反码,用来检验编码接收的正确性,防止误操作,增强系统的可靠性。
    0和1的表示0和1均以0.56ms的高电平开始(实际测量是500us的样子),不同的是后面出现的低电平,如果低电平是0.56ms(实际测量是500us的样子),则表示0,如果低电平是1.68ms(0.56*3=1.68)则表示1。
 
 
 
    
  二进制信号的调制由单片机来完成,它把编码后的二进制信号调制成频率为38kHz 的间断脉冲串(周期约26us的脉冲),相当于用二进制信号的编码乘以频率为 38kHz  的脉冲信号得到的间断脉冲串,即是调制后用于红外发射二极管发送的信号,如图 4 二进制码的调制所示。
 
 
待发射的二进制编码(注意是未调制的
 
    注意上面的一组二进制编码并非完整的NEC编码!完整的NEC协议编码长度为110ms,即剩余的是低电平,大约40ms左右,怎么算的呢?9+4.5+16*2.24+16*1.12 =  67.26,110 - 67.26 = 42.74(有的是108 - 67.26 =40.74)。
    如果我们一直按着键不放,会产生什么效果呢?如下图:
   

    
    
    上面这一些称为重复码,以110ms为周期的重复码,如下图:
    
    就是说,发了一次命令码之后,不会再发送命令码,而是每隔110ms时间,发送一段重复码。重复码由9ms高电平和2.25ms的低电平以及560us的高电平组成。如下图:

    因为HS0038B接收频率是38KHz,约26us,记住这个不是高电平的时间长度,这个是一个脉冲的时间长度也就是一个周期,例如我们利用一个中断产生38K脉冲,占空比是1/2,我们的中断时间就要设置为 1/38000/2 S中断一次,然后通过相隔一次中断电平翻转一次就形成了一个频率为38K占空比1/2的脉冲。所以在编程时,每两次中断的间隔时间为26/2us即13us。由上面可以知道,要发射9ms高电平+4.5ms低电平的前导码,由于高电平的发射要产生的是38KHz的脉冲,所以在每次中断中反转输出形成38KHz的脉冲,而低电平的发射只需要将引脚电平拉低即可,这样接收端接收到38KHz的信号则可知接收到的是高电平,而没有接收到38KHz则认为接收到的是低电平。
    红外接收头只接受38K信号(误差范围内),我们把接收头看出一个转换器。遇到38K就输出低电平,没有遇到38K就被上拉成高电平。于是所谓的“编码”的概念就这样产生了,我们利用有38K信号 跟 没有38K信号 这两种状态,利用红外接收头就翻译成低电平、高电平的信号。这就是最主要的东西。
  1. /***********************定时器0中断处理 **********************/
    void timeint(void) interrupt 1
    { 
        TH0=0xFF;
        TL0=0xF3;        //设定时值为38K*2 也就是每隔13us中断一次
        count++;
        if (flag==1)     //如果是发射“1”,则产生38K信号
        { 
            OP=~OP;
        }
        else             //如果是发射“0”,则单纯拉低电平,不产生38K信号   
        {
            OP = 0;
        }
        ir_in= OP;
    }
    //发送9ms的起始码 
        endcount=692; 
        flag=1;
        count=0;
        do{}while(count<endcount);
        
        /**********************发送4.5ms的结果码***********************/
        endcount=346;
        flag=0; 
        count=0; 
        do{}while(count<endcount);

     

解调
 
    红外接收需先进行解调,解调的过程是通过红外接收管进行接收的。其基本工作过程为:当接收到调制信号时,输出低电平,否则输出为高电平, 是调制的逆过程(图 5  解调)。HS0038 是一体化集成的红外接收器件,直接就可以输出解调后的高低电平信号;红外接收器 HS0038 的应用电路(图6)。
    
 
 
    发送方的电平跟接收方解调出来的电平是反向的红外接收头接收到遥控器的信号后,解码出后的数据格式如下:写程序即根据这个信号的格式来写。
    
 
 
    接收到的信号经过HS0038B解调后得到一系列的高低电平,即遥控码,分为3部分:
    前导码:9ms的低电平+4.5ms的高电平(和发射的时候相反)
    用户码:区别不同的红外设备
    操作码:8bit操作码和8bit的操作反码组成
 
    0和1均以0.56ms的低电平开始(实际测量是500us的样子),不同的是后面出现的高电平,
    如果高电平是0.56ms(实际测量是500us的样子),则表示0,如果高电平是1.68ms(0.56*3=1.68)则表示1
 
    写代码的时候只需要检测高电平的时间即可。
    以下时间都是通过示波器实际测量所得。
    引导码的高电平:4.5ms
    0的高电平     :0.56ms(实测0.5ms的样子)
    1的高电平     :1.68ms
    重复码的高电平:2.1ms
   重复码前的高电平:40ms
 
//获取高电平时间函数伪代码,返回几微妙
Get_Pulse_Time()
begin
   time = 0
   while HS0038B数据引脚的电平为高电平
      time = time + 1
      延时20微妙
      //time等于250,即延时了5ms
      if time == 250
         return time*20
   return time*20
end 
  红外接收函数采用中断函数,通过边沿触发启动高电平时间检测,比较即时准确。
 
//红外中断函数伪代码,frame_data、frame_cnt、frame_flag为全局变量
EXTI15_10_IRQHandler()
begin
   pulse_time = 0           
   leader_code_flag = 0   /* 引导码标志位,当引导码出现时,表示一帧数据开始 */
   irda_data = 0          /* 数据暂存位 */
   while 1
      if 红外接收头数据引脚的电平 == 高电平
         //获取高电平时间
         pulse_time = Get_Pulse_Time()

         //>=50ms 不是有用信号 当出现干扰或者连发码时,也会break跳出while(1)循环
         if( pulse_time >= 50ms
            break;

         //0.56ms:低电平0
         if pulse_time > 0.2ms and pulse_time < 1ms
            irda_data = 0
         //1.68ms:高电平1
         else if pulse_time > 1ms and pulse_time < 2ms
            irda_data = 1

         //4.5ms:前导位
         else if pulse_time > 4ms and pulse_time < 4.5ms
            leader_code_flag = 1

         //2.1ms:连发码,在第二次中断出现,40ms:16位操作码后的高电平时间,位于重复码之前
         else if (pulse_time > 2ms and pulse_time < 4ms) or (pulse_time > 36ms and pulse_time < 44ms)
            frame_flag = 1;               /* 一帧数据接收完成 */
            frame_cnt++;                  /* 按键次数加1 */
            break

         //在第一次中断中完成
         if leader_code_flag == 1
            frame_data <<= 1
            frame_data += irda_data
            frame_cnt = 0
   清除中断标志
end
  1.  

    //获取操作码函数伪代码
    IrDa_Process()
    begin
      first_byte = frame_data >> 24
      sec_byte = (frame_data>>16) & 0xff
      tir_byte = frame_data >> 8
      fou_byte = frame_data
      
      // 清标志位
      frame_flag = 0;
      
      if (first_byte==~sec_byte) && (first_byte== 用户码) 
          if tir_byte ==~fou_byte )
          return tir_byte
    
      return 0;   /* 错误返回 */
    end

     

  2. //main函数里使用红外伪代码
    while 1      
        if( frame_flag == 1 ) /* frame_flag为全局变量,一帧红外数据接收完成 */
          key_val = IrDa_Process()

     

 
 
 
参考链接:
 
posted @ 2015-03-08 08:40  cposture  阅读(24822)  评论(18编辑  收藏  举报
levels of contents