闲言碎语
nodeMCU是基于esp8266的开源项目,项目组让这个小玩意可以使用Lua脚本语言来开发一些有趣的东西。这里有nodeMCU最新的英文文档。当然,也有中文文档,但不是最新的。从这篇文章起,会花几篇文章来讲讲笔者构建的固件中的模块。从简单的开始说起,今天的主角是tmr模块。这里是英文的API文档,以及对应的C文件。
模块函数
提供API的翻译,只会针对性的说一些文档里面的内容 -.-
模块提供7个静态timer,编号0~6(很快将移除)。也可以使用 .create函数动态创建。tmr模块总共有13的函数。
序号 | 函数名 | 参数 | 返回值 |
---|---|---|---|
1 | tmr.alarm() | id / ref, interval_ms, mode, func | true / false |
2 | tmr.create() | 空 | object |
3 | tmr.delay() | us | nil |
4 | tmr.interval() | id / ref, interval_ms | nil |
5 | tmr.now() | 空 | us |
6 | tmr.register() | id / ref, interval_ms, mode, func | nil |
7 | tmr.softwd() | timeout_s | nil |
8 | tmr.start() | id / ref | true / false |
9 | tmr.state() | id / ref | bool, int / nil |
10 | tmr.stop() | id / ref | true / false |
11 | tmr.time() | 空 | s |
12 | tmr.unregister() | id / ref | nil |
13 | tmr.wdclr() | 空 | nil |
先从简单的函数开始说起,
- .softwd 设置一个软件看门狗,时间参数单位为秒。使用任何负数可以失能。
- .wdclr 喂狗。但是,文档说使用这个功能是错误的。没明白tmr这个看门狗干嘛用的。
- .delay 顾名思义,就是最传统的死循环延时,文档中明确指出不推荐使用!
- tmr.now & tmr.time 都是用来获取系统时间,只是单位不一样。前者是微秒,后者是秒。31位计数器,计满后清零。
- .alarm 就是调用 .register 和 .start 两个函数。
- .interval 修改一个定时器的终止时间,单位ms
- .start 启动或者重启定时器.
- .stop 暂停一个正在运行的定时器,可以使用.start重启。
- .state 返回一个定时器的运行状态(启动or暂停)和模式或者nil。注意,该函数返回的是两个参数。Lua的神奇之处在于,返回值可以是多个。
- .register & .unregister 前者用于注册一个定时器。后者注销一个定时器,如果定时器还在运行会先暂停。
- .create 动态创建一个定时器。
还有,就是mode参数有三种选择。分别是:
- tmr.ALARM_SINGLE 单触发模式,会自动注销定时器;
- tmr.ALARM_SEMI 手动重置模式,可以使用.start重启定时器;
- tmr.ALARM_AUTO 自动重置模式。
接下来,会用几个例子来说tmr模块中的函数应该怎样用。前3个函数忽略掉!首先来看看.alarm是什么效果。
count = 0
function print_count()
count = count + 1
print("count = ", count)
end
tmr.alarm(0, 1000, tmr.ALARM_SINGLE, print_count)
单触发模式
保存上面的代码,会自动把文件传到nodeMCU并执行。可以看到只是输出了一次就停下来了。可以在右边的输入框里面输入
=dofile("tmr_1.lua")
重新执行,引号里面是你刚才保存的文件名。接着,把mode换成
tmr.alarm(0, 1000, tmr.ALARM_SEMI, print_count)
手动重置模式
效果如上图所示,也是输出一次就停了。不过,使用.start(0)可以重启该定时器,并输出累计值。如果在单触发模式使用.start(0)则会返回false,不会有输出累计值。对于,自动重置模式,就不用给例子了,我知道你懂的。不过,你使用自动重置模式后,会发现那累计值的输出根本停不下来。这时候,别忘了,还有.stop可以用哈。一不小心,就说了3个函数了。再来试试看.interval,在右边输入
=tmr.interval(0, 10000)
把自动重置时间调整到10s,如果先前你暂停了定时器,那麻烦先启动一下。
=tmr.state(0)
我们还可以用.state来查询一下定时器的状态。我不会告诉你返回了true跟1的。可能你会有疑问,这样子输指令,哪里是编程。这样做只是要看看效果,Lua是异步的,在接收到一条指令后就会执行。这里把手动输入指令当作一个外部中断就可以了。
接下来用另外一个例子介绍剩下的几个函数
count = 0
timer = tmr.create()
runTime = tmr.time()
tmr.register(timer, 1000, tmr.ALARM_AUTO, function()
local temp = 0
count = count + 1
temp = tmr.time()
print("count&runTime=", count, temp - runTime)
runTime = temp
if(count == 10) then
tmr.interval(timer, 3000)
end
if(count == 20) then
tmr.stop(timer)
print(tmr.state(timer))
print(tmr.unregister(timer))
print(tmr.state(timer))
end
end)
tmr.start(timer)
先使用.create动态创建一个定时器,然后使用.register注册这个定时器,在其回调函数里面使用了.interval调整时间间隔。最后使用.stop和** .unregister**停止、注销这个定时器。这里使用print函数打印查询状态、暂停、注销的返回值。
一点问题
第二个例子中,由于定时器是动态创建的。如果你在这个例子中的定时器没有停下来之前,又send了一次文件,那么恭喜你,你会看到一直有输出。每send一次就动态创建一个定时器。因为count是一个全局变量,一直在+1,count = 20只有一次,也就只有一个定时器会被暂停,其他的定时器则不会。
补充一下Lua语法
- Lua中没有像C语言那样的自增运算符,比如++
- 函数是这样声明的
function 函数名(参数)
干活,干活
return 参数,参数
end
- if 语句是这样子的
if (条件) then
干活,干活
end
网友评论
比如:
tmr.alarm(0, 1000, tmr.ALARM_SINGLE, function)
-- 这里想要延迟一段时间然后执行后面的代码
gpio.write(0, gpio.LOW)
dofile("tmr.lua")
tmr.lua:2: attempt to call field 'create' (a nil value)
stack traceback:
tmr.lua:2: in main chunk
[C]: in function 'dofile'
stdin:1: in main chunk
>
很快将移除? 官方api将移除还是内部系统自动回收?
count = 0
function print_count()
count = count + 1
print("count = ", count)
end
tmr.alarm(0, 1, tmr.ALARM_AUTO, print_count)