Toggle navigation
首页
(current)
问答
文章
话题
商城
登录
注册
Luat系列教程:7、串口收发
LUAT
教程
串口
阅读本文需要具有的技能:看过该系列前几篇文章或明白前几篇文章内容的可以明白字符串、字节码之间的区别了解串口的原理和使用 其实串口这个部分,我觉得挺简单的,看demo都能看懂吧。。 官方...
>阅读本文需要具有的技能: 看过该系列前几篇文章或明白前几篇文章内容的 可以明白字符串、字节码之间的区别 了解串口的原理和使用 其实串口这个部分,我觉得挺简单的,看demo都能看懂吧。。 # 官方demo代码 官方代码可以在github(https://github.com/openLuat/Luat_2G_RDA_8955/)的`Luat_2G_RDA_8955/script_LuaTask/demo/uart`目录或luatools的`LuaTools 1.x.x\script\script_LuaTask\demo\uart`目录找到 如果你能看懂官方例程,**那么可以直接去使用,不需要再看本文了** # 先定义一个假装能用来测试的串口收发规则 - 串口通讯使用9600波特率,3.3V ttl电平 - 模块开机第10秒后,向设备发送`0x01 0x02 0x03`三个字节 - 模块收到`qwerty`字符串后,回复`asdfgh`字符串 - 模块收到`0xaa 0xbb 0xcc`三个字节后,回复`0xdd 0xee 0xff`三个字节 - 模块收到`abcdefghijklmnopqrstuvwxyz`字符串后,回复`ok`字符串 # 建立文件结构 测试需要新建两个文件,`main.lua`和`testuart.lua` `main.lua`在前面的文章中,已经新建过大概不下四次了,所以这里不再举例。`main.lua`需要`require"testuart"` testuart.lua ```lua module(...,package.seeall) require"utils" require"pm" --串口ID,1对应uart1 --如果要修改为uart2,把UART_ID赋值为2即可 local UART_ID = 1 --保持系统处于唤醒状态,此处只是为了测试需要,所以此模块没有地方调用pm.sleep("testUart")休眠,不会进入低功耗休眠状态 --在开发“要求功耗低”的项目时,一定要想办法保证pm.wake("testUart")后,在不需要串口时调用pm.sleep("testUart") pm.wake("testUart") --配置并且打开串口 uart.setup(UART_ID,9600,8,uart.PAR_NONE,uart.STOP_1) ``` 可以看到,uart文件中已经配置好了串口 # 发送串口信息 发送接口特别简单,只需要调用`uart.write()`函数即可,我们可以在设置唤醒状态代码前面加上发送函数: ```lua --发送串口数据 function write(s) log.info("testuart.write",s:toHex(),s) uart.write(UART_ID,s) end ``` # 接收串口信息 为了能接收到串口消息,我们在`配置并且打开串口`函数的上方注册串口接收函数: ```lua --注册串口的数据接收函数,串口收到数据后,会以中断方式,调用read接口读取数据 uart.on(UART_ID,"receive",read) ``` 并在发送函数上方新建接收函数: ```lua --接收串口数据 local function read() local data = "" --底层core中,串口收到数据时: --如果接收缓冲区为空,则会以中断方式通知Lua脚本收到了新数据; --如果接收缓冲器不为空,则不会通知Lua脚本 --所以Lua脚本中收到中断读串口数据时,每次都要把接收缓冲区中的数据全部读出,这样才能保证底层core中的新数据中断上来,此read函数中的while语句中就保证了这一点 while true do data = uart.read(UART_ID,"*l") --数据不存在时停止接收数据 if not data or string.len(data) == 0 then break end --打开下面的打印会耗时 log.info("testUart.read bin",data) log.info("testUart.read hex",data:toHex()) --真正的串口数据处理函数 proc(data) end end ``` 我们可以看到,所有串口数据都交给了`proc()`函数进行处理,我们可以在接收函数上方新建一个`proc()`函数: ```lua --处理串口数据 local function proc(data) --todo end ``` # 实现功能 ## 模块开机第10秒后,向设备发送`0x01 0x02 0x03`三个字节 实现这个功能,我们只需要在文件末尾加上一个定时器即可: ```lua --模块开机第10秒后,向设备发送`0x01 0x02 0x03`三个字节 sys.timerStart(function() write(string.fromHex("010203")) end,10000) ``` ## 模块收到`qwerty`字符串后,回复`asdfgh`字符串 处理这个信息,可以去`proc()`函数里进行修改,将函数更改为如下形式: ```lua --处理串口数据 local function proc(data) if data == "qwerty" then --模块收到`qwerty`字符串后,回复`asdfgh`字符串 write("asdfgh") end end ``` ## 剩下两个需求 剩下两个需求处理起来和前面一样,我们直接仿照着改就行: ```lua --处理串口数据 local function proc(data) if data == "qwerty" then --模块收到`qwerty`字符串后,回复`asdfgh`字符串 write("asdfgh") elseif data == string.fromHex("AABBCC") then --模块收到`0xaa 0xbb 0xcc`三个字节后,回复`0xdd 0xee 0xff`三个字节 write(string.fromHex("DDEEFF")) elseif data == "abcdefghijklmnopqrstuvwxyz" then --模块收到`abcdefghijklmnopqrstuvwxyz`字符串后,回复`ok`字符串 write("ok") end end ``` # 测试 这个测试需要大家自己去测试了 测试结果会发现,第三条指令无法完成。为什么呢?因为串口会有截断现象。 # 处理串口数据截断问题 串口数据接收经常会出现的一个问题:数据被截断 这个现象很常见,你可以像普通单片机一样一个字节一个字节去解析,也可以加一个缓冲区定时清空处理 我们首先在`proc()`函数上方,新建一个缓冲区: ```lua local buf = "" ``` 然后可以把`proc()`函数改造成下面这样: ```lua --缓存数据 local buf = "" --处理串口数据 local function proc(data) data = buf..data log.info("testUart.read proc",data) local used = true--数据是否被处理? if data == "qwerty" then --模块收到`qwerty`字符串后,回复`asdfgh`字符串 write("asdfgh") elseif data == string.fromHex("AABBCC") then --模块收到`0xaa 0xbb 0xcc`三个字节后,回复`0xdd 0xee 0xff`三个字节 write(string.fromHex("DDEEFF")) elseif data == "abcdefghijklmnopqrstuvwxyz" then --模块收到`abcdefghijklmnopqrstuvwxyz`字符串后,回复`ok`字符串 write("ok") else --数据没匹配上任何东西,没被使用 used = false end if not used then--数据没被使用 if buf == "" then--如果缓冲区是空的 sys.timerStart(function() buf = "" end,500)--500ms后清空缓冲区 end buf = data--数据追加到缓存区 else buf = "" end end ``` 函数中首先判断数据是否被使用,如果没被使用,就将数据追加到缓冲区,如果已被使用,缓冲区内容会被清除 # 完整代码 经过一系列修改,`testuart.lua`整体代码如下: ```lua module(...,package.seeall) require"utils" require"pm" --串口ID,1对应uart1 --如果要修改为uart2,把UART_ID赋值为2即可 local UART_ID = 1 --缓存数据 local buf = "" --处理串口数据 local function proc(data) data = buf..data log.info("testUart.read proc",data) local used = true--数据是否被处理? if data == "qwerty" then --模块收到`qwerty`字符串后,回复`asdfgh`字符串 write("asdfgh") elseif data == string.fromHex("AABBCC") then --模块收到`0xaa 0xbb 0xcc`三个字节后,回复`0xdd 0xee 0xff`三个字节 write(string.fromHex("DDEEFF")) elseif data == "abcdefghijklmnopqrstuvwxyz" then --模块收到`abcdefghijklmnopqrstuvwxyz`字符串后,回复`ok`字符串 write("ok") else --数据没匹配上任何东西,没被使用 used = false end if not used then--数据没被使用 if buf == "" then--如果缓冲区是空的 sys.timerStart(function() buf = "" end,500)--500ms后清空缓冲区 end buf = data--数据追加到缓存区 else buf = "" end end --接收串口数据 local function read() local data = "" --底层core中,串口收到数据时: --如果接收缓冲区为空,则会以中断方式通知Lua脚本收到了新数据; --如果接收缓冲器不为空,则不会通知Lua脚本 --所以Lua脚本中收到中断读串口数据时,每次都要把接收缓冲区中的数据全部读出,这样才能保证底层core中的新数据中断上来,此read函数中的while语句中就保证了这一点 while true do data = uart.read(UART_ID,"*l") --数据不存在时停止接收数据 if not data or string.len(data) == 0 then break end --打开下面的打印会耗时 log.info("testUart.read bin",data) log.info("testUart.read hex",data:toHex()) --真正的串口数据处理函数 proc(data) end end --发送串口数据 function write(s) log.info("testuart.write",s:toHex(),s) uart.write(UART_ID,s) end --保持系统处于唤醒状态,此处只是为了测试需要,所以此模块没有地方调用pm.sleep("testUart")休眠,不会进入低功耗休眠状态 --在开发“要求功耗低”的项目时,一定要想办法保证pm.wake("testUart")后,在不需要串口时调用pm.sleep("testUart") pm.wake("testUart") --注册串口的数据接收函数,串口收到数据后,会以中断方式,调用read接口读取数据 uart.on(UART_ID,"receive",read) --配置并且打开串口 uart.setup(UART_ID,9600,8,uart.PAR_NONE,uart.STOP_1) --模块开机第10秒后,向设备发送`0x01 0x02 0x03`三个字节 sys.timerStart(function() write(string.fromHex("010203")) end,10000) ``` # 最终测试 ## 开机后发送第10秒后,向设备发送`0x01 0x02 0x03`三个字节 [![](http://oldask.openluat.com/image/show/attachments-2018-08-h6c1Ry575b83d1f881377.png)](http://oldask.openluat.com/image/show/attachments-2018-08-h6c1Ry575b83d1f881377.png) ## 模块收到`qwerty`字符串后,回复`asdfgh`字符串 [![](http://oldask.openluat.com/image/show/attachments-2018-08-8C3gKORM5b83d20424635.png)](http://oldask.openluat.com/image/show/attachments-2018-08-8C3gKORM5b83d20424635.png) ## 模块收到`0xaa 0xbb 0xcc`三个字节后,回复`0xdd 0xee 0xff`三个字节 [![](http://oldask.openluat.com/image/show/attachments-2018-08-BHAKGyl75b83d2113fe0c.png)](http://oldask.openluat.com/image/show/attachments-2018-08-BHAKGyl75b83d2113fe0c.png) ## 模块收到`abcdefghijklmnopqrstuvwxyz`字符串后,回复`ok`字符串 [![](http://oldask.openluat.com/image/show/attachments-2018-08-3zcu6OmM5b83d21d27912.png)](http://oldask.openluat.com/image/show/attachments-2018-08-3zcu6OmM5b83d21d27912.png)
发表于 2018-08-27 18:26
阅读 ( 14265 )
分类:
默认分类
10 推荐
打赏
收藏
你可能感兴趣的文章
6、RDA8910CSDK二次开发:一种新的外设----串口
2057 浏览
10、合宙Air模块Luat开发:JSON字符串的生成与解析
2296 浏览
9、合宙Air模块Luat开发:认识NVS数据管理模块
1997 浏览
8、合宙Air模块Luat开发:基于官方库的二次封装,使串口更加易用
2554 浏览
7、合宙Air模块Luat开发:定时器的使用方法
2137 浏览
X、合宙Air模块Luat开发:全网首发,通过iic直接驱动OLED,720Sl开始有显时代
2733 浏览
相关问题
模块无法接收到串口数据
0 回答
请教 air202f模块的串口接收问题,参考的demo完全和我想的不一样,出现一直接收空数据
1 回答
uart.read()函数能读取16进制数吗?
1 回答
Air208编程
1 回答
Air202设置闹钟“AT+CALA=?”
2 回答
Air202 MQTT如何发送USERNAME PASSWORD ID ?
1 回答
0 条评论
请先
登录
后评论
晨旭
菜鸟
20 篇文章
作家榜
»
技术销售Delectate
43 文章
陈夏
26 文章
国梁
24 文章
miuser
21 文章
晨旭
20 文章
朱天华
19 文章
金艺
19 文章
杨奉武
18 文章
×
发送私信
发给:
内容:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!