跳转至

Uart demo

作者:魏健强

一、串口(UART)概述

UART(Universal Asynchronous Receiver/Transmitter,通用异步收发器)是一种常用的串行通信协议,广泛应用于单片机或各种嵌入式设备之间的通信。以下是 UART 的详细介绍:

1.1 UART 的基本概念

UART 是一种串行通信接口,它允许设备通过串行通信方式发送和接收数据。UART 通信是异步的,这意味着通信双方不需要共享一个时钟信号来同步数据传输。UART 通常用于嵌入式系统中,如微控制器与其他设备之间的数据交换。

1.2 UART 的物理连接

UART 通信通常只需要两条线:一条用于数据的发送(TX),一条用于数据的接收(RX)。此外,还需要一条地线(GND)来提供一个共同的参考电平,确保信号的准确性。在实际连接时,一个设备的 TX 线需要连接到另一个设备的 RX 线,反之亦然,这样才能实现双向通信。

1.3 UART 的数据格式

UART 的数据格式通常包含以下几个部分:

1.3.1 起始位(Start Bit)

  • 起始位是一个逻辑低电平(0),它标志着一个数据字符的开始。在进行数据传输过程中,数据线通常保持为高电平(空闲状态),当有数据要发送时,发送方会将数据线从高电平拉低,维持一个比特时间,这个低电平信号称为起始位。接收方检测到这个低电平后,便开始准备接收后续的数据位。

1.3.2 数据位(Data Bits)

  • 数据位紧跟在起始位之后,包含有实际要传输的数据。数据位的位数可以是 5 - 9 位,具体位数根据实际应用需求和协议约定来确定。
  • 例如,如果使用 8 位数据位,那么它可以表示 256(2⁸)种不同的数据值。对于常见的 ASCII 码字符传输,8 位数据位可以完整地表示一个字符,包括其字节值。

1.3.3 奇偶校验位(Parity Bit,可选)

  • 奇偶校验位用于错误检测。它可以是奇校验或偶校验。如果选择奇校验,发送方会根据数据位中 1 的个数来设置奇偶校验位的值,使得整个数据位(包括奇偶校验位)中 1 的个数为奇数。同样,偶校验则是让 1 的个数为偶数。接收方收到数据后,会根据约定的奇偶校验方式来检查数据的完整性。如果奇偶校验位与数据位的组合不符合约定的奇偶性规则,就认为数据传输过程中可能出现了错误。
  • 例如,假设数据位是 8 位,数据位中有 3 个 1,此时使用偶校验,那么奇偶校验位就设置为 1,使得整个数据(8 位数据位 + 1 位奇偶校验位)有 4 个 1,满足偶校验的要求。

1.3.4 停止位(Stop Bits)

  • 停止位位于数据帧的末尾,是一个或多个逻辑高电平(1)。它用于标志着一个数据字符的结束,并为接收方提供数据恢复时间。停止位的长度可以是 1 位、1.5 位或 2 位,具体取决于选用的 UART 配置。较长的停止位可以为接收方提供更充裕的时间来处理接收到的数据,但对于数据传输速率较高的情况,较短的停止位可以提高数据传输效率。

1.4 UART 的波特率

波特率(Baud Rate)是 UART 通信中最重要的参数之一,它定义了数据传输的速率,即每秒钟传输的位数。常见的波特率值有 300、600、1200、2400、4800、9600、19200、38400、57600、115200 等。波特率必须在通信双方之间进行匹配,否则数据将无法正确传输。

1.5 UART 的信号管脚

UART 的信号管脚主要包括以下几个:

1.5.1 基本信号管脚

  • TX(Transmit):发送数据管脚,用于将数据从发送端传输到接收端。
  • RX(Receive):接收数据管脚,用于接收来自发送端的数据。
  • GND(Ground):地线,用于提供信号的参考电平,确保发送和接收设备之间的电平一致。
  • VCC(Power Supply):电源管脚,为 UART 设备提供直流电源。

二、演示功能概述

