搜索
bottom↓
回复: 66

分享红外解码 基于125us定时 任意IO

  [复制链接]

出0入0汤圆

发表于 2013-8-24 22:33:42 | 显示全部楼层 |阅读模式

本程序适用于NEC协议的红外遥控器。红外接收头可接任意IO引脚;必须每125us调用一次红外解码程序。

代码如下,写得有点难看,能用就好----------
/*
描述:红外解码程序,必须每125us调用一次
*/
void ir_decode(void)//红外解码
{
        static unsigned char state=0;
        static unsigned char cnt=0;
        static unsigned char rec_data;
        static unsigned char rec_cnt=0;
        static unsigned char i=0;

        if(ir_ok)return;

        switch(state)
        {
                case 0:                                 //判断起始码  9m低电平
                        ++cnt;               
                        if(IR_IO == 1)         //高电平到来
                        {
                                if(cnt >= 71 && cnt <= 73)        //高电平之前,维持约为9ms的低电平,cnt=72=9ms,
                                {
                                        state = 1;                                //进入下一状态
                                        cnt = 1;
                                }
                                else
                                {
                                        cnt = 0;
                                }
                        }
                        break;
               
                case 1:                        //判断引导码  4.5ms高电平
                        ++cnt;
                        if(IR_IO == 0)           //低电平到来
                        {
                                if(cnt >= 34) //低电平来之前,维持了约为4.5ms的高电平 cnt=36=4.5ms
                                {
                                        state = 2;
                                        cnt = 1;
                                        rec_cnt = 0;
                                        i = 0;
                                }
                                else                        //不合法退回最初状态
                                {
                                        state = 0;
                                        cnt = 0;
                                }
                        }
                        else                          //为高电平
                        {
                                if(cnt > 37)  //长时间为高电平 退回最初状态
                                {                          
                                        cnt = 0;
                                        state = 0;
                                }
                        }
                        break;
                          
                           // case 2 和 case 3 为接收数据
                case 2:      //560us的低电平
                        ++cnt;
                        if(IR_IO == 1)           //高电平到来
                        {
                                if(cnt >= 3)   //高电平到来之前 维持了约560us的低电平 cnt=4.48=560us
                                {
                                        state = 3;
                                        cnt = 1;       
                                }
                        }
                        else                           //为低电平
                        {
                                if(cnt >8)          //长时间处于低电平 错误 返回
                                {
                                        state = 0;
                                        cnt = 0;
                                }
                        }
                        break;

                case 3:         //560 或 1.69ms  高电平
                        ++cnt;
                        if(IR_IO == 0)            //低电平到来
                        {
                                rec_data >>= 1;
                                if(cnt > 10)  //低电平到来時 高电平维持>560us bit值为1        cnt=4.48=560us
                                {
                                        rec_data |= 0x80;
                                }

                                if(++i >= 8)//是否接收完一个字节
                                {
                                        i = 0;
                                        ir_data[rec_cnt] = rec_data;//保存
                                        if(++rec_cnt >= 4) //接收完所有数据
                                        {
                                                ir_ok = 1;    //標志接收完成
                                                rec_cnt = 0;
                                                state = 0;
                                                cnt = 0;
                                        }
                                        else                          //还没有接收完 返回上一步继续
                                        {
                                                state = 2;
                                                cnt = 1;
                                        }
                                }
                                else                        //还没有接收完 返回上一步继续
                                {
                                        state = 2;
                                        cnt = 1;
                                }

                        }
                        else                                 //为高电平
                        {
                                if(cnt > 15)        //长时间为高电平   错误 返回
                                {
                                        state = 0;
                                        cnt = 0;
                                }
                        }       
                        break;               
        }
}

//读取红外编码值,外部调用
//返回0 没接收到红外遥控信号
unsigned char ir_read(unsigned char *p)
{
        unsigned char i;

        if(ir_ok == 0)return 0;          // 没接收到红外遥控信号

        for(i = 0; i < 4; i++)
        {
                p = ir_data;       
        }       

        ir_ok = 0;

        return 1;
}  


在125us的定时中断里调用红外解码函数;定时中断里还可以用于别的计时,不会因为用于红外解码而独占一个定时器。
//125us 定时中断
void timer0_isr() interrupt 1
{
        static unsigned char _10ms_cnt = 0;
               
        ir_decode();                                //每125us调用红外解码函数

        /*还可以用作别的计时*/
        if(++_10ms_cnt >= 80)
        {
                _10ms_cnt = 0;
                _10ms_ok =1;
        }
}

应用测试
void main()
{       
           unsigned char ir_data[4];

        UartInit();
        timer0_init();     //初始化定时器0为 125us中断

        while(1)
        {
                if(ir_read(ir_data) == 0)continue;            

                UartSendByte(ir_data[0]);       
                UartSendByte(ir_data[1]);
                UartSendByte(ir_data[2]);
                UartSendByte(ir_data[3]);       
        }       
}

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

发表于 2013-8-26 08:43:27 | 显示全部楼层
谢谢分享,有空再下载来玩玩

出0入0汤圆

发表于 2013-8-26 08:53:05 | 显示全部楼层
学习了                           

出0入0汤圆

发表于 2013-8-26 08:57:51 | 显示全部楼层
请问同一设备解出来的码有规律吗?

出0入0汤圆

 楼主| 发表于 2013-8-26 09:07:29 | 显示全部楼层
wangxuedong 发表于 2013-8-26 08:57
请问同一设备解出来的码有规律吗?

地址会一样,就是前两个字节

出0入0汤圆

发表于 2013-8-26 09:13:35 | 显示全部楼层
那74位的怎么解释,比如:8950,4400,650,1650,650,500,650,550,650,1650,650,550,650,500,650,550,600,600,600,550,650,1650,650,500,650,1650,650,550,650,500,650,550,650,500,650,550,650,550,650,500,650,550,650,500,650,550,650,550,650,500,650,550,650,500,650,550,650,500,650,1650,650,550,650,1600,650,550,650,550,600,1650,650,550,650,32896

出0入0汤圆

 楼主| 发表于 2013-8-26 09:22:06 | 显示全部楼层
wangxuedong 发表于 2013-8-26 09:13
那74位的怎么解释,比如:8950,4400,650,1650,650,500,650,550,650,1650,650,550,650,500,650,550,600,600, ...

这个看不懂,你这些数据是怎么来的

出0入0汤圆

发表于 2013-8-26 09:22:11 | 显示全部楼层
好东东,谢谢

出200入0汤圆

发表于 2013-8-26 10:39:26 | 显示全部楼层
好东东,收藏

出0入0汤圆

发表于 2013-8-26 21:54:12 | 显示全部楼层
tianxian 发表于 2013-8-26 09:22
这个看不懂,你这些数据是怎么来的

自己解码解出来的  求高手指教啊

出0入0汤圆

发表于 2013-8-26 22:13:26 来自手机 | 显示全部楼层
学习一下........

出0入0汤圆

发表于 2013-9-9 12:08:24 | 显示全部楼层
mark,多谢分享

出0入0汤圆

发表于 2013-9-9 16:07:01 | 显示全部楼层
灰常感谢,我不知道原来LZ在这里分享了,不然我也不会特别发帖问这个问题。一句话,灰常感谢LZ。

出0入0汤圆

 楼主| 发表于 2013-9-9 16:36:19 | 显示全部楼层
