[英]How can I make sure that my Arduino stopwatch's timing is exact?
我有一個學校作業,要使用 Multifunction Shield 創建一個秒表。 功能很簡單:如果秒表停止,最左邊的按鈕用於啟動/停止,最右邊的按鈕用於重置。 精度為 100ms。
我的代碼按預期工作,但我的老師回復它說我不能保證代碼每 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不時跳過一個數字的受害者,並且您的 function 直到最后一次后 102 毫秒才被調用。 由於您將 previousMillis 設置為 currentMillis,因此從現在開始您將在 2 毫秒內關閉。 相反,將間隔添加到 previousMillis 變量。 這樣一來,您就可以消除那一點點滯后,並且下一個滴答聲會准時到達。
if(currentMillis - previousMillis >= interval) {
previousMillis += interval; // instead of = currentMillis which may be off
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.