最近由于项目需求,研究了一下MSP430,总体感觉MSP430还是非常不错的单片机,不亏是TI的产品。项目中用MSP430实现了红外遥控功能,下面我们先来分析一下红外的发送原理。
红外发送原理

红外发送实际上是按照一定的时间间隔,断断续续的发送红外射线来进行数据传输,为了提高数据传输的准确定和降低功耗,红外一般是采用38K的红外调制信号,其中,38K允许上下浮动1K以内的误差。红外发送的开头需要一个引导位,引导位是发送9ms,然后停止4.5ms,如果发送完一个数据之后还需要再发数据的话还需要连发码,连发码是先发送9ms,然后停止4.5ms。引导码和连发码的波形如下:

android 发送红外函数 红外发送功能_红外编码

引导码和连发码之后是32位数据位,这32位数据位实际上是一个字节,其中,前16位是用户自定义地址码,用来区分红外是发给谁的,比如,电视的红外遥控是不能操作冰箱或空调的,剩下的16位是传输的数据,其中前8位是要传送的一个字节,后8位是这个字节的反码,用来校验数据传输的是否正确的,数据位无非就是0或1,其中0是先发送560us红外,然后停止565us,1是先发送560us然后停止1685us,0和1的波形如下:

android 发送红外函数 红外发送功能_MSP430_02

每次传输实际上就是一个引导码加32位数据位或者一个连发码加32位数据位,整体的波形如下:

android 发送红外函数 红外发送功能_MSP430_03

注意,你上所有的波形都是接收时的波形,由于红外接收头,如HS0038B,在采集到38K红外线时输出低电平,在采集不到38K红外线时输出高电平,所以,当发送红外线时在波形中为低电平,停止发送时反而为高电平。

实现电路
熟习了原理以后,再来设计电路图就非常简单了,用两个三极管停止串联,其中一个的基极(无论是PNP还是NPN,都是旁边那个脚)接到38K方波上,另一个的基极接到发送控制引脚上,我这里没有自己来绘制原理图,采用了一个网上的原理图,具体如下:

android 发送红外函数 红外发送功能_红外编码_04

代码设计

下面的原理部分都理通了,下面,我们用MSP430来实现设计,其中P2.3口是MSP430的PWM输出引脚,这里是输出38K方波,P2.2口为发送停止控制引脚。具体代码如下:

#include  <msp430x14x.h>

static unsigned int cnt = 0;

void delay_ms(unsigned int ms){
  cnt = ms;
  
  TBCCR0 = 1000;
  TBCTL = CNTL_0 + TASSEL_2 + MC_1 + ID_3;
  TBCCTL0 = CCIE;
  
  while(cnt != 0);
  
  TBCTL = MC_0;
}

void delay_us(unsigned int us){
  cnt = 1;
  
  TBCCR0 = us;
  TBCTL = CNTL_0 + TASSEL_2 + MC_1 + ID_3;
  TBCCTL0 = CCIE;
  
  while(cnt != 0);
  
  TBCTL = MC_0;
}

void ir_open(){
  P2DIR |= BIT2 | BIT3;//P2.2, P2.3输出
  P2SEL |= BIT3; //P2.2:IO P2.3:TA0
  P2OUT &= ~(BIT2 | BIT3);
  
  //38K->P2.3
  CCR0 = (int)(26.3*8 + 0.5);
  CCTL1 = OUTMOD_6;
  CCR1 = (int)(13.15*8 + 0.5);

  TACTL = TASSEL_2 + MC_1;
}

void ir_start(){
  P2OUT |= BIT2;
  delay_us(9000);
  
  P2OUT &= ~BIT2;
  delay_us(4500);
}

void ir_next(){
  P2OUT |= BIT2;
  delay_us(9000);
  
  P2OUT &= ~BIT2;
  delay_us(2250);
}

void ir_send_byte(unsigned char c){
  unsigned char i;
  
  for(i = 0; i != 8; ++i){
    P2OUT |= BIT2;
    delay_us(560);
    
    P2OUT &= ~BIT2;
    if(c&0x01){
      delay_us(1685);
    }
    else{
      delay_us(565);
    }
    
    c >>= 1;
  }
}

void ir_end(){
  P2OUT |= BIT2;
  delay_us(300);
  P2OUT &= ~BIT2;
}

void ir_put(unsigned char c){
  ir_start();
  ir_send_byte(0x00);
  ir_send_byte(0xff);
  ir_send_byte(c);
  ir_send_byte(~c);
  ir_end();
}

void ir_close(){
  P2SEL &- ~BIT3;
  P2DIR |= BIT3;
  P2OUT &= ~BIT3;
  TACTL = TACLR;
}

void main(void)
{
  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
  
  BCSCTL1&=~XT2OFF;  //使能XT2
  do
  {
    IFG1&=~OFIFG;        //清除XT2标志
    _NOP();    
  } 
  while((IFG1&OFIFG));   // 等待外部晶振稳定  即寄存器IFGI的OFIFG位等于0
  BCSCTL2|=SELM_2;       //将MCLK配置为XT2
  BCSCTL2|=SELS;  //将SMCLK配置1/2XT2 即4M 
  
  _EINT();
         
  ir_open();
  //ir_close();//关闭红外函数,这里不用
  
  while(1){
    delay_ms(1000);
    //P2OUT ^= BIT2;
    ir_put(0x83);
  }
}

#pragma vector=TIMERB0_VECTOR
__interrupt void timerb_handler(){
  --cnt;
}



好了,看过上面这些资料,红外的发送就不会有什么疑问了,调试的时候我是用51单片机的红外解码测试程序来调试的,现在已经完全没有问题了,如果有什么疑问,欢迎留言讨论。




本文作者:girlkoo