Arduino计时器程序运行速度仅为预期1/4,求问题排查方案
问题诊断与修复方案
核心问题分析
你的计时器运行速度慢4倍的主要原因有两个:
1. 串口打印的耗时远超预期
你在每次循环中执行了大量Serial.print/Serial.println调用,而串口波特率设置为9600。按9600波特计算,每发送1字节数据大约需要1.04毫秒。以你提供的输出示例为例,每一行输出包含约26个字符(含换行符),发送这一行的时间就需要26 × 1.04 ≈ 27毫秒。再加上你设置的delay(10),单次循环的总耗时约为37毫秒,远大于你预期的10毫秒。这直接导致每秒仅能执行约27次循环,而非计划中的100次,最终造成计时速度严重偏慢。
2. 基于delay()的计时方式不可靠
使用delay(10)来模拟10毫秒间隔的思路本身存在缺陷,因为delay()是阻塞式函数,且循环中其他代码(如串口打印、变量进位逻辑)的执行时间会额外增加循环总耗时,导致实际间隔远大于预期的10毫秒。Arduino的标准实践是使用millis()实现非阻塞式计时,避免依赖固定延迟。
修复后的代码示例
以下是优化后的代码,采用millis()进行精确计时,同时减少不必要的串口输出频率(比如每100毫秒打印一次,而非每10毫秒),既保证计时精度,又降低串口开销:
void setup() { Serial.begin(9600); Serial.println(); Serial.println("Timer will start in 5 seconds"); delay(5000); } // 计时变量 unsigned long previousMillis = 0; const long interval = 10; // 10毫秒间隔 int tenMilliSeconds = 0; int hundredMilliSeconds = 0; int seconds = 0; int tenSeconds = 0; int minutes = 0; int tenMinutes = 0; int hundredMinutes = 0; void loop() { unsigned long currentMillis = millis(); // 仅当达到10毫秒间隔时更新计时变量 if (currentMillis - previousMillis >= interval) { previousMillis = currentMillis; tenMilliSeconds++; if (tenMilliSeconds == 10) { tenMilliSeconds = 0; hundredMilliSeconds++; } if (hundredMilliSeconds == 10) { hundredMilliSeconds = 0; seconds++; } if (seconds == 10) { seconds = 0; tenSeconds++; } if (tenSeconds == 6) { tenSeconds = 0; minutes++; } if (minutes == 10) { minutes = 0; tenMinutes++; } if (tenMinutes == 10) { tenMinutes = 0; hundredMinutes++; } if (hundredMinutes == 10) { Serial.println("The limit has been reached."); while (true) { // 停止计时 delay(1000); } } // 每100毫秒打印一次(即每10次间隔打印),减少串口开销 if (hundredMilliSeconds % 10 == 0 && tenMilliSeconds == 0) { Serial.print(hundredMinutes); Serial.print(" : "); Serial.print(tenMinutes); Serial.print(" : "); Serial.print(minutes); Serial.print(" :: "); Serial.print(tenSeconds); Serial.print(" : "); Serial.print(seconds); Serial.print(" :: "); Serial.print(hundredMilliSeconds); Serial.print(" : "); Serial.println(tenMilliSeconds); } } }
额外优化建议
- 如果需要更高的串口输出频率,可以将波特率提高到
115200,这能大幅降低串口发送时间。 - 避免在计时循环中执行任何阻塞操作(如
delay()),所有耗时操作都应采用非阻塞方式处理。
内容的提问来源于stack exchange,提问作者Morten
相关产品推荐
相关产品推荐

