IOT ESP8266 Timer Tutorial – Arduino IDE
This is the second of a multi-part posting on the ESP8266. We are giving an example of how to use the timers on the ESP8266. It was very hard to find a simple example of how to use the timers under the Arduino IDE. We need this for our new IOT project, a pulse meter feeding into the Amazon IOT software. We need a steady 2 millisecond interrupt based timer to do the pulse sampling.
Check out our other ESP8266 Projects and Products
- – OurWeather – ESP8266 Based Weather Station
- – Using the AT Command Set on the ESP8266 from an Arduino
- – Solar Powered ESP8266
- – Connecting to an ESP8266 from Alexa
A series of IOT ESP8266 Tutorials
Part 1 IOT ESP8266 Tutorial – Using nodeMCU/LUA
Part 2 IOT ESP8266 Timer Tutorial – Arduino IDE
Part 3 IOT ESP8266 Tutorial – Using the Arduino IDE
Part 4 IOT ESP8266 Tutorial – AT Command Set Firmware
Part 5 IOT ESP8266 Tutorial – Connect to the IBM Bluemix Internet of Things
Part 6 IOT ESP8266 Tutorial – Sending ESP8266 Data to the IBM Bluemix IOT
Part 7 IOT ESP8266 Tutorial – The IOT Application and Source Code
Part 8 IOT ESP8266 Tutorial – Displaying the data on the IBM Bluemix IOT
We are using the Adafruit ESP8266 Huzzah breakout board for these postings.
Why Use Timers to Generate Interrupts?
Often you want an action to be repeated at specific intervals. Timing your loops and adding delay statements to time your loops is difficult, may change and will not port to a faster processor (and there are faster versions of the ESP8266 coming out). The best way of doing this is to use a timer and a callback routine. That is what we are showing in the example below.
Note that it doesn’t have to be a repeatable event. You can schedule one-shots too in the future.
The ESP8266
The ESP8266 is made by a privately held company in China called Espressif. They are a fabless semiconductor company that just came out of nowhere and shook up the whole industry. Now all the major players are working on inexpensive versions of an IOT chip with WiFi connectivity. And they are all struggling to make it as inexpensive as the ESP8266
The Adafruit ESP8266 Huzzah
The Adafruit ESP8266 Huzzah board is a great breakout for the ESP8266. It makes it much easier to use with the Raspberry Pi that the really cheap modules.
Most of the low cost modules are not breadboard friendly, don’t have an onboard 3.3V regulator or level shifting for signals. The Huzzah has all of those features. For more on the ESP8266 Huzzah board see this posting.
The Timers on the ESP8266
There are two types of timers on the ESP8266. There is os_timer, which is a software based interval timer and the os_timer apparently only has capacity to have seven timers set at one time. The second type of timer is a hardware based timer, hw_timer, of which there is apparently only one. We would suggest not to use the hw_timer, as we really don’t know or understand what the ESP8266 libraries are using it for. You could easily screw up the WiFi, for example. The documentation for the hw_timer is sparse, at best. Our example below uses the os_timer.
The above information is not solid. The ESP8266 is a poorly documented system at this point. It will get better. We will update this as more information becomes available.
Update November 13, 2015: We now have found out that the use of the os_timer set to a 2ms interrupt will cause the WiFi to fail. We are investigating the cause, but right now it definitely kills the WiFi connection and will not reconnect.
Note on the use of os_timer
Because it is a software timer, based on the underlying hardware timer, it is “Soft Real Time”. Depending on what the rest of the operating system is doing (WiFi, PWM, etc.), it will interrupt you when triggered, but it isn’t at an exact time. It will be close. Keep that in mind. You may see jitter in the timing. The faster interval you set for the os_timer, the more jitter you may see.
A Simple Timer Example for the ESP8266
We spent quite a bit of time looking for an example of how to use os_timer in the Arduino IDE. Here is our test program. Our pulse monitor is now running on os_timer correctly. Note there is another set of os_timer functions that allow microsecond resolution. Using them will increase your jitter as above.
// // ESP8266 Timer Example // SwitchDoc Labs October 2015 // extern "C" { #include "user_interface.h" } os_timer_t myTimer; bool tickOccured; // start of timerCallback void timerCallback(void *pArg) { tickOccured = true; } // End of timerCallback void user_init(void) { /* os_timer_setfn - Define a function to be called when the timer fires void os_timer_setfn( os_timer_t *pTimer, os_timer_func_t *pFunction, void *pArg) Define the callback function that will be called when the timer reaches zero. The pTimer parameters is a pointer to the timer control structure. The pFunction parameters is a pointer to the callback function. The pArg parameter is a value that will be passed into the called back function. The callback function should have the signature: void (*functionName)(void *pArg) The pArg parameter is the value registered with the callback function. */ os_timer_setfn(&myTimer, timerCallback, NULL); /* os_timer_arm - Enable a millisecond granularity timer. void os_timer_arm( os_timer_t *pTimer, uint32_t milliseconds, bool repeat) Arm a timer such that is starts ticking and fires when the clock reaches zero. The pTimer parameter is a pointed to a timer control structure. The milliseconds parameter is the duration of the timer measured in milliseconds. The repeat parameter is whether or not the timer will restart once it has reached zero. */ os_timer_arm(&myTimer, 1000, true); } // End of user_init void setup() { Serial.begin(115200); Serial.println(); Serial.println(); Serial.println(""); Serial.println("--------------------------"); Serial.println("ESP8266 Timer Test"); Serial.println("--------------------------"); tickOccured = false; user_init(); } void loop() { if (tickOccured == true) { Serial.println("Tick Occurred"); tickOccured = false; } yield(); // or delay(0); }
Compile the code, run it and you will see “Tick Occurred” printed to your serial console on the Arduino IDE every second.
Comments
Here are few pointers about using interrupts in the ESP8266, as well as in any Arduino based system.
- – Keep your Interrupt Service Routine (ISR) short. ISR is another name for the callback function.
- – Do not use “serial print” commands in an ISR. The serial commands also use interrupts and using them can hang the processor
- – It is good practice to disable interrupts in an ISR routine (os_intr_lock();/os_intr_unlock();) and then enable them as you leave. We are not doing that in this routine as we are not sure what the effects would be on the underlying operating system. Our routine is so short, it clearly doesn’t matter here.
- – Note that the real work of the interrupt is being done in the main loop. That can affect your timing of your servicing your interrupt.
- – You have to put a yield() or a delay(0) in your main loop to allow the underlying operating system to do it’s work.
- – There is a watchdog timer in the ESP8266 that will reset the processor if you keep it busy too long. More on that in a future posting. Put lots of yield() or delay(0) statement in your program to keep this from happening. Note, delays with values greater than zero (delay(10) for example) are fine.
I get amp was not declared when I try compile
Hmmmm. We don’t see amp anywhere in the code. Could you show your code?
SDL
Hi, I has also had two “amp” in my Code, that’s the HTML replace of “&”
Simply replay “&” with “&” and it works fine.
Simply replace “&” with “&” and it works fine.
Hi guys,
Do you know is it possible to get PWM wiht frequencies 20-30 Mhz ? In the article you said that there was another set of os_timer functions that allow microsecond resolution. How to get it?
Thanks.
Birst,
Even if you could get access to the microsecond resolution timer, you just can’t do PWM at 20-30MHz. 1usec resolution limits you to 1MHz (or 500KHz in one sense) speed and there is a bunch of other things going on with the ESP8266 processor (Garbage Collection, WiFi, etc.) to get anywhere near that limit in any case. Not accurately for sure.
To get those kind of speeds, you need to go to an external PWM board. There are a number of them that are controlled by the I2C bus.
Best regards,
SDL
I currently use the TimerOne Library for the Arduino U3. I’m in need of a timer interrupt in the microsecond realm. is that possible on the ESP8266?
John,
Latest that we have seen is that the microsecond timers are being used by the WiFi software and will cause a reset.
Best,
SDL
hi friends…
i am getting error “‘amp’ was not declared in this scope” and seeing the amp in the code
os_timer_setfn(&myTimer, timerCallback, NULL);
please post a comment to remove the error.
thanks
got the solution..it was actually “&myTimer” and was seeing in arduino id as” &myTime”.
thanks
hi..i am using this code to run my fan for 1 one minute .meanwhile i want to perform other task by esp.when i add my code in main loop..delay time is also increasing…can you please correct my code??
my code is
//
// ESP8266 Timer Example
// SwitchDoc Labs October 2015
//
//
extern “C”
{
#include “user_interface.h”
}
os_timer_t myTimer;
bool tickOccured;
unsigned int count = 0; //used to keep count of how many interrupts were fired
unsigned int sec = 0;
unsigned int second = 0;
unsigned int minute= 0;
// start of timerCallback
void timerCallback(void *pArg)
{
tickOccured = true;
second=second++;
} // End of timerCallback
void user_init(void)
{
/*
os_timer_setfn – Define a function to be called when the timer fires
void os_timer_setfn(
os_timer_t *pTimer,
os_timer_func_t *pFunction,
void *pArg)
Define the callback function that will be called when the timer reaches zero. The pTimer parameters is a pointer to the timer control structure.
The pFunction parameters is a pointer to the callback function.
The pArg parameter is a value that will be passed into the called back function. The callback function should have the signature:
void (*functionName)(void *pArg)
The pArg parameter is the value registered with the callback function.
*/
os_timer_setfn(&myTimer, timerCallback, NULL);
/*
os_timer_arm – Enable a millisecond granularity timer.
void os_timer_arm(
os_timer_t *pTimer,
uint32_t milliseconds,
bool repeat)
Arm a timer such that is starts ticking and fires when the clock reaches zero.
The pTimer parameter is a pointed to a timer control structure.
The milliseconds parameter is the duration of the timer measured in milliseconds. The repeat parameter is whether or not the timer will restart once it has reached zero.
*/
os_timer_arm(&myTimer, 1000, true);
} // End of user_init
void setup() {
pinMode(13, OUTPUT);
pinMode(5, OUTPUT);
Serial.begin(115200);
Serial.println();
Serial.println();
Serial.println(“”);
Serial.println(“————————–“);
Serial.println(“ESP8266 Timer Test”);
Serial.println(“————————–“);
tickOccured = false;
user_init();
}
void loop() {
digitalWrite(4, HIGH); // turn the LED on (HIGH is the voltage level)
delay(2000); // wait for a second
digitalWrite(5, LOW); // turn the LED off by making the voltage LOW
delay(500);
if ( second>=60)
{
second=0;
minute++;
//Serial.println(“one minute”);
digitalWrite(13, HIGH); // turn the LED on (HIGH is the voltage level)
delay(500); // wait for a second
digitalWrite(13, LOW); // turn the LED off by making the voltage LOW
delay(500);
}
delay(10); // or delay(0);
}