Flutter串口通信插件embedded_serialport的使用
Flutter串口通信插件embedded_serialport的使用
embedded_serialport简介
embedded_serialport
是一个用于串口通信的Flutter包,它使用Dart FFI(Foreign Function Interface)与Rust和C共享库进行交互。这个包提供了简单的API来列出可用的串口,并执行读写操作。你可以参考这篇文章 Building a Flutter application for serial port communication with embedded system 和 示例演示视频 Demo Video 来了解更多。
平台支持
- Linux
功能特性
- 列出可用的串口
- 打开并配置串口
- 从串口读取数据和向串口写入数据
- 设置串口通信超时时间
安装
要安装 embedded_serialport
,可以使用以下命令:
flutter pub add embedded_serialport
依赖项
对于GNU/Linux系统,需要安装 pkg-config
和 libudev
头文件:
安装 pkg-config
- Ubuntu:
sudo apt install pkg-config
- Fedora:
sudo dnf install pkgconf-pkg-config
安装 libudev
(除非禁用默认的 libudev
特性)
- Ubuntu:
sudo apt install libudev-dev
- Fedora:
sudo dnf install systemd-devel
检查权限
确保你的用户属于 dialout
组或等效组:
sudo usermod -aG dialout $USER
然后注销并重新登录。否则,你会收到 SerialErrorCode.serialErrorOpen
错误。
准备Linux应用程序以供分发
要构建Flutter应用程序作为发布版本,请运行以下命令:
flutter build linux --release
之后,进入 build/linux/release/bundle/
目录并使用以下命令运行应用程序:
./projectname
这将自动复制一个名为 librust_serialport.so
的文件到 lib
文件夹中,该文件负责库在应用程序中的工作。
使用方法
在Dart代码中导入该包:
import 'package:embedded_serialport/embedded_serialport.dart';
示例1:列出所有可用的串口
import 'package:embedded_serialport/embedded_serialport.dart';
void main() {
List<String> ports = Serial.getPorts();
print(ports);
for (int i = 0; i < ports.length; i++) {
print(ports[i]);
}
}
示例2:与串行设备通信
import 'package:embedded_serialport/embedded_serialport.dart';
void main() {
List<String> ports = Serial.getPorts();
var s = Serial(ports.first, Baudrate.b115200);
s.timeout(2);
try {
s.writeString('led,0');
var event = s.read(20);
print(event.toString());
s.writeString('led');
var eventt = s.read(20);
print(eventt.toString());
} finally {
s.dispose();
}
}
示例3:完整的Flutter应用示例
import 'package:flutter/material.dart';
import 'package:embedded_serialport/embedded_serialport.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Serial Port Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const SerialPortPage(),
);
}
}
class SerialPortPage extends StatefulWidget {
const SerialPortPage({super.key});
@override
// ignore: library_private_types_in_public_api
_SerialPortPageState createState() => _SerialPortPageState();
}
class _SerialPortPageState extends State<SerialPortPage> {
late Serial _serial;
List<String> _ports = [];
String _output = "";
@override
void initState() {
super.initState();
_initializeSerialPort();
}
void _initializeSerialPort() {
_ports = Serial.getPorts();
if (_ports.isNotEmpty) {
_serial = Serial(_ports.first, Baudrate.b115200);
_serial.timeout(2);
}
}
void _writeString(String command) async {
_serial.writeString(command);
await Future.delayed(const Duration(milliseconds: 100));
var event = _serial.read(0);
setState(() {
_output += "Hardware says -> ${event.toString()}\n";
});
}
void _disposeSerialPort() {
_serial.dispose();
}
@override
void dispose() {
_disposeSerialPort();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Serial Port Example'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Available Ports: ${_ports.join(", ")}'),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () => _writeString('on'),
child: const Text('Send "on"'),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () => _writeString('off'),
child: const Text('Send "off"'),
),
const SizedBox(height: 20),
Expanded(
child: SingleChildScrollView(
child: Text(_output),
),
),
],
),
),
);
}
}
API说明
Serial 类
静态方法
List<String> getPorts()
:返回可用串口列表。
构造函数
Serial(String port, Baudrate baudrate)
:创建一个新的Serial实例,指定端口和波特率。
方法
void timeout(int seconds)
:设置读写操作的超时时间。void writeString(String data)
:向串口写入字符串。Uint8List read(int length)
:从串口读取指定数量的字节。void dispose()
:关闭串口并释放资源。
Baudrate 枚举
常见的波特率枚举值包括:
Baudrate.b9600
Baudrate.b19200
Baudrate.b38400
Baudrate.b57600
Baudrate.b115200
- 更多…
作者
- Zacchaeus Oluwole
致谢
- Peter Sauer https://flutterdev.at/dart_periphery/
更多关于Flutter串口通信插件embedded_serialport的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter串口通信插件embedded_serialport的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是如何在Flutter应用中使用embedded_serialport
插件来实现串口通信的示例代码。请注意,这个插件主要面向Android平台,并且需要一些额外的配置才能在iOS上工作(但iOS上串口通信的支持较为有限,通常需要MFi认证的硬件)。
首先,确保你已经在pubspec.yaml
文件中添加了embedded_serialport
依赖:
dependencies:
flutter:
sdk: flutter
embedded_serialport: ^x.y.z # 请替换为最新版本号
然后,运行flutter pub get
来安装依赖。
接下来,你需要在Android的AndroidManifest.xml
中添加权限声明,以便应用能够访问串口设备:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.yourapp">
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- 其他权限和配置 -->
</manifest>
由于串口通信通常涉及底层硬件访问,你可能还需要请求运行时权限。以下是一个请求权限的简单示例:
import 'package:permission_handler/permission_handler.dart';
Future<void> requestPermissions() async {
var status = await Permission.storage.status;
if (!status.isGranted) {
Map<Permission, PermissionStatus> statuses = await [
Permission.storage,
].request();
}
}
现在,让我们编写一些代码来初始化串口并进行通信。下面是一个完整的示例,展示如何打开串口、写入数据并读取数据:
import 'package:flutter/material.dart';
import 'package:embedded_serialport/embedded_serialport.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
SerialPort? _serialPort;
String _output = '';
@override
void initState() {
super.initState();
initSerialPort();
}
Future<void> initSerialPort() async {
// 初始化串口
_serialPort = await SerialPort.open('/dev/ttyS0'); // 根据你的设备调整路径
if (_serialPort != null) {
// 设置波特率等参数
_serialPort!.setPortParameters(9600, 8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
// 监听串口数据
_serialPort!.inputStream.listen((Uint8List data) {
setState(() {
_output += String.fromCharCodes(data);
});
});
}
}
Future<void> sendData(String data) async {
if (_serialPort != null && _serialPort!.isOpen) {
_serialPort!.write(data.codeUnits);
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Serial Port Communication'),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextField(
decoration: InputDecoration(labelText: 'Send Data'),
onEditingComplete: () {
sendData(textFieldController.text);
textFieldController.clear();
},
controller: textFieldController,
),
SizedBox(height: 16),
Text('Received Data:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
Text(_output, style: TextStyle(fontSize: 16)),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// 示例:发送 "Hello, Serial Port!"
sendData('Hello, Serial Port!');
},
tooltip: 'Send Data',
child: Icon(Icons.send),
),
),
);
}
final TextEditingController textFieldController = TextEditingController();
@override
void dispose() {
textFieldController.dispose();
_serialPort?.close();
super.dispose();
}
}
注意:
- 串口路径(如
/dev/ttyS0
)在Android上通常是虚拟设备或特定硬件的路径,你需要根据实际情况调整。 embedded_serialport
插件在iOS上的支持有限,如果你需要在iOS上实现串口通信,可能需要考虑其他方法或硬件。- 确保你的设备或模拟器支持串口通信,并且已经正确连接了串口设备。
这个示例展示了基本的串口初始化、数据发送和接收功能。根据你的具体需求,你可能需要添加更多的错误处理、配置参数调整等。