告别复杂配置:用egui轻松实现硬件设备的串口通信
你是否还在为嵌入式系统开发中的界面与串口通信难题而困扰?是否经历过调试硬件时反复切换工具的繁琐?本文将带你探索如何使用egui(一个用Rust编写的跨平台即时模式GUI库)快速构建串口通信界面,实现对硬件设备的数据收发与监控,让嵌入式开发变得简单高效。## 串口通信界面设计与实现egui提供了丰富的UI组件,能够轻松构建直观的串口通信界面。通过结合egui的交互能力和Rust的系统级编程优
告别复杂配置:用egui轻松实现硬件设备的串口通信
你是否还在为嵌入式系统开发中的界面与串口通信难题而困扰?是否经历过调试硬件时反复切换工具的繁琐?本文将带你探索如何使用egui(一个用Rust编写的跨平台即时模式GUI库)快速构建串口通信界面,实现对硬件设备的数据收发与监控,让嵌入式开发变得简单高效。
串口通信界面设计与实现
egui提供了丰富的UI组件,能够轻松构建直观的串口通信界面。通过结合egui的交互能力和Rust的系统级编程优势,我们可以创建出既美观又实用的硬件调试工具。
以下是一个基本的串口通信界面实现示例,包含端口选择、波特率设置、数据收发区域等核心功能:
use eframe::egui;
use serialport::SerialPort;
use std::time::Duration;
struct SerialMonitor {
port_name: String,
baud_rate: u32,
ports: Vec<String>,
connected: bool,
serial_port: Option<Box<dyn SerialPort>>,
received_data: String,
send_data: String,
}
impl SerialMonitor {
fn new(_cc: &eframe::CreationContext<'_>) -> Self {
Self {
port_name: String::new(),
baud_rate: 9600,
ports: Vec::new(),
connected: false,
serial_port: None,
received_data: String::new(),
send_data: String::new(),
}
}
fn update_ports(&mut self) {
self.ports.clear();
if let Ok(ports) = serialport::available_ports() {
self.ports = ports.iter().map(|p| p.port_name.clone()).collect();
}
}
fn connect(&mut self) -> Result<(), Box<dyn std::error::Error>> {
let port = serialport::new(self.port_name.clone(), self.baud_rate)
.timeout(Duration::from_millis(10))
.open()?;
self.serial_port = Some(port);
self.connected = true;
Ok(())
}
fn disconnect(&mut self) {
self.serial_port = None;
self.connected = false;
}
fn read_data(&mut self) {
if let Some(port) = &mut self.serial_port {
let mut buf = [0; 1024];
if let Ok(n) = port.read(&mut buf) {
if n > 0 {
if let Ok(s) = String::from_utf8(buf[..n].to_vec()) {
self.received_data.push_str(&s);
}
}
}
}
}
fn send_data(&mut self) {
if let Some(port) = &mut self.serial_port {
let _ = port.write(self.send_data.as_bytes());
self.send_data.clear();
}
}
}
impl eframe::App for SerialMonitor {
fn setup(&mut self, _ctx: &egui::Context, _frame: &mut eframe::Frame, _storage: Option<&dyn eframe::Storage>) {
self.update_ports();
}
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
if self.connected {
self.read_data();
ctx.request_repaint();
}
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("egui串口监控工具");
ui.horizontal(|ui| {
ui.label("串口号:");
egui::ComboBox::from_label("")
.selected_text(&self.port_name)
.show_ui(ui, |ui| {
for port in &self.ports {
ui.selectable_value(&mut self.port_name, port.clone(), port);
}
});
ui.label("波特率:");
egui::ComboBox::from_label("")
.selected_text(&self.baud_rate.to_string())
.show_ui(ui, |ui| {
for &baud in &[9600, 19200, 38400, 57600, 115200] {
ui.selectable_value(&mut self.baud_rate, baud, &baud.to_string());
}
});
if !self.connected {
if ui.button("刷新").clicked() {
self.update_ports();
}
if ui.button("连接").clicked() && !self.port_name.is_empty() {
if let Err(e) = self.connect() {
eprintln!("连接失败: {}", e);
}
}
} else {
if ui.button("断开").clicked() {
self.disconnect();
}
}
});
if self.connected {
ui.separator();
ui.label("接收数据:");
egui::ScrollArea::vertical().show(ui, |ui| {
ui.text_edit_multiline(&mut self.received_data);
});
ui.separator();
ui.horizontal(|ui| {
ui.text_edit_singleline(&mut self.send_data);
if ui.button("发送").clicked() {
self.send_data();
}
});
}
});
}
}
fn main() -> Result<(), eframe::Error> {
let options = eframe::NativeOptions {
viewport: egui::ViewportBuilder::default().with_inner_size([600.0, 400.0]),
..Default::default()
};
eframe::run_native(
"egui串口监控工具",
options,
Box::new(|cc| Ok(Box::new(SerialMonitor::new(cc)))),
)
}
多窗口串口通信应用
egui不仅支持单个窗口应用,还能轻松创建多窗口串口通信界面,这对于同时监控多个串口设备非常有用。egui的examples/serial_windows目录提供了一个多窗口示例,展示了如何顺序打开多个窗口,并在关闭一个窗口后延迟打开下一个窗口。
该示例的主要实现逻辑如下:
fn main() -> eframe::Result {
env_logger::init();
let options = eframe::NativeOptions {
run_and_return: true,
viewport: egui::ViewportBuilder::default().with_inner_size([320.0, 240.0]),
..Default::default()
};
log::info!("Starting first window…");
eframe::run_native(
"First Window",
options.clone(),
Box::new(|_cc| Ok(Box::new(MyApp { has_next: true }))),
)?;
std::thread::sleep(std::time::Duration::from_secs(2));
log::info!("Starting second window…");
eframe::run_native(
"Second Window",
options.clone(),
Box::new(|_cc| Ok(Box::new(MyApp { has_next: true }))),
)?;
std::thread::sleep(std::time::Duration::from_secs(2));
log::info!("Starting third window…");
eframe::run_native(
"Third Window",
options,
Box::new(|_cc| Ok(Box::new(MyApp { has_next: false }))),
)
}
在实际的串口通信应用中,我们可以利用这种多窗口能力,为每个串口设备创建独立的监控窗口,实现多设备并行监控。
完整示例代码与项目结构
egui串口通信示例项目的完整结构如下:
examples/serial_windows/
├── Cargo.toml # 项目依赖配置
├── README.md # 示例说明文档
├── screenshot.png # 示例截图
└── src/
└── main.rs # 主程序代码
你可以通过以下命令克隆项目并运行串口通信示例:
git clone https://gitcode.com/GitHub_Trending/eg/egui.git
cd egui/examples/serial_windows
cargo run
结语
egui为嵌入式系统和硬件设备开发提供了强大而灵活的界面构建能力。通过结合Rust的系统级编程优势和egui的跨平台UI渲染能力,我们能够快速开发出专业的串口通信工具,极大提高硬件调试和嵌入式开发的效率。
无论是简单的设备监控还是复杂的嵌入式系统调试,egui都能为你提供直观、高效的用户界面解决方案。希望本文介绍的egui串口通信应用能够帮助你更好地连接和控制硬件设备。
如果你想深入了解egui的更多功能,可以参考以下资源:
- 官方文档:README.md
- 核心库源码:crates/egui/src/
- 示例程序集:examples/
- 社区教程:examples/README.md
通过这些资源,你可以进一步探索egui在嵌入式系统、物联网设备和工业控制等领域的应用潜力。
更多推荐

所有评论(0)