应该说现在每一块开发板都带有红外模块,并且大都配置了相应的程序。但其实自己动手写解码程序,更能锻炼自己所学,且不谈程序写的如何,这个过程中肯定是受益良多的。现在我就把我花一下午写出的解码程序与大家分享,期待高手的光临指正

  首先,必须要了解一些基本原理。其实按下遥控器的某一个键,遥控器会发出一连串经过调制后的信号,这个信号经过红外一体化模块接收后,输出解调后的数字脉冲,每个按键对应不同的脉冲,故识别出不同的脉冲就能识别出不同的按键。

上图就是很常见的车载MP3遥控器,比较小巧,很好用。下面是红外发射和接受原理:

到此读者可能会有疑惑,那么不同的调制解调方法那么出来的脉冲规则是不一样的?是的,的确如此。

  遥控发射器专用芯片很多,根据编码格式可以分成两大类,这里我们以运用比较广泛,解码比较容易的一类来加以说明,现以日本NEC的uPD6121G组成发射电路为例说明编码原理(一般家庭用的DVD、VCD、音响都使用这种编码方式)。当发射器按键按下后,即有遥控码发出,所按的键不同遥控编码也不同。这种遥控码具有以下特征:
  采用脉宽调制PWM的串行码,以脉宽为0.565ms、间隔0.56ms、周期为1.125ms的组合表示二进制的“0”;以脉宽为0.565ms、间隔1.685ms、周期为2.25ms的组合表示二进制的“1”,其波形如图所示。

如图可见,0与1前端的低电平持续都是0.56ms,那么就是后面的高电平持续时间不同,0为0.56ms,1为1.685ms,找到不同之处,编程时就有识别的依据了!

上述“0”和“1”组成的32位二进制码经38kHz的载频进行二次调制以提高发射效率,达到降低电源功耗的目的。然后再通过红外发射二极管产生红外线向空间发射,如图所示。

UPD6121G产生的遥控编码是连续的32位二进制码组,其中前16位为用户识别码,能区别不同的电器设备,防止不同机种遥控码互相干扰。该芯片的用户识别码固定为十六进制01H;后16位为8位操作码(功能码)及其反码。UPD6121G最多额128种不同组合的编码。

请看下图,来自网络:

当一个键按下超过36ms,振荡器使芯片激活,将发射一组108ms的编码脉冲,这108ms发射代码由一个引导码(9ms),一个结果码(4.5ms),低8位地址码(9ms~18ms),高8位地址码(9ms~18ms),8位数据码(9ms~18ms)和这8位数据的反码(9ms~18ms)组成。如果键按下超过108ms仍未松开,接下来发射的代码(连发码)将仅由起始码(9ms)和结束码(2.25ms)组成。(实际上人手的动作是很慢的,即使你快速的按下按键,可能对于芯片来说还是超过108ms,所以如何处理连发码是很关键的)

遥控器在按键按下后,周期性地发出同一种32位二进制码,周期约为108ms。一组码本身的持续时间随它包含的二进制“0”和“1”的个数不同而不同,大约在45~63ms之间,图为发射波形图。

下面是我写的代码,按键编码通过串口发送到电脑端:

由于时间关系,代码注释不多。

其中START_Judge()函数是判断9ms低电平,既是判断有无遥控信号。

BOOT_REPEATING_CODE_Judge()是判断是引导码还是连发码,引导码则进入接受数据环节,连发码表明数据已经接受结束。

H_L_LEVEL_Judge()是接受数据时判断高低电平。

如果乱码,请参考:

http://blog.csdn.net/mhjerry/article/details/6601324

