Rust串行通信库z-serial的使用:高效实现跨平台串口数据读写与设备控制
Rust串行通信库z-serial的使用:高效实现跨平台串口数据读写与设备控制
Zenoh Serial
这个仓库包含了基于串行(类似RS232)传输的Zenoh帧格式。
构建
您需要安装rust
和Cargo
,请查看Rust官网了解如何安装。
$ cd ~
$ git clone https://github.com/ZettaScaleLabs/z-serial
$ cd z-serial
$ cargo build --release
如何测试
打开两个终端,在第一个终端启动echo服务器:
$ cd ~/z-serial
$ ./target/release/examples/serial-echo <serial device> -s -b <baud rate>
...
在第二个终端启动客户端:
$ cd ~/z-serial
./target/release/examples/serial-echo <serial device> -i <send interval> -b <baud rate>
完整示例代码
以下是一个使用z-serial库进行串口通信的完整示例:
use std::io::{self, Read, Write};
use std::time::Duration;
use z_serial::{SerialPort, SerialPortBuilder};
fn main() -> io::Result<()> {
// 配置串口参数
let port_builder = SerialPortBuilder::new()
.baud_rate(9600) // 设置波特率
.data_bits(8) // 数据位
.flow_control_none() // 无流控制
.parity_none() // 无校验位
.stop_bits(1); // 停止位
// 打开串口设备(请根据实际设备路径修改)
let mut port = port_builder.open("/dev/ttyUSB0")?;
// 设置读写超时时间
port.set_timeout(Duration::from_millis(1000))?;
// 要发送的数据
let data_to_send = b"Hello, Serial World!";
// 写入数据到串口
port.write_all(data_to_send)?;
println!("Sent: {:?}", data_to_send);
// 读取返回数据
let mut buffer = [0u8; 256];
let bytes_read = port.read(&mut buffer)?;
// 处理接收到的数据
if bytes_read > 0 {
let received_data = &buffer[..bytes_read];
println!("Received: {:?}", received_data);
// 将接收到的数据转换为字符串(如果是文本数据)
if let Ok(received_str) = std::str::from_utf8(received_data) {
println!("Received as string: {}", received_str);
}
}
Ok(())
}
高级使用示例
use z_serial::{SerialPort, SerialPortBuilder, SerialPortInfo};
use std::time::Duration;
use std::io::{self, Read, Write};
// 列出所有可用串口设备
fn list_serial_ports() -> Vec<SerialPortInfo> {
z_serial::available_ports().unwrap_or_default()
}
// 创建串口通信处理函数
fn create_serial_communication(device: &str, baud_rate: u32) -> io::Result<()> {
let mut port = SerialPortBuilder::new()
.baud_rate(baud_rate)
.data_bits(8)
.flow_control_none()
.parity_none()
.stop_bits(1)
.open(device)?;
port.set_timeout(Duration::from_millis(1000))?;
// 主通信循环
loop {
// 读取数据
let mut buffer = [0u8; 1024];
match port.read(&mut buffer) {
Ok(bytes_read) if bytes_read > 0 => {
let data = &buffer[..bytes_read];
println!("Received {} bytes: {:?}", bytes_read, data);
// 这里可以添加数据处理逻辑
process_received_data(data);
// 可选:发送响应
if should_send_response(data) {
let response = prepare_response(data);
port.write_all(&response)?;
}
}
Ok(_) => {} // 没有数据收到
Err(e) if e.kind() == io::ErrorKind::TimedOut => {} // 超时是正常的
Err(e) => return Err(e), // 其他错误
}
}
}
// 数据处理函数
fn process_received_data(data: &[u8]) {
// 实现您的数据处理逻辑
println!("Processing data: {:?}", data);
}
// 判断是否需要发送响应
fn should_send_response(data: &[u8]) -> bool {
// 实现您的响应判断逻辑
!data.is_empty()
}
// 准备响应数据
fn prepare_response(data: &[u8]) -> Vec<u8> {
// 实现您的响应准备逻辑
format!("Echo: {}", String::from_utf8_lossy(data)).into_bytes()
}
安装
在您的项目目录中运行以下Cargo命令:
cargo add z-serial
或者在Cargo.toml中添加以下行:
z-serial = "0.3.1"
完整示例demo
基于上述内容,这里提供一个完整的串口通信示例,包含设备枚举、配置和双向通信:
use std::io::{self, Read, Write};
use std::time::Duration;
use z_serial::{SerialPort, SerialPortBuilder, SerialPortInfo};
fn main() -> io::Result<()> {
// 列出所有可用串口设备
println!("Available serial ports:");
let ports = z_serial::available_ports().unwrap_or_default();
for port in &ports {
println!("- {}", port.port_name);
}
if ports.is_empty() {
eprintln!("No serial ports found!");
return Ok(());
}
// 使用第一个找到的串口设备
let device = &ports[0].port_name;
println!("Using device: {}", device);
// 配置串口参数
let mut port = SerialPortBuilder::new()
.baud_rate(115200) // 设置波特率
.data_bits(8) // 数据位
.flow_control_none() // 无流控制
.parity_none() // 无校验位
.stop_bits(1) // 停止位
.open(device)?; // 打开串口设备
// 设置读写超时时间
port.set_timeout(Duration::from_millis(1000))?;
println!("Serial port opened successfully. Press Ctrl+C to exit.");
// 主通信循环
let mut buffer = [0u8; 1024];
loop {
// 尝试读取数据
match port.read(&mut buffer) {
Ok(bytes_read) if bytes_read > 0 => {
let received_data = &buffer[..bytes_read];
println!("Received {} bytes: {:?}", bytes_read, received_data);
// 尝试转换为字符串显示
if let Ok(text) = std::str::from_utf8(received_data) {
println!("As text: {}", text);
}
// 自动回复接收到的数据
port.write_all(received_data)?;
println!("Echoed back {} bytes", bytes_read);
}
Ok(_) => {
// 没有数据收到,发送测试消息
let test_message = b"PING";
port.write_all(test_message)?;
println!("Sent: {:?}", test_message);
// 短暂等待
std::thread::sleep(Duration::from_millis(500));
}
Err(e) if e.kind() == io::ErrorKind::TimedOut => {
// 超时是正常的,继续循环
continue;
}
Err(e) => {
eprintln!("Read error: {}", e);
break;
}
}
}
Ok(())
}
这个完整示例展示了如何:
- 枚举系统中可用的串口设备
- 配置串口通信参数(波特率、数据位、停止位等)
- 打开串口设备并进行双向数据通信
- 处理超时和错误情况
- 实现简单的数据回显功能
使用时请根据实际硬件设备修改串口设备路径和通信参数。
1 回复
Rust串行通信库z-serial的使用指南
概述
z-serial是一个跨平台的Rust串行通信库,提供了简单高效的API来实现串口数据读写和设备控制。该库支持Windows、Linux和macOS系统,能够帮助开发者快速构建与串口设备通信的应用程序。
主要特性
- 跨平台支持(Windows/Linux/macOS)
- 异步和同步读写操作
- 灵活的串口配置选项
- 错误处理和超时机制
- 零成本抽象和高性能
安装方法
在Cargo.toml中添加依赖:
[dependencies]
z-serial = "0.3"
基本使用方法
1. 打开串口
use z_serial::{SerialPort, SerialPortBuilder};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut port = SerialPortBuilder::new("/dev/ttyUSB0")
.baud_rate(9600)
.data_bits(8)
.stop_bits(1)
.parity_none()
.open()?;
Ok(())
}
2. 同步读写数据
use z_serial::{SerialPort, SerialPortBuilder};
use std::io::{Read, Write};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut port = SerialPortBuilder::new("COM3")
.baud_rate(115200)
.open()?;
// 写入数据
let data = b"Hello, Serial!";
port.write_all(data)?;
// 读取数据
let mut buffer = [0; 128];
let bytes_read = port.read(&mut buffer)?;
println!("Received: {:?}", &buffer[..bytes_read]);
Ok(())
}
3. 异步操作(使用async/await)
use z_serial::{AsyncSerialPort, SerialPortBuilder};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut port = SerialPortBuilder::new("/dev/ttyS0")
.baud_rate(9600)
.open_async()?;
// 异步写入
port.write_all(b"AT+COMMAND\r\n").await?;
// 异步读取
let mut response = vec![0; 1024];
let n = port.read(&mut response).await?;
println!("Response: {}", String::from_utf8_lossy(&response[..n]));
Ok(())
}
4. 配置串口参数
use z_serial::{SerialPortBuilder, DataBits, StopBits, Parity, FlowControl};
let port = SerialPortBuilder::new("COM1")
.baud_rate(115200)
.data_bits(DataBits::Eight)
.stop_bits(StopBits::One)
.parity(Parity::None)
.flow_control(FlowControl::None)
.timeout(std::time::Duration::from_millis(1000))
.open()?;
5. 设备控制示例
use z_serial::{SerialPort, SerialPortBuilder};
use std::thread;
use std::time::Duration;
fn control_device() -> Result<(), Box<dyn std::error::Error>> {
let mut port = SerialPortBuilder::new("/dev/ttyACM0")
.baud_rate(9600)
.open()?;
// 发送控制命令
let commands = [
b"SET_LED_ON\r\n",
b"SET_MOTOR_SPEED:50\r\n",
b"GET_TEMPERATURE\r\n"
];
for cmd in commands.iter() {
port.write_all(cmd)?;
thread::sleep(Duration::from_millis(100));
let mut response = [0; 64];
match port.read(&mut response) {
Ok(n) => println!("Response: {}", String::from_utf8_lossy(&response[..n])),
Err(e) => eprintln!("Read error: {}", e),
}
}
Ok(())
}
错误处理
use z_serial::{SerialPort, SerialPortBuilder, SerialError};
fn handle_serial_errors() -> Result<(), SerialError> {
let port = SerialPortBuilder::new("COM5")
.baud_rate(9600)
.open()
.map_err(|e| {
eprintln!("Failed to open serial port: {}", e);
e
})?;
// 其他操作...
Ok(())
}
注意事项
- 在Linux/macOS上可能需要适当的权限才能访问串口设备
- 确保使用的波特率、数据位等参数与目标设备匹配
- 考虑使用超时设置来避免阻塞操作
- 在生产环境中建议实现完整的错误处理和重试机制
这个库为Rust开发者提供了简单而强大的串口通信能力,适用于各种嵌入式系统、工业控制和物联网设备的开发场景。
完整示例代码
use z_serial::{SerialPort, SerialPortBuilder, DataBits, StopBits, Parity, FlowControl};
use std::io::{Read, Write};
use std::thread;
use std::time::Duration;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 配置并打开串口
let mut port = SerialPortBuilder::new("/dev/ttyUSB0") // 根据实际设备修改端口
.baud_rate(9600) // 设置波特率
.data_bits(DataBits::Eight) // 设置数据位
.stop_bits(StopBits::One) // 设置停止位
.parity(Parity::None) // 设置校验位
.flow_control(FlowControl::None) // 设置流控制
.timeout(Duration::from_millis(1000)) // 设置超时时间
.open()?; // 打开串口
println!("串口打开成功!");
// 同步写入数据
let command = b"AT+VER\r\n"; // 示例命令
port.write_all(command)?;
println!("发送命令: {}", String::from_utf8_lossy(command));
// 等待设备响应
thread::sleep(Duration::from_millis(100));
// 同步读取数据
let mut buffer = [0; 128]; // 接收缓冲区
match port.read(&mut buffer) {
Ok(bytes_read) => {
if bytes_read > 0 {
println!("接收数据: {}", String::from_utf8_lossy(&buffer[..bytes_read]));
} else {
println!("未接收到数据");
}
}
Err(e) => eprintln!("读取错误: {}", e),
}
// 发送多个控制命令
let commands = [
b"LED_ON\r\n",
b"GET_STATUS\r\n",
b"LED_OFF\r\n"
];
for cmd in commands.iter() {
port.write_all(cmd)?;
println!("发送命令: {}", String::from_utf8_lossy(cmd));
thread::sleep(Duration::from_millis(50));
let mut response = [0; 64];
match port.read(&mut response) {
Ok(n) => {
if n > 0 {
println!("设备响应: {}", String::from_utf8_lossy(&response[..n]));
}
}
Err(e) => eprintln!("读取错误: {}", e),
}
thread::sleep(Duration::from_millis(100));
}
println!("通信完成!");
Ok(())
}