跳转至内容

Hempl/UART

来自 Wikibooks,开放世界中的开放书籍

通用异步收发传输器电路或简称 UART(发音为“you art”)是用于串行通信的更常见接口之一。一些计算机,例如 IBM PC,使用称为 UART 的集成电路将字符转换为异步串行形式,并从中转换。通过“串行”,我们的意思是数据一次传输一位。

该电路是推荐标准 232(简称 RS-232)的基础,该标准还定义了 IBM PC 中的物理外部 COM 端口。RS-232 的最新修订版是 1997 年完成的 EIA RS-232。

近年来,PC 已经失去了 RS-232 端口(可能只是外部),取而代之的是 USB,但 RS-232 仍在广泛使用,包括许多变体,从工业中使用的 RS-485 到太空站中使用的 SpaceWire。在其更简单的形式中,它目前在嵌入式行业中被广泛采用。

为了更多地了解 UART 电路和 RS-232,让我们回顾一下过去。串行传输历史悠久,诞生于第一台电传打字机 (TTY)。电传打字机从 1914 年一直使用到最近,最后一家生产 TTY 的公司于 1990 年关闭,而据报道它们在最近几年用于航空公司公告,并且使用的许多术语都来自 TTY 世界。例如,Mark 和 Space 是描述电传打字机电路中逻辑电平的术语。波特率或符号率是串行连接的速度,它基于机电电传打字机的速率的倍数。

如今,尽管它在个人电脑中变得越来越不常见,但它仍然是微控制器 (MCU) 上最常见的外设之一,用于与外部设备和系统通信,与板载串行设备通信或在板之间、盒之间或嵌入式板与具有 RS-232 端口的 PC 之间建立连接。

RS-232 全局指定

  • 布线
  • 信号电压
  • 信号功能
  • 信号时序
  • 信息交换协议
  • UART 配置

我们将从微控制器的角度出发,检查以上所有要点。

UART 是一个全双工通信通道,在异步模式下,每条线路在其主要功能方面都独立于其他线路。RX 引脚可以接收数据,而与 TX 引脚的活动无关,反之亦然。

通常,来自微控制器的 UART 线路在 3 线配置(未实现流控制)中标记为 TX、RX、GND(分别表示发送、接收和接地),以及 5 线 TX、RX、GND、RTS、CTS,带有硬件流控制,其中 RTS 代表请求发送,CTS 代表清除发送。

信号被描述为正电压来通信逻辑值 0,称为“Mark”,以及负电压来通信逻辑值 1,称为“Space”。

这些信号的电流和电压通常太弱,无法从微控制器输出,并且标准规定应使用 ±5V 至 ±15V 的电压,导线长度为 10 米,那么如何与输出 ±3V 且电流非常低的 UART 线路接口呢?

Mizar32 的串口 UART 扩展板上的 MAX232 芯片是一个 TTL 到 RS-232 电平转换器,它将电压从 ±3V 提升到 ±15V。

信号时序以波特率衡量,其中二进制通信中一个波特率对应于每秒一位,因此在 9600 波特率下,我们每秒有 9600 位,每个比特的时间范围为 104 μs 1/9600。通常,时钟将以波特率的 16 倍运行,以允许接收器进行中心采样。

数据交换协议非常简单。

数据包以起始位开头,该起始位是逻辑 0,首先发送/接收。在软件方面,此位很重要,因为我们可以轮询 RX 引脚以获取此位,以表明数据包即将到来。数据位或有效负载可能包含或不包含奇偶校验位,然后数据包以逻辑 1、一个或两个停止位结束。

0 开始)
XXXXXXX (7 或 8 位数据)
X 1 个可选的奇偶校验位
1 一个或两个停止位

请注意,字节的最低有效位首先发送,而我们通常将数字的 LSB 写在右侧,因此我们应该从右到左读取它。

关于配置参数,常见配置(通常存储在寄存器中)是 9600/8n1,这意味着对于串行端口:9600 波特率、8 位数据、无奇偶校验位、1 个停止位。显然,两个 UART 都应该以相同的方式配置才能进行通信。

硬件视图

[编辑 | 编辑源代码]

