51/AVR单片机技术驿站!  <在线翻译>     便利工具    特色网址   无弹窗、无插件的绿色站点...  英才招聘   学历查询  喜欢>>收藏我站 

当前位置:首页 > 单片机技术文章 > MSP430单片机 > 详细内容
分享MSP430与红外芯片HSDL-3201实现红外收发例子
发布时间:2009/7/27  阅读次数:1077  字体大小: 【】 【】【
本人现在在使用MSP430做系统,现在做了一个按键红外发送数组程序,和一个接收红外信息之后,正确识别数组,并将数组发送到串口助手以比较发送和接收的数据是否有误差。这已经通过硬件下载调试了,没有误码,可以直接使用。本人使用的红外芯片是美国安捷伦公司的HSDL-3201,最大支持115.2Kb/S的红外发送。由于程序只是在功能上实现了,还没有进一步优化。
  
1、按键之后红外发送一个数组

  

#include<msp430x417.h>
#include"led.c"
#include"lcd_modle.c"                 //将其他的函数模块包涵在一个文件中
#define uchar   unsigned char
#define uint     unsigned int
#define TIME     6000                 //延时时间常数,延时时间为183ms,其实延时时间常数完全可以设置得小一些,但是由于按键抖动得厉害,所以设这么大

//在IAR EW430 编译器软件中如何实现高精度软件延时,利用IAR EW430 内部延时子程序即可方便地实现
#define CPU_F ((double)1048576)                                     //这里是你当前MSP430 CPU的主频频率,即CPU的MCLK,单位为HZ
#define delay_us(x) __delay_cycles((long)(CPU_F*(double)x/1000000.0))
#define delay_ms(x) __delay_cycles((long)(CPU_F*(double)x/1000.0))
//************************************************************************

//要发送的数据,用关键字"const" 声明,不放在RAM区
  const   uchar   a[6]={0x66,0x83,0x08,0x00,0xE8,0x84};     //加号
  const   uchar   b[6]={0x66,0x83,0x20,0x00,0xF6,0x84};     // 减号
  const   uchar   c[6]={0x66,0x83,0x10,0x00,0xE2,0x84};   //左箭头
  const   uchar   d[6]={0x66,0x83,0x18,0x00,0xE5,0x44};   //右箭头
  const   uchar   e[6]={0x66,0x83,0x28,0x00,0xF1,0x44};   //OK
  const   uchar   f[6]={0x66,0x83,0x30,0x00,0xFB,0x44};   //C/II
  const   uchar   g[6]={0x66,0x83,0x38,0x00,0xFC,0x84}; //开阀
  const   uchar   h[6]={0x66,0x83,0x40,0x00,0xDE,0x84}; //关阀
  const   uchar   i[6]={0x66,0x83,0x48,0x00,0xD9,0x44};   //左右箭头同时按下

extern void lcd_modle();       //利用函数原型(函数声明)扩展函数的作用域,
void led();                             //利用函数原型(函数声明)扩展函数的作用域, extern可以省略


uchar keybuf=0x00;               //键值,全局变量的初始化
uchar keytime=0x06;             //判断连键时,定时中断的次数,初始化为6,即连键时间间隔设置
//************************************************************************
void settime(long uint ti)                         //设置定时时间
{
         CCR0=ti;                                               //定时时间
}

void gostopA(uchar a)   //打开或是关闭定时器,其中a为判断标志
{
  if(a==1)
     {
       TACTL=TASSEL0+TACLR+MC0; //清TAR(消除定时器的方向记忆特性),设置定时器工作在增计数模式,记得选择ASCLK作为定时时钟
       settime(TIME);
         }
   else if(a==0)
         {
           TACTL&=~MC0;         //定时器暂停计数,TACTL=MC_0;但是并不发生复位,当定时器重新计数时,计数器从暂停时的值开始                    
         }
}

//************************************************************************
void timerainit()                       //定时器A的初始化
  {
     TACTL=TASSEL0+TACLR;             //选ASCLK,清TAR, 刚开始并没有计数
     CCTL0=CCIE;                               //先开允许比较中断
     settime(TIME);                         //设置时间放在允许中断的后面
  }

//************************************************************************
void gostopkey(uchar sw)           //打开或者关闭按键中断
{
   if(sw==0)
       P1IE&=0X00;                     //关闭按键中断
   else if (sw==1)
       P1IE|=0XFF;                               //打开按键中断允许
}