注明:以下代码为纯软件方式,没有用到中断,定时器方式,纯CPU查询,但测试结果倒也可以,至少比较稳定,得到的码值不管对不对,都是那个值。

  1. /*------------------------------------------------------------*-
  2. 红外收发.C
  3. ------------------------------------------------------------
  4. 遥控器测试
  5. -*------------------------------------------------------------*/
  6.  
  7. #include <reg52.h>
  8.  
  9. // --- 红外接收一体化输出口 ----------------------------------
  10. sbit IR_Out = P3^;
  11.  
  12. bit START_Flag = ;
  13. bit BOOT_REPEATING_CODE_Flag = ;
  14. unsigned ] = {};
  15. bdata unsigned char TEMP_BIT;
  16.  
  17. sbit B0 = TEMP_BIT^;
  18. sbit B1 = TEMP_BIT^;
  19. sbit B2 = TEMP_BIT^;
  20. sbit B3 = TEMP_BIT^;
  21. sbit B4 = TEMP_BIT^;
  22. sbit B5 = TEMP_BIT^;
  23. sbit B6 = TEMP_BIT^;
  24. sbit B7 = TEMP_BIT^;
  25.  
  26. // --- 有无遥控信号判断函数 ----------------------------------
  27. bit START_Judge();
  28.  
  29. // --- 连发码判断函数 ----------------------------------------
  30. bit BOOT_REPEATING_CODE_Judge();
  31.  
  32. // --- "0"和"1"识别 ------------------------------------------
  33. bit H_L_LEVEL_Judge();
  34.  
  35. // --- 串口初始化 --------------------------------------------
  36. void UART_Initial();
  37.  
  38. void DELAY_Us(unsigned int Us)
  39. {
  40. unsigned int x;
  41. ; x <= (Us/-); x++);
  42. }
  43. void DELAY_Ms(unsigned int Ms)
  44. {
  45. unsigned int x,y;
  46. ; x <= (Ms-); x++)
  47. {
  48. ; y <= ; y++);
  49. }
  50. }
  51.  
  52. void main()
  53. {
  54. unsigned char i;
  55. UART_Initial();
  56. IR_Out = ;
  57. )
  58. {
  59. START_Flag = START_Judge();
  60. BOOT_REPEATING_CODE_Flag = BOOT_REPEATING_CODE_Judge();
  61. if ( START_Flag && !BOOT_REPEATING_CODE_Flag )
  62. {
  63. ;i <; i++)
  64. {
  65. B0 = H_L_LEVEL_Judge();
  66. B1 = H_L_LEVEL_Judge();
  67. B2 = H_L_LEVEL_Judge();
  68. B3 = H_L_LEVEL_Judge();
  69. B4 = H_L_LEVEL_Judge();
  70. B5 = H_L_LEVEL_Judge();
  71. B6 = H_L_LEVEL_Judge();
  72. B7 = H_L_LEVEL_Judge();
  73. DATA[i] = TEMP_BIT;
  74. }
  75. ;i <; i++)
  76. {
  77. SBUF = DATA[i];
  78. );
  79. TI = ;
  80. }
  81. }
  82. }
  83. }
  84.  
  85. void UART_Initial()
  86. {
  87. SCON = 0x50; // SCON: 模式 1, 8-bit UART, 使能接收
  88.  
  89. TMOD |= 0x20; // TMOD: timer 1, mode 2, 8-bit reload
  90.  
  91. TH1 = 0xFD; // TH1: reload value for 9600 baud @
  92. // 11.0592MHz
  93. TR1 = ; // TR1: timer 1 run
  94.  
  95. EA = ; // 关闭总中断
  96. ES = ; // 关闭串口中断
  97. }
  98.  
  99. bit START_Judge()
  100. {
  101. bit TEMP_Flag = ;
  102. unsigned ;
  103.  
  104. //在正常无遥控信号时,一体化红外接收头输出是高电平,程序一直在循环。
  105. );
  106.  
  107. //重复10次,目的是检测在6876~8352微秒内如果出现高电平就退出解码程序
  108. ;i <; i++)
  109. {
  110. DELAY_Us(); // 测试实际延时约为764~928us
  111. )
  112. {
  113. TEMP_Flag = ;
  114. break;
  115. }
  116. }
  117.  
  118. return TEMP_Flag;
  119. }
  120.  
  121. bit BOOT_REPEATING_CODE_Judge()
  122. {
  123. bit TEMP_Flag = ;
  124. ) ; // 等待高电平避开9毫秒低电平引导脉冲
  125.  
  126. DELAY_Ms(); // 测试实际延时约为1.007ms
  127. DELAY_Ms(); // 测试实际延时约为1.007ms
  128. DELAY_Us(); // 0.086ms
  129. DELAY_Us(); // 0.086ms
  130. DELAY_Us(); // 0.086ms
  131. // 共计2.272ms
  132.  
  133. )
  134. {
  135. TEMP_Flag = ; // 是连发码
  136. }
  137. else
  138. {
  139. TEMP_Flag = ; // 不是连发码,而是引导码
  140. }
  141. return TEMP_Flag;
  142. }
  143. bit H_L_LEVEL_Judge()
  144. {
  145. ); // 等待地址码第一位的高电平信号
  146. DELAY_Us(); // 测试实际延时约为764~928us
  147. )
  148. {
  149. DELAY_Ms(); // 测试实际延时约为1.007ms
  150. ;
  151. }
  152. else
  153. {
  154. ;
  155. }
  156. }

