Toggle navigation
首页
(current)
问答
文章
话题
商城
登录
注册
8、合宙Air模块Luat开发:基于官方库的二次封装,使串口更加易用
Lua
串口
Air720SL
二次开发
教程
# 目录 [点击这里查看所有博文](https://blog.csdn.net/weixin_44570083/article/details/104285283) # 一、前言 > 每次写博客最痛苦的事情就是把要讲的东西用小白都能听懂的方式描述一遍...
# 目录 [点击这里查看所有博文](https://blog.csdn.net/weixin_44570083/article/details/104285283) > 本系列博客,理论上适用于合宙的Air202、Air268、Air720x、Air720S以及最近发布的Air720U(我还没拿到样机,应该也能支持)。 > 先不管支不支持,如果你用的是合宙的模块,那都不妨一试,也许会有意外收获 我使用的是Air720SL模块,如果在其他模块上不能用,那就是底层core固件暂时还没有支持,这里的代码是没有问题的。例程仅供参考! # 一、前言 > 每次写博客最痛苦的事情就是把要讲的东西用小白都能听懂的方式描述一遍,所以我决定换一种方式来写这篇博客,不扯这些乱七八糟的东西,默认大家都在其他地方了解过什么是串口,这里只教怎么用 * 串口通讯协议简介 > 串口通讯(Serial Communication)是一种设备间非常常用的串行通讯方式,因为它简单便捷,大部分电子设备都支持该通讯方式,电子工程师在调试设备时也经常使用该通讯方式输出调试信息,因为Air720SL自有一个USB端口用于程序下载和log打印,所以这里主要是讲怎么和其他的单片机或者通讯,不建议用来打印调试信息。 * 串口通讯的波特率 > 串口通讯是一种异步通信,异步通讯中由于没有时钟信号,所以两个通讯设备之间需要约定好波特率,即每个码元的长度,以便对信号进行解码。常见的波特率为9600、19200、115200等。 * 通讯的起始和停止信号 > 串口通讯的一个数据包从起始信号开始,直到停止信号结束。数据包的起始信号由一个逻辑 0的数据位表示,而数据包的停止信号可由 0.5、1、1.5或 2 个逻辑 1 的数据位表示,只要双方约定一致即可。 * 数据位长度 > 在数据包的起始位之后紧接着的就是要传输的主体数据内容,也称为有效数据,有效数据的长度常被约定为 5、6、7或 8位长。 * 数据校验 > 在有效数据之后,有一个可选的数据校验位。由于数据通信相对更容易受到外部干扰导致传输数据出现偏差,可以在传输过程加上校验位来解决这个问题。校验方法有奇校验(odd)、偶校验(even)、0校验(space)、1校验(mark)以及无校验(noparity)。在无校验的情况下,数据包中不包含校验位。 > 以上内容引用[开源一小步的ESP32的两个UART实验](https://blog.csdn.net/qq_24550925/article/details/85335709)有兴趣的自行了解 # 二、Air720SL开发板硬件部分 * 查看硬件设计手册能够看到Air720Sl模组一共拥有两个串口,串口2为主串口,串口1为辅助串口 ![在这里插入图片描述](https://img-blog.csdnimg.cn/2020030518115642.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDU3MDA4Mw==,size_16,color_FFFFFF,t_70)![在这里插入图片描述](https://img-blog.csdnimg.cn/20200305181220854.png) * 官方的开发板用了一个开关,使开发板能够很方便的在一个usb口上实现串口1和串口2的切换 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200305184058469.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDU3MDA4Mw==,size_16,color_FFFFFF,t_70) # 三、编写驱动库函数 * 官方的串口驱动库可以通过订阅系统消息,产生中断来实现通知用户已经接收到数据,但是这个通知是硬件FIFO是从空到非空的时候产生中断,如果在中断到来的那一刻立即去读取可能会存在数据读取不完整。 * 串口会存在分包发送的现象,那么就需要用户自己实现整合多个数据包的内容。 * 官方的串口demo也给出了解决方案,就是利用数据包接收超时来判断系统有没有接受到完整的数据包,这样的话串口接收程序就显得比较复杂,用户需要考虑的东西比较多,用起来也不是很方便 > 我这里基于官方的demo进行了二次封装,采用回调通知的方式通知用户接收到了完整的数据包,提供的库函数包内部自整合的超时合包机制,以及延时读取机制,保证在通知用户的时候已经接收到完整的数据(如果出现通讯故障,是没法保证的) ```c --- 模块功能:更加易用的串口 -- @author CX -- @module -- @license MIT -- @copyright CX -- @release 2020.02.13 module(..., package.seeall) require "clib" ------------------------------------------------------------------------------------ -------------------------------函数说明--------------------------------------------- ------------------------------------------------------------------------------------ --[[ * @description: Uart初始化 * @param ----------uart_id {numble} 串口号,可选0,1,2 ----------baud_rate {numble} 波特率,可选1200,2400,4800,9600,10400,14400,19200,28800,38400,57600,115200,230400,460800,921600 ----------data_bits {numble} 数据位,7或8 ----------parity {numble} 校验位,可选uart.PAR_EVEN, uart.PAR_ODD或uart.PAR_NONE ----------stop_bits {numble} 停止位,可选uart.STOP_1,uart.STOP_2 ----------receive_cb {function} 接收到数据回调函数,回调函数参数uid:接收到数据的串口id ---------------------------------------------------------------------str:接收到的完整数据 ---------------------------------------------------------------------len:接收到的数据长度 * @return: 无 function Uart_Init(uart_id, baud_rate, data_bits, parity, stop_bits, receive_cb) ]] --[[ * @description: 串口发送 * @param ----------uart_id {numble} 串口号,可选0,1,2 ----------String {String} 要发送的数据 ----------sent_cb {function} 可选,数据发送成功回调函数,回调函数参数uid:发送成功的串口id, * @return: 无 function Uart_Sent(uart_id, String, sent_cb) ]] --[[ * @description: 串口关闭,释放占用的资源 * @param ----------uart_id {numble} 串口号,可选0,1,2 * @return: 无 function Uart_Close(uart_id) ]] ------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------ -------------------------------下面都不要管了---------------------------------------- ------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------ local Uart_Receive_Data = {} local Uart_Receive_cb = {} local Uart_Sent_cb = {} local Uart_Sent_Busy = {} local function Uart_Receive_timeout(uid) local str = table.concat(Uart_Receive_Data[uid]) if Uart_Receive_cb[uid] then Uart_Receive_cb[uid](uid, str, #str) end end local function Uart_Re_Notice(uid, ulength) Uart_Receive_Data[uid] = {} table.insert(Uart_Receive_Data[uid], uart.read(uid, 1000)) sys.timerStart(Uart_Receive_timeout, 100, uid) end local function Uart_Se_Notice(uid, ulength) Uart_Sent_Busy[uid] = false if Uart_Sent_cb[uid] then Uart_Sent_cb[uid](uid) end log.info("uart" .. uid .. "send done") end --[[ * @description: Uart初始化 * @param ----------uart_id {numble} 串口号,可选0,1,2 ----------baud_rate {numble} 波特率,可选1200,2400,4800,9600,10400,14400,19200,28800,38400,57600,115200,230400,460800,921600 ----------data_bits {numble} 数据位,7或8 ----------parity {numble} 校验位,可选uart.PAR_EVEN, uart.PAR_ODD或uart.PAR_NONE ----------stop_bits {numble} 停止位,可选uart.STOP_1,uart.STOP_2 ----------receive_cb {function} 接收到数据回调函数,回调函数参数uid:接收到数据的串口id ---------------------------------------------------------------------str:接收到的完整数据 ---------------------------------------------------------------------len:接收到的数据长度 * @return: 无 ]] function Uart_Init(uart_id, baud_rate, data_bits, parity, stop_bits, receive_cb) if receive_cb == nil then log.info("CXUART", "Please fill in the receive data callback function!") return false end Uart_Receive_cb[uart_id] = receive_cb Uart_Sent_Busy[uart_id] = false pm.wake("mcuart") uart.setup(uart_id, baud_rate, data_bits, parity, stop_bits, nil, 1) uart.on(uart_id, "receive", Uart_Re_Notice) uart.on(uart_id, "sent", Uart_Se_Notice) end --[[ * @description: 串口发送 * @param ----------uart_id {numble} 串口号,可选0,1,2 ----------String {String} 要发送的数据 ----------sent_cb {function} 数据发送成功回调函数,可选 * @return: 无 ]] function Uart_Sent(uart_id, String, sent_cb) if Uart_Sent_Busy[uart_id] == false then Uart_Sent_Busy[uart_id] = true Uart_Sent_cb[uart_id] = sent_cb uart.write(uart_id, String) else log.info("CXUART", "Device is busy, please try again later") end end --[[ * @description: 串口关闭,释放占用的资源 * @param ----------uart_id {numble} 串口号,可选0,1,2 * @return: 无 ]] function Uart_Close(uart_id) uart.close(uart_id) Uart_Receive_Data[uart_id] = nil Uart_Receive_cb[uart_id] = nil Uart_Sent_Busy[uart_id] = nil Uart_Sent_cb[uart_id] = nil end ``` > 上面直接给出了二次封装的库函数代码,使用者只需要新建一个文件,我这里是新建了一个`CXUART.lua`,具体新建什么文件,看心情自己定,然后将上面的代码全部复制放到文件中保存 # 四、编写测试程序并且下载测试程序到开发板 > 这里我们直接贴出全部代码 ```c --必须在这个位置定义PROJECT和VERSION变量 --PROJECT:ascii string类型,可以随便定义,只要不使用,就行 --VERSION:ascii string类型,如果使用Luat物联云平台固件升级的功能,必须按照"X.X.X"定义,X表示1位数字;否则可随便定义 PROJECT = "UART" VERSION = "0.0.1" require "sys" --加载日志功能模块,并且设置日志输出等级 --如果关闭调用log模块接口输出的日志,等级设置为log.LOG_SILENT即可 require "log" LOG_LEVEL = log.LOGLEVEL_TRACE require "CXUART" local function Test_Task() while true do log.info("Test_Task_run") sys.wait(5000) end end local function MyUart_receive_cb(uid, str, len)--串口接收回调函数 log.info("uart" .. uid .. ":Len:" .. len) log.info("uart" .. uid .. ":str:" .. str) CXUART.Uart_Sent(uid, str)--原封不动返回 end local function user_main() sys.taskInit(Test_Task) sys.wait(5000) CXUART.Uart_Init(1, 9600, 8, uart.PAR_NONE, uart.STOP_1, MyUart_receive_cb) --串口1初始化 CXUART.Uart_Init(2, 115200, 8, uart.PAR_NONE, uart.STOP_1, MyUart_receive_cb)--串口2初始化 end --启动系统框架 sys.taskInit(user_main) sys.init(0, 0) sys.run() ``` > 下载程序需要连同库函数文件一并下载 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200305190517364.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDU3MDA4Mw==,size_16,color_FFFFFF,t_70) # 五、总结 ## 1、我提供的库函数 * `Uart_Init(uart_id, baud_rate, data_bits, parity, stop_bits, receive_cb)`--串口初始化 * `Uart_Sent(uart_id, String, sent_cb)`--串口发送数据 * `Uart_Close(uart_id)`--关闭串口,释放资源 > 不会下载的[点击这里](https://blog.csdn.net/weixin_44570083/article/details/104285283),进去查看我的第二篇博文`2、Air720SL模块Luat开发:第一个Luat的Hello World`里面讲了怎么下载 > 这里只是我的学习笔记,拿出来给大家分享,欢迎大家批评指正,本篇教程到此结束
发表于 2020-03-05 19:42
阅读 ( 2555 )
分类:
默认分类
7 推荐
收藏
你可能感兴趣的文章
13、RDA8910CSDK二次开发:将你的代码藏起来----编译静态库
5385 浏览
6、RDA8910CSDK二次开发:一种新的外设----串口
2057 浏览
3、RDA8910CSDK二次开发:GPIO输入详解
2042 浏览
11、合宙Air模块Luat开发:通过http协议获取天气信息
2433 浏览
10、合宙Air模块Luat开发:JSON字符串的生成与解析
2296 浏览
9、合宙Air模块Luat开发:认识NVS数据管理模块
1997 浏览
相关问题
Air720SL的I2C及I2C2对应设备ID是?如何使用api读写16位地址寄存器
0 回答
模块无法接收到串口数据
0 回答
关于二次开发功能上的咨询
1 回答
请教 air202f模块的串口接收问题,参考的demo完全和我想的不一样,出现一直接收空数据
1 回答
air202,用mqtt协议连接onenet平台(lua)。
1 回答
uart.read()函数能读取16进制数吗?
1 回答
0 条评论
请先
登录
后评论
陈夏
26 篇文章
作家榜
»
技术销售Delectate
43 文章
陈夏
26 文章
国梁
24 文章
miuser
21 文章
晨旭
20 文章
朱天华
19 文章
金艺
19 文章
杨奉武
18 文章
×
发送私信
发给:
内容:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!