Arduino红外传感器实战:从遥控解码到避障测距的完整指南
1. 项目概述:为什么红外传感器是Arduino入门者的必修课
如果你刚开始玩Arduino,想找一个既有意思又能学到东西的项目,那用红外传感器绝对是绕不开的一环。这东西看起来就是个不起眼的小黑疙瘩,但它的玩法之多,从简单的避障小车到复杂的家电遥控,几乎贯穿了整个电子DIY的入门到进阶。我刚开始接触时,也觉得不就是接收个红外信号嘛,但真上手才发现,从选型、接线到解码、抗干扰,每一步都有门道。今天我就结合自己踩过的坑和积累的经验,把用Arduino玩转红外传感器的完整流程拆开揉碎了讲给你听,让你不仅能照着做出来,更能明白背后的“为什么”。
简单来说,红外传感器就是Arduino的“眼睛”,只不过它“看”的是我们肉眼看不见的红外光。最常见的应用场景有两个:一个是作为“红外接收头”,用来解码电视遥控器、空调遥控器发出的信号,让你的Arduino变身万能遥控器;另一个是作为“红外避障模块”,通过发射和接收红外光来判断前方是否有障碍物,这是智能小车自动避障的核心。无论是哪种,其核心原理都是将不可见的红外光信号,转换成Arduino能读懂的电压变化(数字信号或模拟信号)。理解了这一点,后面的接线和编程就都有了方向。
2. 红外传感器家族:从通用接收头到专用避障模块的选型指南
市面上常见的、能和Arduino搭配的红外传感器主要分两大类,它们的原理、接口和用途截然不同,选错了型号,代码怎么写都可能白搭。
2.1 VS1838B / TSOP382:万能遥控解码的核心
这类传感器通常被称为“红外接收头”或“一体化红外接收模块”。你从旧遥控器里拆出来的,或者网上几毛钱一个买到的,多半就是它。以 VS1838B 为例,它有三个引脚:OUT(信号输出)、GND(地)、VCC(电源,通常3.3V或5V)。
它的工作原理是“一体化”:内部集成了红外接收管、前置放大器、带通滤波器和解调电路。遥控器发出的红外信号是经过38kHz(这是绝大多数消费电子的标准载波频率)调制的脉冲串。VS1838B这个“一体化”设计,就是专门用来滤除环境中的其他红外干扰(比如日光灯、白炽灯),只解调出38kHz载波上承载的原始数据脉冲,然后从OUT引脚输出给Arduino。所以,你直接用
digitalRead
读它的引脚,得到的就是一串高低电平变化的数字信号,对应着遥控器按键的编码。
注意 :这类接收头对电源电压比较敏感。虽然标称支持3-5V,但我实测下来,用5V供电时接收距离和稳定性通常更好。但务必确认你买的型号支持5V,有些为低功耗设备设计的型号(如某些TSOP系列)用5V可能会烧毁。
2.2 TCRT5000 / E18-D80NK:避障与测距的利器
这类是主动式红外传感器,通常被称为“红外避障模块”或“光电开关”。以最经典的 TCRT5000 为例,它其实是一个组合体:一个红外发射二极管(IR LED)和一个红外接收三极管封装在一起。模块上一般会有三个引脚:VCC、GND、OUT(数字量输出),有些还会多一个AO引脚(模拟量输出)。
它的工作原理是“反射式”:模块上的IR LED持续发射红外光,当前方有物体时,红外光被反射回来,被旁边的接收管接收到。接收管接收到光后,其导通程度会变化,从而改变输出引脚的电平。模块上通常有一个电位器,用来调节灵敏度(即检测距离)。当反射光强度超过阈值,数字输出OUT就从高电平变为低电平(或反之,取决于模块设计),告诉你“检测到障碍物了”。
TCRT5000 和 E18-D80NK 的主要区别在于结构和性能:
- TCRT5000 :发射和接收管并排朝前,检测距离短(通常2-30mm),适合近距离的循迹(检测黑白线)或近距避障。价格极其低廉。
- E18-D80NK :这是一种“对射式”结构的漫反射传感器,发射和接收管在同一轴线,通过透镜聚焦,检测距离远(3-80cm可调),抗环境光干扰能力强,适合作为中距离的避障传感器。价格稍高。
选型建议 :
- 想做遥控解码、学习红外编码 :无脑选 VS1838B 或 TSOP382 这类一体化接收头。
- 想做循迹小车、检测桌面黑白线 :选 TCRT5000 ,性价比之王。
- 想做智能小车避障、检测前方较远(10cm以上)的障碍物 :选 E18-D80NK ,效果更稳定可靠。
3. 硬件连接:从原理图到面包板的防错接线
理解了传感器类型,接线就简单了。但新手最容易犯的错就是不看引脚定义瞎接,或者电源接反。下面我们以Arduino Uno为例,分别说明两种传感器的接法。
3.1 一体化接收头(VS1838B)的连接
VS1838B的三个引脚顺序(从半球形透镜方向看,引脚朝下)通常是: OUT | GND | VCC (从左到右)。但不同厂家封装可能略有差异, 最稳妥的方法是查看卖家提供的资料或万用表测量 。
标准接法如下:
- VS1838B VCC -> Arduino 5V 引脚。
- VS1838B GND -> Arduino GND 引脚。
- VS1838B OUT -> Arduino 数字引脚(如 D11) 。
这里为什么选D11?没有特殊原因,只是一个习惯。因为后续我们要用到一个非常强大的库
IRremote
,它默认将一些常用引脚定义为红外接收引脚,D11就是其中之一,用起来方便。实际上,任何支持外部中断的数字引脚(如Uno上的D2, D3)都可以,并且能获得更好的性能,这个我们后面讲代码时会详细说。
3.2 红外避障模块(TCRT5000)的连接
TCRT5000模块通常有4个引脚:VCC、GND、DO(数字输出)、AO(模拟输出)。我们一般先使用DO。
标准接法如下:
- 模块 VCC -> Arduino 5V 。
- 模块 GND -> Arduino GND 。
- 模块 DO -> Arduino 数字引脚(如 D2) 。
接好后,给Arduino上电。正常情况下,模块上的电源指示灯会亮。此时,用手或白纸在传感器前方晃动,你会发现模块上另一个信号指示灯(通常为红色)会随之亮灭,同时用
digitalRead(D2)
读取电平也会变化。这就说明硬件连接成功了。
实操心得 :在接好线、上电前, 务必再三确认VCC和GND没有接反 。接反瞬间可能不会冒烟,但传感器芯片很可能已经默默受损了,表现为工作不稳定或直接失效。养成“上电前检查三遍”的习惯,能省下很多排查故障的时间。
4. 软件核心:IRremote库的深度解析与高效使用
对于红外接收解码,Arduino社区有一个堪称“神器”的库:
IRremote
。它强大到几乎支持所有已知的红外遥控协议(NEC, Sony SIRC, RC5, RC6等),让解码变得异常简单。但要用好它,不止是
#include <IRremote.h>
那么简单。
4.1 库的安装与版本选择
打开Arduino IDE,点击“工具” -> “管理库…”,在搜索框中输入“IRremote”。你会看到好几个结果,最常见的是
IRremote by shirriff
和
IRremoteESP8266
。对于Arduino Uno等AVR平台,我们选择安装**
IRremote by shirriff
**(作者是Ken Shirriff)。
IRremoteESP8266
主要针对ESP8266/ESP32优化,功能更强大但可能对Uno不完全兼容。
安装完成后,你可以通过“文件” -> “示例” ->
IRremote
找到丰富的示例代码。但对于新手,我建议从最基础的
IRrecvDemo
开始。
4.2 基础解码代码拆解
我们来看一个精简并添加了注释的
IRrecvDemo
核心代码:
#include <IRremote.h> // 包含库
// 定义红外接收器连接的引脚
const int RECV_PIN = 11;
// 创建一个红外接收对象,参数是接收引脚
IRrecv irrecv(RECV_PIN);
// 创建一个解码结果对象,用于存放解码后的信息
decode_results results;
void setup() {
Serial.begin(9600); // 启动串口通信,用于在电脑上打印结果
irrecv.enableIRIn(); // 启动红外接收器
Serial.println("红外接收器已启动,请按下遥控器按键...");
}
void loop() {
// 检查是否接收到红外信号
if (irrecv.decode(&results)) {
// 如果接收到,将解码结果以16进制打印到串口监视器
Serial.print("解码类型: 0x");
Serial.println(results.decode_type, HEX);
Serial.print("解码值: 0x");
Serial.println(results.value, HEX);
Serial.println(); // 空行
irrecv.resume(); // 恢复接收,准备接收下一个信号
}
}
上传这段代码到你的Arduino,打开串口监视器(波特率设为9600),然后用电视或机顶盒遥控器对准VS1838B按下按键。你应该能看到类似这样的输出:
解码类型: 0x1
解码值: 0xFFA25D
这里的
0x1
代表NEC协议(最常见),
0xFFA25D
就是你按下的那个按键的十六进制编码。
4.3 进阶技巧:使用外部中断提升响应速度与稳定性
上面的代码将接收引脚设为D11,它工作在“轮询”模式,即
loop()
函数不断检查是否有信号。对于大多数应用这足够了。但如果你需要极快的响应速度,或者你的
loop()
里有其他耗时任务,轮询可能会丢失短暂的信号。
更好的方法是使用 外部中断 。中断可以让引脚在电平变化时立即暂停主程序,去执行一个特定的函数。Arduino Uno的D2和D3引脚支持外部中断。
修改步骤如下:
- 硬件 :将VS1838B的OUT引脚改接到 D2 。
-
软件
:代码需要做一些调整。
IRremote库本身支持中断模式,但需要手动指定。
#include <IRremote.h>
// 使用支持外部中断的引脚,这里用D2(对应中断号0)
const int RECV_PIN = 2;
IRrecv irrecv(RECV_PIN);
decode_results results;
void setup() {
Serial.begin(9600);
// 关键:enableIRIn()内部会自动配置中断,对于D2/D3引脚,库能正确识别
irrecv.enableIRIn();
Serial.println("红外接收器(中断模式)已启动...");
}
void loop() {
// loop函数现在可以空着,或者处理其他任务
// 解码由中断服务程序在后台完成
if (irrecv.decode(&results)) {
Serial.print("解码值: 0x");
Serial.println(results.value, HEX);
irrecv.resume(); // 仍然需要resume来清除缓存
}
// 这里可以添加其他不阻塞的代码,如LED闪烁
delay(100); // 一个小延迟,避免串口打印过快
}
使用中断后,红外接收的实时性大大提高,几乎不会漏掉任何按键信号。这是从“能用”到“好用”的关键一步。
4.4 处理按键连按与不同协议
你可能发现,长按某个按键时,解码出的值可能变成
0xFFFFFFFF
(对于NEC协议),这代表“重复码”,表示按键被持续按住。在编写控制程序时,你需要判断这个值,通常将其视为与前一个有效按键值相同。
另外,不同品牌的遥控器可能使用不同协议。
IRremote
库的
results.decode_type
给出了协议类型。常见的映射关系是:
NEC=1
,
SONY=2
,
RC5=3
,
RC6=4
等。你可以在代码中根据这个类型做不同的处理,但库已经帮你把不同协议的值都统一到了
results.value
中,对于大多数“学习并模拟”的应用,我们直接关心
value
即可。
5. 从解码到控制:实现一个红外遥控智能开关
掌握了解码,我们就可以让Arduino根据不同的红外指令执行动作了。下面我们实现一个经典项目:用遥控器控制一个LED灯的开关、亮度和颜色(如果使用RGB LED)。
5.1 控制单个LED开关
我们假设解码到
0xFFA25D
(通常是电源键)时,翻转LED状态。
#include <IRremote.h>
const int RECV_PIN = 11;
const int LED_PIN = 13; // 使用板载LED
IRrecv irrecv(RECV_PIN);
decode_results results;
bool ledState = LOW; // 记录LED当前状态
void setup() {
Serial.begin(9600);
irrecv.enableIRIn();
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, ledState);
}
void loop() {
if (irrecv.decode(&results)) {
Serial.println(results.value, HEX);
if (results.value == 0xFFA25D) { // 匹配电源键编码
ledState = !ledState; // 翻转状态
digitalWrite(LED_PIN, ledState);
Serial.println("切换LED状态");
}
irrecv.resume();
}
}
5.2 控制LED亮度(PWM调光)
如果想用音量+/-键来控制LED亮度,就需要用到PWM(脉冲宽度调制)。Arduino上标有
~
的引脚(如3, 5, 6, 9, 10, 11)支持PWM。
#include <IRremote.h>
const int RECV_PIN = 11;
const int LED_PIN = 9; // 必须接在支持PWM的引脚上
IRrecv irrecv(RECV_PIN);
decode_results results;
int brightness = 128; // 初始亮度,范围0-255
void setup() {
Serial.begin(9600);
irrecv.enableIRIn();
pinMode(LED_PIN, OUTPUT);
analogWrite(LED_PIN, brightness); // 使用analogWrite设置PWM
}
void loop() {
if (irrecv.decode(&results)) {
Serial.println(results.value, HEX);
if (results.value == 0xFF906F) { // 假设是音量+键
brightness = min(255, brightness + 10); // 增加亮度,不超过255
analogWrite(LED_PIN, brightness);
Serial.print("亮度+: ");
Serial.println(brightness);
}
if (results.value == 0xFFE01F) { // 假设是音量-键
brightness = max(0, brightness - 10); // 减小亮度,不小于0
analogWrite(LED_PIN, brightness);
Serial.print("亮度-: ");
Serial.println(brightness);
}
irrecv.resume();
}
}
5.3 控制RGB LED颜色
这需要用到三个PWM引脚分别控制红、绿、蓝三个LED芯片(如果是共阳极RGB LED,接线和逻辑需反转)。
#include <IRremote.h>
const int RECV_PIN = 11;
const int RED_PIN = 9;
const int GREEN_PIN = 10;
const int BLUE_PIN = 11;
IRrecv irrecv(RECV_PIN);
decode_results results;
int r=0, g=0, b=0;
void setup() {
Serial.begin(9600);
irrecv.enableIRIn();
pinMode(RED_PIN, OUTPUT);
pinMode(GREEN_PIN, OUTPUT);
pinMode(BLUE_PIN, OUTPUT);
setColor(r, g, b);
}
void loop() {
if (irrecv.decode(&results)) {
long val = results.value;
Serial.println(val, HEX);
// 用数字键1-3分别控制红、绿、蓝分量增加
if (val == 0xFF6897) { // 按键1
r = (r + 20) % 256;
} else if (val == 0xFF9867) { // 按键2
g = (g + 20) % 256;
} else if (val == 0xFFB04F) { // 按键3
b = (b + 20) % 256;
} else if (val == 0xFFA25D) { // 电源键清零
r = g = b = 0;
}
setColor(r, g, b);
Serial.print("Color R:");
Serial.print(r);
Serial.print(" G:");
Serial.print(g);
Serial.print(" B:");
Serial.println(b);
irrecv.resume();
}
}
// 设置RGB颜色的辅助函数
void setColor(int red, int green, int blue) {
analogWrite(RED_PIN, red);
analogWrite(GREEN_PIN, green);
analogWrite(BLUE_PIN, blue);
}
通过这个例子,你可以举一反三,用红外遥控器控制舵机角度、继电器开关、电机转速等等,实现真正的“遥控万物”。
6. 红外发射:让你的Arduino变身万能遥控器
既然能接收,自然也能发射。
IRremote
库同样支持红外发射功能。你需要一个
红外发射二极管
(IR LED)和一个约100欧姆的限流电阻。IR LED看起来和普通LED很像,但它的透镜通常是透明或淡蓝色的,发出的光肉眼几乎不可见(用手机摄像头能看到紫色光点)。
6.1 发射电路连接
将IR LED的 长脚(阳极) 通过一个100Ω电阻连接到Arduino的一个 数字引脚(如D3) , 短脚(阴极) 接 GND 。注意,红外发射需要较大的电流才能有足够的发射距离,所以这个引脚最好不是正在用作红外接收的引脚,并且不要使用板载LED引脚(D13),因为其驱动能力可能不足。
6.2 发射代码实现
下面的代码演示了如何发射一个NEC协议的信号,模拟按下编码为
0xFFA25D
的按键。
#include <IRremote.h>
// 定义红外发射LED连接的引脚
const int IR_SEND_PIN = 3;
// 创建红外发射对象
IRsend irsend(IR_SEND_PIN);
void setup() {
Serial.begin(9600);
// 对于发射,不需要特别的初始化
}
void loop() {
Serial.println("发送红外信号:0xFFA25D (NEC协议)");
// 使用irsend.sendNEC()发送NEC协议编码
// 第二个参数是数据位数,对于标准NEC是32位
irsend.sendNEC(0xFFA25D, 32);
delay(3000); // 每隔3秒发送一次
}
上传代码后,用之前做好的接收电路(VS1838B+接收代码)来测试。将发射LED对准接收头,你应该能在接收端的串口监视器里看到解码出的
0xFFA25D
。
6.3 高级发射:学习并重放任意遥控信号
更实用的场景是“学习并重放”:先用接收功能记录下你家空调、风扇遥控器的编码,然后再用发射功能模拟它。
步骤:
-
学习阶段
:运行前面的接收代码,按下你想学习的遥控器按键,记录下打印出的
decode_type和value。例如,得到类型: 0x1 (NEC), 值: 0xC1AA09F7。 -
发射阶段
:修改发射代码,根据记录的类型调用不同的发送函数。
-
对于NEC协议:
irsend.sendNEC(0xC1AA09F7, 32); -
对于SONY协议:
irsend.sendSony(0x1234, 12);// 第二个参数是位数 -
库还支持
sendRC5,sendRC6,sendRaw等。sendRaw可以发送原始时序,用于不常见的协议。
-
对于NEC协议:
重要提示 :红外发射二极管的发射角度小,方向性很强,需要对准设备接收窗。发射距离受驱动电流、LED型号、环境光影响。如果想控制较远的设备,可以考虑使用多个LED并联(每个都串接限流电阻),或者使用晶体管来放大驱动电流。
7. 避障传感器实战:从数字检测到模拟测距
现在我们回到另一大类红外传感器——避障模块。我们以TCRT5000为例,它输出的是简单的数字开关量,使用起来比红外解码简单直接得多。
7.1 基础数字避障
代码非常简单,就是读取数字引脚的电平。
const int sensorPin = 2; // 模块DO接D2
const int ledPin = 13;
void setup() {
Serial.begin(9600);
pinMode(sensorPin, INPUT);
pinMode(ledPin, OUTPUT);
}
void loop() {
int obstacle = digitalRead(sensorPin);
// 注意:模块输出逻辑可能不同!常见是检测到障碍物时输出LOW
// 请根据你的模块实际行为调整判断条件
if (obstacle == LOW) {
Serial.println("检测到障碍物!");
digitalWrite(ledPin, HIGH);
} else {
Serial.println("前方畅通");
digitalWrite(ledPin, LOW);
}
delay(100); // 适当延迟,避免串口刷屏
}
关键点
:模块的输出逻辑务必实测确认。用
Serial.println(obstacle)
打印出来,用手挡住传感器看数值变化。常见的设计是:平时输出HIGH,有障碍物时输出LOW(因为接收管导通拉低电平)。但也有的模块设计相反。代码里的判断条件必须与实际匹配。
7.2 使用模拟输出实现距离感知
TCRT5000的AO引脚输出的是模拟电压,反射光越强,电压越高(或越低,取决于电路)。这让我们可以粗略感知距离的远近,而不仅仅是“有”或“无”。
const int analogPin = A0; // 模块AO接A0
void setup() {
Serial.begin(9600);
}
void loop() {
int sensorValue = analogRead(analogPin);
Serial.print("模拟值: ");
Serial.println(sensorValue);
// 根据实测值设定阈值
if (sensorValue > 800) { // 这个阈值需要根据实际环境校准
Serial.println("非常近");
} else if (sensorValue > 500) {
Serial.println("较近");
} else {
Serial.println("无物体或很远");
}
delay(200);
}
校准技巧 :将模块固定,分别测量前方无物体、有白纸在最近可检测距离、有白纸在中等距离时的模拟值,记下这三个值,就能大致划分出距离区间。注意,不同颜色、材质的物体反射率不同,会导致读数差异很大。黑色物体吸收红外光,可能完全检测不到。
7.3 在智能小车中的应用实例
在循迹小车上,通常会在车底安装2-5个TCRT5000,排成一排,用来检测地面的黑白线。黑线吸收红外光,反射弱,传感器输出高电平(或模拟值小);白纸反射强,输出低电平(或模拟值大)。
一个简单的两传感器循迹逻辑伪代码如下:
左传感器 = 读左侧传感器;
右传感器 = 读右侧传感器;
如果 (左传感器检测到黑线 && 右传感器没检测到黑线) {
说明车偏右了,应该向左转;
} 否则 如果 (右传感器检测到黑线 && 左传感器没检测到黑线) {
说明车偏左了,应该向右转;
} 否则 如果 (都没检测到黑线) {
说明在直道上,直行;
} 否则 如果 (都检测到黑线) {
可能是十字路口或停车线,特殊处理;
}
在避障小车上,可以将E18-D80NK安装在车头左右两侧,当任意一个传感器检测到障碍物时,就命令小车转向或后退。
8. 避坑指南与性能优化:那些教程里不会告诉你的细节
玩红外传感器遇到的坑,多半不是代码逻辑问题,而是物理和电路上的细节。这里我总结几个最常见的。
8.1 红外接收不灵或误触发
- 问题 :遥控器要对得非常准才有反应,或者没按遥控器自己就乱解码。
-
排查
:
- 供电不足 :确保接收头VCC接的是稳定的5V。可以尝试在VCC和GND之间并联一个 47-100μF的电解电容 ,用于滤除电源噪声,效果立竿见影。
- 环境光干扰 :强烈的日光、白炽灯、LED灯都含有红外成分。给接收头套上一段 黑色热缩管 或使用不透明的外壳,只留一个小孔对准前方,能极大提升抗干扰能力。
- 引脚接触不良 :面包板用久了容易接触不良,直接焊接或使用杜邦线直连测试。
- 遥控器电池没电 :电池电压不足会导致发射功率下降,换个新电池试试。
8.2 避障传感器不稳定
- 问题 :检测距离忽远忽近,或者对某些颜色物体没反应。
-
排查
:
- 灵敏度调节 :模块上的蓝色电位器就是调灵敏度的。用小螺丝刀慢慢旋转,同时观察信号指示灯或串口数值,在稳定检测与避免误触发之间找到一个平衡点。
- 环境光干扰 :和接收头一样,强烈的环境光(特别是太阳光)会淹没发射管发出的红外光。尽量在室内使用,或者为传感器制作遮光罩。
- 物体材质与颜色 :深色、尤其是黑色物体会吸收大部分红外光,导致检测距离急剧缩短甚至失效。这是物理特性,无法避免。在设计项目时要考虑应用场景。
- 交叉干扰 :如果两个发射式传感器面对面或并排安装距离太近,一个传感器发出的光可能直接被另一个传感器接收到,造成误触发。错开安装位置或分时工作(一个发射时另一个关闭)可以解决。
8.3 发射距离太短
- 问题 :IR LED发射的信号无法控制远处的设备。
-
优化
:
- 增加驱动电流 :Arduino引脚最大输出电流约20-40mA。可以改用NPN晶体管(如8050)或MOSFET来驱动IR LED,允许流过100mA以上的电流,显著增加发射功率。
- 使用多个LED :将2-3个IR LED并联(每个仍串联一个100Ω左右限流电阻),从不同角度安装,可以增加覆盖范围。
- 选择高功率IR LED :专门购买发射功率大的型号。
-
调制信号要标准
:确保
irsend.sendNEC()等函数发送的编码和载波频率(38kHz)是准确的。不标准的信号接收端可能无法识别。
8.4 代码层面的优化
-
减少
delay()的使用 :在loop()中使用delay()会阻塞程序,可能导致错过红外信号。对于需要同时处理多个任务(如控制小车电机、读取多个传感器)的应用,建议学习使用 状态机 或 非阻塞定时 (利用millis()函数)来重构代码。 - 为红外接收使用独立电源 :如果系统中有电机等大电流设备,可能会引起电源波动,干扰红外接收。考虑使用独立的稳压模块(如AMS1117-5.0)为红外接收部分供电。
-
解码值判断使用
switch case:如果你需要处理很多不同的遥控按键,使用switch(results.value)语句比一长串if else更清晰、效率也可能更高。
红外传感是连接物理世界和数字世界的一座经典桥梁。从按下遥控器到LED点亮,这中间跨越了光电转换、信号调制、编码解码、程序逻辑等多个环节。把这个流程走通、吃透,你收获的不仅仅是一个会闪灯的小装置,更是一套解决类似“感知-控制”问题的通用方法论。无论是后续玩更复杂的传感器,还是做物联网项目,这些底层的硬件交互思想和调试经验,都是极其宝贵的。
更多推荐
所有评论(0)