Atom发送红外编码(一)-Arduino中文社区 - Powered by Discuz! Archiver

vany5921 发表于 2020-5-8 15:03

Atom发送红外编码(一)

M5Stack的几款主机都集成了红外发射二极管,用于对家电进行遥控,之前也提供了一些应用示例,这次再重新对红外发射和接收的程序进行梳理,深入了解IRremote8266这个库的使用,虽然库名字带有8266但是支持ESP32。

===接收红外信号==========================================================
在IRremoteESP8266的参考示例中提供了IRrecvDumpV2这样一个程序,整个程序用于接收红外信号、分析内容并将结果输出到串行监视器
在Atom中使用该示例需要对程序进行一定的修改。

在27行中,Arduino.h要被改为M5Atom.h
在第38行中,将红外传感器连接的GPIO14改为M5Stack IR-Unit对应引脚,在IR-Unit的背面是这样写的

将它连接到Atom,找到对应的端口号

现在我们可以看出来接收引脚连接的是32,发射引脚接的是26(Atom内置的IR发射引脚为12)。
现在更改第27行和第38行

接下来是setup,在修改前是这样的

第112行之后,对Atom进行初始化过程
M5.begin(true, fasle, false);//是否启用串行通讯、是否启用I2C、是否启用屏幕
加上M5.begin()的程序设这样的

运行程序后,串口监视器打印以下内容

如果此时向IR Unit发送遥控信号,串口监视器会显示

从图中看到遥控器使用了NEC协议,
rawData是接收红外开/关时间的原始数据。
address、command、data是对协议原始数据分析的结果
如果我们事先知道遥控的协议可以直接使用对应的函数进行发送,如对于NEC协议使用sendNEC
如果我们不知道协议,则需要使用sendRaw(*)将原始数据作为参宿进行传递。创建学习遥控器时使用sendRaw()很容易,我们不需要知道遥控器的协议,但是缺点也明显,我们需要记住原始数据并消耗大量内存。比如发送空调遥控器信号,数据很长,需要大量内存。

====发送红外信号======================================================
对于发送红外信号来说,Atom Matrix和Atom Lite都带有红外传输LED


在Arduino示例中有一个名为IRsendDemo的程序,我们可以通过修改此程序完成IR的发送

第35行代码是用于红外传输的LED引脚编号,我们在Atom标签上也能看到

第37行创建了一个IRsend对象,传递第35行定义的引脚
在第40到46行中,使用了IRrecvDumpV2分析的红外信号原始数据。
setup()中的第53行通过调用IRsend对象的begin()启动。
第62和63行是使用NEC协议发送红外信号的示例。使用irsend.sendNEC()将unit64_t类型的数据传递给参数(实际只传32位),例如

通过查看Protocol,可以看到是NEC协议,code为sendNEC()的参数0x419F58A7。在程序的63行示例中,由于数字文本作为参数直接传递给sendNEC(),因此添加"UL",调整长度
如果协议是SONY,使用sendSONY(),如第66行所示。传入三个参数。
第68-69行是发送rawData[]的示例。使用名为sendRaw()的函数,第一个参数是指向rawData数组的指针,第二个参数是rawData数组中的元素数,第三个参数是IR LED开/关频率
第67行是irsend.sendRaw(rawData, 67, 38),其中67指第40行数组的元素个数,38为IR的频率,通常遥控器使用的是38khz

分析完后,修改IRremoteESP8266示例,使用Atom发送红外信号。主要修改内容:
•加载Atom头文件
•更改红外LED引脚为12
•从IRrecvDumpV2程序中拷出原始数据和数据行
•在setup()中初始化Atom
•按下按钮时调用sendRaw()或sendNEC()
改造后的程序

#include <M5Atom.h>
#include <IRremoteESP8266.h>
#include <IRsend.h>

const uint16_t kIrLed = 12; // M5Atom IR LED GPIO pin

IRsend irsend(kIrLed);// Set the GPIO to be used to sending the message.

// Example of data captured by IRrecvDumpV2.ino
uint16_t rawData = {9030, 4480,588, 536,584, 1628,612, 536,
                        586, 536,586, 538,562, 564,560, 562,
                        560, 1652,610, 1652,564, 560,584, 540,
                        564, 1672,584, 1652,586, 1626,610, 1628,
                        610, 1632,606, 538,562, 1654,586, 560,
                        562, 1674,586, 1652,586, 538,560, 562,
                        586, 538,562, 1676,586, 538,566, 1672,
                        584, 540,584, 538,586, 1628,610, 1626,
                        612, 1642,588};// NEC 419F58A7

