Friday, January 8, 2021

ESP8266 Ticker library problem

For a complete index of all my stories click this text

I ran into a problem. It took me several test and a lot of time to discover what was wrong.
Let me first tell you what I was trying to achieve.

I was building a webpage with an ESP8266 using the Arduino IDE. The webpage had some buttons and displayed the temperature from an Dallas DS18B20. Next to that I wanted to send the readings also to Domoticz. Nothing dramatic.

The problem rose when I wanted to automatically update the temperature reading on the webpage every x minutes.  I used the Ticker library for that.

Ticker

Ticker is a build-in library for the ESP8266 which allows you to have a process run automatically every x seconds or x milliseconds.
The use of it is very simple. I'll show you an example that switches a led ON and OFF every second in the background while in the meantime the program can do all kind of other things.


#include <Ticker.h>

Ticker everytime;
int Ledstatus = 1;

void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);
  everytime.attach(1, blinkled);
}

void loop()
{ 
  // put your code here
}

void blinkled()
{
  Ledstatus = 1 - Ledstatus;
  digitalWrite(LED_BUILTIN, Ledstatus);
}

The program looks simple and indeed it is.


#include <Ticker.h>

This loads the Ticker library when the program is compiled.

Ticker everytime;

This line glues the Ticker library to our name everytime.

In the setup the build-in ledpin of the Wemos D1 Mini is defined as an output and the led is put OFF (HIGH). Looks strange to put a led OFF by setting the pin HIGH but remember that the pins of the Wemos D1 mini and NodeMCU build-in led are reversed.

everytime.attach(1, blinkled);

This line in the setup sends the routine eveyr second (1) to the blinkled subroutine. Change the 1 in any number of seconds you'd like. Or change attach in attach_ms for miliseconds.

The blinkled routine just puts the led ON or OFF and speaks for itself.

Does this work. ????
Yes it works flawlessly till ...............
Till you start to use wifi.

As soon as you use wifi it is blocked by the Ticker library. So my Dallas temperature routine worked. My Webpage page worked and detected button presses and send them to Domoticz. And as soon as I invoked Ticker my webservice stopped working.

The solution.

Back to the old Arduino Blink without delay routine !!

I adapted this routine for my purposes and then everything worked flawlessly.


// Blink without delay
// adapted by Luc Volders

int Ledstatus = 1;

unsigned long oldMillis = 0;
const long blinkrate = 1000;

void setup() 
{
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() 
{
  unsigned long newMillis = millis();
  if (newMillis - oldMillis >= blinkrate) 
  {
  oldMillis = newMillis;
  Ledstatus = 1 - Ledstatus;
  digitalWrite(LED_BUILTIN, Ledstatus);
  }
}


Just a quick examination.

unsigned long oldMillis = 0;
const long blinkrate = 1000;

The variables are initialised. Alter the blinkrate value to your needs. I used 1000 in this test. That is 1000 Miliseconds and equals 1 second. If you'd need something to happen every 10 minutes it would be 1000 (millis) x 60 (seconds) x 10 minutes = 600000

And for the rest everything is done in the loop.

unsigned long newMillis = millis();

First we test how many Milliseconds have past.

if (newMillis - oldMillis >= blinkrate)

And then we test if the amount that has past minus the amount when we started is larger as the 1000 we set as a tresh-hold (1 second). If that is true:

  oldMillis = newMillis;
  Ledstatus = 1 - Ledstatus;
  digitalWrite(LED_BUILTIN, Ledstatus);

The value of the time past until that moment is put into oldMillis and the leds pin value is reversed. The counter then starts anew.

This works as expected and does not have any influence on the wifi operation.

So no problem here ??

Whish that was true. Life is not that simple. There is a problem with this setup, and how severe it is depends on the kind of program you are writing.

Suppose there is a lot going on in your program and from the loop you call all kinds of functions. If these functions take a lot of time it might be longer as 1 second before the loop is finished and starts again.

Then the time that has elapsed is longer as 1000 millis and your led might blink irreuglarly.

Now when you are timing something that only happens once every 10 minutes it is not a big problem. However if your program is time-critical you might get unexpected results. You could adapt the interval value to straighten that out.

Fortunately there are some other libraries that do not have these problems. I am testing some and will get back on this.

Experiment and have fun !!!
Till next time

Luc