winfuture 发表于 2012-11-8 22:29:34

高效NEC遥控解码,任意IO(精简10行C语言)

以前刚学MCU时做过红外遥控解码,参考别人的程序写了老半天,总共几十行,用外部中断方式,而且还很不好使。
后来在做一个遥控控制RGB灯变色时,发现用外部中断方式解码在按键时RGB灯老闪(中断处理解码去了,PWM波程序被打断了,PWM用软件模拟的),
这时想可不可以不用中断来做呢,就在网上搜了搜,发现一个,就在这个基础上做了大量优化,最后的解码程序只有10行左右,且灵敏度也很好,给大家分享一下。

悄悄告诉你:这个代码相当好用!各种MCU移植都很方便
上源码:(只是核心部分)

sbit IR_IO = P1^6;          // IR管脚 任意IO

//定时器初始化为125uS中断一次
void IR_decode_init(void)
{
   TMOD |= 0x12;                     // T1定时方式2
//--------------设定中断时间------------------------
   TH0 = (-125);TL0 = (-125); // 定时125us 12M晶振
    ET0 = 1;      TR0 = 1;      // 启动T1
    EA = 1;                              // 总中断允许
}
//解码的相关数据            
bit Irprot_LastState = 0;   // 端口状态位
uchar codeCnt = 0;          // 数据码位计数
uchar irTime;                   // 码时间,用于以125us时间计时
uchar IR_data;            // 接收数据缓存

//下面为解码的关键部分,大家自己去分析。主思路就是计算下降沿间隔,其余什么高电平多少时间,低电平多少时间都不关心,因此代码比较精简。
//125us执行中断程序一次
void Timer0(void) interrupt 1                                                            
{   
   irTime++;
   if(irTime==240) {irTime--;codeCnt=0x3f;} // ir解码后码值存放时间, 240*125us = 30ms
   if(IR_IO)   Irprot_LastState=1; // 记录IO状态
   else if(Irprot_LastState)       // 有下降沿
   {
      Irprot_LastState = 0;      // 下降沿后IO状态记录为0
      if(irTime<24)                // 小于24*125us=3ms的间隔才进行处理
      {
         codeCnt++;codeCnt &= 0x1f;
         IR_data <<= 1;
         if( irTime>15 )   IR_data++;// 大于15*125us=1.875ms的间隔为数据1
      }
      irTime = 0;                  // 下降沿处理完成,将时间清0
   }
}

使用时只需查询codeCnt的值是否等于31(如果解码完成30ms后才去判断codeCnt==31,codeCnt将不会再是31,可以在程序中修改该标志的存活时间),是表示解码完成,解码数据放于IR_data[]数组中; 因为该解码的核心思想是检测两个下降沿相隔的时间,所以只要两个下降沿间隔符合,不管高低电平时间都会进行解码,所以如果要提高准确性,需把IR_data[]中的数据进行检验,
也就是看是否IR_data==IR_data,如果是,99%是正确的.




devcang 发表于 2012-11-8 22:39:59

{:victory:}

不错,绑定

wiisir 发表于 2012-11-8 22:54:14

谢谢!以后有机会试试看

sunliezhi 发表于 2012-11-8 23:24:32

CTRL+D

lxvtag 发表于 2012-11-8 23:33:44

LZ这个思路不错,标记下。

ijlc1314 发表于 2012-11-8 23:50:02

哈哈,自己写的比这个长好多,收下学习啦,谢谢LZ

zyyn123 发表于 2012-11-9 07:21:09

这个任意IO口比较方便,哪天试试。

fenxiang1103 发表于 2012-11-9 08:46:22

思路很好,代码页很简洁,收下了

lavenderfr 发表于 2012-11-9 09:29:39

以后试试

lycreturn 发表于 2012-11-9 11:49:00

好东西收藏先~

pcwinner 发表于 2012-11-9 11:59:28

125us执行中断程序一次
也够利害的!

tonyone 发表于 2012-11-9 22:41:12

留个记号先

zy0818 发表于 2012-11-9 23:41:10

留个记号~~

michael.yang 发表于 2012-11-9 23:49:41

markmarkmark

zhonggp 发表于 2012-11-9 23:54:59

125us中断一次,51单片机,建议将计算部分移出来,然后中断就读几个数完了,否则很容易死机.加多几个中断的活,另外没有加长按哦.

