You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Xamarin Android连接STM32 USB CDC设备的UsbSerialForAndroid极简示例请求

Xamarin.Android 连接STM32 USB CDC极简示例

前置准备

  1. 安装NuGet包:UsbSerialForAndroid
  2. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 00:43:11