Arduino stopwatch program almost 4x as slow as it should be

88 Views Asked by At

My program is supposed give an output as a timer on the Serial Monitor going up like a digital clock. It does this well, only extremely slowly, it takes about 4 real seconds to pass for a second to go by in the program.

The program works with a 10milliseconds variable going up by 1 each time, this should mean it goes up 100 times per second. Every time it gets to 10 it sets the next one higher, the next one being 100milliseconds. This keeps going through seconds, 10seconds (this runs to 6 not 10), minutes, 10minutes and 100 minutes. I'm a new programmer sorry if it's messy and unreadable.

void setup()
{
    // put your setup code here, to run once:
    Serial.begin(9600);
    Serial.println();
    Serial.println("Timer will start in 5 seconds");
    delay(5000);
}

void loop()
{
    // put your main code here, to run repeatedly:
    static int tenMilliSeconds = 0;
    static int hundredMilliSeconds = 0;
    if (tenMilliSeconds == 10)
    {
        tenMilliSeconds = 0;
        hundredMilliSeconds++;
    }
    static int seconds = 0;
    if (hundredMilliSeconds == 10)
    {
        hundredMilliSeconds = 0;
        seconds++;
    }
    static int tenSeconds = 0;
    if (seconds == 10)
    {
        seconds = 0;
        tenSeconds++;
    }
    static int minutes = 0;
    if (tenSeconds == 6)
    {
        tenSeconds = 0;
        minutes++;
    }
    static int tenMinutes = 0;
    if (minutes == 10)
    {
        minutes = 0;
        tenMinutes++;
    }
    static int hundredMinutes = 0;
    if (tenMinutes == 10)
    {
        tenMinutes = 0;
        hundredMinutes++;
    }
    if (hundredMinutes == 10)
    {
        Serial.println("The limit has been reached.");
        while (hundredMinutes == 10)
        {
            delay(100000);
        }
    }
    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);

    tenMilliSeconds++;
    delay(10);
}

I get if it's a bit off because it can't run code simultaneously, but I'm surprised that's it's almost 4 times slower in that case, since online it said a typical Arduino microcontroller does a basic command for 60 nanoseconds! That's not big enough to make a dent. Is it just the serial printing time slowing me down while the timer itself runs fine? Or have I messed up somewhere in my code. Thank you.

Edit: This is Serial Monitor output:

0 : 0 : 8 :: 4 : 0 :: 4 : 5
0 : 0 : 8 :: 4 : 0 :: 4 : 6
0 : 0 : 8 :: 4 : 0 :: 4 : 7
0 : 0 : 8 :: 4 : 0 :: 4 : 8
0 : 0 : 8 :: 4 : 0 :: 4 : 9
0 : 0 : 8 :: 4 : 0 :: 5 : 0

As expected but it takes too long.

1

There are 1 best solutions below

0
On

tl;dr: At 9600 baud, you're spending 30 ms transmitting data + 10 ms waiting + the time to run all the instructions, which is about four times longer than the 10 ms you were expecting.


With Serial.begin(9600), you've configured the serial port on the Arduino to transmit at 9600 bits per second, with no parity bit, and one stop bit (see Serial.begin()). At 9600 bits per second, it take 104 microseconds to transmit one bit (a one or a zero). Each byte you send with Serial.print() will be encoded with 10 bits: 1 start bit, the 8 bits for the byte you're sending, and 1 stop bit. At 104 microseconds per bit, you have 10 * 104 = 1040 microseconds, or 1.04 milliseconds, per byte.

Each of your lines is 29 bytes long: 27 characters plus 2 bytes for the carriage return and newline. 29 bytes * 1.04 milliseconds/byte gives you approximately 30 milliseconds to transmit each line.

With the 30 milliseconds it takes to transmit the data and the extra 10 millisecond delay you added with delay(), you have at least 40 milliseconds per loop. I say "at least", because all those instructions do take time. You have simple increment, comparison, and assignment instructions which are pretty quick, but in Serial.print(...) you're also more time-consuming integer-to-string conversions and putting data into the serial port buffer, etc.

So, since the loop is 40 ms + however long it takes to run all those instructions, that explains why the output is coming about 4 times slower than you expected.

Note: Serial.print() is asynchronous and will return immediately after placing the next byte in the buffer, which is much faster than the 30 ms to transmit that I'm counting above. However, because these loops are very short, the buffer will fill up pretty quickly, at which point Serial.print() will wait until there's enough free space in the buffer for the data it wants to send (which will take the same amount of time it takes to transmit that amount of data).

You should notice that everything works closer to what you expected if you transmit the data at a (much) higher rate. Ultimately, however, this approach is never going to be very precise. You'll get much better results if you use micros() or millis() to measure how much time has passed and use that to calculate how much time you need to wait.