簡體   English   中英

如何確保我的 Arduino 秒表的計時准確?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM