tianxian 发表于 2013-8-24 22:33:42

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


本程序适用于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_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;

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

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

                UartSendByte(ir_data);       
                UartSendByte(ir_data);
                UartSendByte(ir_data);
                UartSendByte(ir_data);       
        }       
}

devcang 发表于 2013-8-26 08:43:27

谢谢分享,有空再下载来玩玩

ljt80158015 发表于 2013-8-26 08:53:05

学习了                           

wangxuedong 发表于 2013-8-26 08:57:51

请问同一设备解出来的码有规律吗?

tianxian 发表于 2013-8-26 09:07:29

wangxuedong 发表于 2013-8-26 08:57 static/image/common/back.gif
请问同一设备解出来的码有规律吗?

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

wangxuedong 发表于 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

tianxian 发表于 2013-8-26 09:22:06

wangxuedong 发表于 2013-8-26 09:13 static/image/common/back.gif
那74位的怎么解释,比如:8950,4400,650,1650,650,500,650,550,650,1650,650,550,650,500,650,550,600,600, ...

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

耶和华 发表于 2013-8-26 09:22:11

好东东,谢谢

jsntzxh 发表于 2013-8-26 10:39:26

好东东,收藏

wangxuedong 发表于 2013-8-26 21:54:12

tianxian 发表于 2013-8-26 09:22 static/image/common/back.gif
这个看不懂,你这些数据是怎么来的

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

jz701209李 发表于 2013-8-26 22:13:26

学习一下........

haso2007 发表于 2013-9-9 12:08:24

mark,多谢分享

xiaoxei 发表于 2013-9-9 16:07:01

灰常感谢,我不知道原来LZ在这里分享了,不然我也不会特别发帖问这个问题。一句话,灰常感谢LZ。{:handshake:}

tianxian 发表于 2013-9-9 16:36:19

xiaoxei 发表于 2013-9-9 16:07 static/image/common/back.gif
灰常感谢,我不知道原来LZ在这里分享了,不然我也不会特别发帖问这个问题。一句话,灰常感谢LZ。{:handshak ...

不客气      

abc220 发表于 2013-9-9 21:26:34

刚好有用到,正在学习,感谢楼主。

eedesign 发表于 2013-9-9 21:34:18

不错,我也是这个方法,画板的把io没接在中端上{:mad:}

cyq001 发表于 2013-9-10 08:29:20

学习一下

xou822 发表于 2013-9-10 09:29:59

学习了

谢谢分享{:handshake:}

yixuanyuxiao 发表于 2013-9-18 17:22:29

红外解码mark

mrliangg 发表于 2014-2-7 14:55:37

正在查这些资料呢,,谢谢

zxd08 发表于 2014-2-7 15:37:32

定时最好是50us 或者80us的

xiaojun2019 发表于 2014-2-8 17:41:00

标志,红外解码

zzzljb 发表于 2014-2-9 21:17:47

{:biggrin:} 正在学习

sunliezhi 发表于 2014-2-10 10:16:51

状态机,不错

ST_ATMEL_NXP 发表于 2014-8-4 15:48:44

有用,标记一下!

JZcrystalwlh888 发表于 2014-8-31 16:51:21

问楼主一个问题。我把它移植到AVR上怎么不行啊

颜靖峰 发表于 2014-8-31 16:53:20

占用了一个定时器,可不可以用中断啊,修改一下延时就好了,不用定时器。

JZcrystalwlh888 发表于 2014-8-31 16:57:21

你好,我把你的红外遥控程序移植到我的M48单片机上,怎么不成功呢,是哪里的问题

JZcrystalwlh888 发表于 2014-8-31 16:57:45

你好,我把你的红外遥控程序移植到我的M48单片机上,怎么不成功呢,是哪里的问题

jyrpxj 发表于 2014-8-31 17:01:22

使用一个定时器和引脚电平变化中断。就不需要定时调用解码程序了。

JZcrystalwlh888 发表于 2014-8-31 17:01:29

你好,我把你的红外遥控程序移植到我的M48单片机上,怎么不成功呢,是哪里的问题

JZcrystalwlh888 发表于 2014-8-31 17:03:14

现在问题是不能解码,我的晶体是8M的

JZcrystalwlh888 发表于 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_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;
         }
      
}

