Aug 25, 2021

Arduino: Creating asynchronous timed events auto-increment variables, the convenient elapsedMillis() function

Code snippets to demonstrate use and a clear way to name the variables.

See also the source information from the code function author Paul Stoffgren at: https://www.pjrc.com/teensy/td_timing_elaspedMillis.html

... Here’s one way to have multiple events occurring at different time intervals and not impede other functions like ADC reads and printing. It’s all based on monitoring variables that keep track of relative time (in milliseconds). You create a variable for each event you want to control, and a constant for the update interval for each thing, whether it’s reading pins, printing a message or blinking an LED. It took me a little while to grok the syntax and come up with a consistent way to name variables. It works for milliseconds or hours in the same loop. Here’s an example of what I use now in almost every program I write. The original documentation about it from the author is here.*

This is an excerpt from a program that uses a sensor to read magnetic flux and update the OLED display and the serial port. There are four functions that are accomplished at asynchronous intervals.

 . . . 
const uint16_t LED_INTERVAL  = 1000;
const uint16_t HES_INTERVAL  = 5;                   // fast rate to capture changes
const uint16_t OLED_INTERVAL = 200;
 . . .
const uint16_t status_led_flash_duration = 12;
 . . .
elapsedMillis since_msec    = 0;                        // ms to count a sec
elapsedMillis since_hes     = 0;                        // Hall-Effect magnetic sensor
elapsedMillis since_oled    = 0;
elapsedMillis since_led     = 0;

 . . .
void loop() {
 . . .
    if (since_hes >= HES_INTERVAL) {                 // make flux measurement
        since_hes = 0;

measureFlux();
    }

    if (since_oled >= OLED_INTERVAL) {               // update Gauss value on OLED screen
        since_oled = 0;

        oledUpdateValue(G);
    }

    if (since_msec >= 1000) { // each second, update the time
        since_msec = 0;

        total_sec ++;
        uint16_t sec  = total_sec % 60;
        uint16_t min  = (total_sec % 3600)/60;
        uint16_t hour = total_sec / 360

 . . .
        sprintf(msg, " %02d:%02d:%02d", hour, min, sec);// update time field on OLED   
        display.print(msg);
       
    }
}     


To do PWM, you start (set digital output high) at the beginning of each interval, and then set the pin low at time equal to the desired duty-cycle.
EX: for 33% duty cycle of 100ms period

    if (since_period >= 100) { since_period = 0; LED = ON; } 
    if (since_period == 33)  { LED = OFF; }


No comments: