常用传感器
传感器是 Arduino 感知外部世界的"感官"。本章将介绍最常用传感器的原理和使用方法。
温湿度传感器 DHT11/DHT22
DHT 系列传感器是最常用的温湿度传感器,价格低廉,使用简单。
DHT11 vs DHT22
| 特性 | DHT11 | DHT22 |
|---|---|---|
| 温度范围 | 0-50°C | -40-80°C |
| 温度精度 | ±2°C | ±0.5°C |
| 湿度范围 | 20-80% | 0-100% |
| 湿度精度 | ±5% | ±2-5% |
| 采样间隔 | 1秒 | 2秒 |
| 价格 | 便宜 | 稍贵 |
硬件连接
DHT 引脚 1 (VCC) ── 5V
DHT 引脚 2 (DATA) ── D2(数据引脚)
DHT 引脚 3 (NC) ── 悬空
DHT 引脚 4 (GND) ── GND
DHT 引脚 2 和 5V 之间连接 10kΩ 上拉电阻(部分模块已集成)
代码示例
首先需要安装 DHT 库:项目 → 加载库 → 管理库 → 搜索 "DHT sensor library"
#include <DHT.h>
#define DHT_PIN 2
#define DHT_TYPE DHT22 // 或 DHT11
DHT dht(DHT_PIN, DHT_TYPE);
void setup() {
Serial.begin(9600);
dht.begin();
Serial.println("DHT 传感器测试");
}
void loop() {
// 读取温湿度
float humidity = dht.readHumidity();
float temperature = dht.readTemperature();
// 检查读取是否成功
if (isnan(humidity) || isnan(temperature)) {
Serial.println("读取失败!");
return;
}
// 计算体感温度
float heatIndex = dht.computeHeatIndex(temperature, humidity, false);
Serial.print("湿度: ");
Serial.print(humidity);
Serial.print("% | 温度: ");
Serial.print(temperature);
Serial.print("°C | 体感: ");
Serial.print(heatIndex);
Serial.println("°C");
delay(2000); // DHT22 需要 2 秒采样间隔
}
超声波测距传感器 HC-SR04
HC-SR04 通过发射超声波并接收回波来测量距离,范围 2cm-400cm。
工作原理
- 触发引脚发送 10μs 高电平脉冲
- 模块发射 8 个 40kHz 超声波脉冲
- 接收引脚收到回波后输出高电平
- 高电平持续时间 = 声波往返时间
- 距离 = (时间 × 声速) / 2
硬件连接
HC-SR04 VCC ── 5V
HC-SR04 GND ── GND
HC-SR04 Trig ── D9(触发)
HC-SR04 Echo ── D10(接收)
代码示例
const int TRIG_PIN = 9;
const int ECHO_PIN = 10;
void setup() {
Serial.begin(9600);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
}
void loop() {
float distance = measureDistance();
Serial.print("距离: ");
Serial.print(distance);
Serial.println(" cm");
delay(500);
}
float measureDistance() {
// 发送触发信号
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
// 读取回波时间(微秒)
long duration = pulseIn(ECHO_PIN, HIGH);
// 计算距离(声速 343m/s = 0.0343cm/μs)
float distance = duration * 0.0343 / 2;
return distance;
}
改进版本(带滤波)
const int TRIG_PIN = 9;
const int ECHO_PIN = 10;
const int NUM_SAMPLES = 5;
void setup() {
Serial.begin(9600);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
}
void loop() {
float distance = getFilteredDistance();
if (distance > 0) {
Serial.print("距离: ");
Serial.print(distance);
Serial.println(" cm");
} else {
Serial.println("测量失败");
}
delay(200);
}
float getFilteredDistance() {
float sum = 0;
int validSamples = 0;
for (int i = 0; i < NUM_SAMPLES; i++) {
float d = measureDistance();
if (d > 2 && d < 400) { // 过滤无效值
sum += d;
validSamples++;
}
delay(20);
}
return validSamples > 0 ? sum / validSamples : -1;
}
float measureDistance() {
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
long duration = pulseIn(ECHO_PIN, HIGH, 30000); // 30ms 超时
return duration * 0.0343 / 2;
}
人体红外传感器 HC-SR501
HC-SR501 是一种热释电红外传感器,用于检测人体移动。
硬件连接
HC-SR501 VCC ── 5V
HC-SR501 GND ── GND
HC-SR501 OUT ── D2
调节说明
- 时间延迟调节:检测触发后持续高电平的时间(0.3秒-5分钟)
- 灵敏度调节:检测距离(3-7米)
- 触发模式选择:
- H(可重复触发):持续检测期间保持高电平
- L(不可重复触发):检测后进入锁定状态
代码示例
const int PIR_PIN = 2;
const int LED_PIN = 13;
void setup() {
Serial.begin(9600);
pinMode(PIR_PIN, INPUT);
pinMode(LED_PIN, OUTPUT);
Serial.println("等待传感器稳定...");
delay(10000); // PIR 需要 10-60 秒稳定
Serial.println("系统就绪");
}
void loop() {
int motionDetected = digitalRead(PIR_PIN);
if (motionDetected == HIGH) {
digitalWrite(LED_PIN, HIGH);
Serial.println("检测到人体移动!");
} else {
digitalWrite(LED_PIN, LOW);
}
delay(100);
}
光线传感器
光敏电阻(LDR)
最简单的光线传感器,阻值随光照强度变化。
硬件连接:
5V ── LDR ── A0 ── 10kΩ 电阻 ── GND
代码:
const int LDR_PIN = A0;
void setup() {
Serial.begin(9600);
}
void loop() {
int lightValue = analogRead(LDR_PIN);
// 映射为百分比(根据实际校准)
int brightness = map(lightValue, 0, 1023, 100, 0);
Serial.print("光线强度: ");
Serial.print(brightness);
Serial.println("%");
delay(500);
}
BH1750 数字光强传感器
I2C 接口的数字光强传感器,精度更高。
硬件连接:
BH1750 VCC ── 5V
BH1750 GND ── GND
BH1750 SCL ── A5(Uno)
BH1750 SDA ── A4(Uno)
BH1750 ADDR ── GND(设置地址 0x23)
代码:需要安装 BH1750 库
#include <Wire.h>
#include <BH1750.h>
BH1750 lightMeter;
void setup() {
Serial.begin(9600);
Wire.begin();
lightMeter.begin();
Serial.println("BH1750 测试");
}
void loop() {
float lux = lightMeter.readLightLevel();
Serial.print("光照强度: ");
Serial.print(lux);
Serial.println(" lx");
delay(1000);
}
烟雾/气体传感器 MQ-2
MQ-2 可检测烟雾、液化气、丁烷、丙烷、甲烷、酒精、氢气等。
硬件连接
MQ-2 VCC ── 5V
MQ-2 GND ── GND
MQ-2 A0 ── A0(模拟输出)
MQ-2 D0 ── D2(数字输出,可选)
代码示例
const int MQ_PIN = A0;
const int LED_PIN = 13;
const int BUZZER_PIN = 8;
// 报警阈值(根据实际校准)
const int SMOKE_THRESHOLD = 300;
void setup() {
Serial.begin(9600);
pinMode(LED_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
Serial.println("MQ-2 传感器预热中...");
delay(20000); // 预热 20 秒
Serial.println("系统就绪");
}
void loop() {
int smokeValue = analogRead(MQ_PIN);
Serial.print("烟雾值: ");
Serial.println(smokeValue);
if (smokeValue > SMOKE_THRESHOLD) {
// 触发报警
digitalWrite(LED_PIN, HIGH);
tone(BUZZER_PIN, 1000, 200);
Serial.println("警告:检测到烟雾!");
} else {
digitalWrite(LED_PIN, LOW);
noTone(BUZZER_PIN);
}
delay(500);
}
土壤湿度传感器
用于检测土壤湿度,常用于自动浇花系统。
硬件连接
传感器 VCC ── 5V
传感器 GND ── GND
传感器 A0 ── A0
代码示例
const int SOIL_PIN = A0;
const int PUMP_PIN = 8;
// 阈值(需根据实际校准)
const int DRY_THRESHOLD = 800; // 干燥阈值
const int WET_THRESHOLD = 400; // 湿润阈值
void setup() {
Serial.begin(9600);
pinMode(PUMP_PIN, OUTPUT);
}
void loop() {
int soilValue = analogRead(SOIL_PIN);
// 映射为湿度百分比(值越小越湿)
int moisture = map(soilValue, 1023, 0, 0, 100);
moisture = constrain(moisture, 0, 100);
Serial.print("土壤湿度: ");
Serial.print(moisture);
Serial.println("%");
// 自动浇水逻辑
if (soilValue > DRY_THRESHOLD) {
Serial.println("土壤干燥,开始浇水");
digitalWrite(PUMP_PIN, HIGH);
delay(3000); // 浇水 3 秒
digitalWrite(PUMP_PIN, LOW);
}
delay(5000); // 每 5 秒检测一次
}
声音传感器
声音检测模块
简单的声音检测,输出高低电平。
const int SOUND_PIN = 2;
const int LED_PIN = 13;
void setup() {
Serial.begin(9600);
pinMode(SOUND_PIN, INPUT);
pinMode(LED_PIN, OUTPUT);
}
void loop() {
int soundDetected = digitalRead(SOUND_PIN);
if (soundDetected == LOW) { // 通常低电平有效
digitalWrite(LED_PIN, HIGH);
Serial.println("检测到声音!");
delay(200); // 消抖
} else {
digitalWrite(LED_PIN, LOW);
}
}
麦克风模块(模拟输出)
const int MIC_PIN = A0;
void setup() {
Serial.begin(9600);
}
void loop() {
int soundLevel = analogRead(MIC_PIN);
Serial.print("声音强度: ");
Serial.println(soundLevel);
delay(50);
}
综合示例:环境监测站
整合多个传感器的环境监测系统:
#include <DHT.h>
#define DHT_PIN 2
#define DHT_TYPE DHT22
DHT dht(DHT_PIN, DHT_TYPE);
const int LDR_PIN = A0;
const int SOIL_PIN = A1;
const int MQ_PIN = A2;
const int TRIG_PIN = 9;
const int ECHO_PIN = 10;
void setup() {
Serial.begin(9600);
dht.begin();
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
Serial.println("=== 环境监测站 ===");
}
void loop() {
// 读取温湿度
float temp = dht.readTemperature();
float humidity = dht.readHumidity();
// 读取光线
int light = analogRead(LDR_PIN);
// 读取土壤湿度
int soil = analogRead(SOIL_PIN);
// 读取空气质量
int airQuality = analogRead(MQ_PIN);
// 读取距离
float distance = measureDistance();
// 输出报告
Serial.println("\n----- 环境报告 -----");
Serial.print("温度: "); Serial.print(temp); Serial.println("°C");
Serial.print("湿度: "); Serial.print(humidity); Serial.println("%");
Serial.print("光线: "); Serial.println(light);
Serial.print("土壤: "); Serial.println(soil);
Serial.print("空气质量: "); Serial.println(airQuality);
Serial.print("距离: "); Serial.print(distance); Serial.println("cm");
Serial.println("-------------------");
delay(3000);
}
float measureDistance() {
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
long duration = pulseIn(ECHO_PIN, HIGH, 30000);
return duration * 0.0343 / 2;
}
BMP280 气压温度传感器
BMP280 是一款高精度气压和温度传感器,广泛用于气象监测、高度测量等应用。
主要特性
| 参数 | 规格 |
|---|---|
| 气压测量范围 | 300-1100 hPa |
| 气压精度 | ±1 hPa |
| 温度范围 | -40°C ~ +85°C |
| 温度精度 | ±0.5°C |
| 接口 | I2C / SPI |
| 工作电压 | 1.8V - 3.6V |
硬件连接(I2C 模式)
BMP280 Arduino Uno
────────────────────
VCC → 3.3V(注意:不要接 5V!)
GND → GND
SCL → A5
SDA → A4
BMP280 工作电压为 1.8V-3.6V,必须连接到 3.3V。如果使用 5V 供电可能损坏传感器。部分模块带有稳压器可以使用 5V,请检查模块说明。
安装库
在库管理器中搜索并安装 "Adafruit BMP280 Library"。
代码示例
#include <Wire.h>
#include <Adafruit_BMP280.h>
Adafruit_BMP280 bmp;
void setup() {
Serial.begin(9600);
if (!bmp.begin(0x76)) { // 默认地址 0x76,部分模块可能是 0x77
Serial.println("BMP280 未找到,请检查连接!");
while (1);
}
// 配置传感器参数
bmp.setSampling(Adafruit_BMP280::MODE_NORMAL, // 工作模式
Adafruit_BMP280::SAMPLING_X2, // 温度采样
Adafruit_BMP280::SAMPLING_X16, // 气压采样
Adafruit_BMP280::FILTER_X16, // 滤波
Adafruit_BMP280::STANDBY_MS_500); // 待机时间
Serial.println("BMP280 气压温度传感器");
}
void loop() {
// 读取温度
float temperature = bmp.readTemperature();
// 读取气压(hPa = 毫巴)
float pressure = bmp.readPressure() / 100.0F;
// 计算海拔高度(基于标准大气压 1013.25 hPa)
float altitude = bmp.readAltitude(1013.25);
Serial.print("温度: ");
Serial.print(temperature);
Serial.print(" °C | 气压: ");
Serial.print(pressure);
Serial.print(" hPa | 海拔: ");
Serial.print(altitude);
Serial.println(" m");
delay(2000);
}
实际应用:简易高度计
利用气压计算高度变化:
#include <Wire.h>
#include <Adafruit_BMP280.h>
Adafruit_BMP280 bmp;
float baseAltitude;
void setup() {
Serial.begin(9600);
if (!bmp.begin(0x76)) {
Serial.println("传感器初始化失败");
while (1);
}
// 记录基准高度
baseAltitude = bmp.readAltitude(1013.25);
Serial.print("基准高度: ");
Serial.print(baseAltitude);
Serial.println(" m");
}
void loop() {
float currentAltitude = bmp.readAltitude(1013.25);
float relativeAltitude = currentAltitude - baseAltitude;
Serial.print("相对高度变化: ");
Serial.print(relativeAltitude);
Serial.println(" m");
delay(1000);
}
红外遥控接收
使用红外接收模块接收遥控器信号,实现无线控制。
工作原理
红外遥控通过发射特定频率(通常 38kHz)的红外脉冲来传输数据。不同厂商使用不同的编码协议,常见的有 NEC、Sony、RC5、RC6 等。
硬件连接
红外接收模块 Arduino Uno
─────────────────────
VCC → 5V
GND → GND
OUT → D11(或其他数字引脚)
安装库
在库管理器中搜索并安装 "IRremote" 库。
接收遥控信号
#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)) {
// 打印接收到的原始数据
Serial.print("编码: 0x");
Serial.print(results.value, HEX);
Serial.print(" | 协议: ");
Serial.println(results.decode_type);
// 根据编码执行不同动作
switch (results.value) {
case 0xFFA25D: // 电源键(具体编码取决于遥控器)
Serial.println("电源");
break;
case 0xFF629D: // 模式键
Serial.println("模式");
break;
case 0xFFE21D: // 静音键
Serial.println("静音");
break;
}
irrecv.resume(); // 准备接收下一个信号
}
}
获取遥控器编码
要使用未知遥控器,首先需要获取各按键的编码:
#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)) {
Serial.print("编码: 0x");
Serial.print(results.value, HEX);
Serial.print(" (");
Serial.print(results.value);
Serial.println(")");
irrecv.resume();
delay(100);
}
}
红外遥控控制 LED
#include <IRremote.h>
const int RECV_PIN = 11;
const int LED_PIN = 13;
IRrecv irrecv(RECV_PIN);
decode_results results;
bool ledState = false;
// 遥控器编码(根据实际遥控器修改)
const unsigned long CODE_POWER = 0xFFA25D;
const unsigned long CODE_UP = 0xFF629D;
const unsigned long CODE_DOWN = 0xFFA857;
void setup() {
Serial.begin(9600);
pinMode(LED_PIN, OUTPUT);
irrecv.enableIRIn();
Serial.println("红外遥控 LED 控制");
Serial.println("电源键: 切换 LED");
}
void loop() {
if (irrecv.decode(&results)) {
if (results.value == CODE_POWER) {
ledState = !ledState;
digitalWrite(LED_PIN, ledState ? HIGH : LOW);
Serial.println(ledState ? "LED 开启" : "LED 关闭");
}
irrecv.resume();
}
}
MPU6050 六轴传感器
MPU6050 集成了三轴加速度计和三轴陀螺仪,常用于姿态检测、平衡车、无人机等项目。
主要特性
- 三轴加速度计:测量线性加速度
- 三轴陀螺仪:测量角速度
- I2C 接口
- 内置温度传感器
硬件连接
MPU6050 Arduino Uno
────────────────────
VCC → 3.3V 或 5V(取决于模块)
GND → GND
SCL → A5
SDA → A4
安装库
安装 "MPU6050_tockn" 或 "Adafruit MPU6050" 库。
代码示例
#include <Wire.h>
#include <MPU6050_tockn.h>
MPU6050 mpu6050(Wire);
void setup() {
Serial.begin(9600);
Wire.begin();
mpu6050.begin();
mpu6050.calcGyroOffsets(true); // 校准陀螺仪
Serial.println("MPU6050 已初始化");
}
void loop() {
mpu6050.update();
// 获取加速度
Serial.print("加速度: X=");
Serial.print(mpu6050.getAccX());
Serial.print(" Y=");
Serial.print(mpu6050.getAccY());
Serial.print(" Z=");
Serial.print(mpu6050.getAccZ());
// 获取角速度
Serial.print(" | 陀螺仪: X=");
Serial.print(mpu6050.getGyroX());
Serial.print(" Y=");
Serial.print(mpu6050.getGyroY());
Serial.print(" Z=");
Serial.print(mpu6050.getGyroZ());
// 获取角度
Serial.print(" | 角度: X=");
Serial.print(mpu6050.getAngleX());
Serial.print(" Y=");
Serial.print(mpu6050.getAngleY());
Serial.print(" Z=");
Serial.println(mpu6050.getAngleZ());
delay(100);
}
传感器使用技巧
1. 电源去耦
在传感器电源引脚附近添加 0.1μF 电容,减少电源噪声:
传感器 VCC ──┬── 5V
└── 0.1μF ── GND
2. 数据滤波
传感器读数常有噪声,使用移动平均滤波:
int getSmoothedValue(int pin, int samples = 10) {
long sum = 0;
for (int i = 0; i < samples; i++) {
sum += analogRead(pin);
delayMicroseconds(100);
}
return sum / samples;
}
3. 校准
传感器需要校准才能获得准确读数:
// 在 setup 中进行校准
int baseline;
void setup() {
// 采集 100 个样本求平均作为基准值
long sum = 0;
for (int i = 0; i < 100; i++) {
sum += analogRead(A0);
delay(10);
}
baseline = sum / 100;
}
下一步
掌握了常用传感器后,我们将学习如何控制各种电机,包括直流电机、舵机和步进电机。