Mizar32 在总线连接器上提供了两个串行端口,UART0 在右侧总线上,UART1 在左侧总线上。UART0 只有数据 (TXD、RXD) 和硬件流控制 (CTS、RTS) 信号,而 UART1 还具有调制解调器控制信号 (DSR、DTR、DCD、RI)。

在 Atmel 文档中,这些被称为“USART”,因为它们也可以被编程为同步模式以用作额外的 SPI 端口。

总线引脚
信号 GPIO 总线引脚 PicoLisp
UART0_RX PA0 BUS4 引脚 3 'PA_0
UART0_TX PA1 BUS4 引脚 4 'PA_1
UART0_RTS PA3 BUS4 引脚 5 'PA_3
UART0_CTS PA4 BUS4 引脚 6 'PA_4
UART1_RX PA5 BUS3 引脚 3 'PA_5
UART1_TX PA6 BUS3 引脚 4 'PA_6
UART1_DCD PB23 BUS3 引脚 5 'PB_23
UART1_DSR PB24 BUS3 引脚 6 'PB_24
UART1_DTR PB25 BUS3 引脚 7 'PB_25
UART1_RI PB26 BUS3 引脚 8 'PB_26
UART1_CTS PA9 BUS3 引脚 9 'PA_9
UART1_RTS PA8 BUS3 引脚 10 'PA_8

RS232/RS485 串口扩展板

[编辑 | 编辑源代码]

扩展串口板有两个拨码开关组,DIP1 和 DIP2,用于在 RS232 和 RS485 模式之间切换。

RS232 模式

[编辑 | 编辑源代码]

如果 DIP1 的所有开关都向上,DIP2 的所有开关都向下,它会将总线信号转换为其 DB9 母头连接器 J7 上的 RS232 电平。此连接器配置为 DCE 设备,这与 PC 串行端口相反,因此与 PC 通信的电缆应在每端连接相同的引脚;不需要空闲调制解调器电缆。将其他 DCE 设备(如调制解调器或 GPS 接收器)连接到它需要互换 TX 和 RX,例如使用空闲调制解调器电缆。

请注意,在串行端口的 1.1.1 版本中,CTS 和 RTS 引脚错误地互换了,因此要获得正确的连接,您需要修改电路板或电缆。但是,eLua 中的硬件流控制尚未工作,因此没有区别;请参阅 问题 #29

信号 总线引脚 UART 模块
修订版 1.0
DB-9F 引脚
UART 模块
修订版 1.1.1
DB-9F 引脚
UART0_RX P5 引脚 3 引脚 3(输入) 引脚 3(输入)
UART0_TX P5 引脚 4 引脚 2(输出) 引脚 2(输出)
UART0_RTS P5 引脚 5 引脚 8(输出) 引脚 7(输出)
UART0_CTS P5 引脚 6 引脚 7(输入) 引脚 8(输入)
GND 各种 引脚 5 引脚 5

RS485 模式

[编辑 | 编辑源代码]

如果 DIP1 的所有开关都向下,DIP2 的所有开关都向上,则电路板的 DB9 连接器将被禁用,并且 RS485 信号将出现在四个螺钉端子上。

此接口允许最多 32 个 RS485 设备连接到同一根电线上,电缆长度最长可达 1200 米,速度为 100 kbit/秒。

目前,Hempl 中不支持 RS485 模式;请参阅 问题 #77

软件视图

[编辑 | 编辑源代码]

简单 I/O

[编辑 | 编辑源代码]

根据您使用的固件,UART0 可能用于 PicoLisp 控制台(配置为 115200 波特率,8 个数据位,1 个停止位,无奇偶校验),并且 PicoLisp 的默认输入和输出文件是控制台,因此像“prinl”和“print”这样的函数可用于在串行端口上输出字符(分别带和不带尾随 CR-LF 换行符)。

在 PicoLisp 中

# Greet the user
(prinl "What's your name? ")
(prinl "Hello, " (setq name (read)) "!")

低级 I/O

[编辑 | 编辑源代码]

UART0 也可以使用更低级的 uart Hempl 模块访问(并且必须访问 UART1),这可以更精细地控制 UART 的行为。