//************************************************************************
uchar   conkey()   //连续按键的判断和处理,此模块放在定时中断程序中,不知是否需要清定时中断标志(CCIFG0=0;),不需要消除,它会自动消除,跳出定时中断
{
  uchar x=0x00;
if((P1IN&0XFF)==0X00) //单独按键,或者是连续按键松开之后
  {                                               //没有键按下
     gostopA(0);                       //关闭定时器
     gostopkey(1);                   //打开按键中断
  }
else                                           //连续按键的情况
{
  if(keytime==0)                     //连续按键的时间到
  {
     keytime=0x06;                     //重新置值
       if((P1IN&0XFF)==0X80)
       {
             x=1;                               //给全局变量键值赋值
       }
       else if((P1IN&0XFF)==0X40)
       {
             x=2;
       }
       else if((P1IN&0XFF)==0X20)
       {
             x=3;
       }
     else if((P1IN&0XFF)==0X10)
       {
             x=6;
       }
     else if((P1IN&0XFF)==0X08)
       {
             x=4;
       }
     else if((P1IN&0XFF)==0X04)
       {
             x=7;
       }
       else if((P1IN&0XFF)==0X02)
       {
             x=5;
       }
     else if((P1IN&0XFF)==0X01)
       {
             x=8;
       }
     else if((P1IN&0XFF)==0X18)   //组合键,4、6组合键,组合键有效的时间为:按键之后:183ms*6,即时间间隔为连键时间间隔
     {
         x=9;
     }
       else                         //其他情况
       {
         x=0x00;
         gostopA(0);         //关闭定时器
         gostopkey(1);     //打开按键中断
       }

  }
  else                                 //连续按键的时间没有到
     keytime--;
}
     return(x);
}

//************************************************************************
#pragma vector=TIMERA0_VECTOR           //CCRO中断,为单源中断,自动消除中断标志
__interrupt void Timer_A0(void)     //定时器中断
{
   keybuf=conkey();                               //获取连续按键值,0x00代表没有连续按键
}

//************************************************************************
void keyinit()                             //按键初始化
{
               P1DIR&=0X00;         //P1口接8个按键,全部设为输入
               P1IES&=0X00;         //设为上升沿中断
               P1IE|=0XFF;                   //全部允许中断
               P1IFG&=0X00;         //清中断标
}

//************************************************************************
uchar keycode()                             //判断单个的键值
{
     uchar y, q0=0;
     if((P1IN&0XFF)==0X80)//不使用中断标志查询中断源,在按键中断中不识别组合键
       {
           y=1; q0=1;
       }
       else if((P1IN&0XFF)==0X40)
       {
             y=2; q0=1;
       }
       else if((P1IN&0XFF)==0X20)
       {
               y=3; q0=1;
       }
     else if((P1IN&0XFF)==0X10)
       {
               y=6;   q0=1;
       }
     else if((P1IN&0XFF)==0X08)
       {
                 y=4; q0=1;
       }
     else if((P1IN&0XFF)==0X04)
       {
                 y=7; q0=1;
       }
       else if((P1IN&0XFF)==0X02)
       {
                 y=5;   q0=1;
       }
     else if((P1IN&0XFF)==0X01)
       {
                 y=8;   q0=1;
       }
       else
       y=0x00;                     //没有按键按下,或者是其他情况
       if(q0==1)                 //有按键按下的情况,为判断是否按键连续做准备
       {
           gostopA(1);         //开启定时中断
           gostopkey(0);     //关闭按键中断
       }
       return(y);
}

//************************************************************************
#pragma vector=PORT1_VECTOR
__interrupt void   port1_vector(void)
{
       keybuf=keycode();
       P1IFG=0X00;//消除中断标志,跳出按键中断
}

//************************************************************************
void zijiesend(uchar m)       //以19200bit/S红外发送一个字节,
   {
     uchar n;
     P5OUT&=0xdf;P5OUT|=0X20;delay(4);_NOP();_NOP();_NOP();//发送起始位,设置波特率
     for(n=1;n<=8;n++)             //8个数据位,发8次
       {
         if((m&0x01)==0){P5OUT&=0Xdf;P5OUT|=0X20;delay(4);_NOP();}                                                           //先发最低位(即最右边那位)
         else {P5OUT|=0X20;delay(6);}
         m=m>>0x01;                                     //将要发送的数据右移一位
         }
     P5OUT|=0x20; //发送停止位
     delay(7);_NOP();_NOP();_NOP();_NOP();//延时1个停止位
   }

//************************************************************************
void shuzusend(const uchar *c)   //使用指针调用数组
{
   uchar i,*p;               //i为数组元素个数
   p=(uchar *)c;           //指针类型转换
   keybuf=0x00;             //清零
   for(i=1;i<=6;i++)   //数组有6个元素,发送6次
   {
       zijiesend(*p);     //发送数组元素
         p++;                       //移到下一个元素
         delay_us(500);   //发送完一个字节等待500微秒
   }
   delay_ms(10);           //发送完一个数组等待10毫秒
}

//************************************************************************
main()         //连续去抖动,按键机械扛抖动能力很差,加入了组合键(注意组合键识别的有效时键)
{
     WDTCTL=WDTPW+WDTHOLD;//关看门狗
       P2DIR|=0X04;
       P2OUT|=0X04;               //在P2.2口输出高电位,开启红外部分电源
       keyinit();                   //按键初始化
       timerainit();             //定时器初始化
       P5DIR|=0X20;               //设置P5.5为输出端
     delay_ms(150);             //进入循环前延时,等待低速时钟稳定
         _EINT();                     //开总中断
     while(1)
     {
       switch(keybuf)           //使用keybuf作为判断标志
         {
           case   0x00   : break;
           case   1 : shuzusend(a); break;
           case   2 : shuzusend(b); break;
           case   3 : shuzusend(c); break;
           case   4 : shuzusend(d); break;
           case   5 : shuzusend(e); break;
           case   6 : shuzusend(f); break;
           case   7 : shuzusend(g); break;
           case   8 : shuzusend(h); break;
           case   9 : shuzusend(i); break;     //4、6组合键
         default :   break;
         }
     }
}

//定时器延时时间常数本来可以设得比较小的,但设置得小的时候,由于抖动厉害,会发两次数据;若是需要修改连键识别时间间隔,直接更改"keytime"的值就可以了
//低速时钟需要上百毫秒的建立时间才能稳定下来。

  

2、红外接收数组,并将接收到的数组以19200b/S的速率,经485发送PC串口,并在串口调试助手上显示出来:

  

#include<msp430x417.h>
#include"delay.c"
#define uchar unsigned char
#define   uint     unsigned int

//在IAR EW430 编译器软件中如何实现高精度软件延时,利用IAR EW430 内部延时子程序即

可方便地实现
#define CPU_F ((double)1048576)                                     //这里是你当前MSP430 CPU的主频

频率,即CPU的MCLK,单位为HZ
#define delay_us(x) __delay_cycles((long)(CPU_F*(double)x/1000000.0))
#define delay_ms(x) __delay_cycles((long)(CPU_F*(double)x/1000.0))
//************************************************************************

  uchar a[6]={0};   //定义数组a来存放红外接收到的数据,并初始化为0,

uchar zijiereceive()//用关系统总中断,查询中断标志的方案实现
{
     uchar s,t=0x00;
     for(;;)                                     //没有字节发送则一直等待
         if((P2IFG&0X01)==0X01)
         { P2IFG&=0XFE;           //先将中断标志清零
             break;
         }

       delay(10);                               //从检测到起始位(下降沿)到第一个采样点的延时
       if((P2IFG&0X01)==0X01){s=0x00;P2IFG&=0XFE;}
       else {s=0x01;P2IFG&=0XFE;}
             t+=s;
             delay(7);
       if((P2IFG&0X01)==0X01){s=0x00;P2IFG&=0XFE;}
       else {s=0x01;P2IFG&=0XFE;}
             s<<=1;
             t+=s;
             delay(7);
       if((P2IFG&0X01)==0X01){s=0x00;P2IFG&=0XFE;}
       else{s=0x01;P2IFG&=0XFE;}
               s<<=2;
               t+=s;
         delay(4);
         if((P2IFG&0X01)==0X01){s=0x00;P2IFG&=0XFE;}
         else {s=0x01;P2IFG&=0XFE;}
               s<<=3;
               t+=s;
             delay(4);
         if((P2IFG&0X01)==0X01){s=0x00;P2IFG&=0XFE;}
         else {s=0x01;P2IFG&=0XFE;}
               s<<=4;
         t+=s;
           delay(3);
         if((P2IFG&0X01)==0X01){s=0x00;P2IFG&=0XFE;}
         else {s=0x01;P2IFG&=0XFE;}
               s<<=5;
               t+=s;
             delay(3);
         if((P2IFG&0X01)==0X01){s=0x00;P2IFG&=0XFE;}
         else {s=0x01;P2IFG&=0XFE;}
               s<<=6;
               t+=s;
               delay(6);
         if((P2IFG&0X01)==0X01){s=0x00;P2IFG&=0XFE;}
         else {s=0x01;P2IFG&=0XFE;}
               s<<=7;
               t+=s;
     return(t);
}

