What we want to achieve
Using a nodeMCU ESP8266 development board, a moisture sensor, a Nokia 5110 LED display (with PCD8544 CMOS LCD controller/driver and Lua - we will build a moisture sensor which will:
- Upon startup or reset execute the below only once
- Show welcome screen for three seconds
- average moisture reading using 10 sample reads over 5 seconds while showing the user a "please wait message"
- output average moisture for two minutes
- turn display off
Requirements
- nodeMCU ESP8266 compatible development board
- Display with PCD8544 controller - e.g. Nokia 5110
- nodeMCU firmware with the following modules included: adc,file,gpio,i2c,net,node,spi,tmr,u8g2,uart
- u8g2 configuration - ensure you include your fonts. For the example here we will need the 6x10_tf and 5x8_tf font
- Moisture sensor with
- 3.3V VCC
- GND
- Analog Output with value output representing moisture
- Breadboards and jumper wires
Restrictions
- This tip is focused on Lua and ESP8266
- The pin connections are guaranteed to work with
- our Nokia 5110 displays. Other similar displays might have a different pin layout and you will need to adapt to your specific module.
- our moisture sensor
- The tip uses SPI, hence there might be conflicts if you are using other SPI modules.
- Using a single breadboard might be a bit restrictive due to the width of the nodeMCU. We have used two of our expandable breadboards and connected them together.
How to
We connect the display and moisture sensor to the nodeMCU. See our other tip for more details - click here. There is a small change (for VCC) - see below.
Rather than feeding VCC for display and sensor straight from the 3.3V PIN on the nodeMCU, we will connect those to individual GPIOs.
This will allow us to turn them on and off as needed in preparation of:
- Power saving
- Using more than one analog sensor on the single A0 PIN on the nodeMCU
To read ADC0 (A0), we will need to make sure that the firmware has the adc module include.
Keep in mind that - after the display and sensor is turned off, the nodeMCU board is still "running" and consuming power.
Wiring
Display
PCD8544/LED | ESP8266 |
Pin 1 - RST | D0/GPIO16 |
Pin 2 - CE (CS) | D8/GPIO15 - pull down with 10k resistor to GND |
Pin 3 - DC | D4/GPIO2 |
Pin 4 - DIN | D7/HMOSI (fixed - you can't use a different pin) |
Pin 5 - CLK | D5/HSCLK (fixed - you can't use a different pin) |
Pin 6 - VCC | D1/GPIO5 |
Pin 7 - BL | Not used in this example |
Pin 8 - GND | GND - from Development board |
Moisture Sensor
Sensor | ESP8266 |
VCC | D2 /GPIO4 |
GND | GND - from Development board |
DO | Not used |
AO | A0/ADC0 |
Code
--[[
Moisture Sensor with output to display - PCD8544 (Nokia 5110 LED)
run only once post reset/turn on (init.lua)
- show welcome screen for three seconds
- average moisture using 10 sample reads over 5 seconds, while showing
user a "please wait message"
- output average moisture
Moisture reading to remain on display until device is turned off or
reset button is pressed.
15 November 2018
Author: dante@serveronthemove.com.au
Hardware:
nodeMCU ESP8266(EX) Devkit V3
8 pin Nokia 5110 84x48 display w PCD8544
Moisture sensor with Analog output
Wiring:
PCD8544 -> NodeMCU 8266
1 - RST -> D0/GPIO16
2 - CE (CS) -> D8/GPIO15 - pull down with 10K to GND
3 - DC -> D4/GPIO2
4 - DIN -> D7/HMOSI
5 - CLK -> D5/HSCLK
6 - VCC -> D1/GPIO5
7 - BL -> Not used in this example
8 - GND -> GND
Moisture S -> NodeMCU 8266
VCC -> D2/GPIO4
GND -> GND
AO -> A0/ADC0
nodeMCU Firmware Build
built against the master branch and includes the following modules: adc, file, gpio, i2c, net, node, spi, timer, u8g2, uart, wifi, tls
u8g2 - SPI - pcd8544_84x48 module
u8g2 - fonts: 6x10_tf, 5x8)tf
Note about a few - not so elegant code below.
.. through the code we are using tmr.delay() to wait, before something
else id done. Using tmr.delay is usually not a good idea as nothing
else gets run. Seeing that all we do is a single sensor read, it is
acceptable.
For "parallel" execution this should be implemented with
tmr.alarm()
--]]
-- PIN Variables
PIN_CS = 8 -- GPIO15, pull-down 10k to GND
PIN_DC = 4 -- GPIO2
PIN_RES = 0 -- GPIO16
PIN_LCD = 1 -- GPIO5 - VCC to LCD (turn on/off)
PIN_MOI = 2 -- GPIO4 - VCC to Moisture Sensor (turn on/off)
M_BUS = 1
MOIST_R = 10 -- Number of values from moisture sensor to generate an average
function outputMoistureData()
-- vars we will use
local loop_ctr = 0
local aggregate_reading = 0
-- setup screen with please wait
disp:clearBuffer() -- start with clean buffer
disp:setFont(u8g2.font_6x10_tf) -- set 6x10 font
disp:drawStr(1, 1, "Please wait")
disp:drawStr(1, 9, "Checking Soil")
disp:sendBuffer() -- sent buffer to display
-- turn moisture sensor on
gpio.write(PIN_MOI, gpio.HIGH)
tmr.delay(500 * 1000) -- wait for it to settle
-- take number of readings and provide average
while (loop_ctr < MOIST_R) do
aggregate_reading = aggregate_reading + adc.read(0)
--print("aggregate_reading =" .. aggregate_reading)
loop_ctr = loop_ctr + 1;
-- wait one second (ish) before next reading
tmr.delay(500 * 1000) -- wait for half of a second before next read
end
-- turn moisture sensor off once done (to preserve battery)
gpio.write(PIN_MOI, gpio.LOW)
-- calculate average and print out
disp:clearBuffer() -- start with clean buffer
disp:setFont(u8g2.font_6x10_tf) -- set 6x10 font
disp:drawStr(1, 1, "Soil Moisture")
disp:drawStr(1,12, "..." .. tostring(aggregate_reading/MOIST_R))
disp:sendBuffer() -- sent buffer to display
end
--[[
INITIALISE - Begin
--]]
-- set and init PCD8544 and Moist.Sensor GPIO to output
gpio.mode(PIN_LCD, gpio.OUTPUT)
gpio.write(PIN_LCD, gpio.LOW)
gpio.mode(PIN_MOI, gpio.OUTPUT)
gpio.write(PIN_MOI, gpio.LOW)
-- Initialise PCD8544 module and show welcome screen
gpio.write(PIN_LCD, gpio.HIGH)
spi.setup(M_BUS, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 8)
disp = u8g2.pcd8544_84x48(M_BUS, PIN_CS, PIN_DC, PIN_RES)
disp:setFontRefHeightExtendedText()
disp:setContrast(125)
disp:setFontPosTop()
-- start welcome screen
disp:clearBuffer() -- start with clean buffer
disp:setFont(u8g2.font_6x10_tf) -- set 6x10 font
disp:drawStr(1, 1, "Moisture")
disp:drawStr(1, 9, "Sensor V 1.0")
disp:drawStr(2, 17, "by SOTM")
disp:sendBuffer() -- sent buffer to display
--[[
INITIALISE - End
--]]
-- show moisture sensor data after 5 secs
--tmr.alarm( 0, 3000, tmr.ALARM_SINGLE,
tmr.delay(3000 * 1000) -- wait for three seconds before sensor read
outputMoistureData()
-- wait for 2 minutes and then turn LCD off
tmr.delay(2 * 60 * 1000 * 1000)
gpio.write(PIN_LCD, gpio.LOW)
-- and done