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



java红外通信 红外通信收发系统_红外


红外收发基本原理

 

java红外通信 红外通信收发系统_#include_02

 

1、红外通信的基本原理

1.1 、红外通信的框架

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

 

java红外通信 红外通信收发系统_#include_03

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

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);
    }
     
            
                
        }
}
 
}

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