NodeMCU programming model
NodeMCU is inspired by node.js, a javascript framework and server based on the concept of callback-based asynchronous programming.
This concept can take some getting used to. The following examples should give you an idea of how asynchronous programs are structured.
Synchronous vs. Asynchronous
The previos chapter ended in an example of a blinking LED program. Some of you may have already used Arduino to write a similar program:
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
digitalWrite(LED_BUILTIN, HIGH);
delay(1000);
digitalWrite(LED_BUILTIN, LOW);
delay(1000);
}
The first thing to notice is that no other code
can run while the loop
function is running.
This means that the microcontroller will
sit idly for one second while the delay(1000)
calls are being executed.
The code-snipped below shows the asynchronous counterpart to the Arduino code above.
function led_toggle()
if (status == gpio.LOW) then
status = gpio.HIGH
else
status = gpio.LOW
end
gpio.write(4, status)
end
function led_setup()
gpio.mode(4, gpio.OUTPUT)
-- schedule led_toggle() to run once a second
tmr.create():alarm(1000, tmr.ALARM_AUTO, led_toggle)
end
The function led_toggle
is scheduled to be executed
every 1000ms using the tmr.create():alarm()
call.
In the meantime the microcontroller is free to run different
pieces of code.
Hint: The NodeMCU firmware makes use of this property,
for example for handling network connections.
This is why you should avoid writing functions
in NodeMCU that may take a long time to run,
especially by avoiding the tmr.delay()
function.
Handling input
After learning the basics of what asynchronous programming means we have to learn how they transfer to actual real-world tasks.
One real-world task is acting upon data input.
Replace the content of you application.lua
file
with the code-snippet below and upload it to your
microcontroller.
function uart_on_char(char)
print("Read character: "..char.." from uart")
end
function uart_setup()
-- Whenever 1 byte of data is received
-- run uart_on_char, do not interpret the
-- received byte as lua command
uart.on("data", 1, uart_on_char, 0)
end
uart_setup()
After uploading the program, resetting your microcontroller and connecting to it using picocom the microcontroller should respond to every character you enter with a line like the following:
[user@computer ~]$ picocom -b 115200 /dev/ttyUSB0
Read character: h from uart
Read character: e from uart
Read character: l from uart
Read character: l from uart
Read character: o from uart
Task: modify the application.lua
to turn
on the LED whenever the character l
is received
and off whenever the character d
is received.