查看: 29236|回复: 2

[入门教程] Arduino IRremote多协议红外遥控扩展库[译文]

[复制链接]
惯例,在开始之前,先推荐本系列的前四篇教程。
Arduino红外遥控系列教程2013——发射与接收[链接]
Arduino红外遥控系列教程2013——红外转码[链接]
Arduino红外遥控系列教程2013——红外转码扩展应用1[链接]
Arduino红外遥控系列教程2013——红外协议之NEC[译文][链接]

本系列教程包含两篇翻译文章,这是第二篇,向大家介绍目前最主流的Arduino扩展库之一——IRremote。本库硬件上支持多种主控板,软件上支持多种红外协议本,而且便于扩展和用户自定义,充分体现了开源项目的魅力和价值!本译文遵循CC协议,只要求署名和著名转载出处即可。CC协议详见[链接]

原文[链接]

译文正文

Arduino扩展库之多协议红外遥控库
Arduino 1.0用户注意
本库已支持Arduino 1.0版本,详见Github更新[链接]。安装说明在页面的底部。如果你遇到任何问题请联系作者。

如果你想用红外遥控器来控制你的Arduino?或者用你的Arduino来控制你的立体声音响或其他设备?本红外遥控器库将让您轻松实现多协议红外遥控编码的发送和接收。到目前为止,它已支持NEC,SONY SIRC,Philips RC5,Philips RC6,和原始协议(Raw protocols)。如果你需要额外的协议,还可轻松增加。本库甚至可以记录您的遥控编码并重新发送,如同一个小型的万能遥控器。
01.arduino-ir.jpg
心动不如行动,要使用这个库,请从 github上下载[链接],并按照自述文件中的安装说明操作即可。

如何发送
本红外远程库由两部分组成:负责发射红外遥控器数据包的IRsend,负责接收和解码红外消息的IRrecvIRsend使用一个红外LED连接到Arduino数字输出引脚3。发送消息需要调用所需协议的send方法发送的数据和发送的位数。examples/ IRsendDemo代码提供了一个如何发射编码的简单例子:
  1. #include <IRremote.h>

  2. IRsend irsend;

  3. void setup()
  4. {
  5.   Serial.begin(9600);
  6. }

  7. void loop() {
  8.   if (Serial.read() != -1) {
  9.     for (int i = 0; i < 3; i++) {
  10.       irsend.sendSony(0xa90, 12); // Sony电视电源开关编码
  11.       delay(100);
  12.     }
  13.   }
  14. }
复制代码
本代码实现当电脑串口收到任意字符一个字符则发送的一条Sony电视机电源开/关编码,让Arduino可以打开或关闭电视机。(请注意,根据其协议,SONY编码必须发送3次。)

如何接收
IRrecv使用一个连接到任何数字输入引脚的一体化红外接收器。examples/IRrecvDemo代码展示了一个红外编码接收的简单例子:
  1. #include <IRremote.h>

  2. int RECV_PIN = 11;
  3. IRrecv irrecv(RECV_PIN);
  4. decode_results results;

  5. void setup()
  6. {
  7.   Serial.begin(9600);
  8.   irrecv.enableIRIn(); // 使能红外接收
  9. }

  10. void loop() {
  11.   if (irrecv.decode(&results)) {
  12.     Serial.println(results.value, HEX);
  13.     irrecv.resume(); // 接收下一个数值
  14.   }
  15. }
复制代码
IRrecv类进行解码,初始化函数setup()中要添加enableIRIn()decode()方法被调用来判断是否已收到编码;如果收到,它返回一个非零值,并将结果保存到decode_results结构中。(关于这种结构的详细信息,请参阅 examples/IRrecvDump的代码)。一旦编码已经被解码,resume()函数必须被调用来恢复接收下次编码。值得注意的是decode()不是一面墙,因为编码的接收是通过调用中断进程,所以在等待接收编码的时候,Arduino可以继续执行其他代码任务。

