1、关于GPIO
从实战中开始吧,就让我们利用GPIO2
点亮8266
的一个板载小灯吧。
gpio.mode(4, gpio.OUTPUT)
gpio.write(4, 0)
原理图上是GPIO2
,为什么对应程序要写4
呢?
LUA
固件里面是这样封装的!
IO - Index
与EPS8266 pin
对应关系一览表
2、关于串口
ESP8266
有两个串口,UART0
和UART1
。
由ESP8266 - 12E 规格书<这里, yc6y
>可以知道,
UART0-TXD
在GPIO1
UART1-RXD
在GPIO3
UART1
只有TXD
引脚,在GPIO2
。
print
输出默认用UART0
。
uart.write
输出则可以使用串口0
也可以串口1
,输出前指明即可!
实例:当8266收到数据,就让数据回显!
tmr.alarm(1, 2000, 1, function()
uart.on("data", 0, function(Rec)
uart.write(0, Rec)
end, 0)
end)
实例:
注意,发送命令的时候不要勾选发送新行!
1、H
控制继电器开,L
控制继电器关
继电器在GPIO4
,对应IO-Index
为2
。
gpio.mode(2, gpio.OUTPUT) --设置GPIO模式
tmr.alarm(1, 2000, 0, function() --2s后启动
uart.on("data", 0, function(Rec)
if Rec == 'H' then
gpio.write(2, 1)
print("High")
end
if Rec == 'L' then
gpio.write(2, 0)
print("LOW")
end
uart.write(0, Rec) --回显接收的数据
end, 0)
end)
上面的作为一个实例来控制继电器吸合,当然是没有问题的,接下来我们稍微改动下,把命令从H
改为++H
。
2、++H
控制继电器
gpio.mode(2, gpio.OUTPUT)
tmr.alarm(1, 2000, 0, function()
uart.on("data", 0, function(Rec)
if Rec == '++H' then
gpio.write(2, 1)
print("High")
end
if Rec == '++L' then
gpio.write(2, 0)
print("LOW")
end
uart.write(0, Rec)
end, 0)
end)
理论上可行,但是当我实际真的发送++H
的时候却不行!
你这个时候可以再试一下+++H
的命令,却发现可行!
问题分析
问题出在哪了呢?
这一句uart.on("data", 0, ...
,will receive every char in buffer
当接收到一接收到字符不管多少个,就直接触发回调函数,造成的结果呢,发送一个完整的++H
指令,却被拆分为+
和+H
两个。
这个结论从串口助手打印的回显数据也不能看出。
看串口数据之前,先来了解下print
和uart.write
打印的区别!
print
默认UART0
,不能更换!而uart.write
可以使用UART0
或者UART1
。print
打印数据后会自动加回车换行!而uart.write
不会!
OK,带着上面这两条(主要是第二条)来分析下串口助手打印的信息!
发送++H
串口助手显示
++H
很容易分析出,就是uart.write
把我们输入的命令原封不动的回显过来的!
大概过程:+
触发uart.on
回调函数,都不满足然后用uart.write
(不会自己加回车换行)回显+
,然后接着的+H
也都不满足,就直接回显了+H
。
都是用uart.write
打印的,它们之间自然没有换行了!
也许你有一个问题,为什么第一次只有+一个字符触发,而第二次可以+H两个字符。你可以这样想,uart.on 是一接收到字符就触发,但是第一次触发肯定是一个字符就可以,然后触发要执行回调函数,这段时间完全够剩余数据写入缓冲区,然后再读缓冲区的时候,肯定是截断后的全部数据!
发送+++H
串口助手显示
+High
++H
注意,别自动忽略两条消息不在一行的信息!显然有print
的功劳!
大概过程:+
触发uart.on
回调函数,都不满足然后用uart.write
(不会自己加回车换行)回显出来+
。随后截断剩余数据++H
符合条件,然后执行条件判断print
打印High
(High后加了回车换行!),然后原封不动的数据回显,显然此时的数据是++H
。
问题解决
分析好了问题,自然解决问题相对有点思路了,比如我们这个++H
的指令问题。
No.1
既然uart.on("data", 0, ...
0不行,那换成3不就OK了嘛!接收到三个数据再触发回调!
确实可以,但是程序每次都得事先指定好指令长度,局限性很大!那么有没有一种办法,还是uart.on("data", 0, ...
,然后随意规定指令都可以呢?
of Course
当当当,空闲中断隆重登场!
No.2
ReadCnt = 0
ReadCntCopy = 0
ReadData = nil
ReadDataCopy = nil
gpio.mode(2, gpio.OUTPUT)
tmr.alarm(1, 2000, 0, function() -- 初始化后2s串口进行监听数据
uart.on("data", 0, function(Rec)
ReadData = ReadData..Rec --把接收到的数据连接在一起
ReadCnt = ReadCnt + 1 --记录进入回调函数的次数
end, 0)
end)
tmr.alarm(2, 5, 1, function()
if ReadCnt ~= 0 then
if ReadCnt == ReadCntCopy then
ReadCnt = 0
ReadCntCopy = 0
ReadDataCopy = ReadData
ReadData = ""
if ReadDataCopy == "++H" then
gpio.write(2, 1)
end
if ReadDataCopy == "+L" then
gpio.write(2, 0)
end
else
ReadCntCopy = ReadCnt//只要一赋值就变成了全局变量
end
end
end)
全局变量并未声明,而是直接使用,这个算是LUA
的一个特点吧,但是为了程序的可读性,我们还是进行声明的好!
定时器1还是用来接收数据,但是并不直接处理数据,而是把接收到的数据连接在一起,并记录进入回调函数的次数。
定时器2每隔2S,判断ReadCnt
与 ReadCntCopy
是否相等,一旦相等,就可说明此时一帧数据已经接收完毕,可以进行处理!