红外收发基本原理

2017-05-04  作者:ll  嵌入式基础知识

红外收发基本原理

 

 

1、红外通信的基本原理

1.1 、红外通信的框架

     红外通信由发送端和接收端两部分组成,发送端对数据进行编码,然后调制成一系列的脉冲信号,然后通过带有红外发射管的发射电路发送脉冲信号,即红外信号。接收端完成对脉冲信号的接收、放大、检波、整形,然后解调出编码信号,对其解码获取到发送的数据。具体的如图1.1的通信框架。

 

下面通过示例明说通信的整个过程是如何工作的。

a.数据:假设发送的数据为0xA5,二进制表示:10100101。

b.编码:就是用一种符号表示码元0,另一种符号表示码元1,然后用两种符号分别代表码元0和码元1。现做如下规定,如图1.2所示。

 

 

        码元0用560us的高电平和560us的低电平代替;码元1用560us的高电平和1680us的低电平代替,因此数据0xA5的编码结果如图1.3所示.

 

 

c.调制:就是把编码数据放到一定频率的载波上面,即使用数据调制载波,形成一串脉冲信号。具体的定义在视频中由详细的解释。下面通过图1.4详细的说明调制的过程。

 

 

    由图可以观察出,当有高电平的时候,形成载波信号,当为低电平的时候,无载波信号,最终通过高低电平的变化,产生一串脉冲信号,大家可以通过示波器观察自己产生的脉冲信号是否正确。

d.发送电路:主要是对脉冲信号的放大,和红外管对脉冲信号的发送,电路的设计有许多种,这里只简单列举一种,如图1.5所示.

 

 

    如果想发送的在远一些,信号更加强一些,建议电路选择成二级放大。

 

e.接收电路与解调:为了减少干扰,采用便宜可靠地一体化接收头HS0038,接收的频率是38khz左右,周期为26us,使用它完成对调制后的脉冲信号进行放大、检波、整形得到TTL电平的编码信号,即图1.3所示。具体电路如下。

 

 

 

f.解码:通过对高低电平的时间判断就会得到二进制的01序列,具体的判断算法有许多种,下面说明常见的高电平时间判断法

 

 

 

g.数据:对二进制的01序列进行判断,就可以得到数据0xA5。

 

1.2NEC红外协议

 

该协议是由NEC开发的红外协议,其特征是:

  • 8位地址码、8位命令码;

  • 完整发射两次地址码和命令码,提高可靠性

  • 脉冲时间长短调制方式

  • 38khz的载波频率

  • 位时间1.12ms或2.25ms

调制方式:

 

NEC协议根据脉冲时间长短解码,每个脉冲位560us长的38Khz载波(约21个载波周期),逻辑“1”脉冲时间为2250us,逻辑“0”脉冲时间为1120us,推荐的载波周期为1/3或者1/4。

协议格式:

 

 

  • 引导码:9ms的高电平,4.5ms的低电平,用于判断数据帧的开始;

  • 地址码:注意小端在前,如例子中发送的数据是0x59;

  • 地址反码:地址码取反获得,如0x59的反码是0xA6,用于判断数据的正确

  • 命令码:0x16

  • 命令反码:0xe9

如果一直按着某个键值,发送的则是以110ms为周期的重复码,重复码由9ms的高电平,和4.5ms的低电平,以及一个560us的高电平组成,具体如下图

 

 

2、程序

2.1 接收程序

 

#include  <MSP430X14X.h>

 

typedef unsigned char uchar;

typedef unsigned int  uint;

 

#define t_3ms5  2300

#define t_1ms   666

uchar get_code[4] = {0};

uchar dat_code=0;

uint  timer;

 

#include "msp430.c"

#include "disp_4led.c"

 

void delay(uint time)    //10ms--10000

{

 while(time--);

}

 

void dat_high()

{

  P1DIR |= BIT5;

  P1OUT |= BIT5;

}

void dat_low()

{P1DIR |= BIT5;

 P1OUT &= ~BIT5;

}

uchar rd_dat()

  uchar stat;

  P1DIR |= BIT5;

  P1OUT |= BIT5;

  P1DIR &= ~BIT5;

  stat = P1IN;

  return (stat);

  

}

 