不过挺不错的,一般够用了.

Stone_up 发表于 2012-11-10 13:26:21

谢谢,手下了。

zhzj2007 发表于 2012-11-10 13:46:20

不错,绑定                  

maxims 发表于 2012-11-10 13:47:46

{:lol:}谢谢,收下了。

nec高效10行代码遥控器解码

kmani 发表于 2012-11-10 13:49:16

好东西,要收下

lxa0 发表于 2012-11-10 15:02:14

看不大懂C语言
有汇编的吗?

xue_pic 发表于 2012-11-10 15:21:03

谢谢楼主这个真的不错

haizaolan 发表于 2012-11-10 16:02:59

不错,学习。

nihao_x 发表于 2012-11-10 16:26:02

收藏起了{:smile:}

vvi 发表于 2012-11-10 16:41:28

简洁高效,好东西。

tonyone 发表于 2012-11-11 17:03:05

要是把“遥控控制RGB灯变色”全部程序发出来就好了{:tongue:}

weiwei4 发表于 2012-11-11 17:18:25

记号,不错的程序

propor123 发表于 2012-11-11 17:59:36

学习一下!

beijinggood2008 发表于 2012-11-11 20:34:46

支持原创!

枫恋寒2012 发表于 2012-11-11 21:00:38

我用外部中断写的 好长啊
留个记号 有空试试

呆子 发表于 2012-11-11 21:02:03

很不错,支持一个

eddia2012 发表于 2012-11-11 21:33:17

{:smile:}下同是用外部中断写的也很简洁,MCU为sonix 的SN8P2501B :

/**************************************************************
                  Interrupt Program Zone
**************************************************************/
__interrupt intserv(void)
{
    if(FT0IRQ)
    {
            T0 = D_T0_Preset;
          FT0IRQ =0;
                IR_Time80us++;
           }
        //======================INT0 interrupt IR decode=======================
        if(FP00IRQ)
        {
                FP00IRQ = 0;

      //----------------------ir code receive-----------------------
          if ((IR_Time80us >= D_IR_HeadT_Min) && (IR_Time80us < D_IR_HeadT_Max))
                {
                        IR_bits = 0;
                }
                else if(IR_bits < 32)
                {
                  IR_bits++;
                        IR_Code.dwords <<=1;
                        if(IR_Time80us >= D_IR_TimeBitAs1) IR_Code.bytes |= 0x01;
                }               
          else
          {
                        if((IR_Code.bytes == 0x00)&&(IR_Code.bytes == 0xff))                                        //custor code
                 {
                             if(IR_Code.bytes | IR_Code.bytes == 0xffu) {OpCode = IR_Code.bytes;IR_OK_F=1;}
                          else                                             {IR_OK_F=0;}
                 }   
      }
                IR_Time80us = 0x00;          
        }
}

yaoliangwu 发表于 2013-3-5 22:43:53

MARK,做个记号

zenghl 发表于 2013-3-5 22:49:34

果断收藏!!!

咱厝人 发表于 2013-3-5 23:09:37

{:handshake:}{:call:}收藏了

aaa8001 发表于 2013-3-6 09:15:52

谢谢分享~~

Garbage614 发表于 2013-3-6 09:20:35

不用费这劲,串口1200或者2400波特率直接解码

dong889 发表于 2013-3-6 09:20:51

收下学习!谢谢分享~

nsj21n 发表于 2013-3-7 10:07:52

真不错,学习了!

cqgdlq 发表于 2013-3-7 13:45:23

好东西,要收下

shsofts 发表于 2013-3-7 21:19:55

记号 收藏了

215661599 发表于 2013-3-7 21:57:11

xslff 发表于 2013-3-7 22:16:51

记号备用,谢谢!

夏日么么茶 发表于 2013-3-7 22:35:55

不错,拿来试试看

qinchl 发表于 2013-3-8 11:17:25

收藏来学习,谢谢LZ。

xiaojun2019 发表于 2013-3-8 16:44:06

一定要标记学习下

dujuan8693 发表于 2013-3-8 16:45:55

好东西,要收下

jz701209李 发表于 2013-3-8 20:46:59

不错,学习学习

younge 发表于 2013-3-8 21:06:34

