Patrik Thalin
My personal notebook: 3D Printing, Electronics and Software
October 15, 2020
May 13, 2015
Using the ADC on NodeMCU (ESP8266)
The ADC on ESP8266 is poorly documented. It is note even mentioned in the datasheet. I did some measurements with a variable power supply to understand how it works. The experiments are done with the NodeMCU firmware 0.95. File: nodemcu_20150213.bin (link)
What pin is the ADC input?
TOUT on an ESP8266 module.
A0 on a NodeMCU Devkit.
What is the range of the NodeMCU ADC input?
Measured range: 0 - Vdd. (About 3.1 V in this case)
Number of bits: 10 bit (Codes: 0-1024)
Note that the NodeMCU board has a voltage divider on the ADC input. The ESP8266 module it self has 0 - 1.0 V input range.
Readings are done with the command: print(adc.read(0))
0.5 V => 167
1.0 V => 330
1.5 V => 498
2.0 V => 666
2.5 V => 828
3.0 V => 995
3.1 V => 1024 (saturated)
I did a plot of the values and it looks linear.
Do I need to power down WiFi before using the ADC?
There seems that it at least has been a problem in earlier versions of the SDK but I did not have any problems with interference when using WiFi and the ADC at the same time. If you see any issues try to power down the radio with:
wifi.sleeptype(wifi.MODEM_SLEEP)
Can I measure the supply voltage?
It is possible to read the supply voltage. It is done internaly in the chip so thre is no need to connect it to the ADC input. Use the NodeMCU command:
print(node.readvdd33())
for later versions og NodeMCU firmware use:
print(adc.readvdd33())
It returns a value in mV. I got 3123. Be careful to use this call since it is buggy and will cause reboots quite often when called!
What pin is the ADC input?
TOUT on an ESP8266 module.
A0 on a NodeMCU Devkit.
What is the range of the NodeMCU ADC input?
Measured range: 0 - Vdd. (About 3.1 V in this case)
Number of bits: 10 bit (Codes: 0-1024)
Note that the NodeMCU board has a voltage divider on the ADC input. The ESP8266 module it self has 0 - 1.0 V input range.
Readings are done with the command: print(adc.read(0))
0.5 V => 167
1.0 V => 330
1.5 V => 498
2.0 V => 666
2.5 V => 828
3.0 V => 995
3.1 V => 1024 (saturated)
I did a plot of the values and it looks linear.
Do I need to power down WiFi before using the ADC?
There seems that it at least has been a problem in earlier versions of the SDK but I did not have any problems with interference when using WiFi and the ADC at the same time. If you see any issues try to power down the radio with:
wifi.sleeptype(wifi.MODEM_SLEEP)
Can I measure the supply voltage?
It is possible to read the supply voltage. It is done internaly in the chip so thre is no need to connect it to the ADC input. Use the NodeMCU command:
print(node.readvdd33())
for later versions og NodeMCU firmware use:
print(adc.readvdd33())
It returns a value in mV. I got 3123. Be careful to use this call since it is buggy and will cause reboots quite often when called!
May 8, 2015
Power Meter pulse logger with ESP8266 running NodeMCU
This device is installed in my home to monitor the usage of electricity. It counts the pulses from the meter and produces a log file with number of pulses and a time stamp that can later be analyzed. The hardware is quite simple. The NodeMCU development kit board with an ESP8266 running the NodeMCU firmware is connected to a phototransistor with an pull-down resistor. The firmware and my lua script seems stable since it has been running for more than 10 days without problems.
The phototransistor used is PT204-6C. It is aimed at the pulse windows on the power meter.
I also working on a php script that produces a diagram.
Below is the NodeMCU lua code. Pin 1 is set to generate an interrupt on the rising edge. I had some issues with pulses counted multiple times probably due to bounce in the input signal. I have solved this by only inrement the counter if there is a gap of 20 ms or more between interrupts since the pulse is about 10 ms wide. This is done with the method described in my previous post. Every 60 seconds it also loads a webpage with a php script that writes to a log file.
elog.lua
pin = 1
led = 0
min_pw_ms = 20
upload_rate_ms = 60000
pulse_detected = 0
timestamp = 0
counter = 0
conn = nil
gpio.mode(led, gpio.OUTPUT)
gpio.mode(pin, gpio.INT)
gpio.write(led, gpio.LOW)
if not wifi.sta.getip() then
print("Connecting to wifi")
wifi.setmode(wifi.STATION)
wifi.sta.config("net_name","net_pwd")
ip = wifi.sta.getip()
print(ip)
end
function upload()
conn = net.createConnection(net.TCP, 0)
conn:on("receive",
function(conn, payload)
success = true
print(payload)
end)
conn:on("disconnection",
function(conn, payload)
print('\nDisconnected')
end)
conn:on("connection",
function(conn, payload)
print('\nConnected')
conn:send("GET/ logdata.php?"
.."timestamp="..timestamp
.."&key=your-key"
.."&counter="..counter
.." HTTP/1.1\r\n"
.."Host: your_host.com\r\n"
.."Connection: keep-alive\r\n"
.."Accept: */*\r\n"
.."User-Agent: Mozilla/4.0 (compatible; esp8266 Lua; Windows NT 5.1)\r\n"
.."\r\n")
end)
print("Opening port")
conn:connect(80,'your_host.com')
end
function pin1up(level)
pulse_detected = 1
end
function maintask()
print("Counter is:"..counter)
if not wifi.sta.getip() then
print("Connecting to AP, Waiting...")
else
gpio.write(0, gpio.HIGH)
print("Uploading to server...")
upload()
end
end
function pulsetask()
timestamp = timestamp + 1
if pulse_detected == 1 then
counter = counter + 1
pulse_detected = 0
end
end
gpio.trig(pin, "up", pin1up)
tmr.alarm(0, upload_rate_ms, 1, maintask);
tmr.alarm(1, min_pw_ms, 1, pulsetask);
maintask();
led = 0
min_pw_ms = 20
upload_rate_ms = 60000
pulse_detected = 0
timestamp = 0
counter = 0
conn = nil
gpio.mode(led, gpio.OUTPUT)
gpio.mode(pin, gpio.INT)
gpio.write(led, gpio.LOW)
if not wifi.sta.getip() then
print("Connecting to wifi")
wifi.setmode(wifi.STATION)
wifi.sta.config("net_name","net_pwd")
ip = wifi.sta.getip()
print(ip)
end
function upload()
conn = net.createConnection(net.TCP, 0)
conn:on("receive",
function(conn, payload)
success = true
print(payload)
end)
conn:on("disconnection",
function(conn, payload)
print('\nDisconnected')
end)
conn:on("connection",
function(conn, payload)
print('\nConnected')
conn:send("GET/ logdata.php?"
.."timestamp="..timestamp
.."&key=your-key"
.."&counter="..counter
.." HTTP/1.1\r\n"
.."Host: your_host.com\r\n"
.."Connection: keep-alive\r\n"
.."Accept: */*\r\n"
.."User-Agent: Mozilla/4.0 (compatible; esp8266 Lua; Windows NT 5.1)\r\n"
.."\r\n")
end)
print("Opening port")
conn:connect(80,'your_host.com')
end
function pin1up(level)
pulse_detected = 1
end
function maintask()
print("Counter is:"..counter)
if not wifi.sta.getip() then
print("Connecting to AP, Waiting...")
else
gpio.write(0, gpio.HIGH)
print("Uploading to server...")
upload()
end
end
function pulsetask()
timestamp = timestamp + 1
if pulse_detected == 1 then
counter = counter + 1
pulse_detected = 0
end
end
gpio.trig(pin, "up", pin1up)
tmr.alarm(0, upload_rate_ms, 1, maintask);
tmr.alarm(1, min_pw_ms, 1, pulsetask);
maintask();
This is the php script on the server. It has a simple security feature with a secret key to avoid bots bloating the log. The firmaware loads the url:
http://your-host.com/logdata.php?timestamp=1111&key=your-key&counter=8888
The script extracts the parameters from the url and creates an entry in a file. There is a new file create every 24 hour.
logdata.php
<?php
$delim = ", ";
$referer = getenv('HTTP_REFERER');
$timestamp = $_GET['timestamp'];
$counter = $_GET['counter'];
$key = $_GET['key'];
$secret = "your-key";
date_default_timezone_set("Europe/Stockholm");
$entry = date("Y-m-d") . $delim . date("H:i:s") . $delim . $timestamp . $delim . $counter . "\n";
echo $entry;
$file = "datalog_". date("Y-m-d") . ".txt";
if ($key === $secret)
{
echo "Valid key\n";
file_put_contents($file, $entry, FILE_APPEND);
}
else
{
echo "Invalid key\n";
echo $key;
}
?>
$delim = ", ";
$referer = getenv('HTTP_REFERER');
$timestamp = $_GET['timestamp'];
$counter = $_GET['counter'];
$key = $_GET['key'];
$secret = "your-key";
date_default_timezone_set("Europe/Stockholm");
$entry = date("Y-m-d") . $delim . date("H:i:s") . $delim . $timestamp . $delim . $counter . "\n";
echo $entry;
$file = "datalog_". date("Y-m-d") . ".txt";
if ($key === $secret)
{
echo "Valid key\n";
file_put_contents($file, $entry, FILE_APPEND);
}
else
{
echo "Invalid key\n";
echo $key;
}
?>
April 28, 2015
NodeMCU tmr.time() and tmr.now() bugs
The NodeMCU firmware has some nasty bugs in the tmr.time() and tmr.now() functions so don't use them!
From what I have observed in v0.95 and v0.9.6-dev_20150406 the following happens.
tmr.time(), that returns system time in seconds, makes a jump after 25430 seconds (about 7 hours).
25427
25428
25429
25430
27043
27044
27045
27046
27047
tmr.now(), that returns system time in us, does at some point in time freeze and returns the same value for every call.
Theses bugs makes the functions unusable. The bugs seems to originate from the ESP8266 SDK used for the build rather that the implementation of NodeMCU it self. This will probably make it hard to fix. Luckily there is is a workaround since tmr.alarm() works fine. With tmr.alarm() you can easily create your own time measuring function. At least if you are fine with ms resolution. Hers thee code:
perid_ms = 100
timestamp = 0
tmr.alarm(0, period_ms, 1, function()
timestamp = timestamp + 1
end )
Then you can use the variable timestamp in you code to make time measurements.
September 17, 2014
Smartphone Controlled Home
This post describes a low cost open source home automation system that you can build your self. The goal is to use a smartphone as remote controller for your home. The system is based on the openHAB software and MySensors Arduino library.
Home automation enables you to observe and control your home. You can observe temperature, humidity, energy consumption and so on. It will also let you control your lights, media units, window blinds and other objects in your home. You can also create rules based on senors value, time of day or other conditions that will automatically control your home.
Home automation enables you to observe and control your home. You can observe temperature, humidity, energy consumption and so on. It will also let you control your lights, media units, window blinds and other objects in your home. You can also create rules based on senors value, time of day or other conditions that will automatically control your home.
A standard WiFi router is used to connect the smartphone to your local network. The Server (or Controller) is a computer running openHAB runtime core. This is the heart in the system that keeps track of the system. This can be a Window or Linux computer. A Raspberry Pi will do the job. The Gateway (or Access Point) is an Arduino board running the myControler software. The sensor network is a radio network connecting the sensors and the Gateway.
User Interface
Below is a screenshot of the openHAB smart phone user interface. A web browser can also be used.
Security
The openHAB software with enabled encryption and authentication is fairly secure. But the sensor network has very few security features. Since the range of the sensor are limited it should not be a problem unless you live in a densely populated area. I would not connect it to my door lock or something that could cause damage or fire.
References
MySensors - Arduino library for the sensor radio network.
openHAB - Vendor and technology agnostic open source home automation software.
User Interface
Below is a screenshot of the openHAB smart phone user interface. A web browser can also be used.
Security
The openHAB software with enabled encryption and authentication is fairly secure. But the sensor network has very few security features. Since the range of the sensor are limited it should not be a problem unless you live in a densely populated area. I would not connect it to my door lock or something that could cause damage or fire.
References
MySensors - Arduino library for the sensor radio network.
openHAB - Vendor and technology agnostic open source home automation software.
Etiketter:
Arduino,
Home automation,
MySensors,
nRF24L01,
openHAB,
Raspberry Pi
May 20, 2014
Add Verilog files recursively in Altera Quartus II
This post describes how you add multiple Verilog files recursively to your project in Altera Quartus II. If you are using VHDL you can simply change the file matching from "*.v" to "*.vhd*".
Create a file named "addallv.tcl" in your project folder with the contents listed below. Change "myfolder" to the name of the sub-folder below your project folder that contains the files (or folders with files) you would like to add. Run it in the Tcl Console with:
source addallv.tcl
addall.tcl:
package require ::quartus::project
package require fileutil
#addallv.tcl by http://www.thalin.se
set folderName "myfolder"
foreach file [fileutil::findByPattern $folderName *.v] {
puts $file
set_global_assignment -name VERILOG_FILE $file
}
Run the command by typing it in front of tcl> and press return.
Create a file named "addallv.tcl" in your project folder with the contents listed below. Change "myfolder" to the name of the sub-folder below your project folder that contains the files (or folders with files) you would like to add. Run it in the Tcl Console with:
source addallv.tcl
package require ::quartus::project
package require fileutil
#addallv.tcl by http://www.thalin.se
set folderName "myfolder"
foreach file [fileutil::findByPattern $folderName *.v] {
puts $file
set_global_assignment -name VERILOG_FILE $file
}
Hints
You have to enable the the Tcl Console by selecting View -> Utility Windows -> Tcl Console.
Run the command by typing it in front of tcl> and press return.
May 16, 2014
8051 on Altera Cyclone IV
The 8051 microcontroller (aka MCS-51 or 80C51) was develop by Intel in 1980. Still over 30 year later its architecture is widely used. In this post am using the lightweight 8051 compatible core ligth52 from Open Cores on the Altera Cyclone IV TB276 board from my previous posts. This implementation runs the core at 75 MHz. It has some precompiled examples. To develop your own code you need the free SDCC C-compiler.You will also need python. I use python xy.
Download the design adopted to TB276 here.
Resource usage:
Logic elements: 1,239 / 6,272 ( 20 % )
Memory bits: 20,480 / 276,480 ( 7 % )
Embedded Multiplier 9-bit elements: 1 / 30 ( 3 % )
Total PLLs: 1 / 2 ( 50 % )
To get the serial port output I used an FTID cable (3.3 Volt version) with the following connections:
Black to GND
Oragen to pin 7
Yellow to pin 10
Others are unconnected.
Press button Key2 on the board to reset the core and start the output on the serial port. I used RealTerm to capture the output. Settings are 19200,8,N,1
Download the design adopted to TB276 here.
Resource usage:
Logic elements: 1,239 / 6,272 ( 20 % )
Memory bits: 20,480 / 276,480 ( 7 % )
Embedded Multiplier 9-bit elements: 1 / 30 ( 3 % )
Total PLLs: 1 / 2 ( 50 % )
To get the serial port output I used an FTID cable (3.3 Volt version) with the following connections:
Black to GND
Oragen to pin 7
Yellow to pin 10
Others are unconnected.
Press button Key2 on the board to reset the core and start the output on the serial port. I used RealTerm to capture the output. Settings are 19200,8,N,1
Subscribe to:
Posts (Atom)