![]() You can also directly read the raw timer0_overflow_count as shown above, although the actual speed this increments depends on the Arduino clock rate, and you need to do cli/sei around the read to avoid jumps of +-256, as the interrupt function updates the two bytes of that value. The easy way to avoid these timing jumps is never to use millis() at all! It works to just use micros()/1000, although looking at wiring.c’s implementation of delay(), you need to be a bit careful about when micros() overflows every hour. On my Arduino Uno, the millis() version of this reports regular timing glitches: Still running at 0 ![]() cli() next=timer0_overflow_count sei() // faster, but 1024 microseconds/tick Unsigned long last=0 // last value of millis() Serial.begin(57600) // to report the horrorĮxtern "C" volatile unsigned long timer0_overflow_count // from wiring. * Demonstrate timing gaps in the millis() function */ Here’s an example Arduino Uno sketch that demonstrates these timing jumps, and shows two fixes. This results in millis() instantly jumping up by more than one. Arduino wiring.c fixes this by keeping track of the fractional milliseconds, and adds a sort of “leap millisecond” every 43 milliseconds to keep things in sync. Turns out, the Arduino Uno’s oscillator runs at a power of two rate, 1.024 milliseconds per overflow, so every 1/0.024 = 41.666 milliseconds, it’s a full millisecond off. I assumed it was my code, which does a bunch of other stuff like serial communication, but the glitch didn’t change regardless of what I did. I was using Arduino’s millis() function as my time base, and I kept getting weird screwy timing every 43 milliseconds. I realize professionals do this sort of thing with interrupts, but I hate debugging interrupt code, and I’m always afraid there’s some rare timing glitch that will kill the entire project at the worst possible moment. ![]() That’s what the Arduino example does.I’ve been doing some software-modulated infrared light detection work, and for the signal to be sent correctly I need millisecond-accurate timings. You can then check that millis (now) - millis(then) > duration to determine if it’s time that the LED was toggled. You should, I think, also be holding the previous time that you toggled the LED. You need to grab millis() when you enter the loop, every time. The value increments 1,000 times every second, so even a short time between getting the value and using it will cause it to be different, then when you assign the value to one of the duration variable, it will have moved on again. You are pulling the millis() value twice, well 4 times, in loop() and each one will be very different. Maybe you can study that code and see what’s different from yours? There is an example of using millis() rather than delay() on the Arduino web at which does work. The SREG = oldSREG is where the interrupts are enabled again - assuming they were before they were turned off. You can see a cli instruction above the fetching of 4 bytes in 4 separate instructions. That’s the assembly code generated for the code in the millis() function which fetches the value of timer_0_millis into a variable named m ready to be returned. disable interrupts while we read timer0_millis or we might get an While I wa correct that interrupts could be a problem, they are not because whenever you call millis() interrupts are off while the 4 bytes are transferred: unsigned long millis() It leads to long periods of darnkess or light! (Rollover happens every 2^32 + 1 milliseconds.) You are aware that millis() will roll over at some point? That will affect things too. Try adding noInterrupts() before, and interrupts() after, your assignments from millis() to your duration variables. Between each byte, in interrupt can occur, changing the values in the bytes not yet copied over to your variables. Your updates to the duration generate code to update 4 bytes from a value that is 4 bytes long. That allows the update to work correctly. Millis() turns interrupts off to update its long variables, as it is done within the ISR for Timer/counter 0’s Overflow Interrupt. The data types you are holding your durations in are long but the ATmega328 is byte sized and doesn’t have 16 or 32 bit instructions as such. Your code is possibly suffering from interrupts.
0 Comments
Leave a Reply. |
AuthorWrite something about yourself. No need to be fancy, just an overview. ArchivesCategories |