当前位置: 首页 > news >正文

从零打造可落地的直流电机 PID 驱动系统(四):Android 蓝牙控制 APP 开发(新手友好版)

前言

大家好!在上一篇《从零打造可落地的直流电机 PID 驱动系统(二):增加蓝牙远程控制功能》中,我们基于STM32F103C8T6 主控 + DRV8833 驱动 + HC-05 经典蓝牙模块搭建了完整的无线电机控制系统。

与 iOS 需要 MFi 认证才能使用经典蓝牙不同,Android 原生完全支持 HC-05 等经典蓝牙设备,无需更换任何硬件,直接复用你上一篇的成品即可。本文将使用 Android 官方推荐的 Kotlin 语言和 Jetpack Compose UI 框架,从零教你开发一款功能完整的电机控制 APP,实现电机启停、无级调速、PID 参数在线修改和实时转速显示。全程代码带详细注释,零基础也能一步步跟着做。

一、开发前准备(新手必看)

1.1 硬件准备

  • 已完成的直流电机 PID 驱动系统(上一篇成品,HC-05 模块无需更换)
  • Android 手机 / 平板(系统版本 Android 6.0/API 23 及以上,覆盖 99% 以上现役设备)
  • USB 数据线(用于电脑连接手机调试)

1.2 软件准备

  • Android Studio Hedgehog 2023.1.1 及以上(官方免费下载,新手推荐最新稳定版)
  • 串口助手(如 SSCOM,用于提前测试 HC-05 模块通信)
  • 基础 Kotlin 语法知识(只需了解变量、函数、类的基本概念即可)

1.3 关键前提说明

验证来源:Android 官方蓝牙开发文档

  1. 本文使用经典蓝牙 (RFCOMM)开发,完美兼容原系统的 HC-05 模块,硬件零改动
  2. HC-05 默认串口波特率 9600,与上一篇 STM32 的 UART 配置完全一致
  3. 所有代码均基于 Android 官方标准 API 编写,无第三方依赖,稳定性有保障

2.1 核心概念

Android 经典蓝牙通信采用客户端 - 服务器架构:

  • 客户端:我们的 Android 手机,主动发起连接
  • 服务器:HC-05 蓝牙模块,工作在从模式,被动等待连接
  • RFCOMM 通道:蓝牙串口协议,实现透明数据传输,相当于无线串口
  • UUID:服务唯一标识符,HC-05 使用标准串口服务 UUID:00001101-0000-1000-8000-00805F9B34FB必须正确,否则连接失败

2.2 完整通信流程

三、新建 Android 项目与权限配置

3.1 创建新项目

  1. 打开 Android Studio,点击 "New Project"
  2. 选择 "Phone and Tablet" → "Empty Activity",点击 "Next"
  3. 填写项目名称(如MotorControl),语言选择 "Kotlin",最小 SDK 选择 "API 23: Android 6.0 (Marshmallow)"
  4. 点击 "Finish",等待项目初始化完成

3.2 配置蓝牙权限(最容易踩坑的地方)

打开app/src/main/AndroidManifest.xml文件,添加以下权限(分 API 版本适配,缺一不可):

<!-- 所有Android版本通用 --> <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" /> <!-- Android 6.0-11 (API 23-30) 蓝牙扫描需要位置权限 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30" /> <!-- Android 12+ (API 31+) 新蓝牙权限 --> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <!-- 声明APP需要蓝牙硬件 --> <uses-feature android:name="android.hardware.bluetooth" android:required="true" />

验证来源:Android 官方蓝牙权限配置指南 https://developer.android.com/guide/topics/connectivity/bluetooth/permissions

四、蓝牙管理类实现(核心代码)

新建一个 Kotlin 文件BluetoothManager.kt,这是整个 APP 的核心,负责所有蓝牙操作。使用单例模式,确保整个 APP 只有一个蓝牙连接实例。

