Chinaunix首页 | 论坛 | 博客
  • 博客访问: 241527
  • 博文数量: 181
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 422
  • 用 户 组: 普通用户
  • 注册时间: 2016-06-09 15:34
个人简介

你好 世界

文章分类

全部博文(181)

文章存档

2016年(181)

我的朋友

分类: C/C++

2016-06-06 23:51:25

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

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

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

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

遥控发射器专用芯片很多,根据编码格式可以分成两大类,这里我们以运用比较广泛,解码比较容易的一类来加以说明,现以日本NEC的uPD6121G组成发射电路为例说明编码原理(一般家庭用的DVD、VCD、音响都使用这种编码方式)。当发射器按键按下后,即有遥控码发出,所按的键不同遥控编码也不同。这种遥控码具有以下特征:采用脉宽调制的串行码,以脉宽为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()是接受数据时判断高低电平。

点击(此处)折叠或打开

  1. /*------------------------------------------------------------*-
  2.   红外收发.C
  3.   ------------------------------------------------------------
  4.   遥控器测试
  5. -*------------------------------------------------------------*/
  6.   
  7. #include <reg52.h>
  8.   
  9. // --- 红外接收一体化输出口 ----------------------------------
  10. sbit IR_Out = P3^2;
  11.   
  12. bit START_Flag = 0;
  13. bit BOOT_REPEATING_CODE_Flag = 0;
  14. unsigned char DATA[4] = {0};
  15. bdata unsigned char TEMP_BIT;
  16.   
  17. sbit B0 = TEMP_BIT^0;
  18. sbit B1 = TEMP_BIT^1;
  19. sbit B2 = TEMP_BIT^2;
  20. sbit B3 = TEMP_BIT^3;
  21. sbit B4 = TEMP_BIT^4;
  22. sbit B5 = TEMP_BIT^5;
  23. sbit B6 = TEMP_BIT^6;
  24. sbit B7 = TEMP_BIT^7;
  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.     for(x = 0; x <= (Us/200-1); x++);
  42. }
  43. void DELAY_Ms(unsigned int Ms)
  44. {
  45.     unsigned int x,y;
  46.     for(x = 0; x <= (Ms-1); x++)
  47.     {
  48.         for(y = 0; y <= 120; y++);
  49.     }
  50. }
  51.   
  52. void main()
  53. {
  54.     unsigned char i;
  55.     UART_Initial();
  56.     IR_Out = 1;
  57.     while(1)
  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.             for(i =0;i <4; 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.             for(i =0;i <4; i++)
  76.             {
  77.                 SBUF = DATA[i];
  78.                 while( TI == 0 );
  79.                 TI = 0;
  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 = 1; // TR1: timer 1 run
  94.   
  95.     EA = 0; // 关闭总中断
  96.     ES = 0; // 关闭串口中断
  97. }
  98.       
  99.   
  100. bit START_Judge()
  101. {
  102.     bit TEMP_Flag = 1;
  103.     unsigned char i = 0;
  104.   
  105.     //在正常无遥控信号时,一体化红外接收头输出是高电平,程序一直在循环。
  106.     while ( IR_Out == 1);
  107.   
  108.     //重复10次,目的是检测在6876~8352微秒内如果出现高电平就退出解码程序
  109.     for(i =0;i <9; i++)
  110.     {
  111.         DELAY_Us(800); // 测试实际延时约为764~928us
  112.         if ( IR_Out == 1 )
  113.         {
  114.             TEMP_Flag = 0;
  115.             break;
  116.         }
  117.     }
  118.       
  119.     return TEMP_Flag;
  120. }
  121.   
  122. bit BOOT_REPEATING_CODE_Judge()
  123. {
  124.     bit TEMP_Flag = 1;
  125.     while( IR_Out == 0 ) ; // 等待高电平避开9毫秒低电平引导脉冲
  126.   
  127.     DELAY_Ms(1); // 测试实际延时约为1.007ms
  128.     DELAY_Ms(1); // 测试实际延时约为1.007ms
  129.     DELAY_Us(200); // 0.086ms
  130.     DELAY_Us(200); // 0.086ms
  131.     DELAY_Us(200); // 0.086ms
  132.                             // 共计2.272ms
  133.   
  134.     if( IR_Out == 0 )
  135.     {
  136.         TEMP_Flag = 1; // 是连发码
  137.     }
  138.     else
  139.     {
  140.         TEMP_Flag = 0; // 不是连发码,而是引导码
  141.     }
  142.     return TEMP_Flag;
  143. }
  144. bit H_L_LEVEL_Judge()
  145. {
  146.     while( IR_Out == 0 ); // 等待地址码第一位的高电平信号
  147.     DELAY_Us(800); // 测试实际延时约为764~928us
  148.     if ( IR_Out == 1)
  149.     {
  150.         DELAY_Ms(1); // 测试实际延时约为1.007ms
  151.         return 1;
  152.     }
  153.     else
  154.     {
  155.         return 0;
  156.     }
  157. }


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



阅读(1803) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~