以下示例在 UART0 上设置不同的波特率,并在收到回复字符之前每秒输出两次提示字符。为此,它使用了 setup 函数和 getchar 函数的可选超时参数。

在 PicoLisp 中

# Prompt a 9600 baud serial device until we receive
# a character in reply

(setq
   uartid 0       # Which UART should we be talking on?
   timeout 500000 # Prompt once every half second
   timerid 0      # Use timer 0 to measure the timeout
   prompt "U" )   # The prompt character (0x55 : binary 01010101)

(de get-char-uart ()
   (uart-getchar uartid timeout timerid) )

# Get a character from UART
(setq reply (get-char-uart))

(until (= "" reply)
  (uart-write uartid prompt)
  (setq reply (get-char-uart)) )

请注意:您还可以从我们在 github 上的示例存储库下载上述代码 uart-io.l

硬件流控制

[编辑 | 编辑源代码]

请注意,使用以下方法启用硬件流控制:

(uart-set-flow-control uartid (+ *uart-flow-rts* *uart-flow-cts*) )

尚无法使用。请参阅 问题 #29

输入缓冲区

[编辑 | 编辑源代码]

当 UART 接收字符时,它会记住它,直到您使用 getchar 请求其值。但是,如果在您读取第一个字符之前到达第二个字符,则第一个字符将被遗忘。

您可以通过启用 UART 缓冲区来解决此问题,例如

(uart-setup 1 115200 8 0 1)
(uart-set-buffer 1 1024)

以上配置 UART 1 并为其提供输入缓冲区。这将允许 UART 接收多达 1024 个字符并记住所有这些字符,即使您尚未读取第一个字符(第 1025 个字符将引发错误消息并被遗忘)。

UART 缓冲区大小必须是 2 的幂,即 1、2、4、8、16 等,最大可达 32768 个字符。

某些固件使用 UART0 作为 Alcor6L 控制台。在这种情况下,此 UART 上始终启用缓冲区。

USB CDC 串行端口

[编辑 | 编辑源代码]

Hempl 固件包括模拟 USB 接口上另一个串行端口的软件。您将 Mizar32 的 USB 线缆连接到您的 PC,PC 上会出现一个新的串行端口。在 Linux 下,它称为 /dev/ttyACM0,在 Windows 下,它显示为一个新的“USB 串行端口”。

通常,此虚拟串行端口用作 Hempl 控制台,发送 Hempl 输出和错误消息,并接收用户的键盘输入。

它与物理串行端口略有不同,因为

  • 它比最快的 RS232 串行端口快十倍以上;
  • 它始终实现流控制,确保您不会因超速而丢失任何输出或输入,但如果您的程序产生输出并且没有 PC 连接到 USB 端口,则您的程序将在输出 1 或 2 KB 后冻结;
  • 某些设置(如波特率和停止位)没有区别,因为信号不会通过 RS232 线路传输;
  • 我不知道 Lua 中断是否在 USB 串行端口上工作。

请注意:PicoLisp 目前不支持中断处理。请参阅 问题 #2

波特率精度

[编辑 | 编辑源代码]

下表显示了 Hempl(或 eLua)为最常用的波特率设置的实际波特率

期望 获得 误差
300 300 0%
600 600 0%
1200 1200 0%
2400 2400 0%
4800 4799 -0.02%
9600 9604 +0.04%
19200 19186 -0.07%
31250 31250 0%
38400 38372 -0.07%
57600 57692 +0.07%
115200 114583 -0.5%

劫持串行板的 TX LED

[编辑 | 编辑源代码]

如果未使用 UART0,则可以通过使用 pio.PA_1 作为通用 Mizar32/PIO 输出切换串行板上的 LED:低输出值关闭此 LED,高输出值打开此 LED。

在 PicoLisp 中

# Turn the serial board's TX LED on (a low output lights the LED)
(setq txled 'PA_1)
(pio-pin-setlow txled)              # Prepare "off" as the output value
(pio-pin-setdir *pio-output* txled) # Make the pin a GPIO output, disabling serial port 0

进一步阅读

[编辑 | 编辑源代码]
华夏公益教科书