Flutter USB串口通信插件usb_serial_for_android的使用

发布于 1周前 作者 h691938207 来自 Flutter

Flutter USB串口通信插件usb_serial_for_android的使用

usb_serial_for_android 是一个用于Android设备的串行库。

重要提示!

本项目与 usb_serial 非常相似,你可以使用它的文档来使用这个库。由于还有很多更改和测试需要进行,建议参考 usb_serial 的文档。

动机

在使用 usb_serial 进行开发时遇到了一些问题和错误,这些问题是由于我正在开发的一个项目的特殊需求导致的。

虽然 usb_serial 使用的是 https://github.com/felHR85/UsbSerial,但此库使用的是 https://github.com/mik3y/usb-serial-for-android 来支持其功能。

完整示例代码

以下是一个完整的示例代码,展示了如何使用 usb_serial_for_android 插件进行USB串口通信。

import 'dart:async';
import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'package:usb_serial_for_android/transaction.dart';
import 'package:usb_serial_for_android/usb_device.dart';
import 'package:usb_serial_for_android/usb_event.dart';
import 'package:usb_serial_for_android/usb_port.dart';
import 'package:usb_serial_for_android/usb_serial_for_android.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  [@override](/user/override)
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  UsbPort? _port;
  String _status = "Idle";
  List<Widget> _ports = [];
  List<Widget> _serialData = [];

  StreamSubscription<String>? _subscription;
  Transaction<String>? _transaction;
  UsbDevice? _device;

  TextEditingController _textController = TextEditingController();

  Future<bool> _connectTo(UsbDevice? device) async {
    _serialData.clear();

    if (_subscription != null) {
      _subscription!.cancel();
      _subscription = null;
    }

    if (_transaction != null) {
      _transaction!.dispose();
      _transaction = null;
    }

    if (_port != null) {
      _port!.close();
      _port = null;
    }

    if (device == null) {
      _device = null;
      setState(() {
        _status = "Disconnected";
      });
      return true;
    }

    // 你可以在创建端口时自定义驱动程序和端口号
    _port = await device.create(UsbSerial.CP21xx, 4);
    if (await (_port!.open()) != true) {
      setState(() {
        _status = "Failed to open port";
      });
      return false;
    }
    _device = device;

    await _port!.setDTR(true);
    await _port!.setRTS(true);
    await _port!.setPortParameters(
        115200, UsbPort.DATABITS_8, UsbPort.STOPBITS_1, UsbPort.PARITY_NONE);

    await _port!.connect();

    _transaction = Transaction.stringTerminated(
        _port!.inputStream as Stream<Uint8List>, Uint8List.fromList([13, 10]));

    _subscription = _transaction!.stream.listen((String line) {
      setState(() {
        _serialData.add(Text(line));
        if (_serialData.length > 20) {
          _serialData.removeAt(0);
        }
      });
    });

    setState(() {
      _status = "Connected";
    });
    return true;
  }

  void _getPorts() async {
    _ports = [];
    List<UsbDevice> devices = await UsbSerial.listDevices();
    if (!devices.contains(_device)) {
      _connectTo(null);
    }
    print(devices);

    devices.forEach((device) {
      _ports.add(ListTile(
          leading: Icon(Icons.usb),
          title: Text(device.productName!),
          subtitle: Text(device.manufacturerName!),
          trailing: ElevatedButton(
            child: Text(_device == device ? "Disconnect" : "Connect"),
            onPressed: () {
              _connectTo(_device == device ? null : device).then((res) {
                _getPorts();
              });
            },
          )));
    });

    setState(() {
      print(_ports);
    });
  }

  [@override](/user/override)
  void initState() {
    super.initState();

    UsbSerial.usbEventStream!.listen((UsbEvent event) {
      _getPorts();
    });

    _getPorts();
  }

  [@override](/user/override)
  void dispose() {
    super.dispose();
    _connectTo(null);
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
      appBar: AppBar(
        title: const Text('USB Serial Plugin example app'),
      ),
      body: Center(
          child: Column(children: <Widget>[
        Text(
            _ports.length > 0
                ? "Available Serial Ports"
                : "No serial devices available",
            style: Theme.of(context).textTheme.headline6),
        ..._ports,
        Text('Status: $_status\n'),
        Text('info: ${_port.toString()}\n'),
        ListTile(
          title: TextField(
            controller: _textController,
            decoration: InputDecoration(
              border: OutlineInputBorder(),
              labelText: 'Text To Send',
            ),
          ),
          trailing: ElevatedButton(
            child: Text("Send"),
            onPressed: _port == null
                ? null
                : () async {
                    if (_port == null) {
                      return;
                    }
                    String data = _textController.text + "\r\n";
                    await _port!.write(Uint8List.fromList(data.codeUnits));
                    _textController.text = "";
                  },
          ),
        ),
        Text("Result Data", style: Theme.of(context).textTheme.headline6),
        ..._serialData,
      ])),
    ));
  }
}

