|
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()
改造后的程序
[mw_shl_code=arduino,true]
#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[67] = {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);
}
}[/mw_shl_code]
此程序调用sendRaw(),请将第10到第20行替换为你自己的原始数据,将第33行中的67更改为你自己的原始数据元素个数
=====创建学习型遥控==============================================================
下面我们将演示如何将上述两个代码融合,做到学习红外信号并进行发送
对应发送的信号可能有两种数据,一种是uint16_t rawData[],一种是根据协议传递数据(NEC和uint64_t数据)
对于rawData有以下优缺点:
•优点:控制信号可以在任何协议中传输 •缺点:数据量增加导致需要较大内存
对应根据协议传递的数据来说:
•优点:传递数据流较小 •缺点:必须根据协议对发送函数进行划分,并且无法处理没有发送函数的协议
考虑到学习型遥控器的用途,我们事先不确定遥控器的协议,因此传递rawData是恰当的方法。
现在我们来构建一下整个遥控器的功能,通过使用正面的按钮实现单击、双击、长按来操作遥控器。
[mw_shl_code=arduino,true]void loop() {
M5.update();
if (M5.Btn.wasReleased()) {// 单击/发送信号
} else if (M5.Btn.pressedFor(300)) { // 长按/启用接收
while (! M5.Btn.wasReleased()) { // 等待按键松开
delay(50);
M5.update();
}
} else {
if (收到红外信号) {
取出信号
}
}
}[/mw_shl_code]
取出信号不是在长按过程中,而是在最后,信号接收处理是异步的
最终代码
[mw_shl_code=arduino,true]
#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();
}
}
}[/mw_shl_code]
|
|