Rust串口通信库uart_16550的使用:支持16550 UART芯片的高效硬件通信与控制
Rust串口通信库uart_16550的使用:支持16550 UART芯片的高效硬件通信与控制
概述
uart_16550是一个支持16550 UART芯片的Rust串口通信库,提供对串行通信的最小支持。该库支持通过I/O端口映射(仅x86架构)和内存映射I/O访问UART设备。
使用方法
根据系统架构的不同,UART可以通过端口映射I/O或内存映射I/O进行访问。
使用端口映射I/O
在x86_64等架构上,UART通过端口映射I/O访问。在这些架构上,可以使用SerialPort
类型:
use uart_16550::SerialPort;
const SERIAL_IO_PORT: u16 = 0x3F8;
let mut serial_port = unsafe { SerialPort::new(SERIAL_IO_PORT) };
serial_port.init();
// 现在串口已准备好使用。发送一个字节:
serial_port.send(42);
// 接收一个字节:
let data = serial_port.receive();
使用内存映射串口
大多数其他架构(如RISC-V)使用内存映射I/O访问UART。在这些架构上,可以使用MmioSerialPort
类型:
use uart_16550::MmioSerialPort;
const SERIAL_PORT_BASE_ADDRESS: usize = 0x1000_0000;
let mut serial_port = unsafe { MmioSerialPort::new(SERIAL_PORT_BASE_ADDRESS) };
serial_port.init();
// 现在串口已准备好使用。发送一个字节:
serial_port.send(42);
// 接收一个字节:
let data = serial_port.receive();
完整示例代码
端口映射I/O示例
use uart_16550::SerialPort;
fn main() {
// COM1的标准I/O端口地址
const SERIAL_IO_PORT: u16 = 0x3F8;
// 创建串口实例(需要unsafe块)
let mut serial_port = unsafe { SerialPort::new(SERIAL_IO_PORT) };
// 初始化串口
serial_port.init();
println!("串口初始化完成,开始通信...");
// 发送数据
serial_port.send(b'H');
serial_port.send(b'i');
serial_port.send(b'\n');
// 接收数据(简单示例)
if let Some(data) = serial_port.receive() {
println!("接收到数据: {}", data);
}
}
内存映射I/O示例
use uart_16550::MmioSerialPort;
fn main() {
// 假设UART设备的内存映射基地址
const SERIAL_PORT_BASE_ADDRESS: usize = 0x1000_0000;
// 创建内存映射串口实例(需要unsafe块)
let mut serial_port = unsafe { MmioSerialPort::new(SERIAL_PORT_BASE_ADDRESS) };
// 初始化串口
serial_port.init();
println!("内存映射串口初始化完成,开始通信...");
// 发送字符串
for byte in b"Hello from memory-mapped UART!\n" {
serial_port.send(*byte);
}
// 检查接收缓冲区是否有数据
if let Some(data) = serial_port.receive() {
println!("接收到数据: {}", data);
}
}
构建要求
使用稳定版Rust构建需要满足cc
crate的编译时要求。目前仅在Linux和MacOS上测试过。
许可证
本项目采用MIT许可证授权。
1 回复
Rust串口通信库uart_16550的使用指南
概述
uart_16550
是一个Rust库,专门用于与16550 UART(通用异步收发传输器)芯片进行通信。16550 UART是计算机硬件中常见的串行通信控制器,广泛用于与串行设备如调制解调器、终端和其他嵌入式设备通信。
主要特性
- 支持标准16550 UART芯片功能
- 提供中断驱动和轮询两种操作模式
- 支持波特率配置
- 硬件流控制(RTS/CTS)
- 数据位、停止位和奇偶校验配置
安装
在Cargo.toml中添加依赖:
[dependencies]
uart_16550 = "0.2.0"
基本使用方法
初始化串口
use uart_16550::SerialPort;
const PORT_ADDRESS: u16 = 0x3F8; // COM1的标准I/O地址
fn main() {
let mut serial_port = unsafe { SerialPort::new(PORT_ADDRESS) };
serial_port.init();
println!("Serial port initialized");
}
配置波特率
serial_port.set_baud_rate(115200)
.expect("Failed to set baud rate");
发送数据
let data = b"Hello, UART!";
for &byte in data {
serial_port.send(byte);
}
接收数据
if let Some(byte) = serial_port.receive() {
println!("Received byte: {}", byte);
}
高级功能示例
中断驱动通信
use uart_16550::InterruptId;
// 启用接收数据可用中断
serial_port.enable_interrupt(InterruptId::ReceivedDataAvailable);
// 检查中断标识
if serial_port.has_interrupt(InterruptId::ReceivedDataAvailable) {
// 处理接收到的数据
while let Some(byte) = serial_port.receive() {
process_byte(byte);
}
}
硬件流控制
// 启用RTS/CTS流控制
serial_port.set_flow_control(true);
FIFO缓冲区配置
// 启用FIFO并设置触发级别
serial_port.enable_fifo(16); // 16字节触发级别
注意事项
- 直接硬件访问在大多数操作系统上需要特权级别,通常需要内核模块或裸机环境
- 在x86架构上,标准COM端口地址通常是:
- COM1: 0x3F8
- COM2: 0x2F8
- COM3: 0x3E8
- COM4: 0x2E8
- 使用
unsafe
是必要的,因为直接硬件访问可能影响系统稳定性
完整示例代码
以下是一个完整的串口通信示例,结合了基本使用和高级功能:
use uart_16550::{SerialPort, InterruptId};
const COM1_PORT: u16 = 0x3F8; // COM1端口地址
fn main() {
// 初始化串口
let mut serial = unsafe { SerialPort::new(COM1_PORT) };
serial.init();
// 配置波特率
serial.set_baud_rate(115200).expect("波特率设置失败");
// 启用FIFO缓冲区
serial.enable_fifo(16);
// 启用硬件流控制
serial.set_flow_control(true);
// 启用接收中断
serial.enable_interrupt(InterruptId::ReceivedDataAvailable);
println!("串口初始化完成,开始通信...");
// 发送测试消息
let message = b"Rust UART通信测试\r\n";
for &byte in message {
serial.send(byte);
}
// 主循环处理接收数据
loop {
if serial.has_interrupt(InterruptId::ReceivedDataAvailable) {
while let Some(byte) = serial.receive() {
// 处理接收到的字节
match byte {
// 回车键处理
b'\r' => {
serial.send(b'\r');
serial.send(b'\n');
}
// 回显其他字符
_ => serial.send(byte),
}
}
}
}
}
这个完整示例展示了:
- 串口初始化和配置
- 波特率设置
- FIFO缓冲区启用
- 硬件流控制配置
- 中断驱动通信
- 数据发送和接收处理
- 简单的回显功能实现
使用时需要注意:
- 需要确保有权限访问硬件端口
- 在裸机环境或内核模块中使用最为合适
- 实际波特率需要与连接的设备匹配