面向机器人与云台的双模蓝牙遥控器协议实现

📅 2026/7/15 3:16:54
面向机器人与云台的双模蓝牙遥控器协议实现
基于 STM32F103 的双模蓝牙遥控器设计阈值指令与原始 ADC 混合架构实现使用深圳大夏龙雀科技蓝牙模块DX-BT36通信稳定性和可靠性具有充分保障。摘要本文介绍一款基于 STM32F103C8T6 的可编程蓝牙遥控器创新性地采用阈值指令模式与原始 ADC 模式双模混合架构通过 DMA 非阻塞发送、滑动平均滤波、状态机优先级仲裁等技术解决了传统遥控器指令冲突、精度不足、串口阻塞等痛点。硬件采用 DX-BT36 主从一体蓝牙模块支持 10 路独立按键 4 路摇杆 ADC。一、项目背景与设计目标1.1 传统遥控器的痛点在机器人、无人机、智能小车等场景中蓝牙遥控器普遍存在以下问题痛点具体表现影响指令冲突双摇杆同时推动时多路数据并发导致接收端解析混乱控制失效或误动作精度不足摇杆仅输出高中低三档无法精细控制速度/角度用户体验差串口阻塞软件循环发送占用 CPU高频率时影响按键响应实时性下降模式单一固定协议无法适配不同场景如小车需要档位云台需要连续值兼容性差1.2 设计目标双模切换一键切换阈值档位模式和原始 ADC 模式零冲突仲裁多路摇杆通过优先级状态机任一时刻只发一条有效指令非阻塞传输DMA 发送释放 CPU主循环仅做状态判断可编程按键10 路独立按键支持自定义指令映射二、系统架构2.1 硬件框图2.2 引脚分配功能引脚模式备注摇杆1 XPA0模拟输入ADC12_IN0摇杆1 YPA1模拟输入ADC12_IN1摇杆2 XPA2模拟输入ADC12_IN2摇杆2 YPA3模拟输入ADC12_IN3按键 K1~K3PB12~PB14上拉输入JTAG 引脚按键 K4~K6PB7~PB9上拉输入通用 GPIO按键 K7PA12上拉输入未启用 USB按键 K8PA15上拉输入禁用JTAG后可用模式键1PA11上拉输入切换阈值模式模式键2PB3上拉输入切换原始 ADC 模式蓝牙 TXPA9复用推挽USART1_TX蓝牙 RXPA10浮空输入USART1_RX关键设计PA11、PA12在本项目中仅作 GPIO 使用PA15、PB3、PB4 通过GPIO_Remap_SWJ_JTAGDisable释放 JTAG 后作为普通 IO使用。三、双模架构详解3.1 模式定义typedef enum { MODE_THRESHOLD 0, // 阈值指令模式摇杆分三档单字节指令 MODE_RAW_ADC 1 // 原始 ADC 模式连续值输出固定帧格式 } RemoteMode;3.2 阈值指令模式适用场景控制小车、继电器等只需档位控制的设备。工作原理将 12 位 ADC 值0~4095映射为低/中/高三档通过优先级状态机任一时刻只输出一路摇杆的指令状态变化才触发发送降低串口负载#define VOLTAGE_LOW_THRESHOLD 1000 // 0.8V → 低档位 #define VOLTAGE_HIGH_THRESHOLD 3100 // 2.5V → 高档位 // 中间区域 → 中位时 不发送指令优先级仲裁优先级通道引脚低电平指令高电平指令1右摇杆 YPA10x250x262右摇杆 XPA00x270x283左摇杆 XPA20x240x234左摇杆 YPA30x220x21仲裁逻辑高优先级通道非中位时屏蔽所有低优先级通道。只有当高优先级回到中位才检查下一级。// 状态机优先级仲裁 if(adc_states[1] ! adc_prev[1]) { // 优先级1PA1右Y // 处理右Y状态变化 } else if(adc_states[0] ! adc_prev[0] // 优先级2PA0右X adc_states[1] VOL_MID) { // 仅当右Y为中位时 // 处理右X状态变化 } else if(adc_states[2] ! adc_prev[2] // 优先级3PA2左X adc_states[0] VOL_MID adc_states[1] VOL_MID) { // 当右X、右Y均为中位 // 处理左X状态变化 } // ... 以此类推3.3 原始 ADC 模式适用场景控制云台、机械臂、无人机等需要精细角度/速度控制的设备。工作原理直接输出 12 位 ADC 的滤波后原始值0~4095固定频率发送默认 10Hz帧格式统一便于解析四路摇杆同时输出无优先级屏蔽帧格式设计考量#作为帧头\r\n作为帧尾便于接收端用中断 状态机解析固定 4 位数字 固定位置字母解析时无需分隔符搜索10Hz 发送频率平衡实时性与串口带宽每帧约 22 字节10Hz 仅 220B/s远低于 9600bps 的 960B/s 有效带宽四、关键技术4.1 DMA 非阻塞发送传统USART_SendData()阻塞等待 TXE 标志高频率发送时 CPU 空转严重。本设计采用DMA1 通道 4USART1_TX实现非阻塞发送// DMA 配置核心 DMA_InitTypeDef dma; dma.DMA_PeripheralBaseAddr (uint32_t)USART1-DR; // 外设USART1数据寄存器 dma.DMA_MemoryBaseAddr (uint32_t)usart_dma_buf; // 内存发送缓冲区 dma.DMA_DIR DMA_DIR_PeripheralDST; // 方向内存→外设 dma.DMA_Mode DMA_Mode_Normal; // 单次模式 DMA_Init(DMA1_Channel4, dma); // 使能 USART 的 DMA 发送请求 USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);发送流程忙标志保护usart_send_busy防止帧叠加若 DMA 正在发送则跳过本次避免数据混乱。4.2 滑动平均滤波摇杆电位器存在机械抖动和电源噪声直接采样会导致数值跳变。采用4 点滑动平均滤波#define ADC_FILTER_DEPTH 4 uint16_t adc_filter_buf[4][ADC_FILTER_DEPTH] {0}; // 4通道×4点缓存 uint8_t adc_filter_idx 0; // 主循环每轮采样 for(uint8_t ch 0; ch 4; ch) { adc_filter_buf[ch][adc_filter_idx] Get_ADC_Single(ch); } adc_filter_idx (adc_filter_idx 1) % ADC_FILTER_DEPTH; // 计算平均值 for(uint8_t ch 0; ch 4; ch) { uint32_t sum 0; for(uint8_t i 0; i ADC_FILTER_DEPTH; i) { sum adc_filter_buf[ch][i]; } adc_raw[ch] sum / ADC_FILTER_DEPTH; }实际效果对比滤波方式噪声幅度响应延迟适用场景无滤波±50 LSB0ms不适用单次采样±30 LSB0ms低要求4点滑动平均±10 LSB~4ms本设计8点滑动平均±5 LSB~8ms高稳定要求卡尔曼滤波±3 LSB~2ms复杂系统4.3 精准时钟配置放弃默认的SystemInit()手动配置 RCC 确保 72MHz 精准时钟void SysClock_Config(void) { RCC_DeInit(); // 外部 8MHz HSE → PLL ×9 → 72MHz RCC_HSEConfig(RCC_HSE_ON); while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) RESET); RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); RCC_PLLCmd(ENABLE); while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) RESET); // 总线分频AHB72MHz, APB136MHz, APB272MHz RCC_HCLKConfig(RCC_SYSCLK_Div1); RCC_PCLK1Config(RCC_HCLK_Div2); // APB1 ≤ 36MHzTIM2~7, USART2~3, I2C, SPI2 RCC_PCLK2Config(RCC_HCLK_Div1); // APB2 72MHzADC, USART1, TIM1, SPI1 RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); }关键APB1 分频为 2 后挂载在 APB1 上的 TIM2~7 时钟为 72MHz因分频系数 ≥2 时 TIM 时钟 ×2确保 PWM/定时器精度。五、代码解析5.1 主循环架构int main(void) { // 1. 初始化 SysClock_Config(); // 必须先配时钟 SysTick_Init(); // 1ms 时基 NVIC_Config(); // 中断优先级分组 // 2. 外设初始化 GPIO_Buttons_Init(); // 释放 JTAG配置按键 USART1_Init(); // DMA 模式串口 ADC1_Init(); // 单次采样 ADC // 3. 滤波缓存预热 for(uint8_t ch 0; ch 4; ch) { for(uint8_t i 0; i ADC_FILTER_DEPTH; i) { adc_filter_buf[ch][i] Get_ADC_Single(ch); } } // 4. 主循环 while(1) { // ADC 采样 滑动滤波 // 模式判断阈值模式 原始ADC模式 // 按键检测 // 轻量级延时 } }5.2 模式切换机制两个专用按键负责模式切换按键引脚功能实现K9PA11切阈值模式current_mode MODE_THRESHOLDK10PB3切原始 ADC 模式current_mode MODE_RAW_ADC切换后立即生效无需重启。阈值模式下发送单字节指令原始模式下发送固定帧。5.3 按键消抖与防重复void Check_Buttons(void) { for(uint8_t i 0; i BUTTON_COUNT; i) { uint8_t curr GPIO_ReadInputDataBit(buttons[i].GPIOx, buttons[i].GPIO_Pin); // 下降沿检测按下 50ms 防抖 if(curr Bit_RESET buttons[i].last_state Bit_SET) { if((now - buttons[i].last_time) DEBOUNCE_TIME_MS) { // 执行按键动作 buttons[i].last_state curr; buttons[i].last_time now; } } // 上升沿检测释放 else if(curr Bit_SET buttons[i].last_state Bit_RESET) { buttons[i].last_state curr; } } }六、性能测试测试项参数结果系统时钟72MHz HSEPLL实测 72.00MHzADC 采样率12MHz ADCCLK239.5 cycles~50kHz 单通道滤波后有效分辨率12-bit → 等效 10-bit±10 LSB 噪声串口发送带宽9600bps10Hz 帧频占用率 ~23%DMA 发送耗时22 字节 9600bps~23msCPU 零占用主循环周期含 ADC×4 滤波 按键扫描~5ms200Hz按键响应延迟消抖 50ms 扫描周期 60ms七、应用场景7.1 典型应用受控设备推荐模式配置智能小车阈值模式右Y前进/后退右X转向二轴云台原始 ADC 模式两路摇杆直接映射角度机械臂原始 ADC 模式四路分别控制 XYZ夹爪继电器模组阈值模式按键直接控制开关无人机混合模式原始 ADC 控制姿态按键控制模式切换八、开源与复刻项目链接立创开源硬件OSHWHUB - 基于 STM32 可编程多功能蓝牙遥控器完整代码见上文可直接复制到 Keil、VSCode 编译硬件 BOM见立创工程编译环境Keil MDK-ARM 5.38 STM32F10x Standard Peripheral Library v3.5.0九、总结本文设计的双模蓝牙遥控器通过阈值、原始 ADC 混合架构已经通过实际打样验证兼顾了简单设备的兼容性和复杂设备的精细控制需求。DMA 非阻塞发送释放 CPU 资源滑动平均滤波提升摇杆稳定性优先级状态机彻底解决多路指令冲突。可直接移植到 STM32F103 全系或其他 Cortex-M3 平台。