Hempl/UART
通用异步收发传输器电路或简称 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
|
扩展串口板有两个拨码开关组,DIP1 和 DIP2,用于在 RS232 和 RS485 模式之间切换。
如果 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 |
如果 DIP1 的所有开关都向下,DIP2 的所有开关都向上,则电路板的 DB9 连接器将被禁用,并且 RS485 信号将出现在四个螺钉端子上。
此接口允许最多 32 个 RS485 设备连接到同一根电线上,电缆长度最长可达 1200 米,速度为 100 kbit/秒。
目前,Hempl 中不支持 RS485 模式;请参阅 问题 #77。
根据您使用的固件,UART0 可能用于 PicoLisp 控制台(配置为 115200 波特率,8 个数据位,1 个停止位,无奇偶校验),并且 PicoLisp 的默认输入和输出文件是控制台,因此像“prinl
”和“print
”这样的函数可用于在串行端口上输出字符(分别带和不带尾随 CR-LF 换行符)。
在 PicoLisp 中
# Greet the user (prinl "What's your name? ") (prinl "Hello, " (setq name (read)) "!")
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 上始终启用缓冲区。
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% |
如果未使用 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
- Atmel AT32UC3A 数据手册 第 26 章:通用同步/异步收发器 (USART)
- eLua 手册的 UART 部分,了解所有
uart.*()
函数的详细信息 - 串行编程