UART 总线
UART 是一种用于许多设备的常见串行协议。例如,在向你的 ESP 上传二进制文件时 你可能已经使用 UART 来访问芯片。UART(或对 Arduino 而言通常也称为 Serial)通常 由 2 个引脚组成:
- TX:此线路用于向对端的设备发送数据。
- RX:此线路用于从对端的设备接收数据。
请注意,这两个引脚的命名取决于所选的角度,可能会有歧义。例如,
尽管 ESP 可能在引脚 A 上发送(TX)并在引脚 B 上接收(RX)数据,但从其他设备的
角度来看,这两个引脚是交换的(即它在引脚 B 上发送并在引脚 A 上接收)。因此,如果
立即不起作用,你可能需要将两个引脚交换后再试。
此外,每个 UART 总线可以以不同的速度(波特率)运行,因此 ESPHome 需要知道以什么速度
接收/发送数据,这可以通过 baud_rate 选项指定。两种常见的波特率是 9600 和 115200。
在某些情况下只有 TX 或 RX 存在,因为对端的设备只接受数据或只发送数据。
UART 组件可作为 数据包传输组件 的平台,使传感器数据能够通过 UART 总线从一个 ESPHome 节点直接发送到另一个节点。使用 RS485 时,这可以 以多点配置运行。
NOTE
在 ESP32 上,此组件使用硬件 UART 单元,因此非常精确。在 ESP8266 上, ESPHome 必须使用软件实现,因为没有其他硬件 UART 单元可用(除用于 日志记录的单元之外)。因此,ESP8266 上的 UART 数据可能会出现偶尔的数据错误,特别是在 较高波特率下。
NOTE
从 ESPHome 2021.8 开始,ESP8266SoftwareSerial UART 的 write_byte 函数的校验位已修复为正确
反映发送的数据。如果你使用软件 UART 并且有设备
明确检查校验位,这可能会导致意外问题。很可能你需要翻转 YAML 中的 parity 标志。
NOTE
主机平台的 UART 实现不使用 TX 和 RX 引脚,而使用端口名称。
# 示例配置条目uart: tx_pin: GPIOXX rx_pin: GPIOXX baud_rate: 9600-
baud_rate (必选, int): UART 总线的波特率。
-
tx_pin (可选, Pin): ESP 视角下用于发送数据的引脚。使用完整的引脚 模式并将
inverted: true以反相逻辑电平。主机平台不支持。 -
rx_pin (可选, Pin): ESP 视角下用于接收数据的引脚。使用完整的引脚 模式并将
inverted: true以反相逻辑电平。主机平台不支持。 -
flow_control_pin (可选, Pin): 仅限 ESP32。用于硬件 RS485 流控制的引脚。 使用此设置将启用半双工模式。使用完整的引脚 模式并将
inverted: true以反相逻辑电平。 -
port (可选, string): 仅主机平台。要使用的端口的 Unix 风格名称。
-
rx_buffer_size (可选, int): 用于接收 UART 消息的缓冲区大小。如果你使用需要 从 UART 读取大量负载的集成,可以增加此值。默认为
256。 -
rx_full_threshold (可选, int): 仅限 ESP32。收到此数量的字节后,数据将可供处理。 默认值在编译时计算,大约为 10 毫秒(9600 波特约 8 字节,115200 波特约 114 字节)。
-
rx_timeout (可选, int): 仅限 ESP32。此值指定用于确定超时持续时间的字节数。超时的持续时间基于接收此数量字节所需的时间。换言之,对于给定值和波特率,波特率加倍将使超时持续时间减半。超时过去后,数据将可供处理。默认为
2。 -
flush_timeout (可选, Time): 仅限 ESP32。调用
flush()时等待 TX FIFO 排空的最大时间。如果 TX FIFO 在此时间内未排空,flush()返回TIMEOUT结果。未设置时,flush()将无限期等待。 -
data_bits (可选, int): UART 总线上使用的数据位数。选项:5 到 8。默认为 8。
-
parity (可选): UART 总线上使用的校验方式。选项:
NONE、EVEN、ODD。默认为NONE。 -
stop_bits (可选, int): 要发送的停止位数。选项:1、2。默认为 1。
-
id (可选, ID): 如果你需要多个 UART 中心,可手动指定此 UART 中心的 ID。
-
debug (可选, mapping): 用于调试 UART 中心上通信的选项,参见 调试。
硬件 UART
Section titled “硬件 UART”在可能的情况下,ESPHome 将使用 ESP8266 上的硬件 UART 单元进行快速精确的通信。 当硬件 UART 都被占用时,ESPHome 将回退到软件实现,在较高波特率下可能不精确。
UART0(默认情况下)由 logger 组件 使用,使用 tx_pin: GPIO1 和
rx_pin: GPIO3。如果你配置了一个与这些引脚重叠的 UART,你可以与
logger 共享硬件并使其他的可用。如果你已将 logger 配置为使用不同的硬件 UART,则
用于硬件共享的引脚会相应改变。
原始的 ESP32 有三个 UART。ESP32 变体(ESP32-C3、ESP32-S2 等)可能有不同数量的 UART (通常为 2 到 6 个)。任何一对 GPIO 引脚都可以使用,只要它们支持正确的输出/输入模式即可。
ESP8266 有两个 UART;其中第二个仅 TX。只有有限的一组引脚可以使用。UART0 可
以使用 tx_pin: GPIO1 和 rx_pin: GPIO3,或使用 tx_pin: GPIO15 和 rx_pin: GPIO13。UART1 必须
使用 tx_pin: GPIO2。任何其他引脚组合都将导致使用软件 UART。
NOTE
软件 UART 仅在 ESP8266 上可用。ESP32 和变体上不可用。
uart.write 动作
Section titled “uart.write 动作”此 Action 向给定的 UART 总线发送定义的 UART 信号。
on_...: - uart.write: 'Hello World'
# 对于转义字符,必须使用双引号! - uart.write: "Hello World\r\n"
# 原始数据 - uart.write: [0x00, 0x20, 0x42]
# 模板化,返回类型为 std::vector<uint8_t> - uart.write: !lambda return {0x00, 0x20, 0x42};
# 如果需要指定 uart id - uart.write: id: my_second_uart data: 'other data'如果你需要了解通过 UART 总线发送和/或接收的通信情况,可以使用 调试功能。
# 示例配置条目uart: baud_rate: 115200 debug: direction: BOTH dummy_receiver: false debug_prefix: "[MODBUS] " after: delimiter: "\n" sequence: - lambda: UARTDebug::log_string(direction, bytes, debug_prefix);
# 最小配置示例,默认记录十六进制字符串uart: baud_rate: 9600 debug:-
direction (可选, enum): 要调试的通信方向,可选:
RX(接收,传入)、TX(发送,传出)或BOTH。默认为BOTH。 -
debug_prefix (可选, string): 添加到每个调试日志行前面的字符串,用于此 UART 总线。 当多个 UART 总线启用了调试时,有助于在日志中区分它们的输出。默认为
""。 -
dummy_receiver (可选, boolean): 是否启用 dummy receiver 功能。调试器 只会累积 UART 设备组件实际读取或发送的字节。此功能 在你想要调试所有传入通信、而尚未为 UART 总线配置 UART 设备组件 时很有用。这尤其适合开发者。通常你希望将此 选项保持禁用。默认为
false。 -
after (可选, mapping): 调试器累积通信字节。此选项定义何时 触发发布累积的字节。可能的选项有:
-
bytes (可选, int): 累积指定数量的字节后触发。默认为 150。
-
timeout (可选, Time): 在指定超时期间没有看到任何通信后触发, 前提是已累积一个或多个字节。默认为 100ms。
-
delimiter (可选, string 或字节列表): 检测到通信中出现指定的字节序列后触发。
-
-
sequence (可选, Action): 用于发布调试数据的动作。 默认为以十六进制格式记录字节的动作。这些动作可以使用以下变量:
- direction:
uart::UART_DIRECTION_RX或uart::UART_DIRECTION_TX - bytes:
std::vector<uint8_t>,包含累积的字节 - debug_prefix:
StringRef,包含配置的标题(未设置时为字符串"")
日志记录辅助函数
提供了辅助函数,使以各种格式记录调试数据变得容易:
-
UARTDebug::log_hex(direction, bytes, char separator, debug_prefix) 将字节作为十六进制值记录,用提供的 分隔字符分隔。
-
UARTDebug::log_string(direction, bytes, debug_prefix) 将字节作为字符串值记录,转义不可打印的字符。
-
UARTDebug::log_int(direction, bytes, char separator, debug_prefix) 将字节作为整数值记录,用提供的 分隔字符分隔。
-
UARTDebug::log_binary(direction, bytes, char separator, debug_prefix) 将字节作为
<binary> (<hex>)值记录, 用提供的分隔字符分隔。
所有辅助函数中的
debug_prefix参数都是可选的(默认为空)。使用默认sequence时,debug_prefix会自动传递。Logger 缓冲区大小
请注意,
logger组件默认使用 512 字节的有限缓冲区大小。如果 UART 调试器日志行变得太长,你将注意到它们最终在日志输出中被截断。在这种情况下,确保调试器每行输出的数据更少(例如,通过将
after.bytes选项设置为较低的值),或使用 logger 的tx_buffer_size选项增加 logger 缓冲区大小。 - direction:
在运行时更改
Section titled “在运行时更改”在某些场景中,你可能需要在运行时调整 UART 参数,以提高通信效率 并适应不同的运行条件。ESPHome 通过 lambda 调用来实现这一点。 以下是读取当前设置和动态修改它们的方法:
- 读取当前设置: 使用这些只读属性访问 UART 的当前配置:
// RX 缓冲区大小 id(my_uart).get_rx_buffer_size(); // RX FIFO 满阈值 id(my_uart).get_rx_full_threshold(); // RX 超时 id(my_uart).get_rx_timeout(); // 停止位 id(my_uart).get_stop_bits(); // 数据位 id(my_uart).get_data_bits(); // 校验 id(my_uart).get_parity(); // 波特率 id(my_uart).get_baud_rate();- 在运行时修改设置: 你可以在运行时更改某些 UART 参数。
设置新值后,调用
load_settings()(仅限 ESP)以应用这些更改:
select: - id: change_baud_rate name: Baud rate platform: template options: - "2400" - "9600" - "38400" - "57600" - "115200" - "256000" - "512000" - "921600" initial_option: "115200" optimistic: true restore_value: True internal: false entity_category: config icon: mdi:swap-horizontal set_action: - lambda: |- id(my_uart).flush(); uint32_t new_baud_rate = stoi(x); ESP_LOGD("change_baud_rate", "Changing baud rate from %i to %i",id(my_uart).get_baud_rate(), new_baud_rate); if (id(my_uart).get_baud_rate() != new_baud_rate) { id(my_uart).set_baud_rate(new_baud_rate); id(my_uart).load_settings(); }用于运行时更改的可用方法:
// 设置 TX/RX/流控制引脚 id(my_uart).set_tx_pin(InternalGPIOPin *tx_pin); id(my_uart).set_rx_pin(InternalGPIOPin *rx_pin); id(my_uart).set_flow_control_pin(InternalGPIOPin *flow_control_pin); // RX 缓冲区大小 id(my_uart).set_rx_buffer_size(size_t rx_buffer_size); // RX FIFO 满阈值(以字节为单位) id(my_uart).set_rx_full_threshold(size_t rx_full_threshold); // RX FIFO 满阈值(以时间单位) id(my_uart).set_rx_full_threshold_ms(uint8_t time); // RX 超时 id(my_uart).set_rx_timeout(size_t rx_timeout); // 刷新超时(仅限 ESP32;0 = 无限期等待) id(my_uart).set_flush_timeout(uint32_t flush_timeout_ms); // 停止位 id(my_uart).set_stop_bits(uint8_t stop_bits); // 数据位 id(my_uart).set_data_bits(uint8_t data_bits); // 校验 id(my_uart).set_parity(UARTParityOptions parity); // 波特率 id(my_uart).set_baud_rate(uint32_t baud_rate);这种灵活性允许对不同通信需求进行动态适应,增强了 ESPHome 设置的多功能性。
主机平台上的 UART 组件
Section titled “主机平台上的 UART 组件”由于主机平台没有物理 UART 引脚,UART 组件使用 Unix 风格端口实现。
你可以指定要使用的端口名称,而不是使用引脚。此实现还支持包含
require_tx 和 require_rx 选项的组件,例如 smt100 等。
# 主机平台的示例配置条目uart: baud_rate: 9600 port: "/dev/ttyUSB0"