Garbage614 发表于 2013-3-6 09:20 static/image/common/back.gif
不用费这劲,串口1200或者2400波特率直接解码

有想法,占一个

pangbin4 发表于 2013-3-8 21:34:20

好贴留名先

lurendezi 发表于 2013-3-8 22:04:35

马克,,,,,,,,

Taylor1 发表于 2013-3-9 15:09:37

Mark 外部中断状态解码

yoyobbs 发表于 2013-3-9 15:21:30

MARK.........

miller8708 发表于 2013-3-11 16:49:55

不错 用到后再看看

wzhscj 发表于 2013-3-11 17:18:25

果断收藏!!!

miraclever 发表于 2013-3-11 17:21:49

{:smile:}感谢分享

cddxhy 发表于 2013-3-11 17:46:55

好东西,要收下
Mark

ethan_free 发表于 2013-3-11 17:57:08

不错,收下啦

slotg 发表于 2013-3-11 23:36:04

最近刚做这方面的实验, 外部中断或是这种中断的方式都会让CPU没有时间再去处理其他的工作.
假如系统还有使用其他中断的话, 也会影响到遥控器信号的接收稳定性.不晓得是否还有其他的
解决方案?

shinehjx 发表于 2013-3-12 08:36:10

谢谢楼主分享

sundayzh 发表于 2013-3-12 09:59:42

不错,谢谢楼主

hamipeter 发表于 2013-3-19 09:51:22

都不错,支持下

lryxr2507 发表于 2013-3-19 10:38:11

收藏先,留着备用.

dyzhenhuai 发表于 2013-3-24 18:40:18

支持,支持,学习,学习!!!

catywu 发表于 2013-3-24 18:51:48

不错,学习学习

ka1265 发表于 2013-3-24 21:20:30

收藏先,学习中

cyq001 发表于 2013-3-25 09:39:57

谢谢,收藏

Louis_Bright 发表于 2013-3-25 10:10:42

我来泼几瓢冷水,不过在泼水之前还是夸奖楼主几句:很认真!做得很精简!

但正是因为你做得很精简,所以……反而是有问题的。
这个问题的根本原因就在于……你将实际情况想象得太理想了。
你说灵敏度在99%以上,你跑到一个到处都是日光灯的环境试试?

1、对于红外遥控器来说,其实灵敏度和误码率,是一对矛盾的。
从你自己的描述和程序来看,你其实是牺牲了误码率的,也就是说,很可能外界的干扰(其它发红外线的东西或者类似的遥控器)会误操作你的接收设备的。在我看来,灵敏度很重要,其实误码率更重要。
2、这个程序,只适合移植到小项目中,如果项目稍微大一点,你分给遥控器的时间片还是太多了,系统开销会不够的。

winfuture 发表于 2013-3-25 18:57:15

Louis_Bright 发表于 2013-3-25 10:10 static/image/common/back.gif
我来泼几瓢冷水,不过在泼水之前还是夸奖楼主几句:很认真!做得很精简!

但正是因为你做得很精简,所以… ...

误码率肯定存在,不过不会像楼上说的那样不堪,这个程序是在一大片日光灯下调试的,没有存在乱接收的现象(以测试了很长时间),这个大家可以自己验证。
另外关于时间片开销大得问题,125us应该不算很大开销,因为设为125us还用来做时间计数用的。另外时间间隔可以调至400us一次,如果再大些的话就不能解码了。

ndt2000 发表于 2013-3-25 20:16:56

好使,留个记号

angler12 发表于 2013-4-1 22:31:38

Garbage614 发表于 2013-3-6 09:20 static/image/common/back.gif
不用费这劲,串口1200或者2400波特率直接解码

串口解码,求教?

Garbage614 发表于 2013-4-2 08:52:50

angler12 发表于 2013-4-1 22:31 static/image/common/back.gif
串口解码,求教?

你把IR的接收口街道串口的RX引脚   波特率设置在2400或者1200 就能收到数据了

灰灰不会飞 发表于 2013-4-2 10:01:03

mark 好帖 顶

caicai2317 发表于 2013-4-2 10:20:19

忽略前导码,可以啊,呵呵

number5 发表于 2013-4-2 14:59:35

mark下来学习~~

angler12 发表于 2013-4-3 08:40:48