更多关于Flutter USB串口通信插件usb_serial_for_android的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter USB串口通信插件usb_serial_for_android的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter应用中使用usb_serial_for_android插件来实现USB串口通信的示例代码。这个插件主要用于Android平台,如果你还需要iOS支持,可能需要查看其他插件或解决方案。

首先,确保你的Flutter项目中已经添加了usb_serial_for_android依赖。在pubspec.yaml文件中添加以下依赖:

dependencies:
  flutter:
    sdk: flutter
  usb_serial_for_android: ^x.x.x  # 请替换为最新版本号

然后运行flutter pub get来安装依赖。

接下来是示例代码,展示如何使用usb_serial_for_android插件进行USB串口通信。

主文件:main.dart

import 'package:flutter/material.dart';
import 'package:usb_serial_for_android/usb_serial_for_android.dart';
import 'package:usb_serial_for_android/usb_device.dart';
import 'package:usb_serial_for_android/usb_port.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  UsbSerial? _usbSerial;
  UsbDevice? _usbDevice;
  UsbPort? _usbPort;
  bool _isOpen = false;

  @override
  void initState() {
    super.initState();
    initUsb();
  }

  @override
  void dispose() {
    _usbSerial?.close();
    super.dispose();
  }

  Future<void> initUsb() async {
    UsbSerialManager manager = UsbSerialManager();
    List<UsbDevice> devices = await manager.getDevices();

    if (devices.isNotEmpty) {
      setState(() {
        _usbDevice = devices.first;
      });

      _usbSerial = await UsbSerial.fromUsbDevice(_usbDevice!);
      List<UsbPort> ports = await _usbSerial!.getPorts();
      if (ports.isNotEmpty) {
        setState(() {
          _usbPort = ports.first;
        });
      }
    }
  }

  Future<void> openPort() async {
    if (_usbSerial == null || _usbPort == null) return;

    try {
      await _usbSerial!.openPort(_usbPort!, 9600, UsbSerial.DATABITS_8, UsbSerial.STOPBITS_1, UsbSerial.PARITY_NONE);
      setState(() {
        _isOpen = true;
      });
    } catch (e) {
      print(e);
    }
  }

  Future<void> closePort() async {
    if (_usbSerial != null) {
      await _usbSerial!.closePort();
      setState(() {
        _isOpen = false;
      });
    }
  }

  Future<void> sendData(String data) async {
    if (_usbSerial != null && _isOpen) {
      await _usbSerial!.write(data.codeUnits);
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('USB Serial Communication'),
        ),
        body: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            children: [
              if (_usbDevice != null)
                Text('Connected Device: ${_usbDevice!.deviceName}'),
              ElevatedButton(
                onPressed: _isOpen ? closePort : openPort,
                child: Text(_isOpen ? 'Close Port' : 'Open Port'),
              ),
              SizedBox(height: 16),
              ElevatedButton(
                onPressed: () async {
                  String data = 'Hello USB!';
                  await sendData(data);
                  print('Sent: $data');
                },
                child: Text('Send Data'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

注意事项:

  1. 权限:在AndroidManifest.xml文件中添加必要的USB权限。
<uses-feature android:name="android.hardware.usb.host" />
<uses-permission android:name="android.permission.USB_PERMISSION" />
  1. 运行时权限请求:对于Android 6.0及以上版本,你需要在运行时请求USB权限。你可以在MainActivity.ktMainActivity.java中添加相关代码来处理权限请求。

  2. 调试和错误处理:确保在实际设备上进行调试,因为模拟器通常不支持USB连接。添加适当的错误处理代码,以便在出现问题时能够捕获和记录错误信息。

这个示例代码展示了如何初始化USB设备、打开/关闭串口端口以及发送数据。根据实际需求,你可能需要扩展这个示例,比如添加接收数据的处理逻辑。

回到顶部