ESP8266 Reading/Writing GPIO and Transmitting/Receiving UDP Packets

(click here to see index of all ESP8266 posts)

First, I should mention that I stopped using LUALOADER that I mentioned in a prior post. I don’t know why I was having issues, but I simply could not get it to see files on my hard drive to allow me to edit files on my PC then upload them to the ESP. Perhaps because the system I’ve been using for the ESP8266 is XP. Not sure.

Instead, I downloaded ESPLORER which is a java based IDE for ESP8266. Works great and is very self-explanatory:

https://github.com/4refr0nt/ESPlorer

esp8266-gpio-udp-fig1

Once that was up and running I was able to create programs and upload them without any trouble. The only ‘oddity’ I found was when I try to save the file to the local disk only it saves it to the ESP8266 as well. Turns out that can be turned off in the settings:

esp8266-gpio-udp-fig2

My First Real ESP8266 Program

For my first program I decided I should press a button which the ESP8266 detects. It then transmits a simple UDP packet to a echo server, and,  if the packet comes back properly, the ESP8266 turns on an LED.

I should mention that my ESP8266 has already established a network connection to my WLAN. For this test program, I assume that connection is running and do not attempt to establish a connection.

Hardware

Here is the schematic for the hardware I’ll be using:

gpio-udp-fig3

Loops and the ESP8266

The first lesson I learned is that you CANNOT have an infinite loop on the ESP8266. Its watchdog timer will catch the loop and restart the MCU. You can get around this by constantly resetting the watchdog timer, but if you do that, then networking will not work. Of course, I learned this via trial and error 🙂

My way of programming the arduino was to use an infinite loop in the loop function about like this:

void loop() {

while (true) {
    <<code>>
    }

That works fine for the Arduino, but not for nodeMCU/LUA. This WILL cause the ESP8266 to reboot.

The Code

In pondering this problem, I decided the best way to proceed for my test program is to set an interrupt on the GPIO pin that is connected to the push button:

gpio.mode(3, gpio.INT, gpio.PULLUP)
gpio.trig(3, 'down', btnINT)

I used a pullup resistor which keeps the signal high. When the button is pressed, it will transition from HIGH to LOW, so ‘down’ will cause the an interrupt when the leading edge of the signal transitions from HIGH to LOW. btnINT is the name of the function that will get called when the interrupt occurs.

Next I setup the LED’s GPIO pin:

gpio.mode(4, gpio.OUTPUT)
gpio.write(4, gpio.LOW)

Then I setup the network connection. I setup a UDP connection. cu:0n indicates that when an incoming packet is received, the rxPkt function will be called. cu:connection indicates that I will be sending to IP addr 192.8.50.106 and port 7 (the echo port).

cu=net.createConnection(net.UDP)
cu:on("receive",rxPkt)
cu:connect(7,"192.8.50.106")

Finally I intialize my ‘global’ variables, of which there is only one in this program:

inInt = false

At the end of that statement, control falls thru back to the underlying software. Now my code only gets called if the button is pressed or an inbound UDP packet occurs.

Here is the function for handling the input GPIO pin:

function btnINT(level)
    if inInt then                   -- don't allow interrupt in interrupt
        return
    else 
        inInt = true
    end
    tmr.delay(100000)               -- 100ms debounce
    cu:send("1234")
    gpio.write(4, gpio.LOW)         -- make sure the LED is off
    inInt = false                   -- all done, allow interrupts again
    end -- btnINT

There are a couple thing of interest here. First, I use inInt to determine if the interrupt is already being processed. I can find no way to turn off interrupts and during testing I found if I pressed the button too fast I would interrupt the interrupt.

Second, I have a 100ms timer to also keep me from pressing the button too fast. It appeared that I would periodically get some bounce as I released the button and fire off a packet when I didn’t mean to. I don’t normally use 100ms to debounce a switch, but my normal 10ms didn’t work well, nor did 50ms.

cu:send sends the actual UDP packet to the echo server with a simple ‘1234’ as the payload.

And, finally, here is the function that is called when an inbound packet is seen:

function rxPkt(cu,c)
    if c == '1234' then
        print('correct response')
        gpio.write(4, gpio.HIGH)
    else
        print('incorrect response')
        end
    end -- rxPkt

‘c’ contains the contents of the UDP packet. I check to see if it is the ‘1234’ I transmitted. If it is, the LED is turned on.

This was a very simple program, but taught me how I need to address future nodeMCU/LUA programs. Now I know to avoid infinite loops and use interrupts (and timers) to fire off my own code.

Here is the sample program in full:

-- interrupt called when button is pressed
function btnINT(level)
    if inInt then                   -- don't allow interrupt in interrupt
        return
    else 
        inInt = true
    end
    tmr.delay(100000)               -- 100ms debounce
    cu:send("1234")
    gpio.write(4, gpio.LOW)
    inInt = false
    end -- btnINT

-- function called when UDP packet received
function rxPkt(cu,c)
    if c == '1234' then
        print('correct response')
        gpio.write(4, gpio.HIGH)
    else
        print('incorrect response')
        end
    end -- rxPkt

-- setup gpio pins
gpio.mode(3, gpio.INT, gpio.PULLUP)
gpio.trig(3, 'down', btnINT)
gpio.mode(4, gpio.OUTPUT)
gpio.write(4, gpio.LOW)

-- setup UDP port
cu=net.createConnection(net.UDP)
cu:on("receive",rxPkt)
cu:connect(7,"192.8.50.106")

inInt = false
Advertisements
This entry was posted in c-esp8266 and tagged . Bookmark the permalink.

10 Responses to ESP8266 Reading/Writing GPIO and Transmitting/Receiving UDP Packets

  1. Pingback: ESP8266 UDP to/from Raspberry Pi running LUA | Big Dan the Blogging Man

  2. James says:

    Dear Dan,

    Thank you for sharing your work, your site is a valuable resource to me and I’m sure many others.

    I just wanted to know how you are setting up the network connection? Are you making the Wireless LAN connection in the init.lua script then calling your UDP script file using a one-shot timer interrupt?

    Regards,

    James

    • Dan TheMan says:

      Thanks, James.

      Good point, I never really explain the network connection. I’ll put on my todolist to go back and add that.

      For my first ‘experiments’, I made the connection manually, typing in the necessary commands to make the connection. Once made, it was persistent between resets for about 2 weeks before something happened and forced me to do it again.

      In my most recent post, https://bigdanzblog.wordpress.com/2015/04/25/esp8266-and-ds18b20-transmitting-temperature-data/, I explicitly make the connection in the code. I call a initWIFI function which then repeatedly tries until it makes the connection.

      I took the gist of this code from somewhere on the internet, but I’m not sure that I like it. It doesn’t determine if the connection is already good so always reinitializes. I suspect there must be a better way.

  3. Ambro says:

    I do not understand what should I load on the ESP: could you please clarify ?
    Thanks,
    regards,
    iw2fvo@yahoo.com

  4. duncan yun says:

    excellent explanation. keep coming back and find new idea everytime.

  5. Babu says:

    Sir, I am the beginner to this field so, please help me how can i upload .lua code into esp8266-01 wifi module by esplorer ?

  6. Axit says:

    if inInt then — don’t allow interrupt in interrupt
    return
    else
    inInt = true
    end

    I dont understand what this loop does!?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s