uchar get_num()

  uchar i,j,rd,dat=0;

  _DINT();             //关闭中断

  for(j=0;j<4;j++)

  {

     for(i=8;i>0;i--)

  {   

      dat>>=1; 

      do

       rd=rd_dat();

      while(!(rd & BIT5)); // wait high

      set_timer_b0();    //检测高电平时间

 

  do

      rd=rd_dat();

      while(rd & BIT5); // wait low

      timer=TBR;

      stop_timer_b0();

  if(timer>t_1ms)dat=dat|0x80;

      else dat=dat&0x7f;     

      }

     get_code[j]=dat;

   }

 _EINT(); 

 return(get_code[2]);    

}

 

void main( void )

  uchar rd;

  WDTCTL = WDTPW + WDTHOLD; 

  dat_high();

  set_timer_a0();

  

judge: 

 

  do   

  rd=rd_dat();

  while(rd & BIT5);  //wait low

 

  delay(100); 

  rd=rd_dat();

  if(rd & BIT5)  goto judge; //xiao dou 

 

  do

  rd=rd_dat();

  while(!(rd & BIT5));  //wait high

  set_timer_b0();

 

  do

  rd=rd_dat();

  while(rd & BIT5);  //wait low

  

  timer=TBR;

  stop_timer_b0(); 

  if(timer<t_3ms5)

   {

      delay(1000);

   goto judge;

}//连续按下,重复标志

 

  dat_code=get_num();

  goto judge; 

}

2.2 发送程序

 

#include  <MSP430X14X.h>

#include"Timer.h"

#include"UART.h"

 

typedef unsigned char uchar;

typedef unsigned int  uint;

 

#define t_3ms5  2300

#define t_1ms   666

uchar get_code[4] = {0};

uchar dat_code=0;

uint  timer;

#include "msp430.c"

#include "disp_4led.c"

#include "Keypad.h"

/****************************************************************************

* 名    称:TAPwmInit

* 功    能:TA定时器作为PWM发生器的初始化设置函数             

* 入口参数:Clk:时钟源 'S'=SMCLK;   'A'=ACLK ;     _____

                       'E'=TACLK(外部输入)    'e'= TACLK(TACLK取反)

            Div:时钟分频系数: 1/2/4/8

            Mode1:通道1的输出模式 'P'设为高电平输出,'N'低电平 ,0=禁用

            Mode2:通道2的输出模式 'P'设为高电平输出,'N'低电平 ,0=禁用

* 出口参数:1表示设置成功,0表示参数错误,设置失败。

* 说    明: 在调用PWM相关函数之前,需要调用该函数设置TA的模式和时钟源。

* 范    例: TAPwmInit('A',1,'P','P')TA时钟设为ACLK,通道1和通道2均为高电平输出

            TAPwmInit('S',4,'N','N')TA时钟设为SMCLK/4, 通道1、2均为低电平输出

            TAPwmInit('A',1,'P',0)TA时钟设为ACLK,通道1高电平输出,通道2不用,被

            禁用的PWM通道的输出管脚仍可作为普通IO口使用。

****************************************************************************/

char TAPwmInit(char Clk,char Div,char Mode1,char Mode2)

{

    TACTL = 0;                  //清除以前设置

    TACTL |= MC_1;              //定时器TA设为增计数模式  

    switch(Clk)                 //选择时钟源

    { 

        case 'A': case 'a':  TACTL|=TASSEL_1; break;    ACLK

        case 'S': case 's':  TACTL|=TASSEL_2; break;    //SMCLK

        case 'E':            TACTL|=TASSEL_0; break;    //外部输入(TACLK)

        case 'e':            TACTL|=TASSEL_3; break;    //外部输入(TACLK取反)

        default :  return(0);                           //参数有误

    } 

    switch(Div)                 //选择分频系数

    { 

        case 1:   TACTL|=ID_0; break;   //1

        case 2:   TACTL|=ID_1; break;   //2

        case 4:   TACTL|=ID_2; break;   //4

        case 8:   TACTL|=ID_3; break;   //8

        default :  return(0);           //参数有误

    } 

    switch(Mode1)               //设置PWM通道1的输出模式。

    { 

        case 'P':case 'p':          //如果设置为高电平模式

            TACCTL1 = OUTMOD_7;     //高电平PWM输出

          //  P1SEL |= BIT2;          //从P1.2输出 (不同型号单片机可能不一样)

           // P1DIR |= BIT2;          //从P1.2输出 (不同型号单片机可能不一样)              

            P2SEL |= BIT3; //P2.2:IO P2.3:TA0  

            P2DIR |= BIT3;//P2.2, P2.3输出  

            break;

        case 'N':case 'n':          //如果设置为低电平模式          

            TACCTL1 = OUTMOD_3;     //低电平PWM输出

          //  P1SEL |= BIT2;          //从P1.2输出 (不同型号单片机可能不一样) 

         //   P1DIR |= BIT2;          //从P1.2输出 (不同型号单片机可能不一样)      

            P2SEL |= BIT3; //P2.2:IO P2.3:TA0  

            P2DIR |= BIT3;//P2.2, P2.3输出  

            break; 

        case '0':case 0:            //如果设置为禁用          

           // P1SEL &= ~BIT2;         //P1.2恢复为普通IO口   

            P2SEL &= ~BIT3;

            break;                 

        default :  return(0);       //参数有误

    } 

    switch(Mode2)                   //设置PWM通道1的输出模式。

    { 

        case 'P':case 'p':          //如果设置为高电平模式

            TACCTL2 =OUTMOD_7;      //高电平PWM输出

          //  P1SEL |= BIT3;          //从P1.3输出 (不同型号单片机可能不一样)

           // P1DIR |= BIT3;          //从P1.3输出 (不同型号单片机可能不一样)

            break;

        case 'N':case 'n':          //如果设置为低电平模式          

            TACCTL2 =OUTMOD_3;      //低电平PWM输出

          //  P1SEL |= BIT3;          //从P1.3输出 (不同型号单片机可能不一样)  

          //  P1DIR |= BIT3;          //从P1.3输出 (不同型号单片机可能不一样)              

            break; 

        case '0':case 0:            //如果设置为禁用          

         //   P1SEL &= ~BIT3;         //P1.3恢复为普通IO口              

            break;                 

        default :  return(0);       //参数有误

    }    

    return(1);  

}

