ESP32-S3 红外发射
ESP32-S3 红外发射
从物理学角度看,红外线是波长介于可见光与微波之间的电磁波(波长范围约 0.75 μ m 0.75\mu m 0.75μm 至 1000 μ m 1000\mu m 1000μm)。 在电子工程中,我们通常不依赖自然热辐射,而是通过电致发光(Electroluminescence)效应,利用半导体器件主动产生特定波长的红外光。目前最常用的红外发射源是红外发光二极管(IR LED)。其核心原理是利用半导体 PN 结的能量转换。当给红外发射管施加正向电压时,P 区的空穴和 N 区的电子会向 PN 结移动并发生复合。
- 能量释放: 在复合过程中,电子从高能级(导带)落入低能级(价带)。根据能量守恒定律,多余的能量会以光子的形式释放出来。
- 波长决定: 释放的光子波长
λ
\lambda
λ 取决于材料的禁带宽度(Bandgap Energy,
E
g
E_g
Eg),公式如下:
λ = h ⋅ c E g \lambda = \frac{h \cdot c}{E_g} λ=Egh⋅c
其中 h h h 为普朗克常数, c c c 为光速。 - 常用材料: * 砷化镓 (GaAs): 发射波长约为
940
n
m
940nm
940nm(最常用于遥控器)。
- 铝砷化镓 (AlGaAs): 发射波长约为 850 n m 850nm 850nm(常用于安防监控夜视,肉眼可见微弱红光)。
红外光如何传输信息?
仅仅发射红外光是不够的,为了防止环境光(如太阳光、灯光)的干扰,红外发射通常需要经过调制。
- 载频调制 (Carrier Modulation)
在遥控领域,红外信号通常被调制在 38 k H z 38kHz 38kHz 的载波上。
- 逻辑 0 与 1: 通过控制 38 k H z 38kHz 38kHz 脉冲串的“有”或“无”(或脉冲宽度)来代表二进制数据。
- 抗干扰: 接收端通过带通滤波器滤除其他频率的干扰,只识别 38 k H z 38kHz 38kHz 的闪烁信号,这极大提高了传输的可靠性。
- 硬件实现电路
- 开关电路: 由于单片机 GPIO 口驱动能力有限,通常使用三极管(如 S8050)作为开关,控制红外灯的高电流流过(通常为 20 m A 20mA 20mA 到 100 m A 100mA 100mA)。
- 限流电阻: 必须串联电阻以防止烧毁二极管,其压降通常在 1.2 V − 1.5 V 1.2V - 1.5V 1.2V−1.5V 左右。
点击 牛瘪汤 主页可以了解更多。
1. 核查原理图
ESP32 S3 红外接收使用 TOP75238TR 双红外接收头,接收更稳定。供电范围 3-5V。