编辑如下:

01 FE 8B 74 --- 01 FE 8D 72 --- 01 FE 8F 70

01 FE 89 76 --- 01 FE 81 7E --- 01 FE 87 78

01 FE 0F F0 --- 01 FE 2B D4 --- 01 FE 13 EC

01 FE 2D D2 --- 01 FE 33 CC --- 01 FE 1B E4

01 FE 19 E6 --- 01 FE 31 CE --- 01 FE BD 42

01 FE 11 EE --- 01 FE 39 C6 --- 01 FE B5 4A
以上为对应按键的编码。

过程中存在问题:

一是如何有效的识别引导码和连发码,因为这个能直接影响到长时间按键,单片机的响应与否。这个问题,貌似我以解决,就是长时间按键后,单片机识别一次按键后,如果还是同一按键,就不与理睬。

还有一个问题就是,如果连续按下两次按键,该程序能够识别出,但是如果间隔很短,第二下按键的编码容易出错,容易变成这样:

03 FE 8B 74.。。。就是第一个字节出现误差,这个问题现在还未来得及解决。

还有就是本程序对于延时函数的精度要求很高,因为本身处理的脉冲就是MS级别的。所以需要严格的测试延时函数的实际延时时间:

以上的代码,可以看出许多问题,软件延时不准确,大量的“while( IR_Out == 0 ) ;”代码,抗干扰能力弱,容易进入死循环。

下面介绍的这种解码方法,利用外部中断触发程序,定时器定时(但没有设置定时中断程序,即判断TF的值确定定时结束),在代码过程中,开头的一个7.93ms延时,足以滤掉不合法的红外信号。应该说效率质量更高的。

