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

3. 串口测试(shell)
以 UART1 为例,打开成功后,我们使用命令查看 UART1:
root@luckfox:/home/luckfox# ls /dev/ttyS*
/dev/ttyS1用 stty 工具查询其通信参数:
root@luckfox:/home/luckfox# stty -F /dev/ttyS1
speed 9600 baud; line = 0;
-brkint -imaxbel修改波特率,其中i speed 为输入速率,ospeed 为输出速率:
iomux 0 12 16
iomux 0 13 17
stty -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/ttyS1
echo "world !" > /dev/ttyS1Windows 上的串口调试助手会接收到内容:

4. 串口通信(Python程序)
使用 Python 的
serial库,实现收发数据的完整代码如下:#!/usr/bin/python3
from 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.py
Read 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";
};