Flutter串口通信插件flutter_turbo_serialport的使用
Flutter串口通信插件flutter_turbo_serialport的使用
本库依赖于:felHR85/UsbSerial
变更日志
使用说明
注意:IDs在USB断开后不会保持不变。
默认参数类型
KEY | VALUE |
---|---|
driver | AUTO |
portInterface | -1 |
returnedDataType | UTF8 |
baudRate | 9600 |
dataBit | DATA_BITS_8 |
stopBit | STOP_BITS_1 |
parity | PARITY_NONE |
flowControl | FLOW_CONTROL_OFF |
可选配置
为了确保在Android上记住权限,需要在 android/app/src/main/AndroidManifest.xml
中添加以下意图:
<activity>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter" />
</activity>
并在 android/app/src/main/res/xml/usb_device_filter.xml
文件中创建过滤器文件:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 0x0403 / 0x6001: FTDI FT232R UART -->
<usb-device vendor-id="1027" product-id="24577" />
<!-- 0x0403 / 0x6015: FTDI FT231X -->
<usb-device vendor-id="1027" product-id="24597" />
<!-- 0x2341 / Arduino -->
<usb-device vendor-id="9025" />
<!-- 0x16C0 / 0x0483: Teensyduino -->
<usb-device vendor-id="5824" product-id="1155" />
<!-- 0x10C4 / 0xEA60: CP210x UART Bridge -->
<usb-device vendor-id="4292" product-id="60000" />
<!-- 0x067B / 0x2303: Prolific PL2303 -->
<usb-device vendor-id="1659" product-id="8963" />
<!-- 0x1366 / 0x0105: Segger JLink -->
<usb-device vendor-id="4966" product-id="261" />
<!-- 0x1366 / 0x0105: CH340 JLink -->
<usb-device vendor-id="1A86" product-id="7523" />
</resources>
这里的 vendor-id
和 product-id
需要以十进制形式给出,并且可以从 listDevices()
方法中获取。
示例
示例代码
import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_turbo_serialport/flutter_turbo_serialport.dart';
void main() {
runApp(
const MaterialApp(
debugShowCheckedModeBanner: false,
home: HomePage(),
),
);
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
[@override](/user/override)
State<StatefulWidget> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
late Function _subscribe;
List<Device> _allDevices = [];
String _device = '';
String _data = '';
[@override](/user/override)
void initState() {
super.initState();
// 此方法仅调用一次
// 但它是可选的
SerialportController().init(
autoConnect: false,
mode: Mode.$async,
params: Params(
driver: DriverType.$auto,
portInterface: -1, // 所有端口
returnedDataType: ReturnedDataType.$utf8,
baudRate: BaudRate.$9600,
dataBit: DataBit.$8,
stopBit: StopBit.$1,
parity: Parity.$none,
flowControl: FlowControl.$off,
),
);
WidgetsBinding.instance.addPostFrameCallback((_) {
_subscribe = SerialportController().addListeners(
onReadData: onReadData,
onError: onError,
onConnected: onConnected,
onDisconnected: onDisconnected,
onDeviceAttached: onSearch,
onDeviceDetached: onSearch,
);
});
}
[@override](/user/override)
void dispose() {
super.dispose();
_subscribe();
}
void onReadData({
int? deviceId,
int? portInterface,
dynamic data, // String | Uint8List
}) {
setState(() {
_data += data as String;
});
}
void onError({
int? errorCode,
String? errorMessage,
}) {
if (errorMessage != null) {
_showMyDialog('Error', errorMessage);
}
}
void onConnected({
int? deviceId,
int? portInterface,
}) {
setState(() {
_device = 'id: $deviceId $portInterface +';
});
}
void onDisconnected({
int? deviceId,
int? portInterface,
}) {
setState(() {
_device = 'id: $deviceId $portInterface -';
});
}
void onSearch({
int? deviceId,
}) {
SerialportController().listDevices().then((List<Device> res) {
setState(() {
_allDevices = res;
});
});
}
Future<void> _showMyDialog(String title, String text) async {
return showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text(title),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Text(text),
],
),
),
actions: <Widget>[
TextButton(
child: const Text('Ok'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
connect({
required Device device,
}) {
return () {
device.isConnected().then((bool res) {
if (res) {
device.writeString(message: '${Random().nextDouble()}');
} else {
device.connect();
}
});
};
}
write({
int? deviceId,
}) {
return () {
SerialportController().writeString(
message: '${Random().nextDouble()}',
deviceId: deviceId,
portInterface: 0,
);
};
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Column(
children: [
TextButton(
onPressed: onSearch,
child: Center(
child: Text(
'Search: ${_allDevices.length}\n$_device',
textAlign: TextAlign.center,
),
),
),
],
),
),
body: Column(
children: [
Expanded(
child: ListView.builder(
itemCount: _allDevices.length,
itemBuilder: (BuildContext context, int index) {
final Device device = _allDevices.elementAt(index);
return ListTile(
title: TextButton(
onPressed: connect(device: device),
child: Center(
child: Text(
'Connect id: ${device.deviceId}',
),
),
),
);
},
),
),
const SizedBox(height: 16),
Expanded(
child: SingleChildScrollView(
child: Text(
_data,
textAlign: TextAlign.center,
),
),
),
],
),
);
}
}
更多关于Flutter串口通信插件flutter_turbo_serialport的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter串口通信插件flutter_turbo_serialport的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个使用Flutter串口通信插件flutter_turbo_serialport
的示例代码。这个示例展示了如何初始化串口、打开串口、发送数据以及接收数据。
首先,确保你已经在pubspec.yaml
文件中添加了flutter_turbo_serialport
依赖:
dependencies:
flutter:
sdk: flutter
flutter_turbo_serialport: ^x.y.z # 请替换为最新版本号
然后,运行flutter pub get
来获取依赖。
接下来,是一个完整的Flutter应用示例,展示如何使用flutter_turbo_serialport
进行串口通信:
import 'package:flutter/material.dart';
import 'package:flutter_turbo_serialport/flutter_turbo_serialport.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
FlutterTurboSerialport? _serialPort;
String _receivedData = "";
@override
void initState() {
super.initState();
_initSerialPort();
}
@override
void dispose() {
_closeSerialPort();
super.dispose();
}
void _initSerialPort() async {
// 请求权限(Android特有)
if (await FlutterTurboSerialport.requestPermission()) {
// 初始化串口对象
_serialPort = FlutterTurboSerialport();
// 打开串口
var result = await _serialPort!.openPort('/dev/ttyS0', 9600); // 根据实际情况修改串口路径和波特率
if (result) {
print("串口打开成功");
// 设置数据接收回调
_serialPort!.setDataReceivedCallback((Uint8List data) {
setState(() {
_receivedData += String.fromCharCodes(data);
});
});
} else {
print("串口打开失败");
}
} else {
print("权限请求失败");
}
}
void _closeSerialPort() async {
if (_serialPort != null && _serialPort!.isOpen()) {
await _serialPort!.closePort();
print("串口关闭");
}
}
void _sendData() async {
if (_serialPort != null && _serialPort!.isOpen()) {
String dataToSend = "Hello, Serial Port!";
Uint8List data = Uint8List.fromList(dataToSend.codeUnits);
await _serialPort!.writePort(data);
print("数据发送: $dataToSend");
} else {
print("串口未打开");
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Flutter Serial Port Communication'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('接收到的数据:', style: TextStyle(fontSize: 18)),
SizedBox(height: 8),
Text(_receivedData, style: TextStyle(fontSize: 16)),
SizedBox(height: 24),
ElevatedButton(
onPressed: _sendData,
child: Text('发送数据'),
),
],
),
),
),
);
}
}
代码说明:
- 依赖引入:在
pubspec.yaml
文件中添加flutter_turbo_serialport
依赖。 - 权限请求:在Android上,串口通信需要请求权限,使用
FlutterTurboSerialport.requestPermission()
方法。 - 初始化串口:使用
FlutterTurboSerialport()
创建串口对象,然后使用openPort(path, baudRate)
方法打开串口。 - 设置数据接收回调:通过
setDataReceivedCallback
方法设置数据接收回调,接收到的数据会触发该回调。 - 发送数据:使用
writePort(data)
方法发送数据到串口。 - UI展示:使用Flutter的Material Design组件展示接收到的数据和发送数据的按钮。
注意事项:
- 串口路径:在示例中,串口路径是
'/dev/ttyS0'
,这通常在Linux或Android设备上使用。在Windows或iOS设备上,路径可能会有所不同。 - 权限:在Android设备上,需要在
AndroidManifest.xml
中声明串口权限,但flutter_turbo_serialport
插件通常会处理这些权限请求。 - 错误处理:示例代码中省略了详细的错误处理,但在实际应用中,应该添加适当的错误处理逻辑。
希望这个示例代码能帮助你理解如何使用flutter_turbo_serialport
插件进行串口通信。如果有更多问题,欢迎继续提问!