代码注释很详细,在此不在细述:

  1. /*------------------------------------------------------------*-
  2. IR_Decoder.C (v1.00)
  3. ------------------------------------------------------------
  4. 名称:遥控器红外解码,PO口接LED,显示功能码以供查看
  5. 编写:mhjerry
  6. 日期:20011.7
  7. 内容:按遥控器上的按键,会在PO口LED上显示
  8. -*------------------------------------------------------------*/
  9. #include "reg52.h"
  10.  
  11. // 此口为红外信号输入MCU口
  12. sbit IR_Out = P3^;
  13.  
  14. // 主程序运行标志位,运行主程序时LED灭,运行中断程序时LED亮
  15. sbit IR_Flag = P3^;
  16.  
  17. // LED显示口
  18. #define LED_Port P1
  19.  
  20. // 用于存放按键码值,初始化为0000 0000这样接受数据时可以只考虑1了
  21. unsigned ] = {,,,};
  22.  
  23. /*............................................................*/
  24. void main()
  25. {
  26. IR_Out = ; // 此口为MCU输入口,故需要置1
  27. IR_Flag = ; // 灭LED灯
  28. TMOD = 0x01; // 定时器0,方式1
  29. IT0 = ; // 外部中断0,下降沿触发
  30. EX0 = ; // 准许外部中断
  31. EA = ; // CPU准许中断
  32.  
  33. )
  34. {
  35. IR_Flag = ;// 执行主程序时,LED灯灭
  36. }
  37. }
  38. /*------------------------------------------------------------*-
  39. 函数名称:Int0()
  40. 函数输入:无(容许中断时,外部触发)
  41. 函数输出:无
  42. 函数说明:外部中断0中断处理
  43. -*------------------------------------------------------------*/
  44.  
  45. {
  46. unsigned char i,j;
  47. EX0 = ; // 关闭外部中断0
  48. IR_Flag = ; // 执行中断程序时,LED灯亮
  49. i = ; // 0.793ms延时,运行10次
  50. while( --i )
  51. {
  52. // 定时0.793ms,延时0.793ms*10=7.93ms
  53. TH0 = 0xfc;
  54. TL0 = 0xe7;
  55. TR0 = ;
  56. while( !TF0 );
  57. TF0 = ;
  58. TR0 = ;
  59.  
  60. // 这7.93ms期间只要IR_Out变高电平,就非合法的红外信号,跳出
  61. if( IR_Out )
  62. {
  63. EX0 = ; // 准许中断
  64. return ;
  65. }
  66. }
  67.  
  68. // 程序进行到这里,表明是合法的红外信号(利用9ms判断)
  69. while( !IR_Out ); // 等待9ms低电平过去
  70.  
  71. // 程序进行到这里,表明经过9ms低电平
  72. TH0 = 0xf6;
  73. TL0 = 0xff;
  74. TR0 = ;
  75. while( !TF0 );
  76. TF0 = ;
  77. TR0 = ; // 延时2.305ms
  78.  
  79. // IR_Out 为低表明是连发码,不予理睬,跳出
  80. if( !IR_Out )
  81. {
  82. EX0=;
  83. return;
  84. }
  85.  
  86. // 程序进行到这里,表明是引导码,等待4.5ms高电平的过去
  87. while( IR_Out );
  88.  
  89. // 开始接收用户码
  90. ; i<; i++)
  91. {
  92. ; j<; j++)
  93. {
  94. while( !IR_Out ); // 等待低电平过去
  95. dat[i] >>= ; // 把上次的数据位右移一位
  96.  
  97. TH0 = 0xfc;
  98. TL0 = 0xe7;
  99. TR0 = ;
  100. while( !TF0 );
  101. TR0=;
  102. TF0=; //延时0.793ms
  103.  
  104. // 若为数据"1",则延时后IR_Out为高电平
  105. if( IR_Out )
  106. {
  107. dat[i] |= 0x80; // 所有数据位1放最高位
  108. while( IR_Out ); // 等待高电平过去
  109. }
  110. }
  111. }
  112. LED_Port = dat[];
  113. EX0=; // 开中断
  114. return;
  115. }
  116. /*------------------------------------------------------------*-
  117. ---- END OF FILE -------------------------------------------
  118. -*------------------------------------------------------------*/

