Chapter 06 · Arduino 入门

传感器读取

给 Arduino 装上"感官":光敏电阻感光、DHT11 测温湿度、超声波量距离、PIR 探人体。

课程进度50%

关键概念

传感器 (Sensor)
把物理量(光、温度、距离、运动…)转换成电信号的器件。它是嵌入式系统"感知世界"的入口。Arduino 通过读取传感器输出的电压/电平/时序,把现实变成可运算的数字。
模拟传感器 vs 数字传感器
模拟传感器输出连续变化的电压(如光敏电阻分压、热敏电阻),用 analogRead 读。数字传感器输出高/低电平或按协议(单总线/I2C)传数据(如 DHT11、PIR、超声波),用 digitalRead 或专用库读。买传感器先看它是哪种输出。
光敏电阻 (LDR / 光敏)
Light Dependent Resistor。阻值随光照变化:光越强阻值越小。它本身不输出电压,需和一个定值电阻组成分压电路,把光照变化转成 A0 能读的电压。典型用途:光控夜灯、自动窗帘。
DHT11 / DHT22
常见的温湿度一体传感器,走"单总线"私有协议(时序严格,靠库解析)。DHT11 便宜但精度低(温度 ±2℃、湿度 ±5%,读取间隔 ≥1s);DHT22 精度更高、范围更广。三/四脚模块:VCC、DATA、GND。
HC-SR04 超声波测距
靠发射超声波、接收回波、测量往返时间来算距离(声速约 340m/s)。四脚:VCC、Trig(触发发射)、Echo(回波,其高电平持续时间正比于距离)、GND。量程约 2~400cm,是避障小车、水位检测的常客。
PIR 人体红外感应
Passive InfraRed。被动探测人体发出的红外线变化,检测到"运动的热源"就在输出脚给出高电平。数字输出,直接 digitalRead。用于自动灯、安防。模块上常有两个电位器可调灵敏度和延时。
库 (Library) 的作用
复杂传感器(如 DHT)的通信时序非常繁琐,官方/社区把这些底层细节封装成库。你只需 #include 头文件、创建对象、调 readTemperature() 之类的高层函数即可拿到结果,不必手撕时序。第 2 章学过用库管理器安装。
数据滤波 (Filtering)
传感器读数常有噪声抖动。最简单的滤波是"多次采样取平均",能显著平滑毛刺。更进阶有中值滤波、指数加权平均、卡尔曼滤波。稳定的读数是可靠控制的前提。

模拟传感器:光敏电阻

光敏电阻要和一个 10kΩ 电阻串联成分压器,中间节点接 A0:

光敏电阻分压电路 5V │ ┌──┸──┐ │ LDR │ 光敏电阻(光强→阻值小) └──┰──┘ ┝━━━━━━○ Arduino A0 ← 读这里的分压 ┌──┸──┐ │10kΩ │ 定值电阻 └──┰──┘ │ GND 光强 → LDR 阻值小 → A0 分到的电压高 → analogRead 大 变暗 → LDR 阻值大 → A0 分到的电压低 → analogRead 小
// 光控夜灯:暗了自动开灯
const int ldrPin = A0;
const int ledPin = 13;
const int THRESHOLD = 300;   // 阈值,需按实际环境调

void setup() {
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
}

void loop() {
  int light = analogRead(ldrPin);
  Serial.println(light);

  if (light < THRESHOLD) {       // 光弱 → 天黑
    digitalWrite(ledPin, HIGH);  // 开灯
  } else {
    digitalWrite(ledPin, LOW);
  }
  delay(100);
}

多次采样取平均(简单滤波)

// 采样 10 次取平均,读数更稳
int readAveraged(int pin, int times) {
  long sum = 0;
  for (int i = 0; i < times; i++) {
    sum += analogRead(pin);
    delay(2);   // 每次采样间隔一点点
  }
  return sum / times;
}

数字传感器:DHT11 温湿度

DHT11 用单总线协议,靠库读取。先在库管理器装 "DHT sensor library"(Adafruit)。DATA 脚接 D2,接一个 10kΩ 上拉到 5V(部分模块已内置)。

#include <DHT.h>

#define DHTPIN   2        // DATA 接 D2
#define DHTTYPE  DHT11    // 型号:DHT11 或 DHT22

DHT dht(DHTPIN, DHTTYPE);  // 创建传感器对象

void setup() {
  Serial.begin(9600);
  dht.begin();
}

