I am using a sensor similar to hall effect sensor to count the number of interrupts. After some random time, usually after it has been ON for 1-2 hours it resets and followed by random resets at random intervals.
counter = 0;
sampletime = 0;
lastrisetime = tmr.now()
pin = 2
do
gpio.mode(pin, gpio.INT)
local function rising(level)
-- to eliminate multiple counts during a short period (.5 second) difference is taken
if ((tmr.now() - lastrisetime) > 500000) then
lastrisetime = tmr.now();
end
-- when tmr.now() resets to zero this takes into account that particular count
if ((tmr.now() - lastrisetime) < 0) then
lastrisetime = tmr.now();
end
end
local function falling(level)
if ((tmr.now() - lastrisetime) > 500000) then
-- Only counted when the pin is on falling
-- It is like a sine curve so either the peak or trough is counted
counter = counter + 1;
print(counter)
lastrisetime = tmr.now();
sampletime = lastrisetime;
end
-- when tmr.now() resets to zero this takes into account that particular count
if ((tmr.now() - lastrisetime) < 0) then
lastrisetime = tmr.now();
counter = counter + 1;
print(counter)
end
end
gpio.trig(pin, "up", rising)
gpio.trig(pin, "down", falling)
end
This is the error I get on CoolTerm, also I checked for memory every couple of hours and you can see the results there.
NodeMCU 0.9.6 build 20150704 powered by Lua 5.1.4
> Connecting...
connected
print(node.heap())
22920
> print(node.heap())
22904
> print(node.heap())
22944
> print(node.heap())
22944
> 2. .print(node.heap())
22944
> print(node.heap())
22944
> ∆.)ç˛.䂸 ã ¸#H7.àåË‘
NodeMCU 0.9.6 build 20150704 powered by Lua 5.1.4
> Connecting...
connected
print(node.heap())
21216
> F.)ç˛.¶Ùå¶1.#H .ÊÍ
NodeMCU 0.9.6 build 20150704 powered by Lua 5.1.4
> Connecting...
connected
H!໩.ä‚D.ã ¸å¶H.åb‘
NodeMCU 0.9.6 build 20150704 powered by Lua 5.1.4
> Connecting...
connected
print(node.heap())
22904
> print(node.heap())
21216
>
Thank you for taking the time to read this. Appreciate your input.
Possible watchdog timer issue.
In your interrupt service routine looks like you are waiting too much.
Better to remove timing operations from there, just set a flag and in another loop, check the flag status and complete your timing operations.
NodeMCU 0.9.6 build 20150704 powered by Lua 5.1.4
The first thing really is to use a recent version of the NodeMCU firmware. 0.9.x is ancient, contains lots of bugs and is no longer supported. See here https://github.com/nodemcu/nodemcu-firmware/#releases
lastrisetime = tmr.now()
The real issue is that tmr.now() rolls over at 2147 seconds I believe. I learned about this when I worked on a proper debounce function.
-- inspired by https://github.com/hackhitchin/esp8266-co-uk/blob/master/tutorials/introduction-to-gpio-api.md
-- and http://www.esp8266.com/viewtopic.php?f=24&t=4833&start=5#p29127
local pin = 4 --> GPIO2
function debounce (func)
local last = 0
local delay = 50000 -- 50ms * 1000 as tmr.now() has μs resolution
return function (...)
local now = tmr.now()
local delta = now - last
if delta < 0 then delta = delta + 2147483647 end; -- proposed because of delta rolling over, https://github.com/hackhitchin/esp8266-co-uk/issues/2
if delta < delay then return end;
last = now
return func(...)
end
end
function onChange ()
print('The pin value has changed to '..gpio.read(pin))
end
gpio.mode(pin, gpio.INT, gpio.PULLUP) -- see https://github.com/hackhitchin/esp8266-co-uk/pull/1
gpio.trig(pin, 'both', debounce(onChange))
Related
First time post here, I am new to LUA and have some issues:
I am trying to create a script the outputs the channels from a Keithley Digital Multi-meter to a usb stick . I am able to do this however I would like to have relative time in a readable format stitch to each channel . Using the keithley manual I used the buffer.saveappend syntax to do this but I end up with a TSP run time error
The error received is the following.
TSP>-286, TSP Runtime error: Cannot modify this read-only item.
I have attached my script below:
(1) Keithley DMM6500
(2) Vrpobe (DUT)
(3) Keithley Break Out Board
]]--
--------------------------
--Thermal Couple Reading
--Reset the instrument
reset()
--settimezone("8", "1", "3.3.0/02", "11.2.0/02")
--systemTime = os.time({year = 2022, month = 5, day = 04, hour = 13, min = 49})
--settime(systemTime)
--Establish variables to make a measurement every 60 seconds 1440 times (24 hours).
local scanCnt = 8 * 2 --480 minutes = 8 hours
local chanCnt = 10
local totalRdgs = scanCnt * chanCnt
--Empty the buffer and set it to the capacity calculated by totalRdgs.
defbuffer1.clear()
defbuffer1.capacity = totalRdgs
mybuffer1=dmm.makebuffer(30000, buffer.STYLE_FULL)
mybuffer1.collecttimestamps = 0
mybuffer1.collectsourcevalues = 0
mybuffer1.appendmode = 1
-- Set up the channels to measure voltage and temperature
channel.setdmm("2", dmm.ATTR_MEAS_FUNCTION, dmm.FUNC_AC_VOLTAGE)
channel.setdmm("3", dmm.ATTR_MEAS_FUNCTION, dmm.FUNC_TEMPERATURE)
channel.setdmm("3", dmm.ATTR_MEAS_UNIT, dmm.UNIT_CELSIUS)
channel.setdmm("3", dmm.ATTR_MEAS_NPLC, 1)
channel.setdmm("3", dmm.ATTR_MEAS_DIGITS, dmm.DIGITS_5_5)
channel.setdmm("3", dmm.ATTR_MEAS_TRANSDUCER, dmm.TRANS_THERMOCOUPLE)
channel.setdmm("3", dmm.ATTR_MEAS_THERMOCOUPLE, dmm.THERMOCOUPLE_K)
channel.setdmm("3", dmm.ATTR_MEAS_REF_JUNCTION, dmm.REFJUNCT_EXTERNAL)
channel.setdmm("4:10", dmm.ATTR_MEAS_FUNCTION, dmm.FUNC_RESISTANCE)
channel.setlabel("3", "Thermocouple")
channel.setlabel("2", "SigIn")
channel.setlabel("4", "Ch4")
channel.setlabel("5", "Ch5")
channel.setlabel("6", "Ch6")
channel.setlabel("7", "Ch7")
channel.setlabel("8", "Ch8")
channel.setlabel("9", "Ch9")
channel.setlabel("10", "Ch10")
-- Set up the scan; channel 3 is first available on a 2001-TCSCAN card.
scan.create("2,3,4:10")
scan.scancount = scanCnt
-- Set the amount of time for each scan.
scan.scaninterval =5.0
-- Write the data to a USB flash drive at the end of the scan.
--dmm.appendbuffer("bufferVar","/usb1/Dump_Data.csv", buffer.SAVE_FORMAT_TIME)
--dmm.appendbuffer("debuffer1","/usb1/Dump_Data.csv", buffer.SAVE_FORMAT_TIME)
buffer.saveappend(mybuffer1, "/usb1/Dump_Data.csv", buffer.SAVE_RELATIVE_TIME)
scan.export("/usb1/Dump_Data.csv", scan.WRITE_AFTER_SCAN, buffer.COL_CSV_CHAN_COLS)
trigger.model.initiate()
waitcomplete()
-- Get the data.
printbuffer(l, defbuffer1.n, defbuffer1, mybuffer1)
I am using SIMCOM 5320a chipset
I have a bare bone code with wait() function using os.clock() and a while loop with counter counting up.
However, After counting up to a certain number (around 1 minute), the program crash and the board restart itself.
My question is:
is this violate any rule when using while nest loop like this ?
Is there any replacement for using sleep/wait function in lua. Simcom has vmsleep but it will crash after roughly 7 hours of running.
I have try multiple sleep/wait function
I reduce my code to bare bone in order to debug
function sleep (a)
local sec = tonumber(os.clock() + (a/1000));
while (os.clock() < sec) do
end
end
function main()
local count=0
while (count < 130) do
count = count + 1
print("Nothing yet..".. count .. "\r\n");
sleep(2000)
end
end
main()
I'm attempting to read IR information from a NodeMCU running Lua 5.1.4 from a master build as of 8/19/2017.
I might be misunderstanding how GPIO works and I'm having a hard time finding examples that relate to what I'm doing.
pin = 4
pulse_prev_time = 0
irCallback = nil
function trgPulse(level, now)
gpio.trig(pin, level == gpio.HIGH and "down" or "up", trgPulse)
duration = now - pulse_prev_time
print(level, duration)
pulse_prev_time = now
end
function init(callback)
irCallback = callback
gpio.mode(pin, gpio.INT)
gpio.trig(pin, 'down', trgPulse)
end
-- example
print("Monitoring IR")
init(function (code)
print("omg i got something", code)
end)
I'm triggering the initial interrupt on low, and then alternating from low to high in trgPulse. In doing so I'd expect the levels to alternate from 1 to 0 in a perfect pattern. But the output shows otherwise:
1 519855430
1 1197
0 609
0 4192
0 2994
1 589
1 2994
1 1198
1 3593
0 4201
1 23357
0 608
0 5390
1 1188
1 4191
1 1198
0 3601
0 3594
1 25147
0 608
1 4781
0 2405
1 3584
0 4799
0 1798
1 1188
1 2994
So I'm clearly doing something wrong or fundamentally don't understand how GPIO works. If this is expected, why are the interrupts being called multiple times if the low/high levels didn't change? And if this does seem wrong, any ideas how to fix it?
I'm clearly doing something wrong or fundamentally don't understand how GPIO works
I suspect it's a bit a combination of both - the latter may be the cause for the former.
My explanation may not be 100% correct from a mechanical/electronic perspective (not my world) but it should be enough as far as writing software for GPIO goes. Switches tend to bounce between 0 and 1 until they eventually settle for one. A good article to read up on this is https://www.allaboutcircuits.com/technical-articles/switch-bounce-how-to-deal-with-it/. The effect can be addressed with hardware and/or software.
Doing it with software usually involves introducing some form of delay to skip the bouncing signals as you're only interested in the "settled state". I documented the NodeMCU Lua function I use for that at https://gist.github.com/marcelstoer/59563e791effa4acb65f
-- inspired by https://github.com/hackhitchin/esp8266-co-uk/blob/master/tutorials/introduction-to-gpio-api.md
-- and http://www.esp8266.com/viewtopic.php?f=24&t=4833&start=5#p29127
local pin = 4 --> GPIO2
function debounce (func)
local last = 0
local delay = 50000 -- 50ms * 1000 as tmr.now() has μs resolution
return function (...)
local now = tmr.now()
local delta = now - last
if delta < 0 then delta = delta + 2147483647 end; -- proposed because of delta rolling over, https://github.com/hackhitchin/esp8266-co-uk/issues/2
if delta < delay then return end;
last = now
return func(...)
end
end
function onChange ()
print('The pin value has changed to '..gpio.read(pin))
end
gpio.mode(pin, gpio.INT, gpio.PULLUP) -- see https://github.com/hackhitchin/esp8266-co-uk/pull/1
gpio.trig(pin, 'both', debounce(onChange))
Note: delay is an empiric value specific to the sensor/switch!
I wrote this code to interface the gsm module, can anyone check the code and give me some propositions ?
hex1= '0x1A';
function delay_s(delay)
delay = delay or 1
local time_to = os.time() + delay
while os.time() < time_to do end
end
uart.alt(1);
uart.setup(0, 9600, 8, uart.PARITY_NONE, uart.STOPBITS_1, 1)
uart.write(0,"AT+IPR=9600\n")
for j = 1, 10 do
uart.write(0, "AT\n")
end
delay_s(1000)
uart.write(0, "AT\n")
delay_s(1000)
uart.write(0, 'AT+CSCS="GSM"\n')
delay_s(1000)
uart.write(0, 'AT+CMGF=1\n')
delay_s(1000)
uart.write(0, 'AT+CMGS="+21654102832"\n')
delay_s(1000)
uart.write(0, " Salut tout le mond !!!\n")
delay_s(1000)
uart.write(0, hex1)
delay_s(1000)
This code won't even run on NodeMCU because the standard Lua os.time() will fail since the os module is not available. I suggest you dig into http://nodemcu.readthedocs.io/en/latest/en/lua-developer-faq/#how-is-nodemcu-lua-different-to-standard-lua.
Besides, even if it were available os.time() has 1 second resolution.
The returned value is a number, whose meaning depends on your system. In POSIX, Windows, and some other systems, this number counts the number of seconds since some given start time (the "epoch").
Hence, your delay_s(1000) would delay execution for 1000 seconds. Doing that with busy-waiting is...not optimal.
You probably want to use the tmr module instead.
uart.alt(x);
0 - standard pins
1 - alternate the pins
You havent specify which pins you are gonna use for the communication, or else use uart.alt(0); for standard pins
I'm writing a script in Lua that among many other functions will perform a single loop at a specific time on a specific day. The loop is started when a button is pressed, pondering over this for a while now I have gathered that I will have to check the system time in millis using os.time which in table form can return the date too which is very helpful. The only thing I am stuck with is how to express it, and if it would be possible to include multiple definitions of os.time; so on day (x), loop1 will run and on day (y) loop 2 will occur and so on. I'm most likely over complicating this a lot...
Here's my code so far: (it crashes and burns when called by the button press)
function runiftime()
day1 = a;
day2 = b;
day3 = c;
day4 = d;
status = 0; -- Default status == 0
target = day4;
-- Where a, b, c & d are shown above I would like different os.time outputs which relate to days in the future an example output of os.time is => = os.time() outputs '1384988715'.
repeat
if os.time() == "day1" then
os.execute("Some command");
result = Shell.Execute("Some program", "open", "", "", SW_SHOWNORMAL, false);
status = 1;
end
if os.time() == "day2" then
os.execute("Some command");
result = Shell.Execute("Some program", "open", "", "", SW_SHOWNORMAL, false);
status = 1;
end
if os.time == "day3" then
os.execute("Some command");
result = Shell.Execute("Some program", "open", "", "", SW_SHOWNORMAL, false);
status = 1;
end
if os.time == "day4" then
os.execute("Some command");
result = Shell.Execute("Some program", "open", "", "", SW_SHOWNORMAL, false);
status = 1;
end
if status == 1 then
Input.SetText("feed", "Routine Successful! Waiting for Command...");
else
Input.SetText("feed", "Automated Routine Started! Waiting for OS Clock...");
end
until (os.time == target);
end
I've noticed a few issues with your code. First of all, half the time, you're comparing to os.time which is a function and os.time() which will be a number. Secondly, you're going into an infinite loop with until (os.time == target);, since os.time will never change unless you change it.
Even then, if you were correctly comparing with os.time(), going into an infinite loop to check the time all the time is going to max out CPU usage for the Lua VM, as infinite loops are wont to do. This will probably freeze up the process, which might be what you mean by "crash and burn."
Last but not least, comparing the current time to a time in the future with an == is generally a bad idea, due to the low probability of the condition executing precisely during the exact desired time.
I'd recommend sleeping as long as possible until the earliest task is ready to be carried out. This way, you avoid taking up any unnecessary CPU time with constant polling. From Lua, you could do something like this.
local target = os.time{year = 2013, month = 11, day = 21, hour = 9, min = 30}
local function sleep(s) -- wait for `s` seconds
if type(s) ~= 'number' then
error's is not a number'
elseif s < 1 then
return
end
s = math.floor(s)
-- Windows (delay range limited to 0-9999)
--os.execute('choice /n /d:y /t:' .. math.min(s, 9999) .. ' > NUL')
-- *nix
os.execute('sleep ' .. s)
end
local d
repeat
d = target - os.time()
if d <= 0 then break end
sleep(d) -- sleep for the difference
until false
print'Target time has arrived.'
Ideally, you'd accomplish something like this by having your operating system's scheduler, such as cron on *nix or Task Scheduler on Windows, control the timing of the script's execution. However, if you plan to handle the timing through Lua, have a look through this page in Programming in Lua.
Edit: Making use of our sleep function from last time, we can easily create the foundation for a complete task scheduler in Lua that can handle multiple events with only a few lines of code.
local alarm = {}
local function sort_alarm(a, b) return a.time > b.time end
local function schedule(when, what)
if os.time() <= when then
table.insert(alarm, {time = when, event = what})
table.sort(alarm, sort_alarm)
else -- What to do when a scheduled event is in the past?
what()
end
end
local function run_scheduler()
local d
while #alarm > 0 do
d = alarm[#alarm].time - os.time()
if d <= 0 then
-- Pop the latest alarm from the stack and call it.
table.remove(alarm).event()
else
sleep(d)
end
end
end
-- Schedule some events.
schedule(os.time{year = 2013, month = 11, day = 22, hour = 9}, function()
print'This function runs at a specific point in time.'
end)
schedule(os.time() + 30, function()
print'This function will run 30 seconds from the start of the script.'
end)
schedule(os.time() + 5, function()
print'This function will run 5 seconds from the start of the script.'
schedule(os.time() + 10, function()
print'You can even schedule new functions this way.'
print'This one will run 15 seconds from the start of the script.'
end)
end)
local function repeater()
print'How about a repeating event?'
print'This function will run every 10 seconds.'
schedule(os.time() + 10, repeater)
end
schedule(os.time() + 10, repeater)
-- Start the scheduler loop.
run_scheduler()
-- No more events left at this point, thus the script will end.
In closing, I must note that if you plan to use this seriously, you'll want to replace the sleep function with something more robust in the future. There's a page on the users wiki listing some solutions. I'd say it's easiest to do from LuaJIT using the FFI, if you happen to be using it already.