xiaoxei 发表于 2013-9-9 16:07
灰常感谢,我不知道原来LZ在这里分享了,不然我也不会特别发帖问这个问题。一句话,灰常感谢LZ。{:handshak ...

不客气      

出50入0汤圆

发表于 2013-9-9 21:26:34 | 显示全部楼层
刚好有用到,正在学习,感谢楼主。

出0入0汤圆

发表于 2013-9-9 21:34:18 | 显示全部楼层
不错,我也是这个方法,画板的把io没接在中端上

出0入0汤圆

发表于 2013-9-10 08:29:20 | 显示全部楼层
学习一下

出0入0汤圆

发表于 2013-9-10 09:29:59 | 显示全部楼层
学习了

谢谢分享

出0入0汤圆

发表于 2013-9-18 17:22:29 | 显示全部楼层
红外解码  mark

出0入0汤圆

发表于 2014-2-7 14:55:37 | 显示全部楼层
正在查这些资料呢,,谢谢

出0入0汤圆

发表于 2014-2-7 15:37:32 | 显示全部楼层
定时最好是50us 或者80us的

出0入0汤圆

发表于 2014-2-8 17:41:00 | 显示全部楼层
标志,红外解码

出0入0汤圆

发表于 2014-2-9 21:17:47 | 显示全部楼层
正在学习

出0入4汤圆

发表于 2014-2-10 10:16:51 | 显示全部楼层
状态机,不错

出0入0汤圆

发表于 2014-8-4 15:48:44 | 显示全部楼层
有用,标记一下!

出0入4汤圆

发表于 2014-8-31 16:51:21 | 显示全部楼层
问楼主一个问题。我把它移植到AVR上怎么不行啊

出0入0汤圆

发表于 2014-8-31 16:53:20 | 显示全部楼层
占用了一个定时器,可不可以用中断啊,修改一下延时就好了,不用定时器。

出0入4汤圆

发表于 2014-8-31 16:57:21 | 显示全部楼层
你好,我把你的红外遥控程序移植到我的M48单片机上,怎么不成功呢,是哪里的问题

出0入4汤圆

发表于 2014-8-31 16:57:45 | 显示全部楼层
你好,我把你的红外遥控程序移植到我的M48单片机上,怎么不成功呢,是哪里的问题

出0入213汤圆

发表于 2014-8-31 17:01:22 | 显示全部楼层
使用一个定时器和引脚电平变化中断。就不需要定时调用解码程序了。

出0入4汤圆

发表于 2014-8-31 17:01:29 | 显示全部楼层
你好,我把你的红外遥控程序移植到我的M48单片机上,怎么不成功呢,是哪里的问题

出0入4汤圆

发表于 2014-8-31 17:03:14 | 显示全部楼层
现在问题是不能解码,我的晶体是8M的

出0入4汤圆

发表于 2014-8-31 17:05:01 | 显示全部楼层
贴出程序
////////////////////////////////////////////////////////////

// 描述:红外解码程序,必须每125us调用一次

void ir_decode(void)//红外解码
{
         static unsigned char state=0;
         static unsigned char cnt=0;
         static unsigned char rec_data;
         static unsigned char rec_cnt=0;
         static unsigned char i=0;
   //     if(ir_ok)return;
        switch(state)
         {
                 case 0:                                 //判断起始码  9m低电平
                         ++cnt;               
                        if(IRIN == 1)         //高电平到来
                         {
                                 if(cnt >= 71 && cnt <= 73)        //高电平之前,维持约为9ms的低电平,cnt=72=9ms,
                                 {
                                         state = 1;                                //进入下一状态
                                         cnt = 1;
                                 }
                                 else
                                 {
                                         cnt = 0;
                                 }
                               
                         }
                         break;
                 
                case 1:                        //判断引导码  4.5ms高电平
                        ++cnt;
                         if(IRIN == 0)           //低电平到来
                         {
                                 if(cnt >= 34) //低电平来之前,维持了约为4.5ms的高电平 cnt=36=4.5ms
                                 {
                                         state = 2;
                                         cnt = 1;
                                         rec_cnt = 0;
                                         i = 0;
                                 }
                                 else                        //不合法退回最初状态
                                 {
                                         state = 0;
                                         cnt = 0;
                                 }
                         }
                         else                          //为高电平
                         {
                                if(cnt > 37)  //长时间为高电平 退回最初状态
                                 {                           
                                        cnt = 0;
                                         state = 0;
                                 }
                         }
                         break;
                           
                           // case 2 和 case 3 为接收数据
                 case 2:      //560us的低电平
                         ++cnt;
                         if(IRIN == 1)           //高电平到来
                         {
                                 if(cnt >= 3)   //高电平到来之前 维持了约560us的低电平 cnt=4.48=560us
                                 {
                                         state = 3;
                                         cnt = 1;
                                         
                                }
                         }
                         else                           //为低电平
                         {
                                 if(cnt >8)          //长时间处于低电平 错误 返回
                                 {
                                         state = 0;
                                         cnt = 0;
                                 }
                         }
                         break;

                case 3:         //560 或 1.69ms  高电平
                         ++cnt;
                         if(IRIN == 0)            //低电平到来
                         {
                                 rec_data >>= 1;
                                 if(cnt > 10)  //低电平到来時 高电平维持>560us bit值为1        cnt=4.48=560us
                                 {
                                        rec_data |= 0x80;
                                }

                                if(++i >= 8)//是否接收完一个字节
                                 {
                                   iTemp=12;
                                         i = 0;
                                         addr[rec_cnt] = rec_data;//保存
                                         if(++rec_cnt >= 4) //接收完所有数据
                                         {
                                                 ir_ok = 1;    //標志接收完成
                                                 iTemp=12;
                                                 rec_cnt = 0;
                                                 state = 0;
                                                 cnt = 0;
                                         }
                                         else                          //还没有接收完 返回上一步继续
                                         {
                                                 state = 2;
                                                 cnt = 1;
                                         }
                                 }
                                 else                        //还没有接收完 返回上一步继续
                                 {
                                         state = 2;
                                         cnt = 1;
                                 }

                        }
                         else                                 //为高电平
                         {
                                 if(cnt > 15)        //长时间为高电平   错误 返回
                                 {
                                         state = 0;
                                         cnt = 0;
                                 }
                        }        
                        break;               
        }
}

//读取红外编码值,外部调用
//返回0 没接收到红外遥控信号
unsigned char ir_read(unsigned char *p)
{
         unsigned char i;

        if(ir_ok == 0)return 0;          // 没接收到红外遥控信号

        for(i = 0; i < 4; i++)
         {
                 p = addr;        
        }        
        ir_ok = 0;
        return 1;
}  
////////////////////////////////////////////////////
//125us 定时中断
#pragma vector=TIMER2_OVF_vect
__interrupt void TIMER2_OVF_Server(void)
{
     
        static unsigned char _10ms_cnt = 0;
          
        ir_decode();                                //每125us调用红外解码函数
        TCNT2 = 0x83; //reload counter value   
// iTemp=55;
      
        /*还可以用作别的计时*/
         if(++_10ms_cnt >= 80)
         {
                 _10ms_cnt = 0;
                 _10ms_ok =1;
         }
      
}

出0入0汤圆

 楼主| 发表于 2014-9-3 21:59:41 | 显示全部楼层
JZcrystalwlh888 发表于 2014-8-31 16:57
你好,我把你的红外遥控程序移植到我的M48单片机上,怎么不成功呢,是哪里的问题 ...

沒用過M28,但只要是125us調用一次就沒問題

出0入0汤圆

 楼主| 发表于 2014-9-3 22:00:33 | 显示全部楼层
颜靖峰 发表于 2014-8-31 16:53
占用了一个定时器,可不可以用中断啊,修改一下延时就好了,不用定时器。 ...

定時器不是比延时程序更有优势吗

出0入4汤圆

发表于 2014-9-4 12:32:30 | 显示全部楼层
不行哦,我用M48的T2定时器

出0入0汤圆

发表于 2014-10-21 13:56:25 | 显示全部楼层
正在查这些资料呢,,谢谢

出0入0汤圆

发表于 2014-10-24 08:05:29 | 显示全部楼层
谢谢,分享!!

出0入54汤圆

发表于 2014-10-24 08:22:50 | 显示全部楼层
天。。125us调用一次,得占用多少CPU资源啊。

出0入8汤圆

发表于 2014-10-24 08:32:13 | 显示全部楼层
记下来吧,125是不是太频繁了

出0入0汤圆

发表于 2014-10-24 08:39:52 | 显示全部楼层
同一个单片机 如果做到同时编码,同时解码。有做过类似的出来指导下!!

出0入0汤圆

发表于 2014-10-24 09:34:48 | 显示全部楼层
谢谢分享,学习了

出0入0汤圆

发表于 2014-10-24 09:52:32 | 显示全部楼层
收藏了,如果任务多的话,会有其它中断,会不会影响到解码的?

出0入0汤圆

 楼主| 发表于 2014-10-24 10:46:08 | 显示全部楼层
l769109884 发表于 2014-10-24 09:52
收藏了,如果任务多的话,会有其它中断,会不会影响到解码的?

用定时中断方法 本就是为了解决多任务的问题,按一般用延时的做法,会影响整个软件的性能,多任务的时候就会暴露很多问题

出0入0汤圆

发表于 2014-11-1 15:11:32 | 显示全部楼层
分享红外解码 基于125us定时 任意IO

出0入0汤圆

发表于 2015-7-5 17:02:05 | 显示全部楼层
这个程式是不是参考一位前人(现在没有找那个贴)所写的都是用125us区别就是你用了开关语句,他用if了,我也是一直用那前人的那个方式解码,时实性好。

出0入0汤圆

发表于 2015-7-5 22:47:31 | 显示全部楼层
看一下好像没有写完整,程式中只识别“0”却没有“1”的识别。

出0入0汤圆

发表于 2015-7-5 23:12:44 | 显示全部楼层
再仔细看一下,好像漏洞百出,LZ有没有实际测试过?

出0入0汤圆

发表于 2015-7-5 23:19:25 | 显示全部楼层
本帖最后由 youlongam 于 2015-7-5 23:29 编辑

这种思路曾经用过,250us的时间片就可以了,反应很快。
在250US的定时中断调用下面的程序:
void ir(u32 *p)
{
  static u8 delay=0,delay_n=0;
  static u8 step=0;
  static u32 ir_data1=0;
  switch(step)
  {
    case 0:
      if(!PORT_IR_ST)
      {
        delay++;
      }
      else
      {
        delay_n++;
        if(delay>=20)
        {
          delay=0;
          step=1;
          }
        if(delay_n>4)
        {
          delay=0;
          delay_n=0;
         }
       }
      break;
     case 1:
      if(PORT_IR_ST)
      {
        delay++;
        if(delay>40)
        {
          delay=0;
          step=0;
         }
        
      }
      else
      {
        delay_n++;
        if(delay_n>50)
        {
          delay_n=0;
          delay=0;
          step=0;
        }
        if(delay>12)
        {
          step=2;
          delay=0;
          delay_n=0;
        }
      }
      ir_data1=0;
      break;
    case 2:
      if(PORT_IR_ST)
      {
        step=3;
        delay++;
      }
      break;
     case 3:
      if(PORT_IR_ST)
      {
        delay++;
        if(delay>=20)
        {
          delay=0;
          delay_n=0;
          step=0;
        }
      }
      else
      {
        step=4;
      }
      break;
    case 4:
      if(PORT_IR_ST)
      {
        step=3;
        delay_n++;
        if(delay>4)
        {
          ir_data1=ir_data1|(0x80000000);
         }
        else
        {
          ir_data1=ir_data1&0x7fffffff;
        }
        if(delay_n>=32)
        {
          delay_n=0;
          delay=0;
          step=0;
          *p=ir_data1;
          break;
          }

        ir_data1=ir_data1>>1;
        delay=1;

      }

      break;
    default:
      break;

  }

}

出0入0汤圆

发表于 2015-7-6 11:34:42 | 显示全部楼层
125us对51单片机来说,12M晶振时时间非常吃紧......

出0入0汤圆

发表于 2015-7-6 12:37:54 | 显示全部楼层
学习,谢谢!!!

出0入0汤圆

发表于 2015-7-6 14:15:26 | 显示全部楼层
这个看不懂,你这些数据是怎么来的

出0入0汤圆

 楼主| 发表于 2015-7-6 22:27:47 | 显示全部楼层
freshuman 发表于 2015-7-5 23:12
再仔细看一下,好像漏洞百出,LZ有没有实际测试过?

测试过,漏洞在哪

出0入0汤圆

发表于 2015-9-1 16:03:09 | 显示全部楼层
mark.....

出0入0汤圆

发表于 2015-9-1 21:26:14 | 显示全部楼层
感谢分享!

出0入0汤圆

发表于 2015-10-24 20:42:24 | 显示全部楼层
好用。效果不错。stm8  16M.  在中断运行解码程序只花了2.7us.  125us的中断频率。剩余时间很多。

出0入0汤圆

发表于 2015-11-3 09:18:40 来自手机 | 显示全部楼层
跟我之前看到的一个帖子挺像。马克一下

出0入0汤圆

发表于 2015-11-23 00:20:24 | 显示全部楼层
这个状态法的程序貌似只能解短按,没有解决长按状态的解码问题

出0入0汤圆

发表于 2015-11-23 12:37:44 | 显示全部楼层
mark                                    

出0入0汤圆

发表于 2020-4-15 14:45:57 | 显示全部楼层
不错,谢谢分享

出0入0汤圆

发表于 2020-7-15 21:00:15 | 显示全部楼层
此中断函数中的静态变量,最好不要再函数中定义,东西写多了,容易跑飞。。。。

出100入101汤圆

发表于 2020-7-15 22:32:51 来自手机 | 显示全部楼层
不错,好帖子

出0入0汤圆

发表于 2020-7-23 18:13:00 | 显示全部楼层
谢谢分享

出0入0汤圆

发表于 2020-7-25 15:47:15 来自手机 | 显示全部楼层
这种有长按,短按功能 这个程序就跑不了

出0入0汤圆

发表于 2020-7-25 15:48:00 来自手机 | 显示全部楼层
iamfiavarst 发表于 2015-7-6 11:34
125us对51单片机来说,12M晶振时时间非常吃紧......

pic的也一样吃紧

出0入0汤圆

发表于 2020-7-25 15:52:22 | 显示全部楼层
lnso 发表于 2020-7-25 15:48
pic的也一样吃紧

现在很多51都是1T了,125us很轻松,当初用普通51,都用100us中断做通讯解码都没问题。

出0入0汤圆

发表于 2020-7-25 17:13:37 | 显示全部楼层
也可以上下沿中断加定时器数数,效率更高些。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-25 05:36

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表