硬件安装
本库可以使用任何数字输入引脚连接一个38KHz一体化红外接收模块,用于接收信号其在Radio Shack276-640红外接收器和 Panasonic PNA4602上都是测试过的(译者Leo测试过PC838,有网友用过HS0038B,IRM_3638)。其接线非常简单,电源连引脚1,接地连引脚2,引脚3的输出连到一个Arduino的数字输入引脚,例如引脚11。这些一体化接收器包含一个滤波和解调倒置的逻辑电平输出,因此你不能简单的用一个光电二极管或光电晶体管。我发现这些接收器的范围,可以轻松地覆盖整个房间。
02.ir-schematic.png

对于输出,连接一个红外LED和适当的限流电阻到PWM输出引脚3。确保了LED的极性是正确的,否则它是不会亮的——长的引脚是正极。我用了一个NTE 3027 LED(因为手头正好就有)和100欧姆的电阻,其发射范围大约15英尺(约4.5M)。你也可以用放大三极管增强其输出能力,达到更大的范围。

红外编码的一些背景知识
红外遥控器是通过在一种特定的模式下开闭红外LED来工作的。然而,为了避免例如来自阳光或灯光的干扰,LED不是稳定的接通着,而是在调制频率下(一般为36,38,或40KHz的)进行接通和关断。正在被发送的调制信号时的时间被称为一个信号(mark),当LED关闭时被称为一个空格(space)。

遥控器上的每个按键都有与其相关联的一个特定的编码(通常为12到32位)。当该键被按下时,发射此代码。如果一直按住该键,遥控器通常反复发射此按键编码。对于NEC遥控器,按住按键会发射一个专用的重复编码,而不是重复发送按键的编码。对于的Philips RC5或RC6遥控器,按下键时编码中一个位会每次取反,接收器根据该切换位来确定该键是否被按下了第二次。(译者Leo:不同的应用选择不同的遥控器,例如格斗游戏的双击可选择Philips的,而射击游戏的连击可以用NEC)当接受完之后红外接收头会将信号解调,并输出一个逻辑电平信号,指示是否成功接收信号。最理想的工作状态就是接收器与发射器的频率一致,当然实践证明差点也无所谓。

关于各种红外遥控编码我所发现的最棒的资料是 SB的红外知识基础[链接]

处理原始编码数据
本库支持发射和接收的原始时长数据。本功能主要用于调试,但大家也可以用于某些本库无法识别的协议,或者作为万能遥控器的功能支持。红外接收器的原始数据测量在50us内的连续的空格和标识时长。第一次测量的间隔是发射开始之前的空格。最后测量的是结束的信号。红外发射的原始数据记录微妙内的连续的信号和空格。第一个值是起始信号,而最后一个值是结束信号。发送和接收有两个不同的原始缓冲区。发送缓冲区的值是微秒,当接收缓冲区的值是50微秒。发送缓冲区由连续的起始信号启动,接收缓冲器由起始信号前面的持续间隙空格启动。他们的格式是不同的,因为我认为让库来测量发射之间的差距是非常有用的,但对于发射时的空隙测量并没有太大的用处。对于接收,50微秒的单位是足够的,用于解码并避免间隙溢出,而对于发送,50微秒的单位会有超过10%的误差,因此1us的单位似乎更理想。

获取你的遥控器编码
要想获得用于你的设备的遥控器编码,最简单的方法是使用本库把你手中的遥控器编码解码并打印。

网上有各种版本编码库,他们经常有专用格式。Linux的红外遥控器控制项目(The Linux Infrared Remote Control project,简称 LIRC[链接]),然而,有一个开放的格式用于描述许多遥控器的编码。请注意,即使你找不到用于已知设备型号的编码,特定的制造商通常会为多种产品使用相同的编码。

