亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Manufacturing Technology >> 制造工艺

掌握 Arduino 多任务编程:原型线程分步教程

元器件与材料

Arduino UNO ×1
Sunfounder 蓝色 16x2 液晶显示屏 (LCD) ×1
面包板 (通用) 和跳线 ×1
旋转电位器 (通用,约 1KΩ) ×1

项目简介

本教程演示如何让单核 Arduino 同时执行三项任务:

什么是原型线程?

原型线程 是一种在 Arduino 等单核微控制器上实现“多任务”效果的技术。虽然标题叫“多线程”,但 Arduino 是单核芯片,运行的是顺序代码,真正的多线程是不可能的。那么原型线程有何不同?

“真”多线程 vs 原型线程

要理解原型线程,先要明白为什么它不是真正的多线程。

早年 Intel 推出“超线程”技术,让单核 CPU 表现得像双核。其核心在于时钟周期。无论是微控制器还是 CPU,都在“周期”中工作。Arduino Uno 的 ATmega328P 主频 16MHz,即每秒 1600 万个时钟周期。但这不是代码行数,而是底层指令(如寄存器搬运数据)。

真正的多线程需要多核 CPU,不同线程并行运行在不同核心上。Arduino 只有一个核心,传统多线程无法实现。我们需要在单核心上管理多项工作,这就是原型线程的用武之地。

原型线程如何工作?

原型线程类似于超线程,但不是在 CPU 周期层面,而是在代码循环/行级拆分工作。每个循环若无紧急任务,就执行一些低频或低负载工作。当不忙时,检查是否该执行其他任务,若是则分支执行。

关键点:阻塞性操作(如读取 SD 卡)仍会阻塞其他原型线程“按时”运行。但对于快速动作(变量修改、输出值改变),效果极佳。部分 MCU 支持实时操作系统 (RTOS),能更好地处理阻塞任务。

开始实战

首先明确任务:(a) LCD 背光淡入淡出 (b) 以较慢间隔递增计数器 (c) 以更慢间隔轮换字符串。按“阻塞程度”从低到高排序:

主循环中调用 numberThread.check() 和 textThread.check() 检查子任务是否到期。任何循环内都必须插入检查,否则会阻塞子任务。初始化时用 TimedAction 设定间隔。

完整代码见下方,已详细注释。核心思想:用最高频任务作为主循环,在其循环内穿插检查其他任务。这只是简单示例,欢迎指正。

代码

使用 <TimedAction.h> 库实现三个不同间隔的重复任务:

/* Arduino 原型线程示例 v1.1 by Drew Alden (@ReanimationXP) 1/12/2016
   更新 v1.1 - 8/18/17 Arduino 1.6.6+ 兼容性修复
   注意:TimedAction 库已过时,新版 Arduino 需手动将库中 WProgram.h 改为 Arduino.h */
#include <TimedAction.h>
#include <LiquidCrystal.h>

// 元器件:Sunfounder Arduino 套件蓝色 LCD
// 第三方库:TimedAction (需手动修改库文件)
// 原生库:LiquidCrystal

// 全局变量
int backlightPin = 9;
int timerCounter = 0;
int stringNo = 0;
char* stringArray[] = {"Check it out... ", "I have 3 threads", "going at once...", "Cool, huh?! :D "};

// 初始化 LCD (RS, EN, D4, D5, D6, D7)
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

// 任务函数
void incrementNumber() {
  lcd.setCursor(0, 1);
  timerCounter++;
  lcd.print(timerCounter);
}

void changeText() {
  lcd.setCursor(0, 0);
  lcd.print(stringArray[stringNo]);
  if (stringNo >= sizeof(stringArray)/sizeof(char*)) {
    stringNo = 0;
    changeText();
  } else {
    stringNo++;
  }
}

// 定时任务对象 (间隔ms, 回调函数)
// 注意:必须在函数定义之后创建,否则编译报错
TimedAction numberThread = TimedAction(700, incrementNumber);
TimedAction textThread = TimedAction(3000, changeText);
// 第三个任务就是主循环本身 (背光脉冲)

void setup() {
  lcd.begin(16, 2);
  changeText(); // 显示初始字符串
}

void loop() {
  // 检查子任务
  numberThread.check();
  textThread.check();

  // 任务1: 背光淡入 (主循环核心工作)
  digitalWrite(13, HIGH);
  for (int fadeValue = 0; fadeValue <= 255; fadeValue += 10) {
    numberThread.check(); textThread.check(); // 必须在循环内检查!
    analogWrite(backlightPin, fadeValue);
    delay(20); // 保持极短延迟
  }

  // 任务1: 背光淡出
  digitalWrite(13, LOW);
  for (int fadeValue = 255; fadeValue >= 0; fadeValue -= 10) {
    numberThread.check(); textThread.check();
    analogWrite(backlightPin, fadeValue);
    delay(20);
  }
  // 循环结束,回到开头继续
}

制造工艺

  1. 使用 OpenSensors 监测空气质量:Arduino 与 Python 实战指南
  2. 打造安全的 Arduino RFID 门锁——分步指南
  3. 用 Arduino 制作万能红外遥控器:分步指南
  4. DIY 数字身高仪:Arduino Nano + VL53L0X 激光测距 + OLED 显示
  5. 热敏电阻测温轻松上手:Arduino 分步实战教程
  6. Arduino 合成乐音:从零实现 88 键钢琴全音域
  7. Arduino 连接 NMEA-0183 设备全攻略:从硬件接线到协议解析
  8. Arduino Nano 指纹传感器项目——分步教程
  9. Arduino Modbus 从机开发全攻略:基于 RS485 扩展板的分步实现指南
  10. 用 Arduino UNO 自制迷你钢琴 — 图文教程
  11. Arduino Nano 打造 JARVIS v1 家庭自动化:分步教程
  12. Arduino入门教程01:开始你的第一个项目