分享

基于8952单片机的红外解码(TC9012F编码)

 昵称13389423 2013-08-09

基于8952单片机的红外解码(TC9012F编码)

 (2011-06-17 15:01:00)

  红外操作免去了和机器接触。第一是方便,第二也很自然的可以将用户与管理着分离(使用功能在遥控上,调试功能在机器上)。所以免不了在自己的电子钟设计中加入了红外。加的多,学得也多嘛。

虽然重点在后面,但是先上个程序

  参考总结后,第一次参考归纳出源程序如下:

#include<reg52.h>
#include<stdio.h>
#include<intrins.h>
////////////////////////////////////////////////

sbit ir=P3^2;//红外接口标志

////////////////////////////////////////////

unsigned char  irtime;//电平宽度(以定时器来记录)
bit irpro_ok,irok;
unsigned char ircord[4];
unsigned char   irdata[33];

//////////////////////////////////////////////

void ir_work(void);
void ircordpro(void);

////////////////////////////////////////////////////////////////// 

void tim0_isr (void) interrupt 1 using 1//定时器0中断服务函数
{
  irtime++;
}

///////////////////////////////////////////////////////////////////////
void ex0_isr (void) interrupt 0 using 0//外部中断0服务函数
{
   unsigned char  i;
   bit startflag;

   if(startflag)
   {
    TR0=0;
    if(irtime<38&&irtime>=34)//引导码判断(9MS)
    i=0;
    TR0=1;
      //确认为引导码,初始为新的32位编码开始
    irdata[i]=irtime;//i=0是引导码,后面是其余码。每次记录的是每次高低电平一起的脉冲宽度。
      //收到到一个码算一次中断,中断结束前清零宽度计时
    irtime=0;
    i++;
    if(i==33)
    {
      irok=1;
      i=0;
    }
 }
  //第一次进入中断开启startflag,用于第二次进入中断计时比对
    else
     {irtime=0;startflag=1;}

}

////////////////////////////////////////////////////////////////////
void TIM0init(void)//定时器0初始化
{

  TMOD=0x02;//定时器0工作方式2,TH0是重装值,TL0是初值
  TH0=0;//reload value
  TL0=0;//initial value
  ET0=1;//开中断
  TR0=1;
}
///////////////////////////////////////////////////////////////////
void EX0init(void)
{
 IT0 = 1;   
 EX0 = 1;   
 EA = 1; 
}
 void ir_work(void)//红外键值散转程序
  {
      
    switch(ircord[2])//判断第三个数码值(数据码,后面是反码,前面是引导码和地址码)
    {
      case 0:P1=0x00;break;//1 LED显示相应的按键值
      case 1:P1=0xfe;break;//2
      case 2:P1=0xfd;break;//3
    }

  

    irpro_ok=0;//处理完成标志清零

  }


void ircordpro(void)//红外码值处理函数
{
  unsigned char i, j, k;
  unsigned char cord,value;

  k=1;//从1开始,是引导码以后的一帧所有数据
  for(i=0;i<4;i++)//处理4个字节
     {
      for(j=0;j<8;j++) //处理1个字节8位
         {
          cord=irdata[k];
          if(cord>7)//电平宽度大于某个值,可以判断为1(2.25ms)   时间范围要大点,否则重复按键出现混乱
           {
             value|=0x80;//若为1则赋值
           }
         //其余情况可以判断为0(是不是证明了,irdata接收的是引导码之后的一帧所有电平?)
         else
            {
             value=value;//若判断为0则不变(移位后自然为0)
             }
          if(j<7)
            {
               value>>=1;//为什么|0X01 与<<1配合,不行。因为最后完成值要求最先写入的最低位,用这个想法会反过来。
            }
                k++;
         }
     ircord[i]=value;
     value=0;    
   } irpro_ok=1;//处理完毕标志位置1
   
}

/////////////////////////////////////////////////////////////////

void main(void)
{
 EX0init(); // 初始化中断

 TIM0init();//初始化定时器0
 while(1)//主循环
   {
    if(irok)
   {  
    ircordpro();//码值处理
     irok=0;
   }

    if(irpro_ok)//step press key
  {
    ir_work();//码值识别散转
     }
   }
}
  程序基础来自已有程序,在看完下面的说明后,就可以移植了,毕竟同一个解码标准,都是大同小异,甚至就算不同解码标准也仅仅是判断编码的时间要求上长短不同。但为什么这是经过我自己消化的呢,这里有个非常有趣的问题。

  在我单独实验红外模块的时候(也就是上面的源程序),能够正常运行。但是移植入开启了T2中断的大程序里之后,红外部分一点反应也没有。在接下来的调试过程中,因为不会使用DEBUG进入外部中断,在不断地比对程序中浪费了许多时间。当我使用LED调试法时(把P1=0x55;插入任意想要检验的程序行,亮了就证明程序走到了这里),亮与不亮在这里分界了(红色标记):

void ex0_isr (void) interrupt 0 using 0//外部中断0服务函数
{
   unsigned char  i;
   bit startflag;

 if(startflag)
 {
    TR0=0;
    if(irtime<38&&irtime>=34)

    i=0;
    TR0=1;
    irdata[i]=irtime;

    irtime=0;
    i++;
    if(i==33)
     {
      irok=1;
      i=0;
     }

 }

 恰好最近有重温static定义变量的特点,不然可能死得不明不白。因为抱着单独运行正常,移植整合之后也正常的想法,源程序的static unsigned char i;被我改为了uchar i;(我在自己程序里已做#define uchar unsigned char)。

  答案清楚了:因为我不允许任何配角程序打扰T2时钟工作,所以设置了最高优先级(PT2=1;),这样每次外部中断0里面局部变量i的累加会被打断,如果不能保值,就每次都被撤销和重新构建,或许永远达不到(i==33)要求。static按我的理解,最大的作用就是能够保持上一次的值,至于其他作用印象就不大深刻了。

  哈哈,有意思,记住  中断里的局部变量定义 unsigned char  i;要改为static unsigned char i;

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多