65.9K
CodeProject 正在变化。 阅读更多。
Home

红外遥控您的电脑

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.98/5 (19投票s)

2017 年 11 月 13 日

CPOL

14分钟阅读

viewsIcon

31267

downloadIcon

717

本文介绍了一种最简单的方法,可以使用您已有的任何红外遥控器来远程控制任何计算机。想法是从沙发上控制计算机上的音乐或视频播放器。我在互联网上看到了许多此类项目,但没有一个让我满意。

特点

  • 这个项目非常容易构建。也非常适合绝对的初学者
  • 它适用于任何操作系统:Windows、Linux、Macintosh……
  • 超简单的硬件。您只需要焊接3根电线
  • 硬件非常小巧(3.6厘米 x 1.8厘米)
  • 非常便宜:总硬件成本为 21 美元
  • 您无需在计算机上安装任何额外软件
  • 适用于任何遥控器,无论其发送何种信号
  • 无需为每种遥控信号类型编程特殊的解码器
  • 自动检测红外数据速率(“比特率”)
  • 通过模拟USB键盘向计算机发送按键
  • 通过虚拟串行端口(CDC)将调试输出发送到计算机,该端口实时显示红外信号
  • 接收器非常灵敏。即使红外信号需要反射两次才能到达,也能在几米远的地方接收到
  • 只需几分钟即可将源代码适配到您的需求(将按键分配给遥控按钮)

要求

  • 您需要一个可以通过键盘按键控制的音乐播放器或视频播放器。
  • 播放器程序必须在前台(活动窗口),否则将无法接收到按键。

我的目的

我想控制我电脑上的音乐播放器。我使用的是MusicMatch。这个程序已经比较老了,但比WinAmp或Windows Media Player好很多。该程序最主要的功能可以通过键盘控制:播放、暂停、停止、下一曲、上一曲。这对我来说已经足够了。

MusicMatch JukeBox

我的功放有这个遥控器
Yamaha remote control
我用红色标记的按钮在听电脑音乐时没有功能。
它们是用于调谐器和其他用途的。
当我按下这些按钮中的任何一个时,功放都不会有任何反应。
所以我的想法是重新利用这些按钮来控制电脑。

硬件

只需要两个组件:一个红外接收芯片和一个Teensy 3.2。
IR接收器的+5V电源来自USB线。

infrared remote control for the computer

即使是初学者也很容易焊接这3根线。

infrared remote control for the computer

IR接收器TSOP38238非常灵敏。它有一个38 kHz的带通滤波器,用于过滤来自遥控器的信号。
此滤波器是必需的,以消除噪声,因为荧光灯会发出非常“嘈杂”的光。
如果您在客厅使用荧光灯,您可能会发现遥控器的灵敏度会变差。
大多数遥控器使用38 kHz载波频率。有些使用36 kHz,这也可以工作。(请参阅Zip文件中的数据手册)
只有少数公司(如 Bang & Olufsen)使用完全不同的频率。
在这种情况下,您需要另一个接收芯片或另一个遥控器。

您可以在一些在线商店购买此IR接收器(或类似型号)

Teensy (20 美元) 也可以从 Adafruit 和 Digikey 购买。或者您可以直接从 PJRC 购买。

Teensy 3.2 是一款非常通用且速度极快的开发板,内存容量大。
Arduino开发板不同,Teensy配备了更好的软件库(TeensyDuino),可以轻松模拟USB设备(键盘、鼠标、游戏手柄等)。此外,Teensy比Arduino开发板体积更小(3.6厘米 x 1.8厘米),价格也更便宜(20 美元)。

Teensy pin layout

遥控器

这里可以看到我用于测试的一些遥控器

infrared remote controls

它们分别来自雅马哈功放、Grundig 功放(来自20世纪90年代,至今仍可用!)和 LG 电视。下方中间是一个来自RGB LED 灯带的遥控器,可以用来选择颜色。它们中的任何一个都可以控制电脑,无需修改我的源代码,尽管它们发送的信号完全不同。

红外信号

雅马哈、LG、NEC 和 LED 控制器的红外信号看起来是这样的

infrared remote control code