uint64_t data = 0x419F58A7;

void setup() {
M5.begin(true, false, false);
irsend.begin();
}

void loop() {
M5.update();
if (M5.Btn.wasReleased()) {
    Serial.println("Button pressed");
   
    Serial.println("sendRaw");
    irsend.sendRaw(rawData, 67, 38);// Send a raw data capture at 38kHz.
   
    // Serial.println("sendNEC()");
    // irsend.sendNEC(data);
}
}
此程序调用sendRaw(),请将第10到第20行替换为你自己的原始数据,将第33行中的67更改为你自己的原始数据元素个数

=====创建学习型遥控==============================================================
下面我们将演示如何将上述两个代码融合,做到学习红外信号并进行发送
对应发送的信号可能有两种数据,一种是uint16_t rawData[],一种是根据协议传递数据(NEC和uint64_t数据)
对于rawData有以下优缺点:
•优点:控制信号可以在任何协议中传输 •缺点:数据量增加导致需要较大内存
对应根据协议传递的数据来说:
•优点:传递数据流较小 •缺点:必须根据协议对发送函数进行划分,并且无法处理没有发送函数的协议
考虑到学习型遥控器的用途,我们事先不确定遥控器的协议,因此传递rawData是恰当的方法。

现在我们来构建一下整个遥控器的功能,通过使用正面的按钮实现单击、双击、长按来操作遥控器。
void loop() {
M5.update();
if (M5.Btn.wasReleased()) {// 单击/发送信号
} elseif (M5.Btn.pressedFor(300)) { // 长按/启用接收
    while (! M5.Btn.wasReleased()) { // 等待按键松开
      delay(50);
      M5.update();
    }
} else {
    if (收到红外信号) {
取出信号
}
}
}
取出信号不是在长按过程中,而是在最后,信号接收处理是异步的
最终代码

#include <M5Atom.h>
#include <IRrecv.h>
#include <IRremoteESP8266.h>
#include <IRac.h>
#include <IRtext.h>
#include <IRutils.h>

// Select IR_LED in M5Atom or M5Stack IR Unit
#define IR_LED 12// IR LED in M5Atom
//#define IR_LED 26// IR LED in the M5Stack IR Unit

// ============ IRremoteESP8266 TUNEABLE PARAMETERS ================
const uint16_t kRecvPin = 32;
const uint32_t kBaudRate = 115200;
const uint16_t kCaptureBufferSize = 1024;
#if DECODE_AC
const uint8_t kTimeout = 50;
#else   // DECODE_AC
const uint8_t kTimeout = 15;
#endif// DECODE_AC
const uint16_t kMinUnknownSize = 12;
#define LEGACY_TIMING_INFO false
// =================================================================

IRrecv irrecv(kRecvPin, kCaptureBufferSize, kTimeout, true);
decode_results results;// Somewhere to store the results
IRsend irsend(IR_LED);

uint16_t *rawData;      // IR message container
uint16_t dataLength = 0;// IR message length

void setup() {
M5.begin(true, false, false); // SerialEnable = true, I2CEnable = false, DisplayEnable = false);
Serial.printf("\n\n### IR Remote Controller ###\n");
Serial.printf("IR Sensor Pin Number =%d \n", kRecvPin);
irrecv.setUnknownThreshold(kMinUnknownSize);
irsend.begin();
}

void loop() {
M5.update();
if (M5.Btn.wasReleased()) {
    Serial.print("Button wasReleased(): ");
    if (dataLength > 0) {
      Serial.printf("send rawData[%d]\n", dataLength);
      irsend.sendRaw(rawData, dataLength, 38);
    } else {
      Serial.println("rawData[] is empty. Skip sending");
    }
} else if (M5.Btn.pressedFor(300)) {
    irrecv.enableIRIn();
    Serial.println("M5.Btn.pressedFor(300): waiting for IR signal");
    while (! M5.Btn.wasReleased()) {
      delay(50);
      M5.update();
    }
} else {
    if (irrecv.decode(&results)) {
      irrecv.disableIRIn();
      if (results.overflow)
      Serial.printf(D_WARN_BUFFERFULL "\n", kCaptureBufferSize);
      rawData = resultToRawArray(&results);
      dataLength = getCorrectedRawLength(&results);
      Serial.printf("rawData[%d] : ", dataLength);
      for (int i = 0; i < dataLength; i++) {
      Serial.printf("%d, ", rawData);
      }
      Serial.println();
    }
}
}



页: [1]
查看完整版本: Atom发送红外编码(一)