UART设备
# 简介
串口通讯(Serial Communication)是一种设备间非常常用的串行通讯方式,主要按位(bit)发送和接收字节,典型地,串口用于ASCII码字符的传输。通信使用3根线完成,分别是**地线、发送、接收**。由于串口通信是异步的,端口能够在一根线上发送数据同时在另一根线上接收数据。其他线用于握手,但不是必须的。串口通信最重要的参数是**波特率、数据位、停止位和奇偶校验**。对于两个进行通信的端口,这些参数必须匹配。因为它简单便捷,因此大部分电子设备都支持该通讯方式,电子工程师在调试设备时也经常使用该通讯方式输出调试信息。
---
合宙Cat.1模块UART接口可以作为主器件或从器件,与带外部UART串口的设备进行数据之间的相互通信,进行数据接收和发送,达到相互控制的目的。
-- ---
# UART接口控制
UART的库由底层core实现,相关API接口如下:
|API接口| 描述|
| --- | --- |
|uart.on()| 注册串口的数据接收或发生函数|
|uart.setup()|配置并且打开串口,可设置使用模块的串口ID号,波特率,数据位,奇偶校验位等|
|uart.write()|向串口写字符串或者整型数据|
|uart.read()|从串口读取字符串|
|uart.getchar()|从串口读取单字符|
|uart.close()|关闭uart对应接口|
> 详细的API介绍见[LuatOS-Air core API](https://doc.openluat.com/wiki/21?wiki_page_id=2250 "LuatOS-Air core API")章节
# UART使用示例
UART 的具体使用方式可以参考如下示例代码,示例代码的主要步骤如下:
1. 配置串口参数,即设置与从机或上位机通信一致的波特率、数据位、校验位等。
2. 注册串口数据接收函数,通过uart.on()将用户设计的读取函数注册,串口收到数据后,会以中断方式注册的函数读取数据。
3. 注册串口数据发送函数,当用户调用uart.write()函数发送数据时,将请求一次发送通知函数。
```lua
module(...,package.seeall)
require"utils"
require"pm"
--[[
功能定义:
uart按照帧结构接收外围设备的输入,收到正确的指令后,回复ASCII字符串
帧结构如下:
帧头:1字节,0x01表示扫描指令,0x02表示控制GPIO命令,0x03表示控制端口命令
帧体:字节不固定,跟帧头有关
帧尾:1字节,固定为0xC0
收到的指令帧头为0x01时,回复"CMD_SCANNER\r\n"给外围设备;例如接收到0x01 0xC0两个字节,就回复"CMD_SCANNER\r\n"
收到的指令帧头为0x02时,回复"CMD_GPIO\r\n"给外围设备;例如接收到0x02 0xC0两个字节,就回复"CMD_GPIO\r\n"
收到的指令帧头为0x03时,回复"CMD_PORT\r\n"给外围设备;例如接收到0x03 0xC0两个字节,就回复"CMD_PORT\r\n"
收到的指令帧头为其余数据时,回复"CMD_ERROR\r\n"给外围设备;例如接收到0x04 0xC0两个字节,就回复"CMD_ERROR\r\n"
]]
--串口ID,1对应uart1
--如果要修改为uart2,把UART_ID赋值为2即可
local UART_ID = 1
--帧头类型以及帧尾
local CMD_SCANNER,CMD_GPIO,CMD_PORT,CMD_DATA,FRM_TAIL = 1,2,3,4,string.char(0xC0)
--串口读到的数据缓冲区
local rdbuf = ""
--[[
函数名:parse
功能 :按照帧结构解析处理一条完整的帧数据
参数 :
data:所有未处理的数据
返回值:第一个返回值是一条完整帧报文的处理结果,第二个返回值是未处理的数据
]]
local function parse(data)
if not data then return end
local tail = string.find(data,string.char(0xC0))
if not tail then return false,data end
local cmdtyp = string.byte(data,1)
local body,result = string.sub(data,2,tail-1)
log.info("testUart.parse",data:toHex(),cmdtyp,body:toHex())
if cmdtyp == CMD_SCANNER then
write("CMD_SCANNER")
elseif cmdtyp == CMD_GPIO then
write("CMD_GPIO")
elseif cmdtyp == CMD_PORT then
write("CMD_PORT")
elseif cmdtyp == CMD_DATA then
write("Hello world!")
else
write("CMD_ERROR")
end
return true,string.sub(data,tail+1,-1)
end
--[[
函数名:proc
功能 :处理从串口读到的数据
参数 :
data:当前一次从串口读到的数据
返回值:无
]]
local function proc(data)
if not data or string.len(data) == 0 then return end
--追加到缓冲区
rdbuf = rdbuf..data
local result,unproc
unproc = rdbuf
--根据帧结构循环解析未处理过的数据
while true do
result,unproc = parse(unproc)
if not unproc or unproc == "" or not result then
break
end
end
rdbuf = unproc or ""
end
--[[
函数名:read
功能 :读取串口接收到的数据
参数 :无
返回值:无
]]
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
--[[
函数名:write
功能 :通过串口发送数据
参数 :
s:要发送的数据
返回值:无
]]
function write(s)
log.info("testUart.write",s)
uart.write(UART_ID,s.."\r\n")
end
local function writeOk()
log.info("testUart.writeOk")
end
--保持系统处于唤醒状态,此处只是为了测试需要,所以此模块没有地方调用pm.sleep("testUart")休眠,不会进入低功耗休眠状态
--在开发“要求功耗低”的项目时,一定要想办法保证pm.wake("testUart")后,在不需要串口时调用pm.sleep("testUart")
pm.wake("testUart")
--注册串口的数据接收函数,串口收到数据后,会以中断方式,调用read接口读取数据
uart.on(UART_ID,"receive",read)
--注册串口的数据发送通知函数
uart.on(UART_ID,"sent",writeOk)
--配置并且打开串口
--uart.setup(UART_ID,115200,8,uart.PAR_NONE,uart.STOP_1)
--如果需要打开“串口发送数据完成后,通过异步消息通知”的功能,则使用下面的这行setup,注释掉上面的一行setup
uart.setup(UART_ID,115200,8,uart.PAR_NONE,uart.STOP_1,nil,1)
```
# RS485通信的收发方向控制
可使用uart.set_rs485_oe接口配置此功能。必须先使用setup,并且最后一个参数是1(打开发送完成后的通知功能)例子:
```lua
uart.setup(UART_ID,115200,8,uart.PAR_NONE,uart.STOP_1,nil,1) --必须先使用setup,并且最后一个参数是1(打开发送完成后的通知功能)
uart.set_rs485_oe(UART_ID, pio.P0_18) --仅4G 0013版本之后支持
```
# 硬件流控使用说明
首先要通过uart.setup打开硬件流控功能,第8个参数是打开流控功能
硬件要接RTS,CTS管脚,串口工具要设置为硬件流控模式(>=V3037版本支持)
[uart.setup接口说明](https://doc.openluat.com/wiki/21?wiki_page_id=2250#uartsetup_id_baud_databits_parity_stopbitsmsgmodetxDoneReportflowcontrol__32 "uart.setup接口说明")
[硬件流量详细操作示例](https://doc.openluat.com/share_article/WyeqftFpUbL57 "硬件流量详细操作示例")
```lua
uart.setup(UART_ID,460800,8,uart.PAR_NONE,uart.STOP_1,0,0,1)
```
# 硬件设计
见硬件设计指南 [UART接口 章节](https://hmi.wiki.luatos.com/doc/65042949/e6zPC3k9/po7ZmdZF)