本文将演示如何在 Air8000 整机开发板上实现 UART(通用异步收发传输器)的通信。演示功能主要包括以下几个方面:

  1. 初始化 UART:将介绍如何配置 UART 的波特率、数据位、停止位和校验位等参数,并初始化 UART。
  2. 接收数据:将展示如何通过注册接收事件的回调函数接收来自 UART 的数据,并处理接收到的数据。
  3. 发送数据:将介绍如何使用 UART 的 API 接口发送数据,包括发送普通字符串、十六进制数据和 JSON 格式的数据。
  4. 单串口通信:将展示如何在 Air8000 整机开发板上实现单串口通信,包括配置和发送接收数据的步骤。
  5. 单串口大数据通信:将展示如何在 Air8000 整机开发板上实现大数据量的通信,包括配置和发送接收数据的步骤。
  6. 多串口通信:将展示如何在 Air8000 整机开发板上实现多串口通信,包括配置和发送接收数据的步骤。
  7. RS485 通信:将展示如何在 Air8000 整机开发板实现 rs485 通信,包括配置和发送接收数据的步骤。
  8. USB 虚拟串口:将介绍如何在 Air8000 整机开发板上使用 USB 虚拟串口进行通信,包括配置和发送接收数据的步骤。同时,该功能已单独写了一篇文档,可移步此处查看
  9. UART 电平:将介绍 UART 电平的标准和如何在 Air8000 整机开发板上修改 UART 电平。
  10. 串口动态引脚复用:串口 3 功能从 pin38,pin39 和 pin25,pin26 两组引脚复用中动态切换;

通过这些演示,大家可以了解如何在 Air8000 整机开发板上实现 UART 通信,包括初始化、接收和发送数据、以及实现单串口、多串口、rs485 和 USB 虚拟串口通信等。

三、演示硬件环境

参考:硬件环境清单第二章节内容

本文以 Air8000 整机开发板为例进行演示。可通过 淘宝 进行购买。

四、准备软件环境

参考:软件环境清单第二章节内容

  1. 烧录工具:参考 Luatools 工具使用说明

  2. 内核固件文件(底层 core 固件文件):

本demo开发测试时使用的固件为 LuatOS-SoC_V2016_Air8000_1.soc,本demo对固件版本没有什么特殊要求,所以你如果要测试本demo时,可以直接使用最新版本的内核固件;如果发现最新版本的内核固件测试有问题,可以使用我们开发本demo时使用的内核固件版本来对比测试;

  1. 需要烧录的脚本和资源文件:

  2. 脚本和资源文件参考 https://gitee.com/openLuat/LuatOS/tree/master/module/Air8000/demo/uart

  3. lib 脚本文件:使用 Luatools 烧录时,勾选 添加默认lib 选项,使用默认 lib 脚本文件;
  4. 准备好软件环境之后,接下来查看 Air8000 开发板使用说明,烧录项目文件到 Air8000 整机开发板,将本篇文章中演示使用的项目文件烧录到 Air8000 整机开发板中。

五、软硬件资料

5.1 uart 库介绍

5.1.1 主要功能介绍

uart 库即串口操作库,该库为内部库,因此在程序中使用时无需 require 调用。该库主要用于支持 UART(通用异步收发传输)功能,适用于一些嵌入式设备或平台。它使用 C 语言,并结合 Lua 脚本提供了一些 API 供用户方便地控制和操作串口。该库包含如下主要功能:

  • 初始化、配置和管理多个串口设备,包括支持软件 UART。
  • 发送和接收数据,支持串口的基本通信功能。
  • 提供事件回调机制,用户可以注册接收和发送的数据处理函数。
  • 允许用户检查串口的存在以及读取剩余数据缓存的大小。
  • 支持 485 模式的特定操作及其管理。

5.1.2 API 接口介绍

本教程所用 API 接口参考:uart - 串口操作库

5.2 串口接线介绍

Air8000 用户可用 4 个串口,分别为 UART1、UART3、UART11、UART12,UART2在支持GNSS的Air8000型号中被占用了,不支持GNSS的型号可以使用 本文使用 UART1、UART11 进行演示。 特别说明,UART0 和 UART10 分别用于输出 4G 和 WIFI 日志,不能连接任何外设。

5.2.1 串口管脚位置说明

在进行复用之前请先参考:GPIO 使用注意事项 - luatos@Air8000 - 合宙文档中心

Air8000 整机开发板串口管脚位置示意图:

5.2.2 串口接线说明

接下来进行接线操作,Air8000 整机开发板与 MCU/串口板 之间是 TX 接 RX,RX 接 TX,GND 接 GND 。 关于 Air8000 UART 电路说明请参考:Air8000 UART 电路介绍

UART1 接线说明:

Air8000整机开发板
MCU或者串口板
UART1_TXD
UART_RXD
UART1_RXD
UART_TXD
GND
GND

UART2 接线说明:

Air8000整机开发板
MCU或者串口板
CAM_SPI_D1
UART_RXD
CAM_SPI_D0
UART_TXD
GND
GND

