Arduino UNO
Arduino UNO 详细指南
1. Arduino UNO 概览
1.1 基本规格
// Arduino UNO R3 核心参数
- 微控制器:ATmega328P (8位 AVR)
- 工作电压:5V
- 输入电压:7-12V(推荐),6-20V(极限)
- 数字I/O引脚:14个(6个支持PWM)
- 模拟输入引脚:6个
- 闪存(Flash):32KB(其中0.5KB用于引导程序)
- SRAM:2KB
- EEPROM:1KB
- 时钟速度:16MHz
- USB接口:Type-B
- 尺寸:68.6mm × 53.4mm
1.2 引脚布局图
┌─────────────────┐
│ USB Type-B │
└─────────────────┘
┌─┬───────────────────┬─┐
│R│ │R│
│E│ │E│
│S│ │S│
│E│ │E│
│T│ │T│
└─┘ └─┘
┌─────────────────────────────┐
│ D13 SCK AREF │
│ D12 MISO GND │
│ D11 MOSI PWM A0/14 │
│ D10 SS PWM A1/15 │
│ D9 PWM A2/16 │
│ D8 A3/17 │
│ D7 A4/18(SDA)│
│ D6 PWM A5/19(SCL)│
│ D5 PWM A4 │
│ D4 A3 │
│ D3 PWM INT1 A2 │
│ D2 INT0 A1 │
│ TX(D1) A0 │
│ RX(D0) GND │
└─────────────────────────────┘
│ │ │ │
GND D13 VIN 5V
2. 引脚功能详解
2.1 数字引脚 (D0-D13)
// 数字引脚功能分布
const int pinFunctions[14] = {
/* D0 */ RX, // 串口接收
/* D1 */ TX, // 串口发送
/* D2 */ INT0, // 外部中断0
/* D3 */ INT1, // 外部中断1 + PWM
/* D4 */ GPIO, // 通用IO
/* D5 */ PWM, // 定时器0 PWM
/* D6 */ PWM, // 定时器0 PWM
/* D7 */ GPIO,
/* D8 */ GPIO,
/* D9 */ PWM, // 定时器1 PWM
/* D10 */ PWM, // 定时器1 PWM + SS(SPI从机选择)
/* D11 */ PWM, // 定时器2 PWM + MOSI(SPI主出从入)
/* D12 */ MISO, // SPI主入从出
/* D13 */ SCK // SPI时钟 + 板载LED
};
// PWM引脚:3, 5, 6, 9, 10, 11(标有~符号)
// 中断引脚:2, 3
// SPI引脚:10(SS), 11(MOSI), 12(MISO), 13(SCK)
2.2 模拟引脚 (A0-A5)
// 模拟引脚特性
// 分辨率:10位(0-1023)
// 参考电压:默认5V,可通过AREF引脚改变
const int analogPins = 6; // A0-A5
// 特殊功能:
// A4 - SDA (I2C数据线)
// A5 - SCL (I2C时钟线)
2.3 电源引脚
// 电源相关引脚
- VIN:外部电源输入(7-12V)
- 5V:5V输出(最大电流500mA)
- 3.3V:3.3V输出(最大电流50mA)
- GND:接地(共3个)
- RESET:复位(低电平有效)
3. 基础程序示例
3.1 Hello World - 闪烁LED
// 最简单的Arduino程序
// 板载LED连接在D13引脚
const int LED_PIN = 13;
void setup() {
// 初始化设置
pinMode(LED_PIN, OUTPUT);
Serial.begin(9600); // 初始化串口
Serial.println("Arduino UNO is ready!");
}
void loop() {
// 主循环
digitalWrite(LED_PIN, HIGH); // LED亮
delay(1000); // 等待1秒
digitalWrite(LED_PIN, LOW); // LED灭
delay(1000); // 等待1秒
// 串口输出状态
static int count = 0;
Serial.print("Blink count: ");
Serial.println(count++);
}
3.2 按钮输入控制
// 按钮控制LED
const int BUTTON_PIN = 2; // 按钮接D2
const int LED_PIN = 13;
void setup() {
pinMode(BUTTON_PIN, INPUT_PULLUP); // 使用内部上拉电阻
pinMode(LED_PIN, OUTPUT);
}
void loop() {
int buttonState = digitalRead(BUTTON_PIN);
// 注意:使用上拉电阻时,按钮按下为LOW,释放为HIGH
if (buttonState == LOW) {
digitalWrite(LED_PIN, HIGH); // 按下时LED亮
} else {
digitalWrite(LED_PIN, LOW); // 释放时LED灭
}
}
3.3 模拟输入读取
// 读取电位器值
const int POT_PIN = A0; // 电位器中间引脚接A0
void setup() {
Serial.begin(9600);
// 注意:模拟输入引脚不需要pinMode设置
}
void loop() {
int sensorValue = analogRead(POT_PIN);
// 转换为电压值
float voltage = sensorValue * (5.0 / 1023.0);
Serial.print("ADC Value: ");
Serial.print(sensorValue);
Serial.print(" | Voltage: ");
Serial.print(voltage);
Serial.println("V");
delay(500);
}
4. 中断应用
4.1 外部中断
// 使用外部中断检测按钮按下
const int INTERRUPT_PIN = 2; // D2支持外部中断0
const int LED_PIN = 13;
volatile bool buttonPressed = false; // volatile确保中断中正确读取
void setup() {
pinMode(LED_PIN, OUTPUT);
pinMode(INTERRUPT_PIN, INPUT_PULLUP);
// 设置中断
// 参数:中断号,中断处理函数,触发模式
attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN),
buttonISR, FALLING);
}
void loop() {
if (buttonPressed) {
digitalWrite(LED_PIN, HIGH);
delay(2000); // LED亮2秒
digitalWrite(LED_PIN, LOW);
buttonPressed = false; // 重置标志
}
}
// 中断服务程序(必须简短!)
void buttonISR() {
buttonPressed = true;
}
4.2 定时器中断
// 使用定时器1产生精确中断
#include <TimerOne.h>
const int LED_PIN = 13;
bool ledState = false;
void setup() {
pinMode(LED_PIN, OUTPUT);
Serial.begin(9600);
// 初始化定时器1,设置中断间隔1000000微秒(1秒)
Timer1.initialize(1000000);
// 绑定中断处理函数
Timer1.attachInterrupt(timerISR);
}
void loop() {
// 主程序可以执行其他任务
Serial.println("Main loop running...");
delay(100);
}
// 定时器中断处理函数
void timerISR() {
ledState = !ledState;
digitalWrite(LED_PIN, ledState);
}
5. PWM控制
5.1 LED调光
// 使用PWM控制LED亮度
const int LED_PIN = 9; // 必须是PWM引脚(3,5,6,9,10,11)
void setup() {
pinMode(LED_PIN, OUTPUT);
}
void loop() {
// 呼吸灯效果
for (int brightness = 0; brightness <= 255; brightness++) {
analogWrite(LED_PIN, brightness);
delay(10);
}
for (int brightness = 255; brightness >= 0; brightness--) {
analogWrite(LED_PIN, brightness);
delay(10);
}
}
// PWM频率:
// 引脚5,6:约980Hz
// 引脚3,9,10,11:约490Hz
5.2 控制舵机
#include <Servo.h>
Servo myServo;
const int SERVO_PIN = 9;
void setup() {
myServo.attach(SERVO_PIN);
Serial.begin(9600);
}
void loop() {
// 读取电位器控制舵机
int potValue = analogRead(A0);
// 将0-1023映射到0-180度
int angle = map(potValue, 0, 1023, 0, 180);
myServo.write(angle);
Serial.print("Potentiometer: ");
Serial.print(potValue);
Serial.print(" -> Angle: ");
Serial.print(angle);
Serial.println("°");
delay(50);
}
6. 通信协议
6.1 串口通信
// 完整的串口通信示例
void setup() {
Serial.begin(9600);
while (!Serial) {
; // 等待串口连接
}
Serial.println("=== Arduino UNO Serial Monitor ===");
Serial.println("Commands: LED_ON, LED_OFF, STATUS");
}
void loop() {
// 检查是否有数据可读
if (Serial.available() > 0) {
String command = Serial.readStringUntil('\n');
command.trim(); // 去除首尾空格
Serial.print("Received: ");
Serial.println(command);
// 处理命令
if (command == "LED_ON") {
digitalWrite(LED_BUILTIN, HIGH);
Serial.println("Built-in LED turned ON");
}
else if (command == "LED_OFF") {
digitalWrite(LED_BUILTIN, LOW);
Serial.println("Built-in LED turned OFF");
}
else if (command == "STATUS") {
int sensorValue = analogRead(A0);
float voltage = sensorValue * (5.0 / 1023.0);
Serial.println("=== System Status ===");
Serial.print("Analog A0: ");
Serial.print(sensorValue);
Serial.print(" (");
Serial.print(voltage);
Serial.println("V)");
Serial.print("Free RAM: ");
Serial.print(freeMemory());
Serial.println(" bytes");
}
else {
Serial.println("Unknown command");
}
}
// 定期发送数据
static unsigned long lastSend = 0;
if (millis() - lastSend > 5000) {
Serial.print("Uptime: ");
Serial.print(millis() / 1000);
Serial.println(" seconds");
lastSend = millis();
}
}
// 计算可用内存
extern int __heap_start, *__brkval;
int freeMemory() {
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
6.2 I2C通信
// I2C LCD1602显示
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// I2C地址通常是0x27或0x3F,根据实际情况调整
LiquidCrystal_I2C lcd(0x27, 16, 2);
void setup() {
Serial.begin(9600);
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Arduino UNO");
lcd.setCursor(0, 1);
lcd.print("I2C LCD Test");
delay(2000);
lcd.clear();
}
void loop() {
// 显示温湿度(假设有I2C温湿度传感器)
float temperature = readTemperature();
float humidity = readHumidity();
lcd.setCursor(0, 0);
lcd.print("Temp: ");
lcd.print(temperature);
lcd.print("C");
lcd.setCursor(0, 1);
lcd.print("Humidity: ");
lcd.print(humidity);
lcd.print("%");
delay(2000);
}
// I2C设备扫描
void scanI2C() {
Serial.println("Scanning I2C devices...");
byte error, address;
int nDevices = 0;
for (address = 1; address < 127; address++) {
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0) {
Serial.print("I2C device found at 0x");
if (address < 16) Serial.print("0");
Serial.print(address, HEX);
Serial.println();
nDevices++;
}
}
if (nDevices == 0) {
Serial.println("No I2C devices found");
}
}
6.3 SPI通信
// SPI OLED显示
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_MOSI 11 // D11
#define OLED_CLK 13 // D13
#define OLED_DC 9 // D9
#define OLED_CS 10 // D10
#define OLED_RESET 8 // D8
Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);
void setup() {
Serial.begin(9600);
// 初始化OLED
if (!display.begin(SSD1306_SWITCHCAPVCC)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;); // 死循环
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
}
void loop() {
// 显示系统信息
display.clearDisplay();
display.setCursor(0, 0);
display.println(F("Arduino UNO"));
display.println(F("=========="));
display.print(F("Uptime: "));
display.print(millis() / 1000);
display.println(F("s"));
display.print(F("Free RAM: "));
display.print(freeMemory());
display.println(F(" bytes"));
// 读取模拟值
int sensorValue = analogRead(A0);
display.print(F("A0: "));
display.print(sensorValue);
display.display();
delay(1000);
}
7. 传感器集成
7.1 DHT11温湿度传感器
#include <DHT.h>
#define DHTPIN 2 // D2引脚
#define DHTTYPE DHT11 // DHT11类型
DHT dht(DHTPIN, DHTTYPE);
void setup() {
Serial.begin(9600);
dht.begin();
Serial.println("DHT11 Test");
}
void loop() {
delay(2000); // DHT11需要至少2秒的读取间隔
float humidity = dht.readHumidity();
float temperature = dht.readTemperature();
if (isnan(humidity) || isnan(temperature)) {
Serial.println("Failed to read from DHT sensor!");
return;
}
Serial.print("Humidity: ");
Serial.print(humidity);
Serial.print("%\t");
Serial.print("Temperature: ");
Serial.print(temperature);
Serial.println("°C");
}
7.2 HC-SR04超声波测距
const int TRIG_PIN = 9; // D9
const int ECHO_PIN = 10; // D10
void setup() {
Serial.begin(9600);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
}
void loop() {
// 发送10μs的高电平触发信号
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
// 读取回波时间
long duration = pulseIn(ECHO_PIN, HIGH);
// 计算距离(声速340m/s)
float distance = duration * 0.034 / 2;
Serial.print("Distance: ");
Serial.print(distance);
Serial.println(" cm");
delay(100);
}
7.3 光敏电阻
const int LDR_PIN = A0; // 光敏电阻接A0
void setup() {
Serial.begin(9600);
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
int ldrValue = analogRead(LDR_PIN);
Serial.print("Light Level: ");
Serial.println(ldrValue);
// 根据光线控制LED
if (ldrValue < 500) { // 光线暗
digitalWrite(LED_BUILTIN, HIGH);
} else {
digitalWrite(LED_BUILTIN, LOW);
}
delay(500);
}
8. 高级应用
8.1 多任务调度
// 使用millis()实现非阻塞多任务
unsigned long previousMillisLED = 0;
unsigned long previousMillisSensor = 0;
unsigned long previousMillisDisplay = 0;
const long intervalLED = 500;
const long intervalSensor = 1000;
const long intervalDisplay = 2000;
void setup() {
Serial.begin(9600);
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
unsigned long currentMillis = millis();
// 任务1: LED闪烁
if (currentMillis - previousMillisLED >= intervalLED) {
previousMillisLED = currentMillis;
static bool ledState = false;
digitalWrite(LED_BUILTIN, ledState);
ledState = !ledState;
}
// 任务2: 读取传感器
if (currentMillis - previousMillisSensor >= intervalSensor) {
previousMillisSensor = currentMillis;
int sensorValue = analogRead(A0);
// 处理传感器数据...
}
// 任务3: 更新显示
if (currentMillis - previousMillisDisplay >= intervalDisplay) {
previousMillisDisplay = currentMillis;
Serial.print("Uptime: ");
Serial.print(currentMillis / 1000);
Serial.println("s");
}
}
8.2 数据记录器
// 简易数据记录器
#include <SD.h>
const int chipSelect = 10; // SD卡模块CS引脚接D10
void setup() {
Serial.begin(9600);
// 初始化SD卡
Serial.print("Initializing SD card...");
if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");
return;
}
Serial.println("card initialized.");
// 创建数据文件
File dataFile = SD.open("datalog.txt", FILE_WRITE);
if (dataFile) {
dataFile.println("Time(ms),A0,A1,A2");
dataFile.close();
}
}
void loop() {
// 读取传感器
int a0 = analogRead(A0);
int a1 = analogRead(A1);
int a2 = analogRead(A2);
// 保存到SD卡
File dataFile = SD.open("datalog.txt", FILE_WRITE);
if (dataFile) {
dataFile.print(millis());
dataFile.print(",");
dataFile.print(a0);
dataFile.print(",");
dataFile.print(a1);
dataFile.print(",");
dataFile.println(a2);
dataFile.close();
Serial.print("Data saved: ");
Serial.print(millis());
Serial.print(", ");
Serial.print(a0);
Serial.print(", ");
Serial.print(a1);
Serial.print(", ");
Serial.println(a2);
}
delay(1000); // 每秒记录一次
}
9. 优化技巧
9.1 内存优化
// Arduino UNO只有2KB SRAM,需要优化
void setup() {
Serial.begin(9600);
// 1. 使用PROGMEM存储常量字符串
const char menuText[] PROGMEM = "Welcome to Arduino UNO";
// 2. 使用F()宏将字符串存储在Flash中
Serial.println(F("This string is in Flash memory"));
// 3. 避免使用String类,使用字符数组
char buffer[20]; // 而不是 String str;
// 4. 减小全局变量,使用局部变量
}
// 检查内存使用
void checkMemory() {
Serial.print("Free RAM: ");
Serial.print(freeMemory());
Serial.println(" bytes");
}
9.2 性能优化
// 优化数字读写
void optimizedDigitalWrite() {
// 直接操作寄存器(速度更快)
// 替代 digitalWrite(13, HIGH);
PORTB |= (1 << PB5); // D13 = PB5
// 替代 digitalWrite(13, LOW);
PORTB &= ~(1 << PB5);
// 替代 digitalRead(8);
// bool state = (PINB & (1 << PB0)) != 0;
}
// 减少delay()使用
void noDelayBlink() {
static unsigned long lastToggle = 0;
static bool ledState = false;
if (millis() - lastToggle > 1000) {
ledState = !ledState;
digitalWrite(LED_BUILTIN, ledState);
lastToggle = millis();
}
}
10. 常见问题与调试
10.1 问题排查清单
// 常见问题及解决方案
void troubleshoot() {
// 1. 上传失败
// - 检查USB线连接
// - 选择正确的板和端口
// - 重启Arduino IDE
// 2. 程序无响应
// - 检查电源是否充足
// - 检查是否进入死循环
// - 使用看门狗复位
// 3. 传感器读数异常
// - 检查接线是否正确
// - 检查参考电压
// - 添加滤波算法
// 4. 内存不足
// - 优化字符串使用
// - 减少全局变量
// - 使用PROGMEM
}
10.2 串口调试工具
// 增强的调试函数
class Debug {
public:
static void begin(unsigned long baud = 9600) {
Serial.begin(baud);
while (!Serial);
Serial.println(F("=== Debug Started ==="));
}
static void log(const char* message, int value = -9999) {
Serial.print(F("[LOG] "));
Serial.print(millis());
Serial.print(F("ms: "));
Serial.print(message);
if (value != -9999) {
Serial.print(F(" = "));
Serial.print(value);
}
Serial.println();
}
static void warn(const char* message) {
Serial.print(F("[WARN] "));
Serial.println(message);
}
static void error(const char* message) {
Serial.print(F("[ERROR] "));
Serial.println(message);
}
static void memory() {
Serial.print(F("[MEMORY] Free RAM: "));
Serial.print(freeMemory());
Serial.println(F(" bytes"));
}
};
// 使用示例
void setup() {
Debug::begin(115200);
Debug::log("Setup complete");
Debug::memory();
}
void loop() {
static int counter = 0;
Debug::log("Loop count", counter++);
if (counter > 100) {
Debug::warn("Counter is getting large");
}
delay(1000);
Debug::memory();
}
11. 项目示例:智能气象站
// 完整的气象站项目
#include <DHT.h>
#include <LiquidCrystal_I2C.h>
#define DHTPIN 2
#define DHTTYPE DHT11
#define LDR_PIN A0
#define RAIN_PIN A1
DHT dht(DHTPIN, DHTTYPE);
LiquidCrystal_I2C lcd(0x27, 16, 2);
void setup() {
Serial.begin(9600);
dht.begin();
lcd.init();
lcd.backlight();
Serial.println(F("Weather Station V1.0"));
lcd.setCursor(0, 0);
lcd.print(F("Weather Station"));
delay(2000);
lcd.clear();
}
void loop() {
// 读取所有传感器
float humidity = dht.readHumidity();
float temperature = dht.readTemperature();
int lightLevel = analogRead(LDR_PIN);
int rainValue = analogRead(RAIN_PIN);
bool isRaining = rainValue < 500; // 假设小雨时值较小
// 串口输出
Serial.println(F("=== Weather Data ==="));
Serial.print(F("Temp: ")); Serial.print(temperature); Serial.println(F("°C"));
Serial.print(F("Humidity: ")); Serial.print(humidity); Serial.println(F("%"));
Serial.print(F("Light: ")); Serial.println(lightLevel);
Serial.print(F("Rain: ")); Serial.println(isRaining ? "Yes" : "No");
// LCD显示
lcd.setCursor(0, 0);
lcd.print(F("T:"));
lcd.print(temperature, 1);
lcd.print(F("C H:"));
lcd.print(humidity, 0);
lcd.print(F("%"));
lcd.setCursor(0, 1);
lcd.print(F("L:"));
lcd.print(lightLevel);
lcd.print(F(" R:"));
lcd.print(isRaining ? "Yes" : "No ");
// 延迟5秒
delay(5000);
}
总结
Arduino UNO 是:
- 入门最佳选择:引脚标记清晰,资源丰富
- 功能全面:支持数字、模拟、PWM、通信
- 社区强大:海量的库和教程
- 扩展性好:各种扩展板(Shield)可用
学习建议:
- 从基本的LED和按钮开始
- 逐步学习各种传感器
- 掌握串口调试技巧
- 学习通信协议(I2C、SPI)
- 尝试综合项目实践
- 关注内存和性能优化
Arduino UNO 虽然内存有限,但通过学习优化技巧,可以实现很多有趣的项目!
本文来自博客园,作者:ukyo--碳水化合物,转载请注明原文链接:https://www.cnblogs.com/ukzq/p/19432308

浙公网安备 33010602011771号