如何确保我的 Arduino 秒表的时间准确?

How can I make sure that my Arduino stopwatch's timing is exact?

本文关键字:时间 Arduino 何确保 确保 我的      更新时间:2023-10-16

我有一个学校作业,使用多功能盾牌制作秒表。功能很简单:如果秒表停止,最左边的按钮用于启动/停止,最右边的按钮用于重置。精度为 100 毫秒。

我的代码按预期工作,但我的老师返回它说我不能保证代码每 100 毫秒执行一次,以便秒表不会落后。我做错了什么?

以前的硬件有一些遗留代码,希望这不是问题。

// Funshield Constants
// Constants for switching ON/OFF
constexpr int ON = LOW;
constexpr int OFF = HIGH;
// 7-Segs
constexpr int latchPin = 4;
constexpr int clockPin = 7;
constexpr int dataPin = 8;
// Buzzer
constexpr int buzzerPin = 3;
// LEDS
constexpr int firstPin = 13;
constexpr int secondPin = 12;
constexpr int thirdPin = 11;
constexpr int fourthPin = 10;
// Buttons
constexpr int firstButton = A1;
constexpr int secondButton = A2;
constexpr int thirdButton = A3;
// Trimr
constexpr int trimrPin = A0;
// Digits
constexpr int digits[11] = { 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, 0xFF };
constexpr int digitsPos[4] = { 0x08, 0x04, 0x02, 0x01 };
// End of Funshield Constants
// Beginning of the Program
// Buttons Variables
unsigned int buttons[] = {firstButton, secondButton, thirdButton};
unsigned int lengthOfButtons = sizeof(buttons) / sizeof(buttons[0]);
unsigned int previousButtonState[] = {1, 1, 1};
// Global Variables
unsigned long int previousMillis = millis();
unsigned int numberDigits[] = {0, 0, 0, 0};
unsigned int interval = 100;
bool isRunning = false;
int numberLength = 0;
int digitIndex = 0;
int dotIndex = 1;
int number = 0;
int DISPLAY_DECIMAL_DOT = 0x7F;
// Functions
unsigned long int displayController(unsigned long int previousMillis, unsigned int interval) {
unsigned long int currentMillis = millis();
if (currentMillis - previousMillis >= interval) { 
previousMillis = currentMillis;
updateSetNumber(++number, 1);
}
return previousMillis;
}
int calculateNumberLength(int innerNumber) {
int len = 0;
while (innerNumber != 0) {
innerNumber = innerNumber / 10;
len++;
}
if (len <= dotIndex) len = dotIndex + 1;
return len;
}
void updateSetNumber(int innerNumber, int dot) {
numberLength = calculateNumberLength(innerNumber) - 1;
dotIndex = dot;
for (int i = 0; i < 4; i++) {
numberDigits[i] = innerNumber % 10;
innerNumber = innerNumber / 10;
}
}
void displayLoop() {
if (digitIndex > numberLength) {
digitIndex = (digitIndex + 1) % 4;
return;
}
if ((digitIndex == dotIndex) && (dotIndex > 0)) {
displayDigit(digits[numberDigits[digitIndex]] & DISPLAY_DECIMAL_DOT, digitsPos[digitIndex]);    
} else {
displayDigit(digits[numberDigits[digitIndex]], digitsPos[digitIndex]);  
}
digitIndex = (digitIndex + 1) % 4;
}
void displayDigit(byte digit, byte pos) {
digitalWrite(latchPin, OFF);
shiftOut(dataPin, clockPin, MSBFIRST, digit);
shiftOut(dataPin, clockPin, MSBFIRST, pos);
digitalWrite(latchPin, ON);
digitalWrite(latchPin, OFF);
}
// Program
void setup() {
for (int i = 0; i < lengthOfButtons; i++) {
pinMode(buttons[i], INPUT);
}
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
}
void loop() {
if (isRunning) {
previousMillis = displayController(previousMillis, interval);
}
unsigned int currentButtonState = digitalRead(buttons[0]);
if ((!isRunning) && (digitalRead(buttons[2]) == ON)) {
digitIndex = 0;
number = 0;
updateSetNumber(number, 1);
}
displayLoop();
if (currentButtonState != previousButtonState[0]) {
if (currentButtonState == ON) {
isRunning = !isRunning;
}
previousButtonState[0] = currentButtonState;
}
}

你的老师指出的问题可能是你如何更新 previousMillis。 想象一下,由于某种原因,中断时间太长,或者你成为 millis 时不时跳过一个数字并且你的函数直到最后一次后 102ms 才被调用的事实的受害者。 由于您将 previousMillis 设置为 currentMillis,因此从现在开始您将关闭 2 毫秒。 相反,将间隔添加到 previousMillis 变量中。 这样,您可以抵消一点延迟,下一个即时报价准时。

if(currentMillis - previousMillis >= interval) {
previousMillis += interval;  // instead of = currentMillis which may be off
}