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字节触发级别

注意事项

  1. 直接硬件访问在大多数操作系统上需要特权级别,通常需要内核模块或裸机环境
  2. 在x86架构上,标准COM端口地址通常是:
    • COM1: 0x3F8
    • COM2: 0x2F8
    • COM3: 0x3E8
    • COM4: 0x2E8
  3. 使用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),
                }
            }
        }
    }
}

这个完整示例展示了:

  1. 串口初始化和配置
  2. 波特率设置
  3. FIFO缓冲区启用
  4. 硬件流控制配置
  5. 中断驱动通信
  6. 数据发送和接收处理
  7. 简单的回显功能实现

使用时需要注意:

  • 需要确保有权限访问硬件端口
  • 在裸机环境或内核模块中使用最为合适
  • 实际波特率需要与连接的设备匹配
回到顶部