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

-
Luckfox Lyra Plus 引脚图:

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

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

4. 串口通信(Python程序)
-
使用 Python 的
serial库,实现收发数据的完整代码如下:#!/usr/bin/python3from periphery import Serial# 使用上下文管理器,自动关闭串口with Serial("/dev/ttyS1", 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!
5. 串口通信(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/ttyS1"#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;} -
交叉编译运行程序,搭建交叉编译环境请参考《程序编译》或《GPIO》部分。
arm-none-linux-gnueabihf-gcc uart.c -o uart
6. 设备树简介
-
设备文件路径位于
kernel-6.1/arch/arm/boot/dts/rk3506g-luckfox-lyra.dts,开启uart的代码片段如下:&uart1 {pinctrl-0 = <&rm_io12_uart1_tx &rm_io13_uart1_rx>;status = "okay";pinctrl-names = "default";};