import android.bluetooth.BluetoothAdapter import android.bluetooth.BluetoothDevice import android.bluetooth.BluetoothSocket import android.content.Context import android.util.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.launch import java.io.IOException import java.io.InputStream import java.io.OutputStream import java.util.* // 蓝牙管理单例类 object BluetoothManager { private const val TAG = "BluetoothManager" // HC-05标准串口服务UUID(固定不变) private val MY_UUID: UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB") private val bluetoothAdapter: BluetoothAdapter? = BluetoothAdapter.getDefaultAdapter() private var bluetoothSocket: BluetoothSocket? = null private var inputStream: InputStream? = null private var outputStream: OutputStream? = null private var readJob: Job? = null // 状态回调接口,用于通知UI层蓝牙状态和数据 interface BluetoothCallback { fun onConnected(device: BluetoothDevice) fun onDisconnected() fun onDataReceived(data: String) fun onError(message: String) } var callback: BluetoothCallback? = null var isConnected: Boolean = false private set // 检查蓝牙是否开启 fun isBluetoothEnabled(): Boolean { return bluetoothAdapter?.isEnabled == true } // 获取已配对设备列表 fun getPairedDevices(): List<BluetoothDevice> { return bluetoothAdapter?.bondedDevices?.toList() ?: emptyList() } // 连接指定蓝牙设备 fun connect(device: BluetoothDevice) { if (isConnected) disconnect() CoroutineScope(Dispatchers.IO).launch { try { // 创建RFCOMM Socket bluetoothSocket = device.createRfcommSocketToServiceRecord(MY_UUID) // 取消扫描(扫描会降低连接速度) bluetoothAdapter?.cancelDiscovery() // 建立连接(阻塞操作,必须在后台线程执行) bluetoothSocket?.connect() // 获取输入输出流 inputStream = bluetoothSocket?.inputStream outputStream = bluetoothSocket?.outputStream isConnected = true callback?.onConnected(device) // 启动数据接收线程 startReading() } catch (e: IOException) { Log.e(TAG, "连接失败: ${e.message}") callback?.onError("连接失败: ${
http://www.gsyq.cn/news/1339604.html

相关文章:

  • 最好用的AI论文写作软件推荐(从开题选题到定稿排版全流程)适合全体毕业生
  • 3大实战技巧:如何用FastExcel极速处理百万级Excel数据?
  • 通过Taotoken CLI工具一键配置多款AI开发工具环境
  • 从零打造直流电机 PID 驱动系统(三):iOS 蓝牙控制 APP 开发(新手友好版)
  • 智能音频切片工具终极指南:告别手动剪辑的烦恼
  • 邻近连接技术伯远邻近连接技术深耕邻近连接技术
  • 英伟达816亿营收+国产2000亿参数图像模型:AI军备赛再升级
  • 智能体之间互相结算 怎么定价呢 评论区告诉我
  • 企业内训系统集成AI问答时采用Taotoken的成本控制实践
  • 智慧树视频自动化插件的技术实现与架构解析
  • 诺玛斯基棱镜设计与加工实现
  • IDM激活脚本:破解30天限制背后的注册表权限技术内幕
  • 通过用量看板清晰追踪团队大模型API消费明细
  • 初次使用Taotoken从注册到成功发起调用的全过程体验
  • 多模态大模型Grounding目标检测数据集 - 苹果检测数据集下载
  • 2026年AI岗位薪资揭秘:高薪背后是挑战,小白如何抓住机遇并收藏这份指南?
  • 中东出口静电粉末喷枪口碑推荐
  • 戴尔G15散热终极控制:开源TCC-G15高效替代方案完全指南
  • 2026数字营销岗位需要具备的能力有哪些
  • 软考高项案例分析11:项目管理概述
  • 荷兰市场本地化突围关键,ElevenLabs语音合成合规性解析,欧盟GDPR+NL-ALP认证细节首次公开
  • 【抽奖系统-0】Redis 缓存与 RabbitMQ 削峰实战;架构梳理
  • 随机数Random
  • 美联储加息降息,如何牵动美黄金价格?
  • Pearcleaner:macOS应用彻底清理的终极指南,3步告别垃圾文件
  • 初创公司如何利用Taotoken的Token Plan降低AI原型开发成本
  • 临沂十大三聚氰胺装饰纸厂
  • 饮品防窜货系统:数字化管控,筑牢渠道秩序防线 附联系方式 - 易全一物一码提供商
  • MySQL 8.0 vs 国产数据库 vs PostgreSQL:索引特性全面对比
  • 从 AI 工具到音乐生态:可酷加速布局,构建数字音乐全新基础设施