Xamarin Android连接STM32 USB CDC设备的UsbSerialForAndroid极简示例请求
Xamarin.Android 连接STM32 USB CDC极简示例
前置准备
- 安装NuGet包:
UsbSerialForAndroid - 在
AndroidManifest.xml中添加权限:
<uses-feature android:name="android.hardware.usb.host" /> <uses-permission android:name="android.permission.USB_PERMISSION" />
布局文件(Main.axml)
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="16dp"> <Button android:id="@+id/btnConnect" android:text="连接设备" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <Button android:id="@+id/btnDisconnect" android:text="断开连接" android:layout_width="wrap_content" android:layout_height="wrap_content" android:enabled="false" /> <TextView android:id="@+id/tvReceivedData" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:minHeight="100dp" android:background="#f0f0f0" /> </LinearLayout>
核心代码(MainActivity.cs)
using Android.App; using Android.Content; using Android.Hardware.Usb; using Android.OS; using Android.Widget; using UsbSerial; using UsbSerial.Driver; using System.IO; using System.Threading.Tasks; namespace UsbSerialDemo { [Activity(Label = "@string/app_name", MainLauncher = true)] [IntentFilter(new[] { UsbManager.ActionUsbDeviceAttached })] public class MainActivity : Activity { private UsbManager _usbManager; private IUsbSerialPort _serialPort; private Button _btnConnect; private Button _btnDisconnect; private TextView _tvReceivedData; // 替换为你的STM32设备VID和PID private readonly string _targetVid = "1234"; private readonly string _targetPid = "5678"; private const int _baudRate = 115200; protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); SetContentView(Resource.Layout.Main); _usbManager = (UsbManager)GetSystemService(Context.UsbService); _btnConnect = FindViewById<Button>(Resource.Id.btnConnect); _btnDisconnect = FindViewById<Button>(Resource.Id.btnDisconnect); _tvReceivedData = FindViewById<TextView>(Resource.Id.tvReceivedData); _btnConnect.Click += ConnectDevice; _btnDisconnect.Click += DisconnectDevice; } private async void ConnectDevice(object sender, System.EventArgs e) { // 枚举所有支持的USB串口设备 var drivers = UsbSerialProber.DefaultProber.FindAllDrivers(_usbManager); if (drivers.Count == 0) { Toast.MakeText(this, "未找到支持的串口设备", ToastLength.Short).Show(); return; } // 筛选目标STM32设备 IUsbSerialDriver targetDriver = null; foreach (var driver in drivers) { if (driver.Device.VendorId.ToString() == _targetVid && driver.Device.ProductId.ToString() == _targetPid) { targetDriver = driver; break; } } if (targetDriver == null) { Toast.MakeText(this, "未找到目标STM32设备", ToastLength.Short).Show(); return; } // 请求USB权限 var permissionIntent = PendingIntent.GetBroadcast(this, 0, new Intent("USB_PERMISSION"), 0); _usbManager.RequestPermission(targetDriver.Device, permissionIntent); // 等待权限授予(实际项目建议用广播接收器监听结果) await Task.Delay(1000); if (!_usbManager.HasPermission(targetDriver.Device)) { Toast.MakeText(this, "未获取设备权限", ToastLength.Short).Show(); return; } // 打开并配置串口 _serialPort = targetDriver.Ports[0]; try { _serialPort.Open(_usbManager.OpenDevice(targetDriver.Device)); _serialPort.SetParameters(_baudRate, 8, StopBits.One, Parity.None); _btnConnect.Enabled = false; _btnDisconnect.Enabled = true; Toast.MakeText(this, "连接成功", ToastLength.Short).Show(); // 启动后台线程接收数据 Task.Run(ReadSerialDataLoop); } catch (IOException ex) { Toast.MakeText(this, $"连接失败:{ex.Message}", ToastLength.Short).Show(); _serialPort?.Close(); } } private void DisconnectDevice(object sender, System.EventArgs e) { _serialPort?.Close(); _btnConnect.Enabled = true; _btnDisconnect.Enabled = false; Toast.MakeText(this, "已断开连接", ToastLength.Short).Show(); } private void ReadSerialDataLoop() { var buffer = new byte[1024]; while (_serialPort != null && _serialPort.IsOpen) { try { int readBytes = _serialPort.Read(buffer, 1000); if (readBytes > 0) { // 转换为字符串(根据设备实际编码调整,比如UTF-8) var receivedText = System.Text.Encoding.ASCII.GetString(buffer, 0, readBytes); // 回到主线程更新UI RunOnUiThread(() => _tvReceivedData.Append(receivedText)); } } catch (IOException) { // 连接断开时退出循环 break; } } } } }
关键注意事项
- 替换VID/PID:打开Windows设备管理器,找到你的STM32 CDC设备,查看其硬件ID中的VID和PID,替换代码中的
_targetVid和_targetPid - 权限优化:示例中用延迟等待权限,实际项目建议注册
BroadcastReceiver监听权限请求结果,避免延迟带来的不可靠性 - 编码格式:如果你的STM32发送的是UTF-8编码数据,将
Encoding.ASCII改为Encoding.UTF8 - 串口参数:确保波特率、数据位、停止位、奇偶校验和STM32端配置一致
内容的提问来源于stack exchange,提问作者user2134766
相关产品推荐
相关产品推荐