这是在 IR 接收芯片输出端测得的。当没有 IR 信号时,输出为高电平。当检测到 38 kHz 的载波频率时,输出变为低电平。换句话说:上述信号中的每个低电平对应一个 38 kHz 调制光的脉冲。对于上述所有遥控器,最短的低电平脉冲约为 550 µs。整个信号包含 67 个高/低过渡。开头有一个较长的起始阶段,为电视或 Hi-Fi 设备中的接收微处理器提供足够的时间来准备接收 IR 信号。下方的数字(白色)表示低电平或高电平脉冲的长度。“1”表示 550 µs。“3”表示 3 x 550 µs = 1650 µs。我的源代码会自动检测 IR 信号的“比特率”。

上面的信号编码了遥控器上按下的一个按钮。每个按钮会产生不同的信号。但如果您长时间按下某个按钮(例如,调高音量),遥控器会发送一个“重复序列”,该序列始终相同。

infrared remote control repeater

所以,如果您按下“音量增大”按钮,就会发送第一个图像中的信号一次,然后只要您按住该按钮,就会重复发送第二个图像中的信号。

通用遥控信号检测

我在 Github 和 Teensyduino 库中看到了非常长的 IR 信号解码代码。对于每种遥控信号类型,都编写了一个单独的解码器:适用于 Aiwa、Denon、JVC、LG、Lego、Mitsubishi、NEC、Panasonic、RC5、RC6、Samsung、Sanyo、Sharp、Sony、Whynter。巨大的库包含数千行代码。那么,哪个对应雅马哈呢?如果我的型号未实现怎么办?例如,Grundig 就缺失了。这肯定不是一个通用的解决方案。

我还找到了一个 Linux 项目,需要数百个配置文件。每种遥控器都必须编写一个单独的配置文件。这肯定不是我的项目。

互联网上也有一些硬件项目,它们使用的硬件要复杂得多,也昂贵得多。我发现一个项目甚至使用了无法通过 USB 线像 Teensy/Arduino 板那样编程的微处理器。您需要购买额外的硬件编程器来上传固件。对我来说,这绝对不可能!

我一直在寻找一种不依赖于遥控信号类型的最简单的解决方案。我找到了一个:我根本不关心信号中每个比特的含义。在第一步,我检测短脉冲长度的平均值(对于绝大多数控制,这个值在 400µs 到 700µs 之间)。有些遥控器对 Lo 和 Hi 脉冲使用不同的间隔。例如,Hi 为 400µs,Low 为 600µs。因此,我的代码会单独计算它们。然后我计算乘数。对于上图中的信号,我得到:16,8,1,1,1,3,1,1,1,3,1,3,1,3,..... 我不需要理解它们的意思。我只需要识别它们何时出现。然后我将信号转换为字符串,并从此字符串计算 CRC 32。对于遥控器上的每个按钮,我都会得到一个不同的 8 位十六进制值。我的“解码器”只需要不到 50 行 C 代码。

当信号为低电平时,我使用小写字母;当信号为高电平时,我使用大写字母。
例如,“1”变成“A”或“a”。“3”变成“C”或“c”,等等...
但是,起始阶段的两个长脉冲(9毫秒和4.5毫秒)是一个例外。它们不是短脉冲的整数倍。因此,第一个长脉冲可能有时被检测为短脉冲长度的16倍,有时是15倍。因此,我将长脉冲替换为“X”或“x”,因为它们的精确长度并不重要。

雅马哈代码

Lo:  9000 us       --> Len: 15 --> Char: 'x'
Hi:  4473 us       --> Len:  8 --> Char: 'X'
Lo:   585 us short --> Len:  1 --> Char: 'a'
Hi:   537 us short --> Len:  1 --> Char: 'A'
Lo:   613 us short --> Len:  1 --> Char: 'a'
Hi:  1633 us       --> Len:  3 --> Char: 'C'
Lo:   579 us short --> Len:  1 --> Char: 'a'
Hi:   541 us short --> Len:  1 --> Char: 'A'
Lo:   581 us short --> Len:  1 --> Char: 'a'
Hi:  1657 us       --> Len:  3 --> Char: 'C'
Lo:   585 us short --> Len:  1 --> Char: 'a'
Hi:  1662 us       --> Len:  3 --> Char: 'C'
Lo:   581 us short --> Len:  1 --> Char: 'a'
Hi:  1659 us       --> Len:  3 --> Char: 'C'
Lo:   584 us short --> Len:  1 --> Char: 'a'
Hi:  1659 us       --> Len:  3 --> Char: 'C'
Lo:   583 us short --> Len:  1 --> Char: 'a'
Hi:   537 us short --> Len:  1 --> Char: 'A'
Lo:   581 us short --> Len:  1 --> Char: 'a'
Hi:  1662 us       --> Len:  3 --> Char: 'C'
Lo:   581 us short --> Len:  1 --> Char: 'a'
Hi:   539 us short --> Len:  1 --> Char: 'A'
Lo:   585 us short --> Len:  1 --> Char: 'a'
Hi:  1660 us       --> Len:  3 --> Char: 'C'
Lo:   579 us short --> Len:  1 --> Char: 'a'
Hi:   541 us short --> Len:  1 --> Char: 'A'
Lo:   584 us short --> Len:  1 --> Char: 'a'
Hi:   536 us short --> Len:  1 --> Char: 'A'
Lo:   583 us short --> Len:  1 --> Char: 'a'
Hi:   537 us short --> Len:  1 --> Char: 'A'
Lo:   585 us short --> Len:  1 --> Char: 'a'
Hi:   535 us short --> Len:  1 --> Char: 'A'
Lo:   585 us short --> Len:  1 --> Char: 'a'
Hi:  1658 us       --> Len:  3 --> Char: 'C'
Lo:   585 us short --> Len:  1 --> Char: 'a'
Hi:   535 us short --> Len:  1 --> Char: 'A'
Lo:   586 us short --> Len:  1 --> Char: 'a'
Hi:  1659 us       --> Len:  3 --> Char: 'C'
Lo:   609 us short --> Len:  1 --> Char: 'a'
Hi:   510 us short --> Len:  1 --> Char: 'A'
Lo:   584 us short --> Len:  1 --> Char: 'a'
Hi:  1659 us       --> Len:  3 --> Char: 'C'
Lo:   581 us short --> Len:  1 --> Char: 'a'
Hi:  1636 us       --> Len:  3 --> Char: 'C'
Lo:   606 us short --> Len:  1 --> Char: 'a'
Hi:   539 us short --> Len:  1 --> Char: 'A'
Lo:   586 us short --> Len:  1 --> Char: 'a'
Hi:   532 us short --> Len:  1 --> Char: 'A'
Lo:   588 us short --> Len:  1 --> Char: 'a'
Hi:   537 us short --> Len:  1 --> Char: 'A'
Lo:   583 us short --> Len:  1 --> Char: 'a'
Hi:  1637 us       --> Len:  3 --> Char: 'C'
Lo:   632 us short --> Len:  1 --> Char: 'a'
Hi:   486 us short --> Len:  1 --> Char: 'A'
Lo:   607 us short --> Len:  1 --> Char: 'a'
Hi:  1662 us       --> Len:  3 --> Char: 'C'
Lo:   581 us short --> Len:  1 --> Char: 'a'
Hi:   539 us short --> Len:  1 --> Char: 'A'
Lo:   581 us short --> Len:  1 --> Char: 'a'
Hi:   541 us short --> Len:  1 --> Char: 'A'
Lo:   583 us short --> Len:  1 --> Char: 'a'
Hi:  1655 us       --> Len:  3 --> Char: 'C'
Lo:   584 us short --> Len:  1 --> Char: 'a'
Hi:  1659 us       --> Len:  3 --> Char: 'C'
Lo:   585 us short --> Len:  1 --> Char: 'a'
Hi:  1657 us       --> Len:  3 --> Char: 'C'
Lo:   585 us short --> Len:  1 --> Char: 'a'
Lo: Shortest:  579 us, Limit:  868 us, Average over 33 short intervals:  587 us
Hi: Shortest:  486 us, Limit:  729 us, Average over 16 short intervals:  532 us
Decoded: xXaAaCaAaCaCaCaCaAaCaAaCaAaAaAaAaCaAaCaAaCaCaAaAaAaCaAaCaAaAaCaCaCa
CRC:     0x1856440C
Button:  Volume Up
--------------------------

Lo:  9025 us       --> Len: 16 --> Char: 'x'
Hi:  2210 us short --> Len:  4 --> Char: 'D'
Lo:   581 us short --> Len:  1 --> Char: 'a'
Lo: Shortest:  581 us, Limit:  871 us, Average over  1 short intervals:  581 us
Decoded: xDa
CRC:     0xF4FCC4CA
Button:  Volume Up
--------------------------

这是发送到计算机虚拟串行 COM 端口的调试输出。例如,您可以在 Arduino 编译器的“Serial Monitor”中看到此输出。您可以确切地看到 Teensy 接收到了什么以及它是如何处理的。最后会打印出 CRC,它标识了遥控器上的按钮或重复序列。

我的代码也处理“重复序列”。只要按住遥控器上的任何按钮,就会发送重复器。对于音量增大/减小等按钮,让按键重复到计算机是有意义的。但对于“暂停”按钮则没有意义。如果您重复“暂停”命令,音频/视频播放器会在您按下按钮时在播放和暂停之间不断切换。有些遥控器根本不使用重复序列。因此,我的代码有一个标志,您必须只为需要重复的命令设置该标志。

注意:在计算机上调节音量是错误的。您应该始终将计算机的音量保持在 100%,只在您的功放上调节音量。

Grundig 代码

Decoded: aXaAaAaAaAaAaAaAaAaAa
Decoded: aXaAaBbAaAaAaAaAaAa
Decoded: aXaAaBbAaAaAaAaAaAa
Decoded: aXaAaBbAaAaAaAaAaAa
Decoded: aXaAaAaAaAaAaAaAaAaAa

它完全不同

  • 它使用短脉冲和长脉冲之间 1:2 的比例,而不是雅马哈的 1:3。(“b”和“B”而不是“c”和“C”)
  • 数据包短得多。
  • 与其发送重复序列,不如在按住按钮时重复发送命令本身。
  • 命令的前后会发送一个始终相同的序列:0101010101010101010

但遥控器之间的所有这些差异都不重要。我的代码适用于任何遥控器。

控制电脑

对于 MusicMatch 播放器,需要发送以下按键

  • 遥控器上的播放按钮发送 CTRL + P 到电脑
  • 遥控器上的停止按钮发送 CTRL + S 到电脑
  • 遥控器上的暂停按钮发送 Pause 键到电脑
  • 遥控器上的调低按钮发送 ALT + 左箭头 到电脑(上一曲)
  • 遥控器上的调高按钮发送 ALT + 右箭头 到电脑(下一曲)

您只需要修改 `ExecuteAction()` 函数以满足您的需求。您可以通过调试输出来获取每个按钮的 CRC 代码,然后将其复制粘贴到源代码中。 `PressKey()` 函数随后通过 Teensy 模拟的 USB 键盘将按键发送到计算机。

void ExecuteAction(uint32_t u32_CRC)
{
    .....

    switch (u32_CRC)
    {
       case 0xA9EBE518:
          Serial.println("Button:  Tuning Up");      
          PressKey(MODIFIERKEY_ALT,  KEY_RIGHT, 0);  // Next Track
          break;
       case 0x168ECD6E:
          Serial.println("Button:  Tuning Down");  
          PressKey(MODIFIERKEY_ALT,  KEY_LEFT,  0);  // Previous Track  
          break;
       case 0x8F21CFD3:
          Serial.println("Button:  Play");    
          PressKey(MODIFIERKEY_CTRL, KEY_P, 0);      // Play
          break;
       case 0x3044E7A5:
          Serial.println("Button:  Stop");           
          PressKey(MODIFIERKEY_CTRL, KEY_S, 0);      // Stop
          break;
       case 0x57041AEF:
          Serial.println("Button:  Pause");          
          PressKey(0, KEY_PAUSE, 0);                 // Pause
          break;

       .....
    }
    ......
}

特殊情况:RC5

有些遥控器会发送一个切换位。一个典型的例子是飞利浦开发的 RC5 代码

RC5 remote control code

这意味着每次按下遥控器上的同一个按钮时,这个位都会被切换。所以您会为同一个按钮得到两个 CRC 代码:一个切换位为高,一个切换位为低。在这种情况下,您的代码应该如下所示

    switch (u32_CRC)
    {
       case 0xA9EBE518: // Toggle bit = 1
       case 0x4F78A03C: // Toggle bit = 0
          Serial.println("Button:  Tuning Up");      
          PressKey(MODIFIERKEY_ALT,  KEY_RIGHT, 0);  // Next Track
          break;
       .....
    }

编程

要对 Teensy 的处理器进行编程,您需要一根 micro USB 线,并需要安装

  1. Arduino 编译器。(下载
  2. TeensyDuino 库。(下载

您需要像此截图中的红色设置一样配置编译器

Arduino Compiler Configuration

使用“Serial + Keyboard + Mouse + Joystick”选项,Teensy 可以模拟 USB HID 键盘、HID 鼠标和 HID 游戏手柄。这里只使用键盘。“Serial”是您将在计算机上看到的虚拟 COM 端口,您将从那里接收调试输出。

您可以使用免费软件 TeraTerm 或 Arduino 编译器的“Serial Monitor”来读取调试输出。

注意:连接 Teensy 的 USB 线时,Windows 可能会变得非常慢。Teensy 会同时模拟 4 个 USB 设备,Windows 可能需要长达 10 秒才能访问串行端口。此外,Arduino 编译器中的 Serial Monitor 存在一个 bug,可能导致 COM 端口从未出现。为了避免此问题,您在上传固件到 Teensy 之前必须关闭 Serial Monitor。

故障排除

如果不起作用,请检查以下步骤

  1. 将 USB 线插入 Teensy 时,Teensy 板上的 LED 必须闪烁一次。如果不闪烁,则说明您可能没有正确上传固件。解压 Zip 文件,双击“IR_Receiver.ino”文件。如上图所示配置 Arduino 编译器。在编译器工具栏中,单击第二个“Upload”(上传)按钮(带右箭头)。必须打开另一个窗口:Teensy Loader。现在按下 Teensy 板上的小按钮。等待 Teensy Loader 显示“Reboot OK”。
     
  2. 每当 Teensy 接收到任何 IR 信号时,Teensy 上的 LED 必须以红外信号的节奏快速闪烁。如果您按下遥控器上的按钮,LED 保持关闭,请检查遥控器是否正常工作,并检查 IR 接收器与 Teensy 之间的连接是否正确。
     
  3. 当 Teensy 连接到计算机时,必须出现一个 COM 端口。这可能需要长达 10 秒。第一次连接 Teensy 时,甚至需要更长时间,并且您需要安装CDC 驱动程序(只有一个 INF 文件)。您可以在 ZIP 文件中找到驱动程序。您可以在控制面板的“Ports”(端口)下看到此端口,显示为“Teensy USB serial”。此外,在“Human Interface Devices”(人体接口设备)下,您会找到三个“HID Input Device”。它们是键盘、鼠标和游戏手柄,您可以在“Keyboards”(键盘)和“Mice and other pointing devices”(鼠标和其他指针设备)下找到它们。如果您不确定,请断开 Teensy,这些设备应该会在几秒钟后在控制面板中消失。
     
  4. 在编译器的“Tools”(工具)菜单中选择 Teensy COM 端口,然后打开“Serial Monitor”(串行监视器)。然后按一下遥控器上的按钮。您必须看到 Teensy 发送的调试输出。在源代码中,您可以将 PRINT_RAW_SAMPLES 设置为 true 或 false,具体取决于您想要多少调试输出。

可能的扩展

您可以通过此项目完成更多事情。此外,您还可以将继电器连接到 Teensy 以打开或关闭设备,或者用遥控器调暗灯光。如果您连接 12V 的LED 灯带或 LED 灯,您可以使用 Teensy 的 500 Hz PWM 输出,并通过 MOSFET 晶体管(如 BUZ71A)放大信号。

您还可以为计算机编写一个程序,该程序在串行 COM 端口上监听 Teensy 发送的 CRC 代码,并执行更复杂的操作(例如,关闭操作系统、启动程序等)。在 C# 中,可以使用 System.IO.Ports.SerialPort 用几行代码完成。

简易电灯开关

您可以在房间的主灯开关上扩展一个双稳态继电器。这样,您就可以通过遥控器或灯开关来打开和关闭灯。

IR remote control your light

一个双稳态继电器有两个线圈,只需要一个短脉冲即可切换到另一个位置并永久保持在该位置,直到另一个线圈通电。您可以在 Digikey 等地方找到双稳态继电器。PB1695-ND 在 5V 下需要 80mA。它售价 4.40 美元,可切换 16A。Teensy 的 Vin 引脚直接连接到 USB 线缆的 +5V,该线缆提供足够的电流(500mA)用于继电器,因此您不需要额外的 5V 电源,只要计算机在运行。

但是,如果您想在计算机关闭时也能切换灯,则需要额外的 5V 电源,并且您必须剪断 Teensy 底部的跳线,以将此 5V 电源与 USB 线缆的 5V 断开。

Teensy cut jumper 5V

更多使用 Teensy 的项目

这是我用 Teensy 制作并发布在 Codeproject 上的第三个电子项目。您可能也对以下项目感兴趣:

© . All rights reserved.