UART
1. UART 简介
UART(Universal Asynchronous Receiver-Transmitter,通用异步收发器)是一种广泛应用于嵌入式系统和计算机之间的串行通信协议。UART 通过将数据一位一位地传输,采用异步通信方式,数据传输和接收之间无需共享时钟信号。这使得UAR T成为短距离低速设备之间数据传输的常用选择。在 Linux 系统中通常被注册为串口终端设备。这些串口设备在 Linux 系统中以/dev/tty*或/dev/serial/*的形式出现,具体设备名取决于硬件和驱动程序的设置。
2. 串口引脚图
-
在 Omni3576 中,UART0_M0 被指定为调试串口(有关调试串口的使用方法,请参考《登录》章节中的“串口登录”部分),调试串口的接口位置如图:

-
Omni3576 引脚图:

3. 串口测试(shell)
-
以 UART2_M1 为例,打开成功后,我们使用命令查看 UART2_M1:
root@luckfox:/home/luckfox# ls /dev/ttyS*/dev/ttyS2 /dev/ttyS4 -
用 stty 工具查询其通信参数:
root@luckfox:/home/luckfox# stty -F /dev/ttyS2speed 9600 baud; line = 0;-brkint -imaxbel -
修改波特率,其中i speed 为输入速率,ospeed 为输出速率:
stty -F /dev/ttyS2 ispeed 115200 ospeed 115200 -
关闭回显:
stty -F /dev/ttyS2 -echo
3.1 与Windows主机通讯
-
将串口转 TTL 模块一端连接电脑,另一端连接 Omni3576 开发板的引脚6(GND)、8(UART2_TX)和10(UART2_RX)上。
-
下载并打开 MobaXterm,选择串口,设置波特率(默认为9600,请根据自己实际修改过的数值设置)。

-
在开发板上的终端执行以下指令,使用 echo 命令向终端设备文件写入字符串"Hello"和"world !":
echo Hello > /dev/ttyS2echo "world !" > /dev/ttyS2 -
Windows 上的串口调试助手会接收到内容:

4. 串口通信(Python程序)
-
使用 Python 的
serial库,实现收发数据的完整代码如下:#!/usr/bin/python3from periphery import Serial# 使用上下文管理器,自动关闭串口with Serial("/dev/ttyS3", baudrate=115200, databits=8, parity="none", stopbits=1, xonxoff=False, rtscts=False) as serial:try:# 发送数据serial.write(b"Hello World!\n")# 读取数据buf = serial.read(128, 1)if buf:data_string = buf.decode("utf-8")print(f"Read {len(buf)} bytes:\n{data_string}")else:print("No data received.")except Exception as e:print(f"An error occurred: {e}") -
运行程序。
root@luckfox:/home/luckfox# sudo python3 uart.pyRead 13 bytes:Hello World!
串口通信(C程序)
-
打开串口。
int open_serial(const char *device) {int fd = open(device, O_RDWR | O_NOCTTY | O_SYNC);if (fd < 0) {perror("Error opening serial port");return -1;}return fd;} -
配置串口参数。
int configure_serial(int fd, speed_t baudrate) {struct termios tty;if (tcgetattr(fd, &tty) != 0) {perror("Error getting tty attributes");return -1;}cfsetospeed(&tty, baudrate); // 设置输出波特率cfsetispeed(&tty, baudrate); // 设置输入波特率tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8位数据位tty.c_cflag |= (CLOCAL | CREAD); // 启用接收器,忽略调制解调器线状态tty.c_cflag &= ~(PARENB | PARODD); // 无奇偶校验tty.c_cflag &= ~CSTOPB; // 1个停止位tty.c_cflag &= ~CRTSCTS; // 不使用RTS/CTS硬件流控tty.c_iflag &= ~(IXON | IXOFF | IXANY); // 关闭软件流控tty.c_iflag &= ~(ICRNL | INLCR); // 关闭CR-LF转换tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // 关闭规范模式,关闭回显tty.c_oflag &= ~OPOST; // 关闭输出处理tty.c_cc[VMIN] = 0; // 非阻塞模式tty.c_cc[VTIME] = 10; // 1秒超时if (tcsetattr(fd, TCSANOW, &tty) != 0) {perror("Error setting tty attributes");return -1;}return 0;} -
发送数据。
int send_data(int fd, const char *data) {int len = strlen(data);int bytes_written = write(fd, data, len);if (bytes_written < 0) {perror("Error writing to serial port");return -1;}return bytes_written;} -
接受数据。
int receive_data(int fd, char *buffer, int buffer_size) {int bytes_read = read(fd, buffer, buffer_size);if (bytes_read < 0) {perror("Error reading from serial port");return -1;}return bytes_read;} -
关闭串口。
void close_serial(int fd) {if (close(fd) != 0) {perror("Error closing serial port");}} -
使用 C 程序来实现收发数据完整代码如下:
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <fcntl.h> // open()#include <termios.h> // tcgetattr(), tcsetattr()#include <unistd.h> // read(), write(), close()#include <errno.h> // errno#define SERIAL_PORT "/dev/ttyS3"#define BAUDRATE B115200#define BUFFER_SIZE 128// 打开串口int open_serial(const char *device) {int fd = open(device, O_RDWR | O_NOCTTY | O_SYNC);if (fd < 0) {perror("Error opening serial port");return -1;}return fd;}// 配置串口参数int configure_serial(int fd, speed_t baudrate) {struct termios tty;if (tcgetattr(fd, &tty) != 0) {perror("Error getting tty attributes");return -1;}cfsetospeed(&tty, baudrate); // 设置输出波特率cfsetispeed(&tty, baudrate); // 设置输入波特率tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8位数据位tty.c_cflag |= (CLOCAL | CREAD); // 启用接收器,忽略调制解调器线状态tty.c_cflag &= ~(PARENB | PARODD); // 无奇偶校验tty.c_cflag &= ~CSTOPB; // 1个停止位tty.c_cflag &= ~CRTSCTS; // 不使用RTS/CTS硬件流控tty.c_iflag &= ~(IXON | IXOFF | IXANY); // 关闭软件流控tty.c_iflag &= ~(ICRNL | INLCR); // 关闭CR-LF转换tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // 关闭规范模式,关闭回显tty.c_oflag &= ~OPOST; // 关闭输出处理tty.c_cc[VMIN] = 0; // 非阻塞模式tty.c_cc[VTIME] = 10; // 1秒超时if (tcsetattr(fd, TCSANOW, &tty) != 0) {perror("Error setting tty attributes");return -1;}return 0;}// 发送数据int send_data(int fd, const char *data) {int len = strlen(data);int bytes_written = write(fd, data, len);if (bytes_written < 0) {perror("Error writing to serial port");return -1;}return bytes_written;}// 接收数据int receive_data(int fd, char *buffer, int buffer_size) {int bytes_read = read(fd, buffer, buffer_size);if (bytes_read < 0) {perror("Error reading from serial port");return -1;}return bytes_read;}// 关闭串口void close_serial(int fd) {if (close(fd) != 0) {perror("Error closing serial port");}}int main() {int serial_fd;char recv_buffer[BUFFER_SIZE];// 打开串口serial_fd = open_serial(SERIAL_PORT);if (serial_fd < 0) return 1;// 配置串口if (configure_serial(serial_fd, BAUDRATE) != 0) {close_serial(serial_fd);return 1;}// 发送数据const char *message = "Hello World!\n";if (send_data(serial_fd, message) < 0) {close_serial(serial_fd);return 1;}printf("Sent: %s", message);// 接收数据int bytes_received = receive_data(serial_fd, recv_buffer, BUFFER_SIZE - 1);if (bytes_received > 0) {recv_buffer[bytes_received] = '\0'; // 添加字符串终止符printf("Received: %s\n", recv_buffer);} else if (bytes_received == 0) {printf("No data received.\n");}// 关闭串口close_serial(serial_fd);return 0;} -
编译运行程序。
root@luckfox:/home/luckfox# gcc uart.c -o uartroot@luckfox:/home/luckfox# ./uartSent: Hello World!Received: Hello World!
5. 设备树简介
-
UART2 DTS 源文件在
kernel-6.10/arch/arm64/boot/dts/rockchip/rk3576.dtsi已经定义,我们可以直接调用。uart2: serial@2ad50000 {compatible = "rockchip,rk3576-uart", "snps,dw-apb-uart";reg = <0x0 0x2ad50000 0x0 0x100>;interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;clocks = <&cru SCLK_UART2>, <&cru PCLK_UART2>;clock-names = "baudclk", "apb_pclk";reg-shift = <2>;reg-io-width = <4>;dmas = <&dmac0 10>, <&dmac0 11>;pinctrl-names = "default";pinctrl-0 = <&uart2m0_xfer>;status = "disabled";}; -
设备文件路径位于
kernel-6.1/arch/arm64/boot/dts/rockchip/luckfox-omni3576.dts,开启pwm2m0_ch0的代码片段如下:&uart2 {status = "okay";pinctrl-names = "default";pinctrl-0 = <&uart2m1_xfer>;};