红外遥控系统原理及单片机软件解码程序,我的编写经历(C版本)的更多相关文章

  1. 基于FPGA的红外遥控解码与PC串口通信

    基于FPGA的红外遥控解码与PC串口通信 zouxy09@qq.com http://blog.csdn.net/zouxy09 这是我的<电子设计EDA>的课程设计作业(呵呵,这个月都拿 ...

  2. 基于Arduino、STM32进行红外遥控信号接收

    catalogue . 遥控器原理简介 . 红外遥控原理 . 常见红外遥控器红外线信号传输协议 . 遙控器的发展 . 实验过程 . 攻击面 . 基于STM32实现红外信号解码 1. 遥控器原理简介 0 ...

  3. 玩转X-CTR100 l STM32F4 l 红外遥控接收

    我造轮子,你造车,创客一起造起来!塔克创新资讯[塔克社区 www.xtark.cn ][塔克博客 www.cnblogs.com/xtark/ ]      X-CTR100控制器具有红外接收头,例程 ...

  4. 红外遥控接收发射原理及ESP8266实现

    红外遥控是利用近红外光进行数据传输的一种控制方式.近红外光波长0.76um~1.5um ,红外遥控收发器件波长一般为 0.8um~0.94um ,具有传输效率高,成本低,电路实现简单,抗干扰强等特点, ...

  5. 46.Linux-分析rc红外遥控平台驱动框架,修改内核的NEC解码函数BUG(1)

    内核版本          :  Linux 3.10.14 rc红外接收类型:  GPIO 类型的NEC红外编码 本章内容 1) rc体系结构分析 2) 分析红外platform_driver平台驱 ...

  6. 51单片机tea5767收音机 红外遥控 自动搜台 存台 DIY

    先看效果图: 显示 频道CH , 频率 100.0Mhz 欢迎信息,1602 内置日文平假名, 正好用来显示博主名称. 焊接前,已经万能面包板上试验成功. 焊接完成以后,1602 的D0 - D7 接 ...

  7. 《嵌入式系统原理与接口技术》——嵌入式系统接口应用基础

    本文为我负责编写的电子工业出版社出版的<嵌入式系统原理与接口技术>一书第七章部分,这里整理的仍然是修改稿,供需要的同学参考,本书为普通高等教育"十二五"规划教材,电子信 ...

  8. 基于STC89C52的oled红外遥控闹钟

    这个红外遥控主要是程序通过对按下的键的键码进行解析,并运行相应的功能代码 一次按键动作的遥控编码信息为 32 位串行二进制码.对于二进制信号“0”,一个脉冲占 1.2ms:对于二进制信号“1”,一个脉 ...

  9. STM32之红外遥控信号自学习实现

    一.序言 很早前就想实现这个红外遥控自学习的这个实验,用于来自己控制房子里如空调等红外遥控设备的自动化,NEC的标准到具体的产品上可能就被厂家定义为不一样了,所以自学习就应该是接收到什么就发送什么,不 ...

随机推荐

  1. information_schema.triggers 学习

    mysql实例中的每一个trigger 对应到information_schema.triggers 中有一行 1.information_schema.triggers 表的常用列: 1.trigg ...

  2. Keil C51.uew

    /L15"Keil C51" Line Comment = // Block Comment On = /* Block Comment Off = */ Escape Char ...

  3. javascript 之 location.href、跨窗口调用函数

    location.href这个东西常常用于跳转,location既是window对象的属性,又是document对象的属性. JavaScript hash 属性 -- 返回URL中#符号后面的内容 ...

  4. Android中退出多个Activity的两个经典方法

    这里介绍两种方法:一种把每个activity记住,然后逐一干掉:另一种思路是使用广播. 方法一.用list保存activity实例,然后逐一干掉 上代码: import java.util.Linke ...

  5. Linux系统编程(19)——正则表达式在sed和awk中的使用

    sed意为流编辑器(Stream Editor),在Shell脚本和Makefile中作为过滤器使用非常普遍,也就是把前一个程序的输出引入sed的输入,经过一系列编辑命令转换为另一种格式输出.sed和 ...

  6. VS Visual Studio connection(); Microsoft Visulal Studio vNext & Azure

    http://www.visualstudio.com/connect-event-vs

  7. 剑指offer-面试题11.数值的整数次方

    题目:实现函数double Power(double base,int exponent),求base的 exponent次方.不得使用库函数,同时不需要考虑大数的问题. 这道题看似很简单: 然而需要 ...

  8. iOS 10 (X8)上CoreData的使用(包含创建工程时未添加CoreData)

    1.在创建工程时未添加CoreData,后期想要使用CoreData则要在工程Appdelegate.h文件中添加CoreData库和CoreData中的通道类(用来管理类实例和CoreData之间的 ...

  9. 【取对数+科学计数法】【HDU1060】 N^N

    Leftmost Digit Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Tota ...

  10. Deppon接口开发

    一.1)  支持的传输协议  http ,暂时只支持HTTP协议进行通信. (2) 支持的数据传输格式  Json  ,所有接口暂只支持json消息格式. (3) 编码格式:UTF-8   交互编码格 ...