第一次接触Arduino和传感器时,我被它们简单直接的交互方式所震撼。作为一个电子爱好者,我发现这套系统最迷人的地方在于:用几行代码就能让硬件"活"起来。Arduino Uno开发板上有14个数字I/O引脚(其中6个可做PWM输出)和6个模拟输入引脚,这为连接各类传感器提供了充分的可能性。
传感器本质上是一种将物理量转换为电信号的装置。在Arduino项目中,我们常用的传感器大致可分为三类:
提示:新手建议从数字传感器开始上手,这类传感器接线简单,编程逻辑直观,能快速建立信心。
以最常见的按钮开关为例,接线步骤如下:
arduino复制const int buttonPin = 2;
void setup() {
pinMode(buttonPin, INPUT);
Serial.begin(9600);
}
void loop() {
int buttonState = digitalRead(buttonPin);
Serial.println(buttonState);
delay(100);
}
以光敏电阻为例,典型接线方式:
arduino复制const int lightSensor = A0;
void setup() {
Serial.begin(9600);
}
void loop() {
int sensorValue = analogRead(lightSensor);
Serial.println(sensorValue);
delay(500);
}
注意:模拟传感器的读数范围是0-1023,对应0-5V电压。实际应用中需要将这个值转换为具体的物理量。
以I2C接口的BMP280气压传感器为例:
arduino复制#include <Wire.h>
#include <Adafruit_BMP280.h>
Adafruit_BMP280 bmp;
void setup() {
Serial.begin(9600);
if (!bmp.begin(0x76)) {
Serial.println("传感器未找到");
while (1);
}
}
void loop() {
Serial.print("温度 = ");
Serial.print(bmp.readTemperature());
Serial.println(" *C");
delay(2000);
}
arduino复制// 温度传感器LM35数据处理示例
const int tempPin = A0;
void setup() {
Serial.begin(9600);
}
void loop() {
int rawValue = analogRead(tempPin);
float voltage = rawValue * (5.0 / 1023.0);
float temperature = voltage * 100; // LM35每mV对应0.1°C
Serial.print("温度: ");
Serial.print(temperature);
Serial.println(" °C");
delay(1000);
}
arduino复制// 按钮消抖示例
const int buttonPin = 2;
int lastButtonState = HIGH;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;
void setup() {
pinMode(buttonPin, INPUT_PULLUP);
Serial.begin(9600);
}
void loop() {
int reading = digitalRead(buttonPin);
if (reading != lastButtonState) {
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
if (reading != buttonState) {
buttonState = reading;
if (buttonState == LOW) {
Serial.println("按钮按下");
}
}
}
lastButtonState = reading;
}
DHT11是一款低成本数字温湿度传感器,采用单总线通信协议。使用时需注意:
arduino复制#include <DHT.h>
#define DHTPIN 2
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
void setup() {
Serial.begin(9600);
dht.begin();
}
void loop() {
float h = dht.readHumidity();
float t = dht.readTemperature();
if (isnan(h) || isnan(t)) {
Serial.println("读取失败");
return;
}
Serial.print("湿度: ");
Serial.print(h);
Serial.print("% 温度: ");
Serial.print(t);
Serial.println("°C");
delay(2000);
}
工作原理:
arduino复制const int trigPin = 9;
const int echoPin = 10;
void setup() {
Serial.begin(9600);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
}
void loop() {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
long duration = pulseIn(echoPin, HIGH);
float distance = duration * 0.034 / 2;
Serial.print("距离: ");
Serial.print(distance);
Serial.println(" cm");
delay(500);
}
电源检查:
接线检查:
代码检查:
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 读数跳动大 | 电源干扰 | 增加滤波电容(10-100μF) |
| 数值固定不变 | 接线错误 | 检查信号线连接 |
| 偶尔读取失败 | 时序问题 | 增加适当延迟 |
| 数值明显偏差 | 校准问题 | 进行传感器校准 |
将多个传感器数据组合使用可以创造更智能的应用。例如:
arduino复制// 多传感器数据采集示例
#include <DHT.h>
#define DHTPIN 2
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
const int lightPin = A0;
void setup() {
Serial.begin(9600);
dht.begin();
}
void loop() {
// 读取温湿度
float h = dht.readHumidity();
float t = dht.readTemperature();
// 读取光照
int light = analogRead(lightPin);
// 输出所有数据
Serial.print("温度:");
Serial.print(t);
Serial.print("°C 湿度:");
Serial.print(h);
Serial.print("% 光照:");
Serial.print(light);
Serial.println();
delay(2000);
}
arduino复制// 数据格式化输出示例(兼容多数可视化工具)
void loop() {
float temp = readTemperature();
float humi = readHumidity();
// JSON格式
Serial.print("{\"temperature\":");
Serial.print(temp);
Serial.print(",\"humidity\":");
Serial.print(humi);
Serial.println("}");
// CSV格式
Serial.print(millis());
Serial.print(",");
Serial.print(temp);
Serial.print(",");
Serial.println(humi);
delay(1000);
}
| 方案 | 传输距离 | 功耗 | 适用场景 |
|---|---|---|---|
| HC-05蓝牙 | 10m | 中 | 手机APP控制 |
| NRF24L01 | 100m | 低 | 点对点通信 |
| ESP8266 WiFi | 室内 | 高 | 物联网云平台 |
| LoRa | 千米级 | 极低 | 远距离监测 |
arduino复制// ESP8266 WiFi传输示例
#include <ESP8266WiFi.h>
const char* ssid = "your_SSID";
const char* password = "your_PASSWORD";
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("连接成功");
}
void loop() {
if(WiFi.status() == WL_CONNECTED){
WiFiClient client;
if (client.connect("api.thingspeak.com", 80)) {
String data = "field1=" + String(readTemperature());
client.print("POST /update HTTP/1.1\n");
client.print("Host: api.thingspeak.com\n");
client.print("Connection: close\n");
client.print("X-THINGSPEAKAPIKEY: YOUR_KEY\n");
client.print("Content-Type: application/x-www-form-urlencoded\n");
client.print("Content-Length: ");
client.print(data.length());
client.print("\n\n");
client.print(data);
}
}
delay(15000); // Thingspeak限制15秒/次
}
对于需要精确测量的场景,建议进行传感器校准:
arduino复制// 温度传感器两点校准示例
float rawLow = 205; // 在0°C时的读数
float rawHigh = 310; // 在100°C时的读数
float calibrateTemperature(float rawValue) {
float slope = 100.0 / (rawHigh - rawLow);
float intercept = -slope * rawLow;
return slope * rawValue + intercept;
}
某些传感器的读数会受到环境因素影响:
可以在代码中加入补偿算法:
arduino复制// 带温度补偿的气压计算
float readCompensatedPressure() {
float temperature = readTemperature();
float rawPressure = readPressure();
// 简化的温度补偿公式
return rawPressure * (1.0 + (25.0 - temperature) * 0.0005);
}
| 供电方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| Arduino直接供电 | 简单 | 功率有限 | 低功耗传感器 |
| 独立稳压模块 | 稳定 | 增加复杂度 | 高精度传感器 |
| 电池+升压电路 | 便携 | 需管理电池 | 移动设备 |
| 太阳能供电 | 环保 | 不稳定 | 户外监测 |
arduino复制#include <avr/sleep.h>
const int wakePin = 2; // 中断唤醒引脚
void setup() {
pinMode(wakePin, INPUT_PULLUP);
Serial.begin(9600);
}
void sleepNow() {
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
attachInterrupt(digitalPinToInterrupt(wakePin), wakeUp, LOW);
sleep_mode();
sleep_disable();
detachInterrupt(digitalPinToInterrupt(wakePin));
}
void wakeUp() {
// 唤醒处理
}
void loop() {
readSensors();
sendData();
sleepNow(); // 进入低功耗模式
}
经验分享:使用Fusion 360设计外壳时,可以先3D打印简化原型验证尺寸和结构,确认无误后再打印最终版本。记得为螺丝孔和接插件预留足够空间。
arduino复制#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <DHT.h>
#include <BH1750.h>
#include <ESP8266WiFi.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define DHTPIN 2
#define DHTTYPE DHT11
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire);
DHT dht(DHTPIN, DHTTYPE);
BH1750 lightMeter;
const char* ssid = "your_SSID";
const char* password = "your_PASSWORD";
void setup() {
Serial.begin(115200);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
dht.begin();
lightMeter.begin();
WiFi.begin(ssid, password);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
}
void loop() {
float h = dht.readHumidity();
float t = dht.readTemperature();
float soil = analogRead(A0) / 10.23; // 转换为百分比
float lux = lightMeter.readLightLevel();
display.clearDisplay();
display.setCursor(0,0);
display.print("Temp:"); display.print(t); display.println("C");
display.print("Hum:"); display.print(h); display.println("%");
display.print("Soil:"); display.print(soil); display.println("%");
display.print("Light:"); display.print(lux); display.println("lx");
display.display();
if(WiFi.status() == WL_CONNECTED){
sendToCloud(t, h, soil, lux);
}
delay(30000); // 每30秒更新一次
}
void sendToCloud(float t, float h, float s, float l) {
// 实际项目中实现数据上传逻辑
}
在实际部署中,我发现土壤湿度传感器的读数会随时间漂移,定期手动校准可以保持测量精度。另外,将传感器探针垂直插入土壤中部能获得最具代表性的湿度数据。