void delay(uint time)    //10ms--10000

{

  while(time--);

}

 

void SendData(unsigned char data)

{

unsigned char i=0;

   unsigned char temp=0;

   unsigned char datac=0;

   datac=~data;

   TAPwmInit('s',1,'P','P');   //引导码

   delay(10000);//延时9ms

   delay(2000);

   TAPwmInit('s',1,'0','0');

   delay(5000);//延时4.5ms

 

for(i=0;i<8;i++)//用户码 0x00

{

   TAPwmInit('s',1,'P','P');   

       delay(600);//延时ms

       TAPwmInit('s',1,'0','0');  

       delay(600);//延时ms

}

 

for(i=0;i<8;i++)//用户码 反码0xff

{

   TAPwmInit('s',1,'P','P');   

       delay(600);//延时0.56ms

       TAPwmInit('s',1,'0','0');  

       delay(1900);//延时1690ms

}

 

    

for(i=0;i<8;i++)

{

   temp=data>>i;

   temp=temp&0x01;

   if(0x01==temp)

    {

       TAPwmInit('s',1,'P','P');

       delay(600);

       TAPwmInit('s',1,'0','0');  

       delay(1900);

    }

   else

    {

       TAPwmInit('s',1,'P','P');   

       delay(600);//延时ms

       TAPwmInit('s',1,'0','0');  

       delay(600);//延时ms

       

    }

   

}

 

for(i=0;i<8;i++)

{

   temp=datac>>i;

   temp=temp&0x01;

   if(0x01==temp)

{

   TAPwmInit('s',1,'P','P');

   delay(600);

   TAPwmInit('s',1,'0','0');  

   delay(1900);

}

   else

{

   TAPwmInit('s',1,'P','P');   

   delay(600);//延时ms

   TAPwmInit('s',1,'0','0');  

   delay(600);//延时ms

   

}

 

}

   

}

void main( void )

   unsigned char i=0;

   uchar temp,keyval = 0;

   // Stop watchdog timer to prevent time out reset

    WDTCTL = WDTPW + WDTHOLD;

 

TimerAClkInit();

 

    TAPwmInit('s',1,'0','0');   //将定时器TA初始化成为PWM发生器

                                 //时钟源=SMCLK ; 无分频;  通道1和通道2均设为高电平模式。

    TAPwmSetPeriod(25);        //通道1/2的PWM方波周期均设为500个时钟周期

   

    TAPwmSetDuty(1,13);        //1通道 有效200个时钟周期

  

    TAPwmSetPermill(2,50);     //2通道 20.0%

#if 1   

   Uart_main();

#endif

Init_Keypad();              //初始化键盘端口

 _EINT();                      //打开全局中断 

while(1)

{

 

         Key_Event();

    

        if(key_Flag == 1)

        {

            key_Flag = 0;  

            if(key_val>=0&&key_val<=9)

    {

       SendData(key_val);

    }

     

            

                

        }

}

 

}

至此红外的收发设计完成,按照此过程便可以实现红外的双向通信。

 

  • 3
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值