Garbage614 发表于 2013-4-2 08:52 static/image/common/back.gif
你把IR的接收口街道串口的RX引脚   波特率设置在2400或者1200 就能收到数据了 ...

谢谢,不错的解决方法!

cyq001 发表于 2013-4-3 08:48:10

记号,谢谢

pxq8410 发表于 2013-4-3 14:34:50

记号,留存

clarkewayne 发表于 2013-4-3 23:14:50

最近在研究这个 谢谢

linguicheng 发表于 2013-4-4 17:32:40

红外采用中断方式来处理,我以前做过,是有很多缺点。看了楼主的定时方式,还是不错的。可以借鉴。

大漠游民 发表于 2013-4-5 09:45:03

好东西,要收下

downtoearth 发表于 2013-4-5 09:55:21

mark,mark,mark

kxm2008 发表于 2013-4-5 09:57:40

有机会试试看

cyq001 发表于 2013-4-5 10:54:58

好东西,要收下

2005n2005 发表于 2013-4-21 23:51:35

学习了            

inkfish321 发表于 2013-4-22 03:11:41

最近也要搞一个rgb灯,还没加遥控。

renwocai 发表于 2013-4-22 06:23:36

谢谢楼主分享,这个就是采样的原理

hu_kai 发表于 2013-4-22 08:11:08


好东西,要记下

miller8708 发表于 2013-4-24 00:33:21

先收藏再说

l769109884 发表于 2013-4-27 14:25:59

哈哈,,明白了,,下次要移植试下,,,多谢LZ分享!!

gongyoutao 发表于 2013-4-28 01:05:45

试一下!

yh8637 发表于 2013-4-28 17:31:20

if(irTime==240) {irTime--;codeCnt=0x3f;} // ir解码后码值存放时间, 240*125us = 30ms
这句什么时候能执行到?有空回复下,谢谢!

mcu5i51 发表于 2013-4-28 17:52:09

好热闹,很不错的代码

winfuture 发表于 2013-4-28 19:33:58

yh8637 发表于 2013-4-28 17:31 static/image/common/back.gif
if(irTime==240) {irTime--;codeCnt=0x3f;} // ir解码后码值存放时间, 240*125us = 30ms
这句什么时候能 ...

解码过后(或者没有下降沿后)30ms irTime就会加到240,然后会一直为240(如果没有下降沿过来),codeCnt就会变成0x3f(0011 1111),这样是为了方便 codeCnt++;codeCnt &= 0x1f;
这段代码,这样再次进入解码时,codeCnt又会自动从0开始计数

HeP028 发表于 2013-4-28 21:57:41

标记,这要用

qq511153186 发表于 2013-4-29 22:35:56

很好的代码,最近自己写了一个,

MCU89c52 发表于 2013-4-30 11:56:45

{:biggrin:}下来试了一下!真的是很不错!

qq502835899 发表于 2013-4-30 13:26:14

mark;万恶的7个字节;

benqme 发表于 2013-4-30 15:06:31

copy下来再研究

qq511153186 发表于 2013-4-30 15:35:33

好东西,正在玩这个

HeP028 发表于 2013-4-30 23:17:11

本帖最后由 HeP028 于 2013-4-30 23:18 编辑

11.0592MHZ

误码率很搞啊00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 01 3A C5 00 FF 3A C5 00 FF 3A C5 00 7F 3A C5 00 FF 3A C5 00 FF 3A C5 00 07 3A C5 00 FF 3A C5 00 FF 3A C5 00 7F 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 03 3A C5 00 03 3A C5 00 FF 3A C5 00 1F 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 7F 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 0F 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 01 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 0F 3A C5 00 0F 3A C5 00 07 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 01 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 03 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 1F 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 1F 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 7F 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 3F 3A C5 00 FF 3A C5 00 7F 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 FF 3A C5 00 0F 3A C5 00 FF 3A C5 00 FF 3A C5

void IRConfiguration(void)
{
        T2MOD= 0X00;                                                                        //16位自动重装
        T2CON= 0X00;
        RCAP2H = (65535-115) / 256;
        RCAP2L = (65535-115) % 256;
        ET2    = 1;
        TR2    = 1;
        EA   = 1;
}

但为何老是误第二字节呢?
页: [1] 2
查看完整版本: 高效NEC遥控解码,任意IO(精简10行C语言)