485 串口接线说明:

Air8000整机开发板
MCU或者串口板
485-A
485-A
485-B
485-B
GND
GND

串口动态复用接线说明:

第一组串口 3:

Air8000核心板
MCU或者串口板
SPI1_SCLK
UART_RXD
SPI1_MISO
UART_TXD
GND
GND

第二组串口 3:

Air8000核心板
MCU或者串口板
LCD_CS
UART_RXD
LCD_CLK
UART_TXD
GND
GND

六、代码示例介绍

6.1 初始化

6.1.1 单串口

大家任选其中一个就行,本文使用 UART1 串口进行演示。

  • 使用 UART1 串口:
local uartid = 1 -- 使用uart1,可根据实际设备选取不同的uartid

--初始化 参数都可以根据实施情况修改
uart.setup(
    uartid,--串口id
    115200,--波特率
    8,--数据位
    1--停止位
)

6.1.2 多串口

本文以 UART1 串口进行演示.

-- 根据实际设备选取不同的uartid
local uartid1 = 1 -- 第一个串口id
local uartid2 = 2 -- 第二个串口id

-- 初始化第一个串口
uart.setup(
    uartid1,--串口id
    115200,--波特率
    8,--数据位
    1--停止位
)

-- 初始化第二个串口
uart.setup(
    uartid2,--串口id
    115200,--波特率
    8,--数据位
    1--停止位
)

6.1.3 RS485 串口

local uartid = 1        -- 根据实际设备选取不同的uartid
local uart485Pin = 17   -- 用于控制485收发转换的方向转换脚
gpio.setup(16, 1)        --打开电源(开发板485供电脚是gpio16,用开发板测试需要开机初始化拉高gpio16)

-- 初始化串口参数
uart.setup(
    uartid, -- 串口ID
    9600, -- 波特率
    8, -- 数据位
    1, -- 停止位
    uart.NONE, -- 校验位
    uart.LSB, -- 大小端
    1024, -- 缓冲区大小
    uart485Pin, -- 485模式下收发转换脚gpio
    0, -- 485模式下rx方向gpio的电平
    20000 -- 485模式下tx向rx转换的延迟时间
)

6.1.4 USB 虚拟串口

local uartid = uart.VUART_0 -- 使用USB虚拟串口,固定id

--初始化 参数都可以根据实施情况修改
uart.setup(
    uartid,--串口id
    115200,--虚拟串口的波特率选择多少都无所谓
    8,--数据位
    1--停止位
)

6.1.6 动态切换串口引脚复用

log.info("uart", "重新配置uart3到新管脚")
uart.close(uartid)       -- 先关闭串口
pins.setup(38, "GPIO15") -- 把原有的uart改成其他功能, 或者gpio
pins.setup(39, "GPIO14") -- 把原有的uart改成其他功能, 或者gpio
gpio.close(15)           -- 关闭对应的gpio
gpio.close(14)           -- 关闭对应的gpio
pins.setup(25, "UART3_RX") -- 设置新管脚为uart3
pins.setup(26, "UART3_TX") -- 设置新管脚为uart3
uart.setup(uartid,115200,8,1) -- 重新初始化串口
log.info("uart", "uart3重新配置完成")

6.2 注册接收数据的回调函数

uart.on 函数用于注册一个接收事件的回调函数,当指定的串口 uartid 接收到数据时,该回调函数会被自动触发并执行。回调函数通过 uart.on(uartid1, "receive", function(id, len) ... end) 定义,并处理接收到的数据。数据的读取是通过 uart.read() 函数进行的,uart.read() 函数是非阻塞的,它是直接从现有缓存区中直接读取数据。