void loop() {
  delay(2000);   // DHT11 至少间隔 1 秒,稳妥用 2 秒

  float h = dht.readHumidity();      // 读湿度 %
  float t = dht.readTemperature();   // 读温度 ℃

  // 读取失败会返回 NaN,必须检查
  if (isnan(h) || isnan(t)) {
    Serial.println("读取 DHT 失败!");
    return;
  }

  Serial.print("温度: ");
  Serial.print(t);
  Serial.print(" C  湿度: ");
  Serial.print(h);
  Serial.println(" %");
}
DHT 读取失败排查

返回 NaN 通常是:① 读取太频繁(DHT11 需 ≥1s 间隔);② DATA 脚没接上拉电阻;③ 型号选错(DHT11 vs DHT22);④ 接线松动。务必用 isnan() 判断再使用数据,否则拿 NaN 去计算或显示会出错。

HC-SR04 超声波测距

无需库,用 pulseIn 测回波时间即可换算距离:

超声波测距原理与接线 接线:Trig→D9 Echo→D10 VCC→5V GND→GND ①给 Trig 一个 10μs 高脉冲 → 模块发出 8 个 40kHz 超声波 ②超声波撞到障碍物反弹回来 ③模块把 Echo 拉高,高电平持续时间 = 声波往返时间 Trig ──┐ ┌───────────────────── └─┘ (10μs 触发) Echo ────────┐ ┌────── └──────────┘ ← 回波时间 t → 距离 = t(μs) × 声速(0.034cm/μs) ÷ 2 = t × 0.034 / 2 (除 2 因为是往返)
// HC-SR04 超声波测距(厘米)
const int trigPin = 9;
const int echoPin = 10;

void setup() {
  Serial.begin(9600);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
}

float measureCm() {
  // 发一个 10μs 触发脉冲
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  // 测量 Echo 高电平持续时间(μs),超时 30ms 防卡死
  long duration = pulseIn(echoPin, HIGH, 30000);
  if (duration == 0) return -1;  // 超时/超量程

  return duration * 0.034 / 2;   // 换算成 cm
}

void loop() {
  float cm = measureCm();
  if (cm < 0) {
    Serial.println("超出量程");
  } else {
    Serial.print(cm);
    Serial.println(" cm");
  }
  delay(200);
}
pulseIn 是什么

pulseIn(pin, HIGH) 会阻塞等待引脚变高,然后测量它保持高电平的微秒数直到变低。第三个参数是超时(μs),务必设置(如 30000),否则障碍物太远收不到回波时程序会一直卡在这里。

PIR 人体感应

最简单的数字传感器,检测到人就输出高电平:

// PIR 检测到人就亮灯并打印
const int pirPin = 3;   // PIR 输出接 D3
const int ledPin = 13;

void setup() {
  Serial.begin(9600);
  pinMode(pirPin, INPUT);
  pinMode(ledPin, OUTPUT);
}

void loop() {
  if (digitalRead(pirPin) == HIGH) {
    digitalWrite(ledPin, HIGH);
    Serial.println("检测到有人!");
  } else {
    digitalWrite(ledPin, LOW);
  }
  delay(100);
}

常见传感器速查

传感器测量量输出类型读取方式需要库
光敏电阻 LDR光照强度模拟(分压)analogRead
热敏电阻 NTC温度模拟(分压)analogRead+公式
DHT11/22温度+湿度数字(单总线)库函数是(DHT)
HC-SR04距离数字(脉宽)pulseIn
PIR人体运动数字(电平)digitalRead
MPU6050加速度/陀螺仪数字(I2C)库函数
供电与共地

传感器供电看清是 3.3V 还是 5V(有的模块两者兼容)。所有传感器的 GND 必须和 Arduino 的 GND 相连(共地),否则电平没有共同参考,读数全乱。多个模块用外部电源时,外部电源负极也要和 Arduino GND 相连。

本章小结

传感器是 Arduino 感知世界的入口,分两类:模拟传感器输出连续电压(光敏、热敏电阻,需组分压电路用 analogRead 读),数字传感器输出电平或按协议传数据(用 digitalRead 或专用库)。光敏电阻+10kΩ 分压做光控夜灯;读数抖动用"多次采样取平均"简单滤波。DHT11/22 走单总线协议,装 DHT 库后 readTemperature/readHumidity 即可,读取间隔 ≥1s,失败返回 NaN 要用 isnan() 判断。HC-SR04 超声波无需库:Trig 发 10μs 脉冲,用 pulseIn(带超时)测 Echo 高电平时长,距离 = 时长 × 0.034 / 2。PIR 是最简单的数字传感器,检测到人输出高电平直接 digitalRead。复杂传感器优先找现成库省去手撕时序。铁律:看清供电电压,所有传感器必须与 Arduino 共地

⚒️ 配套开发者工具箱 · 17 款免费在线工具