要注意的是在如何处理这些协议上其他来源可能有所不同,例如指令颠倒,翻转1和0的位,产生明确的起始位,落下前导或结束位,等等。(译者Leo:这里翻译的有些牵强=_=#)换句话说,要想IRremote库顾及到大家所能列出的所有不同的协议编码是不可能的,因为这些协议本身就是矛盾的。

接收库的详细介绍
IRrecv库由两部分组成。一个每50微秒调用的中断程序,负责测量信号和空格的长度,并将其持续时间保存在缓冲器中。用户调用一个解码程序来解码缓存中的测量结果,转换成被发送的编码值(通常为11到32位)(译者Leo:前面说是12到32位)。解码库会陆续尝试解码不同的协议,成功则停止。它返回一个结构,该结构中包含的原始数据,解码后的数据,解码后的数据的位数,和所使用的解码数据协议。

对于解码,MATCH()(仅在调试模式使用)用来判断所测量的信号或者空格的时间是否约等于规定的时长。

RC5 / 6的解码过程与其他协议略有不同,因为RC5 / 6编码位包括 标记位+空格或空格+标记位,而不是由连续的信号和空格构成。由getRClevel()方法将连续时间拆分成单独的信号/空格时间间隔。

对于重复发射(按钮按住),解码代码将一次次的返回相同的解码值。唯一的例外是NEC,会重复发射一个特殊的代码,而不是重复的发射该按键编码值。因此, 解码程序返回一个特殊REPEAT值(NEC默认返回值为0xFFFFFFFF,用户也可以在库中进行修改)。

更确切的说,每次Timer1溢出50微秒后调用接收器的中断的代码。在每次中断时,检查输入状态并且定时器计数增加。中断程序计时连续的信号(接收的调制信号)和空格(没有接收到的信号),并把连续时间记录在缓冲区中。 第一个连续时间是发射开始前的间隔长度。这之后是交替的信号和空格测量。所有的测量是在50微秒内的“滴答周期”。

中断服务程序作为一个状态机来实现。程序在等待间隔结束时启动STATE_IDLE。当信号被成功接收时,它切换到计时连续信号的STATE_MARK。然后在STATE_MARK和STATE_SPACE之间交替计时信号和空格。当持续时间足够长的空格被接收时,切换状态到STATE_STOP,表示一次完整的发射被接收。中断程序继续计时间隔,但停止在该状态。

STATE_STOP用一个标志 指示解码程序,作为一个完整的发射是有效的。当处理完成后,resume()函数置位STATE_IDLE,于是中断程序可以开始记录下一次发射。这里要注意的几件事情。间隔的计时在STATE_STOP和STATE_IDLE期间是一直连续着,以便可以获得发射之间精确测量的计时。如果resume()没能在下次发射开始之前调用 之前 ,部分发射将被丢弃。停止/恢复都是为了确定接收缓存没有在使用时被覆盖掉。 如果缓冲区的值是不断变化的,调试将变得非常困难,无从下手。

发射库的详细介绍
发射编码是很简单的。为了确保精确的输出频率和占空比,我用的是PWM定时器,相比用延时循环来调制LED的输出更加恰当。(详见我的   Arduino之PWM的秘密[链接]文章中有关PWM定时器的详细介绍)。在较为底层,enableIROut ()为Arduino数字引脚3的PWM输出设置一个恰当的频率。mark()函数通过使能PWM输出和延时特定的时间来发送信号。space()函数通过禁用PWM输出并延时特定的时间来发送空格。

IRremote库支持以下不同的协议:
NEC:32位传输,最高有效位优先。 (协议的细节[英文原文链接],考虑到NEC应用的广泛性,译者Leo也翻译了本链接内容。[中文译文链接]
Sony:12位或更多位传输,最高有效位优先。通常情况下使用12位或20位。需要注意的是官方协议首先是最低有效位优先。 协议的细节[链接]对于更多的细节,我写了一篇介绍Sony的协议细节的文章 了解索Sony外遥控器编码[链接]
RC5:12位或更多位的,最高有效位优先。消息开始有两个起始位,并不包含在编码值内。 (协议的细节[链接]
RC6:20位(典型的)传输,最高有效位优先。消息由脉搏头开始,和一个起始位,这些并不包含在编码值内。第四个比特位当拖车点(trailer bit)时为发送双倍宽度的。 (协议的细节[链接]

对于Sony和RC5 / 6,协议规定每个发射必须被重复3次。发射编码没有实现RC5 / 6触发位,这取决于调用者。

添加新的协议
制造商已经实施了比这个库所能支持的更多的协议。如果你看过现有的库代码,添加新的协议应该是简单的。一些提示:根据协议描述来写库代码会更轻松,而不是试图将协议完全的反向工程。你所接收的连续时间相对协议规范的时间而言,信号会比协议的略长, 而空格比协议的略短。这是很容易的由最后一位的;最后一个空格可能是隐藏的。

故障排除
为了让红外通讯的问题更容易调试,我的库里有一些可选的调试代码。增加#define DEBUG来启动你的代码,可以通过Arduino串口监控窗口使能调试输出。您需要将其删除.o文件和/或重新启动IDE来重新编译。

发射有关问题
如果发射无法工作,首先要确定您的IR LED确实正在发射。红外光通常可以在摄像机或手机摄像头上显示出来,所以这是一个简单的检查方法。尝试让LED正对着接收器,不要指望尚未放大输出下就拥有一个很大的范围。

下一个潜在的问题是,是否接收器无法理解发射器,例如,如果你正在发送错误的数据或者使用了错误的协议。如果你有一个遥控器,使用这个库来检查它发送什么样的数据,以及使用什么样的协议。

示波器将提供一个直观的显示,Arduino或遥控器传输的是什么。您可以使用红外线光敏二极管,看看到底发射些什么,把它直接连到示波器并让发射器正对光敏二极管。如果你有一台示波器,只是将示波器连接到光敏二极管。如果你没有示波器,您可以使用一个声卡示波器软件,如xoscope[链接]

Sony和RC5 / 6协议指定消息必须被发送三次。我已经发现,如果只发送一次,接收器将忽略该消息,但会在被发送两次时工作。对于RC5 / 6,在连续发射时切换位必须由调用代码进行翻转,否则接收器只响应一次编码。

最后,这个库可能有个漏洞。特别是,我没有任何RC5/RC6接收器,所以他们是未经测试的。

接收有关问题
如果接收不工作,首先要确认Arduino是至少能接收原始编码。Arduino接在引脚13上的LED会在接收到红外时闪烁。如果没有,则可能是硬件问题。

如果收到,但不能被解码成编码,确认编码在支持的协议中。如果编码应被解码,但都没有,一些测量计时有可能超出规定时间内的容差范围20%。您可以打印出的最低和最高规定值并与原始测量值进行比较。

examples/IRrecvDump代码将转存接收到的数据。存储方法转存这些连续时间,将它们转换到微秒,并且依照惯例用一个带减号前缀的空格进行分隔。这样更容易保持信号和空格测量的整齐。

红外传感器通常导致信号时长大于设定值,而空格时长小于设定值。编码扩展信号由100us用于记录这个(变量 MARK_EXCESS)。在这种情况下,您可能需要调整规定值或者公差。

本库不支持同时发送和接收编码。接收期间发射会被禁止。


结束语
本文作详细介绍了IRremote的使用方法和工作原理。不过由于本人水平有限,部分词汇翻译可能有些晦涩难懂,甚至用词不当,欢迎大家指正!最后感谢Google的翻译工具[链接]和金山词霸[链接]。在此将本文推荐给大家,希望看到更多的Maker做出红外应用!

补充说明
1. 翻译并增加少量译者观点
2. 修复部分失效链接
3. IRremote Github[链接]
4. 下载Arduino-IRremote-master库后,将其解压缩到arduino-1.x/libraries并重命名为IRremote
正确的参考路径:arduino-1.x/libraries/IRremote/IRremote.cpp

Arduino-IRremote-master.zip (32.96 KB, 下载次数: 2655)

question  见习技师

发表于 2019-3-13 09:50:24

mark一下
回复 支持 反对

使用道具 举报

gada888  版主

发表于 2019-3-14 08:41:06

这个文章好。收藏
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
wifi气象站

硬件清单

btnicon
我也要做!
点击进入购买页面
关于楼主
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2019 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail