前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >简单红外线解码

简单红外线解码

作者头像
云深无际
发布2020-11-23 11:06:08
2.2K0
发布2020-11-23 11:06:08
举报
文章被收录于专栏:云深之无迹
代码语言:javascript
复制
https://github.com/z3t0/Arduino-IRremote

支持的硬件

代码语言:javascript
复制
#include <IRremote.h>
int RECV_PIN = 11;
IRrecv irrecv(RECV_PIN);
decode_results results;
void setup()
{
    Serial.begin(9600);
    irrecv.enableIRIn(); //初始化红外遥控
    pinMode(12, 1);
}
void loop()
{
    if (irrecv.decode(&results))
    {
        if (results.value == 16753245) //确认接收到的第一排按键1的编码,此码是预先读出来的按键编码。
        {
            digitalWrite(12, 1);           //点亮LED
            Serial.println("turn on LED"); //串口显示开灯
        }
        else if (results.value == 16736925) //确认接收到的第一排按键2的编码
        {
            digitalWrite(12, 0);            //熄灭LED
            Serial.println("turn off LED"); //串口显示关灯
        }
        irrecv.resume(); // 接收下一个值
    }
}

放一个最简单代码,基于ardunio1.0的版本建立的代码

以下稍微分析一下

加入一个红外线的头文件

定义了一个引脚

创建了一个红外线的对象

接着下面的是一个存储红外线波形的变量

我去搜索了一个回来了

配置一下

开启串口

然后使能

把12的引脚配置成高电平

接着开始对收到信息开始解码

对比接收的值是不是第一个的键值

是的话就驱动引脚输出电压

然后打印

以下逻辑相同

这个是红外线的库.我下载下来了

先在软件里面加载库,加载成功

这个是样板的代码库,我这里看一个录制的例子

代码语言:javascript
复制
/*
 
* IRrecord:最少记录和播放IR信号
 * IR检测器/解调器必须连接到输入RECV_PIN。
 * IR LED必须连接到输出PWM引脚3。
 *必须在输入SEND_BUTTON_PIN与地面之间连接一个按钮。
 *可见的LED可以连接到STATUS_PIN以提供状态。
 *
 *逻辑是:
 *如果按下按钮,则发送IR代码。
 *如果收到IR代码,请记录下来。
 *
 *最初编码为2009 Ken Shirriff,网址为http://www.righto.com
 */

#include <IRremote.h>

#if defined(ESP32)
int IR_RECEIVE_PIN = 15;
int SEND_BUTTON_PIN = 16; // RX2 pin
#else
int IR_RECEIVE_PIN = 11;
int SEND_BUTTON_PIN = 12;
#endif
int STATUS_PIN = LED_BUILTIN;

int DELAY_BETWEEN_REPEAT = 50;

IRrecv IrReceiver(IR_RECEIVE_PIN);
IRsend IrSender;

// On the Zero and others we switch explicitly to SerialUSB
#if defined(ARDUINO_ARCH_SAMD)
#define Serial SerialUSB
#endif

void setup()
{
    Serial.begin(115200);
#if defined(__AVR_ATmega32U4__) || defined(SERIAL_USB) || defined(SERIAL_PORT_USBVIRTUAL)
    delay(2000); // To be able to connect Serial monitor after reset and before first printout
#endif
    // Just to know which program is running on my Arduino
    Serial.println(F("START " __FILE__ " from " __DATE__));

    IrReceiver.enableIRIn();  // Start the receiver
    IrReceiver.blink13(true); // Enable feedback LED

    pinMode(SEND_BUTTON_PIN, INPUT_PULLUP);
    pinMode(STATUS_PIN, OUTPUT);

    Serial.print(F("Ready to receive IR signals at pin "));
    Serial.println(IR_RECEIVE_PIN);

#if defined(SENDING_SUPPORTED)
    Serial.print(F("Ready to send IR signals at pin "));
    Serial.print(IR_SEND_PIN);
    Serial.print(F(" on press of button at pin "));
    Serial.println(SEND_BUTTON_PIN);

#else
    Serial.println(F("Sending not supported for this board!"));
#endif
}

// Storage for the recorded code
int codeType = -1;                    // The type of code
uint32_t codeValue;                   // The code value if not raw
uint16_t address;                     // The address value if not raw
uint16_t rawCodes[RAW_BUFFER_LENGTH]; // The durations if raw
uint8_t codeLen;                      // The length of the code
int toggle = 0;                       // The RC5/6 toggle state

// Stores the code for later playback
// Most of this code is just logging
void storeCode()
{
    if (IrReceiver.results.isRepeat)
    {
        Serial.println("Ignore repeat");
        return;
    }
    codeType = IrReceiver.results.decode_type;
    address = IrReceiver.results.address;

    //  int count = IrReceiver.results.rawlen;
    if (codeType == UNKNOWN)
    {
        Serial.println("Received unknown code, saving as raw");
        codeLen = IrReceiver.results.rawlen - 1;
        // To store raw codes:
        // Drop first value (gap)
        // Convert from ticks to microseconds
        // Tweak marks shorter, and spaces longer to cancel out IR receiver distortion
        for (int i = 1; i <= codeLen; i++)
        {
            if (i % 2)
            {
                // Mark
                rawCodes[i - 1] = IrReceiver.results.rawbuf[i] * MICROS_PER_TICK - MARK_EXCESS_MICROS;
                Serial.print(" m");
            }
            else
            {
                // Space
                rawCodes[i - 1] = IrReceiver.results.rawbuf[i] * MICROS_PER_TICK + MARK_EXCESS_MICROS;
                Serial.print(" s");
            }
            Serial.print(rawCodes[i - 1], DEC);
        }
        Serial.println();
    }
    else
    {
        IrReceiver.printResultShort(&Serial);
        Serial.println();

        codeValue = IrReceiver.results.value;
        codeLen = IrReceiver.results.bits;
    }
}

void sendCode(bool aSendRepeat)
{
    if (codeType == NEC)
    {
        if (aSendRepeat)
        {
            IrSender.sendNEC(REPEAT, codeLen);
            Serial.println("Sent NEC repeat");
        }
        else
        {
            IrSender.sendNEC(codeValue, codeLen);
            Serial.print("Sent NEC ");
            Serial.println(codeValue, HEX);
        }
    }
    else if (codeType == NEC_STANDARD)
    {
        if (aSendRepeat)
        {
            IrSender.sendNECRepeat();
            Serial.println("Sent NEC repeat");
        }
        else
        {
            IrSender.sendNECStandard(address, codeValue);
            Serial.print("Sent NEC_STANDARD address=0x");
            Serial.print(address, HEX);
            Serial.print(", command=0x");
            Serial.println(codeValue, HEX);
        }
    }
    else if (codeType == SONY)
    {
        IrSender.sendSony(codeValue, codeLen);
        Serial.print("Sent Sony ");
        Serial.println(codeValue, HEX);
    }
    else if (codeType == PANASONIC)
    {
        IrSender.sendPanasonic(codeValue, codeLen);
        Serial.print("Sent Panasonic");
        Serial.println(codeValue, HEX);
    }
    else if (codeType == JVC)
    {
        IrSender.sendJVC(codeValue, codeLen, false);
        Serial.print("Sent JVC");
        Serial.println(codeValue, HEX);
    }
    else if (codeType == RC5 || codeType == RC6)
    {
        if (!aSendRepeat)
        {
            // Flip the toggle bit for a new button press
            toggle = 1 - toggle;
        }
        // Put the toggle bit into the code to send
        codeValue = codeValue & ~(1 << (codeLen - 1));
        codeValue = codeValue | (toggle << (codeLen - 1));
        if (codeType == RC5)
        {
            Serial.print("Sent RC5 ");
            Serial.println(codeValue, HEX);
            IrSender.sendRC5(codeValue, codeLen);
        }
        else
        {
            IrSender.sendRC6(codeValue, codeLen);
            Serial.print("Sent RC6 ");
            Serial.println(codeValue, HEX);
        }
    }
    else if (codeType == UNKNOWN /* i.e. raw */)
    {
        // Assume 38 KHz
        IrSender.sendRaw(rawCodes, codeLen, 38);
        Serial.println("Sent raw");
    }
}

int lastButtonState;

void loop()
{
    // If button pressed, send the code.
    int buttonState = digitalRead(SEND_BUTTON_PIN); // Button pin is active LOW
    if (lastButtonState == LOW && buttonState == HIGH)
    {
        Serial.println("Button released");
        IrReceiver.enableIRIn(); // Re-enable receiver
    }

    if (buttonState == LOW)
    {
        Serial.println("Button pressed, now sending");
        digitalWrite(STATUS_PIN, HIGH);
        sendCode(lastButtonState == buttonState);
        digitalWrite(STATUS_PIN, LOW);
        delay(DELAY_BETWEEN_REPEAT); // Wait a bit between retransmissions
    }
    else if (IrReceiver.decode())
    {
        storeCode();
        IrReceiver.resume(); // resume receiver
    }
    lastButtonState = buttonState;
}

这个地方我把代码贴上来了
代码语言:javascript
复制
/ *
 * IRrecord:最少记录和播放IR信号
 *红外检测器/解调器必须连接到输入RECV_PIN。
 * IR LED必须连接到输出PWM引脚3。
 *必须在输入SEND_BUTTON_PIN与地面之间连接一个按钮。
 *可见的LED可以连接到STATUS_PIN以提供状态。
 *
 *逻辑是:
 *如果按下按钮,则发送IR代码。
 *如果收到IR代码,请记录下来。
 *
 *最初编码为2009 Ken Shirriff,网址为http://www.righto.com
 * /

#包括 < IRremote.h >

#如果已定义(ESP32)
整数IR_RECEIVE_PIN = 15 ;
int SEND_BUTTON_PIN = 16 ; // RX2引脚
#其他
int IR_RECEIVE_PIN = 11 ;
int SEND_BUTTON_PIN = 12 ;
#ENDIF
int STATUS_PIN = LED_BUILTIN;

int DELAY_BETWEEN_REPEAT = 50 ;

IRrecv IrReceiver(IR_RECEIVE_PIN);
发送IrSender;

//在零号和其他零号上,我们明确切换到SerialUSB
#如果已定义(ARDUINO_ARCH_SAMD)
#定义 串行SerialUSB
#ENDIF

无效 设置(){
    序列号。开始(115200);
#如果已定义(__AVR_ATmega32U4__)|| 已定义(SERIAL_USB)|| 已定义(SERIAL_PORT_USBVIRTUAL)
    延迟(2000); //能够在重置后和首次打印之前连接串行监视器
#ENDIF
    //只知道哪个程序正在我的Arduino上运行
    序列号。println(F(来自“ __DATE__的” START “ __FILE__ ”);

    IrReceiver。enableIRIn();  //启动接收器
    IrReceiver。blink13(true); //启用反馈LED

    pinMode(SEND_BUTTON_PIN,INPUT_PULLUP);
    pinMode(STATUS_PIN,OUTPUT);

    序列号。打印(F(“准备在引脚上接收红外信号”));
    序列号。println(IR_RECEIVE_PIN);

#如果已定义(SENDING_SUPPORTED)
    序列号。打印(F(“准备在引脚上发送IR信号”));
    序列号。列印(IR_SEND_PIN);
    序列号。打印(F(“按下按钮上的”“));
    序列号。println(SEND_BUTTON_PIN);

#其他
    序列号。println(F(“该板不支持发送!”));
#ENDIF
}

//存储已记录的代码
int codeType = -1 ; //代码类型
uint32_t codeValue; //代码值(如果不是原始值)
uint16_t地址;//地址值(如果不是原始值)
uint16_t rawCodes [RAW_BUFFER_LENGTH]; //原始的持续时间
uint8_t codeLen; //代码长度
int切换= 0 ; // RC5 / 6切换状态

//存储代码以供以后播放
//大部分代码只是记录
无效的 storeCode(){
    如果(IrReceiver。结果。isRepeat){
        序列号。println(“忽略重复”);
        回报;
    }
    codeType = IrReceiver。结果。解码类型;
    地址= IrReceiver。结果。地址;

//   int count = IrReceiver.results.rawlen;
    如果(codeType == UNKNOWN){
        序列号。println(“收到未知代码,另存为raw ”);
        codeLen = IrReceiver。结果。rawlen - 1 ;
        //要存储原始代码:
        //删除第一个值(间隙)
        //从刻度转换为微秒
        //调整标记更短,间隔更长以消除红外接收器失真
        for(int i = 1 ; i <= codeLen; i ++){
            如果(i%2){
                //标记
                rawCodes [i- 1 ] = IrReceiver。结果。rawbuf [i] * MICROS_PER_TICK-MARK_EXCESS_MICROS;
                序列号。打印(“ m ”);
            }其他{
                //空格
                rawCodes [i- 1 ] = IrReceiver。结果。rawbuf [i] * MICROS_PER_TICK + MARK_EXCESS_MICROS;
                序列号。打印(“ s ”);
            }
            序列号。打印(rawCodes [i- 1 ],DEC);
        }
        序列号。println();
    }其他{
        IrReceiver。printResultShort(&Serial);
        序列号。println();

        codeValue = IrReceiver。结果。价值;
        codeLen = IrReceiver。结果。位;
    }
}

无效 sendCode(bool aSendRepeat){
    如果(codeType == NEC){
        如果(aSendRepeat){
            IrSender。sendNEC(REPEAT,codeLen);
            序列号。println(“发送NEC重复”);
        }其他{
            IrSender。sendNEC(codeValue,codeLen);
            序列号。打印(“已发送NEC ”);
            序列号。println(codeValue,HEX);
        }
    }否则, 如果(codeType == NEC_STANDARD){
        如果(aSendRepeat){
            IrSender。sendNECRepeat();
            序列号。println(“发送NEC重复”);
        }其他{
            IrSender。sendNECStandard(地址,codeValue);
            序列号。打印(“已发送NEC_STANDARD地址= 0x ”);
            序列号。打印(地址,十六进制);
            序列号。打印(“,command = 0x ”);
            序列号。println(codeValue,HEX);
        }
    }否则, 如果(codeType == SONY){
        IrSender。sendSony(codeValue,codeLen);
        序列号。打印(“已发送索尼”);
        序列号。println(codeValue,HEX);
    }否则, 如果(codeType == PANASONIC){
        IrSender。sendPanasonic(codeValue,codeLen);
        序列号。打印(“已发送松下”);
        序列号。println(codeValue,HEX);
    }否则, 如果(codeType == JVC){
        IrSender。sendJVC(codeValue,codeLen,false);
        序列号。打印(“已发送JVC ”);
        序列号。println(codeValue,HEX);
    }否则, 如果(codeType == RC5 || codeType == RC6){
        如果(!aSendRepeat){
            //翻转切换位以按下新按钮
            切换= 1-切换;
        }
        //将切换位放入代码中进行发送
        codeValue = codeValue&〜(1 <<(codeLen- 1));
        codeValue = codeValue | (切换<<(codeLen- 1));
        如果(codeType == RC5){
            序列号。打印(“发送RC5 ”);
            序列号。println(codeValue,HEX);
            IrSender。sendRC5(codeValue,codeLen);
        }其他{
            IrSender。sendRC6(codeValue,codeLen);
            序列号。打印(“发送RC6 ”);
            序列号。println(codeValue,HEX);
        }
    }否则, 如果(codeType == UNKNOWN / *即原始* /){
        //假设38 KHz
        IrSender。sendRaw(rawCodes,codeLen,38);
        序列号。println(“发送原始”);
    }
}

int lastButtonState;

无效 循环(){
    //如果按下按钮,则发送代码。
    int buttonState = digitalRead(SEND_BUTTON_PIN); //按钮引脚为低电平有效
    如果(lastButtonState == LOW && buttonState == HIGH){
        序列号。println(“按钮释放”);
        IrReceiver。enableIRIn(); //重新启用接收器
    }

    如果(buttonState == LOW){
        序列号。println(“按下按钮,正在发送”);
        digitalWrite(STATUS_PIN,HIGH);
        sendCode(lastButtonState == buttonState);
        digitalWrite(STATUS_PIN,LOW);
        延迟(DELAY_BETWEEN_REPEAT); //在重传之间稍等
    }否则, 如果(IrReceiver。解码()){
        storeCode();
        IrReceiver。简历(); //恢复接收者
    }
    lastButtonState = buttonState;
代码语言:javascript
复制
http://www.righto.com/2009/08/multi-protocol-infrared-remote-library.html

看注释,我翻译了一下

重点是这个人的博客,好厉害

我终于在09年的时候8月份找到了

打开以后就是老哥最近对一个老式计算机的X光照片

这个是红外线这个篇文章

如何发送

该红外远程库由两部分组成:IRsend发送IR远程数据包,而IRrecv接收和解码IR消息。IRsend使用连接到输出引脚3的红外LED。要发送消息,请针对所需协议调用send方法,其中包含要发送的数据和要发送的位数。该examples/IRsendDemo草图提供了如何发送代码一个简单的例子:

代码语言:javascript
复制
#include <IRremote.h>
IRsend irsend;
无效setup()
{
  Serial.begin(9600);
}
void loop(){
  如果(Serial.read()!= -1){
    对于(int i = 0; i <3; i ++){
      irsend.sendSony(0xa90,12); //索尼电视电源代码
      延迟(100);
    }
  }
}

每当有字符发送到串行端口时,此code都会发送Sony TV电源开/关代码,从而允许Arduino打开或关闭电视。(请注意,根据协议,Sony代码必须发送3次。)

如何读取

IRrecv使用连接到任何数字输入引脚的红外检测器。

examples/IRrecvDemo草图提供了如何接收验证码的简单示例:

代码语言:javascript
复制
#include <IRremote.h>
int RECV_PIN = 11;
IRrecv irrecv(RECV_PIN);
解码结果结果;
void setup()
{
  Serial.begin(9600);
  irrecv.enableIRIn(); //启动接收器
}

void loop(){
  如果(irrecv.decode(&results)){
    Serial.println(results.value,HEX);
    irrecv.resume(); //接收下一个值
  }
}

IRrecv类执行解码,并与初始化enableIRIn()decode()调用该方法以查看是否已接收到代码。如果是这样,它将返回一个非零值,并将结果放入decode_results结构中。(有关此结构的详细信息,请参见examples/IRrecvDump code。)解码代码后,resume()必须调用该方法以恢复接收代码。注意decode()不会阻塞;在等待代码时,code可以执行其他操作,因为代码是由中断例程接收的。

就是这个便宜货

红外检测器是带有光电管的微芯片,可调谐以侦听红外光。它们几乎总是用于远程控制检测-每个电视和DVD播放器的前面都装有其中之一,用于监听来自答题器的IR信号。遥控器内部有一个匹配的IR LED,该LED发出IR脉冲以告知电视打开,关闭或更改频道。人眼看不到红外光,这意味着需要更多的工作来测试设置。


  • 红外检测器经过特殊过滤以防红外线,它们不擅长检测可见光。另一方面,光电管擅长检测黄/绿可见光,而不擅长红外光
  • 红外检测器内部有一个解调器,用于寻找38 KHz的调制IR。只是无法检测到红外LED发光,它必须以38KHz的PWM频率闪烁。光电管没有任何类型的解调器,可以检测到光电管响应速度(大约1KHz)内的任何频率(包括DC)
  • 红外检测器是数字输出-它们检测38KHz红外信号并输出低电平(0V),或者不检测任何信号并输出高电平(5V)。光电管就像电阻一样,电阻随曝光量而变化
  • 尺寸:正方形,探测器面积7mm x 8mm
  • 输出:检测到38KHz载波时为0V(低),否则为5V(高)
  • 灵敏度范围: 800nm至1100nm,峰值响应在940nm。频率范围为35KHz至41KHz,峰值检测为38KHz
  • 电源: 3-5V DC 3mA

从这些数据表图表中可以看到,峰值频率检测为 38 KHz ,峰值LED颜色为 940 nm。你可以使用大约35 KHz至41 KHz的频率,但灵敏度会下降,因此远距离也无法检测到。同样,您可以使用850至1100 nm的LED,但它们不能与900至1000nm的LED一样工作,因此请确保获得匹配的LED!检查数据表中的IR LED以验证波长。

尝试获得940nm-记住940nm不是可见光(它是红外光)!

芯片手册

代码语言:javascript
复制
https://www.adafruit.com/product/157
代码语言:javascript
复制
https://www.adafruit.com/product/157
代码语言:javascript
复制
https://learn.adafruit.com/ir-sensor/testing-an-ir-sensor
代码语言:javascript
复制
https://learn.adafruit.com/ir-sensor/ir-remote-signals

硬件设定

该库可以使用任何数字输入信号来接收来自38KHz红外接收器模块的输入。它已通过Radio Shack 276-640红外接收器和Panasonic PNA4602进行了测试。只需将电源线连接到引脚1,将地线连接到引脚2,并将引脚3的输出输出到Arduino数字输入引脚。这些接收器提供经过滤波和解调的反相逻辑电平输出;您不能只使用光电二极管或光电晶体管。我发现这些探测器的射程非常好,可以轻松地在整个房间工作。

对于输出,将IR LED和适当的电阻连接到PWM输出引脚3。确保LED的极性正确,否则它将不亮-长引线为正极。我使用了NTE 3027 LED(因为这很方便)和100欧姆电阻;范围约为15英尺。对于其他范围,您可以使用晶体管放大输出。

IR代码的一些背景

红外遥控器通过以特定模式打开和关闭LED来工作。但是,为了防止受到阳光或光线等IR源的干扰,LED不能稳定地打开,而是以调制频率(通常为36、38或40KHz)打开和关闭。发送调制信号的时间称为标记,而LED熄灭的时间称为空格。

遥控器上的每个键都有一个与之关联的特定代码(通常为12至32位),并在按下该键时广播该代码。如果按住该键,则遥控器通常会重复广播该键代码。对于NEC遥控器,在按下键时会发送特殊的重复代码,而不是重复发送代码。对于Philips RC5或RC6遥控器,每按一次键,代码中的一位就会切换一次。接收器使用此切换位来确定何时再次按下某个键。

在接收端,IR检测器对该信号进行解调,并输出指示其是否正在接收信号的逻辑电平信号。当红外探测器的频率与发送器的频率匹配时,红外探测器的工作效果最佳,但实际上并不重要。

关于各种IR代码的详细信息,我找到的最好的来源是SB IR知识库。

处理原始代码

该库提供了发送和接收原始持续时间的支持。这主要用于调试,但也可以用于该库未实现的协议或提供通用的远程功能。

接收到的IR的原始数据将测量连续间隔的持续时间,并以50us的滴答作答。第一个测量值是间隙,即传输开始之前的空间。最后的测量是最终标记。

发送IR的原始数据包含连续标记和空格的持续时间(以微秒为单位)。第一个值是第一个标记,最后一个值是最后一个标记。

发送和接收的原始缓冲区之间有两个区别。发送缓冲区值以微秒为单位,而接收缓冲区值以50微秒为单位。发送缓冲区从第一个标记的持续时间开始,而接收缓冲区从第一个标记之前的间隙空间的持续时间开始。格式是不同的,因为我认为对于库测量传输之间的间隙有用,但对于库在传输时提供这些间隙没有帮助。对于接收而言,50us的粒度足以进行解码并避免间隙的溢出,而对于发送而言,50us的粒度的误差大于10%,因此1us的粒度似乎更好。

获取遥控器的代码

获取与设备兼容的代码的最简单方法是使用此库从现有遥控器解码和打印代码。

在线提供各种代码库,通常为专有格式。但是,Linux红外远程控制项目(LIRC)具有用于描述许多遥控器代码的开放格式。请注意,即使您找不到确切设备型号的代码,特定的制造商通常也会对多个产品使用相同的代码。

请注意,其他来源在如何处理这些协议方面可能会不一致,例如反转顺序,翻转1和0位,使起始位明确,丢弃前导或尾随位等。换句话说,如果IRremote库产生不同的代码与您在其他地方列出的相比,这些不一致可能是原因。

接收库的详细信息

IRrecv库由两部分组成。每隔50微秒调用一次中断例程,该例程测量标记和空格的长度,并将持续时间保存在缓冲区中。用户调用解码例程,将缓冲的测量结果解码为已发送的代码值(通常为11到32位)。

解码库尝试连续解码不同的协议,如果一个成功,则停止。它返回一个结构,该结构包含原始数据,解码后的数据,解码后的数据中的位数以及用于解码该数据的协议。

对于解码,MATCH宏确定所测量的标记或间隔时间是否近似等于预期时间。

RC5 / 6解码与其他解码有所不同,因为RC5 / 6编码的标记是带有mark + space或space + mark的,而不是按mark和space的持续时间来编码的。getRClevel帮助器方法拆分持续时间,并获取单个时间间隔的标记/空格级别。

对于重复传输(按住按钮),解码代码将一遍又一遍地返回相同的解码值。NEC是一个例外,它发送一个特殊的重复代码,而不是重复发送值。在这种情况下,解码例程将返回一个特殊的REPEAT值。

更详细地讲,每次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。(有关PWM计时器的更多详细信息,请参阅我的Arduino PWM Secrets文章。)在低电平时,enableIROut会将计时器设置为在引脚3上以合适的频率进行PWM输出。mark()方法通过启用PWM输出并延迟指定的时间来发送标记。space()方法通过禁用PWM输出并延迟指定的时间来发送空间。

IRremote库按以下方式处理不同的协议:

NEC:传输32位,最高有效位在前。(协议详细信息)

Sony:传输12位或更多位,最高位在前。通常使用12或20位。请注意,正式协议是最低有效位在前。(协议详细信息)有关更多详细信息,我写了一篇文章,更详细地描述了Sony协议:了解Sony IR远程代码。

RC5:12个或更多位首先发送最高有效位。该消息以两个起始位开头,这两个起始位不属于代码值。(协议详细信息)

RC6:传输20(通常)位,最高有效位在前。该消息以前导脉冲和起始位开头,起始位不属于代码值。第四位是尾随位,因此它是两倍宽传输的。(协议详细信息)

对于Sony和RC5 / 6,每次传输必须按照协议中的规定重复3次。传输代码未实现RC5 / 6触发位。这取决于来电者。

添加新协议

制造商已经实现了比该库支持更多的协议。如果您查看现有的库代码,则添加新协议应该很简单。一些提示:与协议描述一起工作,而不是尝试对协议进行完全反向工程,将更加容易。您收到的持续时间可能比协议建议的更长,而空格更短。最后一点很容易一一对应。最后一个空格可能是隐式的。

故障排除

为了使调试IR通信问题更容易,我在库中提供了可选的调试代码。添加#define DEBUG到代码的开头,以在串行控制台上启用调试输出。您将需要删除.o文件和/或重新启动IDE以强制重新编译。

传输问题

如果发送失败,请首先确保您的IR LED实际正在发送。IR通常会显示在摄像机或手机摄像机上,因此这是一种简单的检查方法。尝试将LED对准接收器;除非您放大输出,否则不要期望很大的范围。

下一个潜在的问题是,如果接收方不理解发送方,例如,如果您发送了错误的数据或使用了错误的协议。如果您有遥控器,请使用此库检查其发送的数据和所使用的协议。

示波器可以很好地了解Arduino或遥控器正在传输的内容。您可以使用红外光电二极管查看正在传输的内容。将其直接连接到示波器,并保持发射器直达光电二极管。如果您有示波器,只需将示波器连接到光电二极管即可。如果没有示波器,则可以使用声卡示波器程序,例如xoscope。

Sony和RC5 / 6协议指定消息必须发送3次。我发现接收者仅发送一次将忽略该消息,但是如果发送两次则将起作用。对于RC5 / 6,切换位必须在连续传输中被调用代码翻转,否则接收器可能仅对代码响应一次。

最后,该库中可能存在错误。特别是,我没有收到RC5 / RC6的任何东西,因此它们未经测试。

接收问题

如果接收不起作用,请首先确保Arduino至少正在接收原始代码。当接收到红外线时,Arduino引脚13上的LED指示灯将闪烁。如果没有,则可能是硬件问题。

如果代码已收到但无法解码,请确保代码在受支持的协议之一中。如果应该解码而不是解码,则某些测量时间可能不在预期时间的20%容忍范围内。您可以打印出最小和最大期望值,并与原始测量值进行比较。

examples/IRrecvDump小品将倾出接收到的数据的详细信息。转储方法转储这些持续时间,但将其转换为微秒,并使用在空间测量值前加上减号的约定。这样可以更轻松地使标记和空间测量保持直线。

红外传感器通常会使标记的测量时间长于预期,而空间的距离则短于预期。该代码将标记扩展了100us,以解决此问题(值MARK_EXCESS)。在这种情况下,您可能需要调整期望值或公差。

该库不支持同时发送和接收代码。发送将禁用接收。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-11-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 云深之无迹 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 如何发送
  • 如何读取
  • 硬件设定
  • IR代码的一些背景
  • 处理原始代码
  • 获取遥控器的代码
  • 接收库的详细信息
  • 发送库的详细信息
  • 添加新协议
  • 故障排除
    • 传输问题
      • 接收问题
      相关产品与服务
      验证码
      腾讯云新一代行为验证码(Captcha),基于十道安全栅栏, 为网页、App、小程序开发者打造立体、全面的人机验证。最大程度保护注册登录、活动秒杀、点赞发帖、数据保护等各大场景下业务安全的同时,提供更精细化的用户体验。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档