红外发送头(如VS1838B)的IN引脚 → ESP32-S3 GPIO8
红外发送头 VCC → 3.3V
红外接收头(如VS1838B)的OUT引脚 → ESP32-S3 GPIO7
红外接收头 VCC → 3.3V
红外接收头 GND → GND
建议在OUT与VCC之间连接10kΩ上拉电阻,或使用代码中的INPUT_PULLUP启用内部上拉(内部上拉较弱,可能影响远距离接收)。
2. 编写代码
-
红外发射管
红外发射管,不能直接由 GPIO 驱动,因为其工作电流较大(通常 50~100mA),而 ESP32 的 GPIO 最大输出电流有限。建议使用一个 NPN 三极管(如 2N2222)或 MOSFET 搭建驱动电路,串联一个 10~20Ω 的限流电阻。简单的电路参考:GPIO8 通过 1kΩ 电阻接三极管基极,发射极接地,集电极接红外发射管负极,发射管正极接 3.3V 或 5V(根据发射管参数)。 -
按键 IO0
ESP32-S3 开发板上的 BOOT 按钮通常连接 GPIO0,默认内部上拉,按下为低电平,符合“低电平有效”。
#include <Arduino.h>
#include <IRremoteESP8266.h>
#include <IRrecv.h>
#include <IRsend.h>
#include <IRutils.h>
// 引脚定义
#define IR_RECV_PIN 36 // 红外接收器引脚
#define IR_SEND_PIN 37 // 红外发射器引脚
#define BUTTON_PIN 0 // 按键引脚(注意:GPIO0通常有上拉电阻)
// 红外接收设置
#define CAPTURE_BUFFER_SIZE 1024
#define TIMEOUT 50 // 解码超时时间(ms)
// 红外接收对象
IRrecv irrecv(IR_RECV_PIN, CAPTURE_BUFFER_SIZE, TIMEOUT, true);
// 红外发送对象
IRsend irsend(IR_SEND_PIN);
// 存储接收到的红外数据
decode_results received_data;
bool has_received_data = false;
// 按键状态
int button_state = HIGH;
int last_button_state = HIGH;
unsigned long last_debounce_time = 0;
unsigned long debounce_delay = 50;
// 用于存储原始数据的数组
uint16_t rawData[CAPTURE_BUFFER_SIZE];
uint16_t rawDataLen = 0;
void setup() {
Serial.begin(115200);
while (!Serial) delay(10);
Serial.println("\nESP32-S3 红外收发程序");
Serial.println("等待接收红外信号...");
// 初始化红外接收
irrecv.enableIRIn();
Serial.print("红外接收器已启用,引脚: ");
Serial.println(IR_RECV_PIN);
// 初始化红外发送
irsend.begin();
Serial.print("红外发射器已启用,引脚: ");
Serial.println(IR_SEND_PIN);
// 初始化按键引脚(使用内部上拉电阻)
pinMode(BUTTON_PIN, INPUT_PULLUP);
Serial.print("按键已初始化,引脚: ");
Serial.println(BUTTON_PIN);
// 测试按键初始状态
button_state = digitalRead(BUTTON_PIN);
Serial.print("按键初始状态: ");
Serial.println(button_state == HIGH ? "HIGH (未按下)" : "LOW (按下)");
// 打印使用说明
Serial.println("\n使用说明:");
Serial.println("1. 用遥控器对准红外接收器发送信号");
Serial.println("2. 按下按键触发发送存储的红外信号");
Serial.println("3. 串口监视器显示详细信息");
delay(1000);
}
void loop() {
// 1. 检查红外接收
checkIRReceive();
// 2. 检查按键(带防抖)
checkButton();
delay(10); // 短暂延迟减少CPU占用
}
void checkIRReceive() {
// 检查是否接收到红外信号
if (irrecv.decode(&received_data)) {
Serial.println("\n=== 收到红外信号 ===");
// 打印接收到的信号信息
Serial.print("解码类型: ");
Serial.println(typeToString(received_data.decode_type));
if (received_data.decode_type == UNKNOWN) {
Serial.println("收到未知格式信号");
} else {
Serial.print("值: 0x");
Serial.println(uint64ToString(received_data.value, HEX));
Serial.print("位数: ");
Serial.println(received_data.bits);
}
// 保存原始数据用于发送
if (received_data.rawlen > 1) {
rawDataLen = received_data.rawlen - 1;
for (uint16_t i = 1; i < received_data.rawlen; i++) {
rawData[i-1] = received_data.rawbuf[i] * kRawTick;
}
Serial.print("原始数据长度: ");
Serial.println(rawDataLen);
}
// 标记已接收到数据
has_received_data = true;
// 恢复接收
irrecv.resume();
Serial.println("信号已存储,按下按键发送");
}
}
void checkButton() {
// 读取按键状态
int reading = digitalRead(BUTTON_PIN);
// 检查状态变化
if (reading != last_button_state) {
// 重置防抖计时器
last_debounce_time = millis();
Serial.print("按键状态变化: ");
Serial.println(reading == HIGH ? "HIGH -> 释放" : "LOW -> 按下");
}
// 检查防抖时间是否已过
if ((millis() - last_debounce_time) > debounce_delay) {
// 如果状态稳定且已改变
if (reading != button_state) {
button_state = reading;
// 按键按下(低电平)
if (button_state == LOW) {
Serial.println("\n=== 按键按下 ===");
if (has_received_data) {
sendIRData();
} else {
Serial.println("错误: 没有存储的红外数据");
}
} else {
// 按键释放
Serial.println("按键释放");
}
}
}
// 保存当前状态用于下次比较
last_button_state = reading;
}
void sendIRData() {
if (!has_received_data) {
Serial.println("错误: 没有存储的红外数据");
return;
}
Serial.println("\n=== 发送红外信号 ===");
// 根据解码类型发送相应的信号
switch (received_data.decode_type) {
case NEC:
Serial.println("发送 NEC 格式信号");
irsend.sendNEC(received_data.value, received_data.bits);
break;
case SONY:
Serial.println("发送 SONY 格式信号");
irsend.sendSony(received_data.value, received_data.bits);
break;
case RC5:
Serial.println("发送 RC5 格式信号");
irsend.sendRC5(received_data.value, received_data.bits);
break;
case RC6:
Serial.println("发送 RC6 格式信号");
irsend.sendRC6(received_data.value, received_data.bits);
break;
case PANASONIC:
Serial.println("发送 Panasonic 格式信号");
irsend.sendPanasonic64(received_data.value);
break;
case LG:
Serial.println("发送 LG 格式信号");
irsend.sendLG(received_data.value, received_data.bits);
break;
case JVC:
Serial.println("发送 JVC 格式信号");
irsend.sendJVC(received_data.value, received_data.bits, 0);
break;
case SAMSUNG:
Serial.println("发送 SAMSUNG 格式信号");
irsend.sendSAMSUNG(received_data.value, received_data.bits);
break;
case WHYNTER:
Serial.println("发送 Whynter 格式信号");
irsend.sendWhynter(received_data.value, received_data.bits);
break;
case COOLIX:
Serial.println("发送 Coolix 格式信号");
irsend.sendCoolix48(received_data.value);
break;
case RAW:
Serial.println("发送原始数据格式信号");
irsend.sendRaw(rawData, rawDataLen, 38); // 38kHz
break;
default:
case UNKNOWN:
Serial.println("发送未知格式信号(原始数据)");
if (rawDataLen > 0) {
irsend.sendRaw(rawData, rawDataLen, 38); // 38kHz
} else {
Serial.println("错误: 原始数据为空");
}
break;
}
Serial.println("信号发送完成");
Serial.println("等待接收新信号...");
}
按下开发板上的 BOOT 按钮(IO0),串口应打印“Button pressed! Repeating last IR code…”,然后红外发射管应转发刚才接收到的信号。
结语
文章都看到完了,就不点个关注吗,老铁!
欢迎关注博主–牛瘪汤 。
更多推荐
所有评论(0)