//************************************************************************
void shuzureceive( uchar *a)       //使用指针完成一个数组的接收,并将他们按顺序存入

已定义的数组。
{   uchar i,*p;                 //定义循环常数和指针变量
       p=a;                             //将数组首地址赋给指针p
       P2IES|=0X01;             //P2.0设为下降沿中断触发
       P2IFG&=0XFE;     //将中断标志清零,初始化
         for(i=1;i<=6;i++)
         {
             *p=zijiereceive();   //存入一个字节
             p++;                               //更新存储单元
         }
}

//************************************************************************
void transmit(uchar m)       //485以19200bit/S发送一个字节,
   {
     uchar n;
     P5OUT&=0xdf;               //发送起始位
     delay(6);                             //设置波特率
     for(n=1;n<=8;n++)             //8个数据位,发8次
       {
         if((m&0x01)==0)P5OUT&=0Xdf;//先发最低位(即最右边那位)
         else P5OUT|=0X20;
         delay(6);
         m=m>>0x01;                                                 //将要发送的数据右移一位
         }
     P5OUT|=0x20;                                                 //发送停止位
     delay(8);_NOP();                                         //延时1个停止位
   }

//************************************************************************
void send( uchar *c)                                     //使用指针调用数组,485发送一个数组
{
   uchar i,*p;                                                   //i为数组元素个数
   p=c;   //指针类型转换
   for(i=1;i<=6;i++)                                       //数组有6个元素,发送6次
   {
       transmit(*p);                                           //发送数组元素
         p++;                                                           //移到下一个元素
   }
}

//************************************************************************
main()
{
     WDTCTL=WDTPW+WDTHOLD;//关看门狗
   _DINT();//关总中断

     P2DIR|=0X04;
     P2OUT|=0X04;                                   //输出高电平,开启红外部分电源,这也是用的P2口
     P5DIR|=0X20;                                   //设置P5.5为输出端
     delay_ms(20);                                 // 等待低速时钟稳定

while(1)
   {   shuzureceive(a);                       //红外接收一个数组
         send(a);                                       //485发送接到的数据
   }

}
//不允许中断,但中断标志仍然存在,须用软件清零

实验结果(串口助手上显示的数据):
00
66 83 38 00 FC 84
00
66 83 18 00 E5 44
66 83 18 00 E5 44
66 83 18 00 E5 44
66 83 18 00 E5 44
00
66 83 18 00 E5 44
66 83 18 00 E5 44
66 83 18 00 E5 44
00
66 83 38 00 FC 84
66 83 38 00 FC 84
00
66 83 30 00 FB 44
66 83 30 00 FB 44
00
00 00 00
00
66 83 08 00 E8 84
66 83 08 00 E8 84
66 83 08 00 E8 84
66 83 08 00 E8 84
00
66 83 20 00 F6 84
66 83 20 00 F6 84
66 83 20 00 F6 84
66 83 20 00 F6 84

我要评论
  • 匿名发表
  • [添加到收藏夹]
  • 发表评论:(匿名发表无需登录,已登录用户可直接发表。) 登录状态:未登录
最新评论
所有评论[0]
    暂无已审核评论!

网站导航 管理登陆 ┊ 免责声明 问题反馈  友链说明
本站部分内容来自网络共享资源,如有冒犯您的权利请来信告之删除或纠正!
不得对本站进行复制、盗链或镜像,转载内容须获得同意或授权;欢迎友情链接、站务合作!

    我要报警 Alexa
 mcusy_cn#126.com (请把#改成@) 交流:522422171
本站学习交流群:138..158(高级群1-)、77930286(高级群2)、61804809(群3)
Copyright© MCUSY All Rights Reserved
本站网警备案号: WZ36040002485
  ICP备案证书号:粤ICP备09034963号