-- 收取数据会触发回调, 这里的 "receive" 是固定值不要修改。
uart.on(uartid, "receive", function(id, len)
    local s = ""
    repeat
        s = uart.read(id, 128)
        if #s > 0 then -- #s 是取字符串的长度
            -- 关于收发hex值,请查阅 https://doc.openluat.com/article/583
            log.info("uart", "receive", id, #s, s)
            log.info("uart", "receive(hex)", id, #s, s:toHex())   -- 如果传输二进制/十六进制数据, 部分字符不可见, 不代表没收到,可以用以hex格式打印
        end
    until s == ""
end)

使用 zbuff 接收数据:

local rxbuff = zbuff.create(10240) -- 接收数据的zbuff
local function uart_cb(id, len)  -- 串口接收数据回调函数
        while true do
            log.info("uart", "缓冲区", uart.rxSize(id))
            local len = uart.rx(id, rxbuff)
            if len <= 0 then
                break
            end
            log.info("uart", "receive", id, rxbuff:used(), rxbuff:toStr())
            rxbuff:seek(0)
        end
    end

6.3 注册数据发送完成的回调函数

uart.on 函数用于注册一个接收事件的回调函数,当指定的串口 数据发送完成时,该回调函数会被自动触发并执行。回调函数通过 uart.on(uartid1, "sent", function(id) ... end) 定义

local function uart_send_cb(id)
    log.info("uart", id , "数据发送完成回调")
end

6.4 发送数据

本文中字符串编码格式为 UTF-8 编码格式,SSCOM 串口调试工具无法正确显示字符串中的中文,需要注意。

  • 发送普通字符串
uart.write(uartid, "\r\nRDY\r\n模块型号:" .. hmeta.model())
  • 发送十六进制的数据串
uart.write(uartid, string.char(0x55,0xAA,0x4B,0x03,0x86))
  • 通过 zbuff 的方式发送数据
local buff = zbuff.create(1024)
buff:copy(0, "aa:bb:cc:dd, zbuff!")
uart.tx(uartid, buff)
  • 发送 json 格式的数据
local data =
{
    host = "abcdefg.com",
    port = "1883",
    clientID = "c88885",
    username = "user",
    password = "123456",
    ca_self = {ssl=false},
}

local jsondata = json.encode(data)
uart.write(uartid, jsondata)

七、功能验证

7.1 单串口

7.1.1 接线展示

下方为 UART1 的接线图

7.1.2 运行结果展示

7.2 多串口

7.2.1 接线展示

7.2.2 运行结果展示

7.3 RS485 通信

7.3.1 RS485 通信介绍

物联网(IoT)在工业场景中的应用越来越广泛,而 RS485 是一种常见的通信协议,广泛应用于工业自动化和物联网系统中。RS485 是一种串行通信标准,主要用于长距离、多节点通信。适用于工业环境中的传感器、执行器、控制器等设备之间的数据传输,且支持多点通信,可以连接多个设备,实现分布式控制。因为具有较好的抗干扰能力,也很适用于噪声环境下的通信。RS485 支持长距离传输,通常可达 1200 米,适用于工业现场中的远程监控和控制。

RS485 是一种半双工通信协议。半双工通信协议允许数据在两个方向上传输,但同一时间只能在一个方向上传输数据。在 RS485 通信中,当发送数据时,只能发送数据而不能接收数据;当接收数据时,只能接收数据而不能发送数据。

比如:在 RS485 通信中,通常使用一个引脚(如 A 或 RX )作为发送引脚,另一个引脚(如 B 或 TX )作为接收引脚。当发送数据时,发送引脚输出高电平或低电平,接收引脚不工作;当接收数据时,接收引脚输出高电平或低电平,发送引脚不工作。有的也有单独一根线专门用于控制收发逻辑,输出高低电平,负责管理 RS485 的通讯,包括发送、接收、处理错误等数据。

优点

  • 抗干扰能力强:RS485 采用差分信号传输,抗干扰能力强,适用于工业环境中的噪声干扰。
  • 传输距离远:RS485 支持长距离传输,适用于工业现场中的远程监控和控制。
  • 多节点通信:RS485 支持多点通信,可以连接多个设备,实现分布式控制。
  • 兼容性好:RS485 是一种标准化的通信协议,具有较好的兼容性,可以与其他设备进行通信。
  • 成本较低:RS485 模块和电缆的成本相对较低,适用于工业现场中的成本控制。

缺点

  • 信号衰减:随着距离的增加,信号衰减会加剧,影响通信质量。
  • 速率限制:RS485 的传输速率相对较低,通常在 9600bps 到 115200bps 之间,适用于低速数据传输。
  • 电气特性要求:RS485 对电气特性有较高的要求,需要使用特定的电缆和连接器。
  • 布线复杂:RS485 需要使用双绞线进行布线,布线复杂度较高。

7.3.2 接线展示

Air8000 整机开发板的 A 接 USB 转 RS485 的 A,B 接 USB 转 RS485 的 B。

7.3.3 运行结果展示

7.4 单串口,大数据量收发

7.4.1 接线展示

下方为 UART1 的接线图

7.4.2 运行结果展示

7.5 串口动态引脚复用

7.5.1 接线展示

7.4.2 运行结果展示

7.6 USB 虚拟串口

7.6.1 USB 虚拟串口介绍

USB 虚拟串口是一种将 USB 接口转换为串行通信接口的技术。它允许计算机通过 USB 接口与其他设备进行串行通信,如调制解调器、打印机、扫描仪等。USB 虚拟串口通常由一个 USB 转串行适配器和一个驱动程序组成。

并且虚拟串口通常没有波特率要求,因为它们是软件模拟的串行通信接口,不依赖于物理硬件。然而,在实际应用中,虚拟串口仍然需要遵守一些基本的通信协议,比如数据位、停止位和校验位等。

USB 虚拟串口的主要功能包括:

  • 串行通信:USB 虚拟串口可以模拟串行通信接口,实现数据的串行传输。它支持各种串行通信协议,如 RS-232、RS-485 等。
  • 传输可靠:传统的串口连接线容易受到干扰,而 USB 虚拟串口采用的 USB 技术可以更好地抵抗干扰,提高了通信的可靠性。
  • 串行控制:USB 虚拟串口可以控制串行通信参数,如波特率、数据位、停止位、奇偶校验等。它还支持串行通信的流控制和错误处理。
  • 使用方便:USB 虚拟串口无需再使用传统的串口连接线,只需要一个标准的 USB 数据线即可连接计算机和外部设备,使得设备连接更加方便

USB 虚拟串口广泛应用于各种领域,如工业自动化、物联网、智能家居等。它为各种设备提供了便捷的串行通信解决方案,提高了系统的灵活性和可靠性。

7.6.2 虚拟通讯串口-端口位置说明

首先通过带有 DM、DP 的 USB 数据线两端连接 模块 和 Windows10 或者 Windows11 系统的电脑。

然后将模块开机,就可以从电脑的设备管理器中看到端口处多出来 3 个 USB 端口。

找到"USB\VID_19D1&PID_0001&MI_06\7&17910EBA&0&0006"就是用于软件控制串口传输的 USB 虚拟串口。

7.7 UART 电平

7.7.1 UART 电平介绍

UART 电平是指串行通信中使用的电压电平标准。常见的串口电平标准有 RS-232、TTL 和 RS-485 等。

  1. RS-232 电平:RS-232 是一种常用的串口通信标准,它使用负逻辑电平,即逻辑 1 用 -3V 到 -15V 表示,逻辑 0 用 +3V 到 +15V 表示。RS-232 电平适用于短距离、低速率的通信。 2. TTL 电平:TTL(Transistor-Transistor Logic)电平是一种常见的数字电路电平标准,它使用正逻辑电平,即逻辑 1 用 +5V 表示,逻辑 0 用 0V 表示。TTL 电平适用于短距离、高速率的通信。 3. RS-485 电平:RS-485 是一种常用的串口通信标准,它使用差分电平,即逻辑 1 用 +2V 到 +6V 表示,逻辑 0 用 -2V 到 -6V 表示。RS-485 电平适用于长距离、高速率的通信。

在串口通信中,选择合适的电平标准非常重要,它直接影响到通信的可靠性和稳定性。

Air8000 模块的 UART IO 电压为 3.3V,如果不满足使用场景需要更改电压,可以通过软件调用接口

在 luatOS 开发中,开机时通过使用 pm.ioVol() 接口,可以实现更改串口的电压。下面是使用实例:

注意:带有 gnss 定位功能的模块不要修改电压,会影响定位芯片的正常工作

-- pm.ioVol接口第二个参数设置电压范围:(1650~2000,2650~3400) 单位毫伏
-- 接口调用位置可以放到task里面,也可以放在task外面
-- 切换成3.0v
pm.ioVol(pm.IOVOL_ALL_GPIO, 3300)    -- 所有GPIO高电平输出3.0V

-- 切换成1.8v
pm.ioVol(pm.IOVOL_ALL_GPIO, 1800)    -- 所有GPIO高电平输出1.8V

七、总结

本文演示如何在 Air8000 整机开发板上实现 UART(通用异步收发传输器)的通信。

八、常见问题

  1. 串口电平电压过低或过高可能会导致什么问题?

如果电压过低,可能会导致接收器无法正确识别信号,如果过高,可能会导致信号损坏或损坏接收器。 概述:可能会导致串口无法正常通讯,或通讯数据会突然出现乱码,数据错乱等问题。

  1. 有没有推荐的串口设计电路可以作为参考?

有,请跳转至 https://docs.openluat.com/air8000/luatos/hardware/design/uart/ 查看