tianxian 发表于 2014-9-3 21:59:41

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

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

tianxian 发表于 2014-9-3 22:00:33

颜靖峰 发表于 2014-8-31 16:53
占用了一个定时器,可不可以用中断啊,修改一下延时就好了,不用定时器。 ...

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

JZcrystalwlh888 发表于 2014-9-4 12:32:30

不行哦,我用M48的T2定时器

yytyu 发表于 2014-10-21 13:56:25

正在查这些资料呢,,谢谢

iygniqiew 发表于 2014-10-24 08:05:29

谢谢,分享!!

lusson 发表于 2014-10-24 08:22:50

天。。125us调用一次,得占用多少CPU资源啊。

蓝蓝的恋 发表于 2014-10-24 08:32:13

记下来吧,125是不是太频繁了

terencechang 发表于 2014-10-24 08:39:52

同一个单片机 如果做到同时编码,同时解码。有做过类似的出来指导下!!

nongsan 发表于 2014-10-24 09:34:48

谢谢分享,学习了

l769109884 发表于 2014-10-24 09:52:32

收藏了,如果任务多的话,会有其它中断,会不会影响到解码的?

tianxian 发表于 2014-10-24 10:46:08

l769109884 发表于 2014-10-24 09:52
收藏了,如果任务多的话,会有其它中断,会不会影响到解码的?

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

yat 发表于 2014-11-1 15:11:32

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

freshuman 发表于 2015-7-5 17:02:05

这个程式是不是参考一位前人(现在没有找那个贴)所写的都是用125us区别就是你用了开关语句,他用if了,我也是一直用那前人的那个方式解码,时实性好。

freshuman 发表于 2015-7-5 22:47:31

看一下好像没有写完整,程式中只识别“0”却没有“1”的识别。

freshuman 发表于 2015-7-5 23:12:44

再仔细看一下,好像漏洞百出,LZ有没有实际测试过?

youlongam 发表于 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;

}

}

iamfiavarst 发表于 2015-7-6 11:34:42

125us对51单片机来说,12M晶振时时间非常吃紧......

dory_m 发表于 2015-7-6 12:37:54

学习,谢谢!!!

杰菱科技 发表于 2015-7-6 14:15:26

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

tianxian 发表于 2015-7-6 22:27:47

freshuman 发表于 2015-7-5 23:12
再仔细看一下,好像漏洞百出,LZ有没有实际测试过?

测试过,漏洞在哪

52HLX 发表于 2015-9-1 16:03:09

mark.....

大超134 发表于 2015-9-1 21:26:14

感谢分享!

wangfan0212 发表于 2015-10-24 20:42:24

好用。效果不错。stm816M.在中断运行解码程序只花了2.7us.125us的中断频率。剩余时间很多。

babys 发表于 2015-11-3 09:18:40

跟我之前看到的一个帖子挺像。马克一下

sailing8 发表于 2015-11-23 00:20:24

这个状态法的程序貌似只能解短按,没有解决长按状态的解码问题

iqxt88 发表于 2015-11-23 12:37:44

mark                                    

sumec_jszx 发表于 2020-4-15 14:45:57

不错,谢谢分享

changshs 发表于 2020-7-15 21:00:15

此中断函数中的静态变量,最好不要再函数中定义,东西写多了,容易跑飞。。。。

fengyunyu 发表于 2020-7-15 22:32:51

不错,好帖子

lijianxing 发表于 2020-7-23 18:13:00

谢谢分享

lnso 发表于 2020-7-25 15:47:15

这种有长按,短按功能 这个程序就跑不了

lnso 发表于 2020-7-25 15:48:00

iamfiavarst 发表于 2015-7-6 11:34
125us对51单片机来说,12M晶振时时间非常吃紧......

pic的也一样吃紧

kap 发表于 2020-7-25 15:52:22

lnso 发表于 2020-7-25 15:48
pic的也一样吃紧

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

无眼顽石 发表于 2020-7-25 17:13:37

也可以上下沿中断加定时器数数,效率更高些。
页: [1]
查看完整版本: 分享红外解码 基于125us定时 任意IO