STM32蓝牙遥控小车DIY从硬件选型到手机APP控制全流程附源码周末的午后看着书桌上闲置的STM32开发板和几个电机突然萌生了一个想法——何不自己动手做一辆蓝牙遥控小车这个念头一旦产生就挥之不去。作为一个电子爱好者最享受的就是从零开始构建一个完整项目的成就感。本文将带你完整经历从硬件选型、电路设计到手机APP开发的每一个环节最终实现一辆可以通过手机蓝牙遥控的小车。1. 硬件选型与成本控制在开始项目前我们需要明确几个关键点低成本、易获取和稳定性。经过多次对比测试我最终确定了以下硬件配置方案1.1 核心控制器选择STM32系列单片机因其出色的性价比成为首选。经过对比STM32F103C6T6脱颖而出价格优势零售价约8-12元性能参数ARM Cortex-M3内核72MHz主频32KB Flash10KB RAM37个GPIO支持多种外设接口开发便利丰富的库函数支持和活跃的社区资源提示初学者可以选择带调试接口的核心板避免焊接困难。1.2 电机驱动方案驱动模块的选择直接影响小车的运动性能。经过测试对比DRV8833双路电机驱动芯片表现最佳参数DRV8833L298NTB6612单芯片价格1.2元5元8元最大电流1.5A2A3.2A工作电压2.7-10.8V5-35V4.5-13.5VPWM频率支持500kHz5kHz100kHz对于小型直流电机3-6V200-300mADRV8833完全够用且成本最低。1.3 蓝牙模块选型HC-05蓝牙模块是最经济实惠的选择价格约15元通信距离10米空旷环境接口UART串口通信供电3.3V-5V// 典型蓝牙模块初始化代码 void USART2_Init(u32 bound) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); // USART2_TX PA.2 GPIO_InitStructure.GPIO_Pin GPIO_Pin_2; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; GPIO_Init(GPIOA, GPIO_InitStructure); // USART2_RX PA.3 GPIO_InitStructure.GPIO_Pin GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, GPIO_InitStructure); USART_InitStructure.USART_BaudRate bound; USART_InitStructure.USART_WordLength USART_WordLength_8b; USART_InitStructure.USART_StopBits USART_StopBits_1; USART_InitStructure.USART_Parity USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART2, USART_InitStructure); USART_Cmd(USART2, ENABLE); }2. 电路设计与PCB制作2.1 电源系统设计考虑到灵活性我们设计了双电源输入方案USB供电5V稳定输入适合调试阶段锂电池供电7.4V航模电池通过AMS1117-5.0稳压到5V关键电路设计要点电源开关采用自锁开关增加100μF电解电容和0.1μF陶瓷电容滤波电源指示灯使用3mm红色LED2.2 电机驱动电路DRV8833外围电路非常简单只需注意以下几点每个电机通道需要两个控制信号IN1/IN2睡眠控制引脚(nSLEEP)需接高电平电机电源与逻辑电源隔离// DRV8833驱动代码示例 void Motor_Control(u8 motor, u8 dir, u8 speed) { switch(motor) { case MOTOR_A: if(dir FORWARD) { AIN1_H(); AIN2_L(); } else if(dir BACKWARD) { AIN1_L(); AIN2_H(); } else { AIN1_L(); AIN2_L(); } // 设置PWM占空比 set_pwm_duty(MOTOR_A_PWM, speed); break; case MOTOR_B: // 类似实现... } }2.3 PCB布局技巧经过多次迭代总结了以下PCB设计经验模块化布局将单片机、蓝牙、电机驱动分区域放置电源走线电机电源线宽≥1mm逻辑电源线宽≥0.5mm信号隔离PWM信号线远离模拟信号线散热考虑DRV8833下方铺铜并增加散热过孔3. 固件开发与蓝牙通信3.1 系统初始化流程固件开发采用模块化编程思想主要初始化顺序如下系统时钟配置72MHz延时函数初始化GPIO初始化定时器配置PWM生成USART初始化蓝牙通信电机驱动初始化int main(void) { SystemInit(); delay_init(); GPIO_Config(); TIM3_PWM_Init(719, 0); // 10kHz PWM USART2_Init(9600); DRV8833_Init(); while(1) { Bluetooth_Process(); delay_ms(10); } }3.2 蓝牙协议设计为简化开发我们定义了简单的文本协议方向控制F前进B后退L左转R右转S停止速度控制Vxxxxxx为0-100的速度值void Bluetooth_Process(void) { if(USART2_RX_STA 0x8000) { u8 len USART2_RX_STA 0x3FFF; USART2_RX_BUF[len] \0; switch(USART2_RX_BUF[0]) { case F: Motor_Control(MOTOR_A, FORWARD, current_speed); Motor_Control(MOTOR_B, FORWARD, current_speed); break; case B: // 类似处理... case V: current_speed atoi(USART2_RX_BUF1); break; } USART2_RX_STA 0; } }3.3 PWM调速实现使用定时器TIM3的通道1和通道2生成PWM信号void TIM3_PWM_Init(u16 arr, u16 psc) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // PA6-TIM3_CH1, PA7-TIM3_CH2 GPIO_InitStructure.GPIO_Pin GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); TIM_TimeBaseStructure.TIM_Period arr; TIM_TimeBaseStructure.TIM_Prescaler psc; TIM_TimeBaseStructure.TIM_ClockDivision 0; TIM_TimeBaseStructure.TIM_CounterMode TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, TIM_TimeBaseStructure); TIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OCPolarity TIM_OCPolarity_High; TIM_OC1Init(TIM3, TIM_OCInitStructure); TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); TIM_OC2Init(TIM3, TIM_OCInitStructure); TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); TIM_Cmd(TIM3, ENABLE); }4. 手机APP开发4.1 Android控制端设计使用Android Studio开发控制APP主要功能包括蓝牙设备搜索与连接方向控制按钮虚拟摇杆速度调节滑块连接状态显示关键实现代码// Bluetooth连接核心代码 private class ConnectThread extends Thread { private final BluetoothSocket mmSocket; private final BluetoothDevice mmDevice; public ConnectThread(BluetoothDevice device) { BluetoothSocket tmp null; mmDevice device; try { tmp device.createRfcommSocketToServiceRecord(MY_UUID); } catch (IOException e) { Log.e(TAG, Socket创建失败, e); } mmSocket tmp; } public void run() { BluetoothAdapter.getDefaultAdapter().cancelDiscovery(); try { mmSocket.connect(); } catch (IOException connectException) { try { mmSocket.close(); } catch (IOException closeException) { Log.e(TAG, 无法关闭socket, closeException); } return; } manageConnectedSocket(mmSocket); } }4.2 控制界面优化为提高操作体验我们采用了以下设计虚拟摇杆通过触摸位置计算方向向量速度曲线非线性映射低速段更精细自动重连连接断开后自动尝试重连状态反馈实时显示连接状态和电池电量4.3 常见问题解决在实际测试中遇到的一些问题及解决方案问题现象可能原因解决方法蓝牙无法连接模块未进入配对模式长按HC-05按键直到指示灯快闪电机不转电源功率不足更换更大容量电池或检查接线控制延迟大蓝牙信号干扰远离WiFi路由器等2.4GHz设备APP闪退蓝牙权限未开启检查AndroidManifest.xml权限设置5. 项目进阶与扩展完成基础功能后可以考虑以下扩展方向5.1 功能增强速度PID控制实现更平滑的加减速自动避障增加超声波传感器路线记忆存储并复现行驶路径5.2 性能优化低功耗设计空闲时进入睡眠模式协议优化改用二进制协议提高传输效率OTA升级通过蓝牙更新固件5.3 外观改造3D打印外壳设计个性化车体LED装饰增加可编程灯带摄像头扩展实现FPV第一人称视角// PID控制算法示例 typedef struct { float Kp, Ki, Kd; float integral, prev_error; } PIDController; float PID_Update(PIDController* pid, float setpoint, float measurement) { float error setpoint - measurement; pid-integral error; if(pid-integral 100) pid-integral 100; if(pid-integral -100) pid-integral -100; float derivative error - pid-prev_error; pid-prev_error error; return pid-Kp * error pid-Ki * pid-integral pid-Kd * derivative; }在完成这个小项目后最深的体会是硬件开发远比纯软件开发更具挑战性。一个小小的接触不良就可能导致数小时的调试但当看到小车按照指令精准运动时那种成就感也是无与伦比的。建议初学者在焊接时多检查几遍连接使用万用表测试关键点电压这样可以节省大量调试时间。
STM32蓝牙遥控小车DIY:从硬件选型到手机APP控制全流程(附源码)
发布时间:2026/6/9 18:14:15
STM32蓝牙遥控小车DIY从硬件选型到手机APP控制全流程附源码周末的午后看着书桌上闲置的STM32开发板和几个电机突然萌生了一个想法——何不自己动手做一辆蓝牙遥控小车这个念头一旦产生就挥之不去。作为一个电子爱好者最享受的就是从零开始构建一个完整项目的成就感。本文将带你完整经历从硬件选型、电路设计到手机APP开发的每一个环节最终实现一辆可以通过手机蓝牙遥控的小车。1. 硬件选型与成本控制在开始项目前我们需要明确几个关键点低成本、易获取和稳定性。经过多次对比测试我最终确定了以下硬件配置方案1.1 核心控制器选择STM32系列单片机因其出色的性价比成为首选。经过对比STM32F103C6T6脱颖而出价格优势零售价约8-12元性能参数ARM Cortex-M3内核72MHz主频32KB Flash10KB RAM37个GPIO支持多种外设接口开发便利丰富的库函数支持和活跃的社区资源提示初学者可以选择带调试接口的核心板避免焊接困难。1.2 电机驱动方案驱动模块的选择直接影响小车的运动性能。经过测试对比DRV8833双路电机驱动芯片表现最佳参数DRV8833L298NTB6612单芯片价格1.2元5元8元最大电流1.5A2A3.2A工作电压2.7-10.8V5-35V4.5-13.5VPWM频率支持500kHz5kHz100kHz对于小型直流电机3-6V200-300mADRV8833完全够用且成本最低。1.3 蓝牙模块选型HC-05蓝牙模块是最经济实惠的选择价格约15元通信距离10米空旷环境接口UART串口通信供电3.3V-5V// 典型蓝牙模块初始化代码 void USART2_Init(u32 bound) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); // USART2_TX PA.2 GPIO_InitStructure.GPIO_Pin GPIO_Pin_2; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; GPIO_Init(GPIOA, GPIO_InitStructure); // USART2_RX PA.3 GPIO_InitStructure.GPIO_Pin GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, GPIO_InitStructure); USART_InitStructure.USART_BaudRate bound; USART_InitStructure.USART_WordLength USART_WordLength_8b; USART_InitStructure.USART_StopBits USART_StopBits_1; USART_InitStructure.USART_Parity USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART2, USART_InitStructure); USART_Cmd(USART2, ENABLE); }2. 电路设计与PCB制作2.1 电源系统设计考虑到灵活性我们设计了双电源输入方案USB供电5V稳定输入适合调试阶段锂电池供电7.4V航模电池通过AMS1117-5.0稳压到5V关键电路设计要点电源开关采用自锁开关增加100μF电解电容和0.1μF陶瓷电容滤波电源指示灯使用3mm红色LED2.2 电机驱动电路DRV8833外围电路非常简单只需注意以下几点每个电机通道需要两个控制信号IN1/IN2睡眠控制引脚(nSLEEP)需接高电平电机电源与逻辑电源隔离// DRV8833驱动代码示例 void Motor_Control(u8 motor, u8 dir, u8 speed) { switch(motor) { case MOTOR_A: if(dir FORWARD) { AIN1_H(); AIN2_L(); } else if(dir BACKWARD) { AIN1_L(); AIN2_H(); } else { AIN1_L(); AIN2_L(); } // 设置PWM占空比 set_pwm_duty(MOTOR_A_PWM, speed); break; case MOTOR_B: // 类似实现... } }2.3 PCB布局技巧经过多次迭代总结了以下PCB设计经验模块化布局将单片机、蓝牙、电机驱动分区域放置电源走线电机电源线宽≥1mm逻辑电源线宽≥0.5mm信号隔离PWM信号线远离模拟信号线散热考虑DRV8833下方铺铜并增加散热过孔3. 固件开发与蓝牙通信3.1 系统初始化流程固件开发采用模块化编程思想主要初始化顺序如下系统时钟配置72MHz延时函数初始化GPIO初始化定时器配置PWM生成USART初始化蓝牙通信电机驱动初始化int main(void) { SystemInit(); delay_init(); GPIO_Config(); TIM3_PWM_Init(719, 0); // 10kHz PWM USART2_Init(9600); DRV8833_Init(); while(1) { Bluetooth_Process(); delay_ms(10); } }3.2 蓝牙协议设计为简化开发我们定义了简单的文本协议方向控制F前进B后退L左转R右转S停止速度控制Vxxxxxx为0-100的速度值void Bluetooth_Process(void) { if(USART2_RX_STA 0x8000) { u8 len USART2_RX_STA 0x3FFF; USART2_RX_BUF[len] \0; switch(USART2_RX_BUF[0]) { case F: Motor_Control(MOTOR_A, FORWARD, current_speed); Motor_Control(MOTOR_B, FORWARD, current_speed); break; case B: // 类似处理... case V: current_speed atoi(USART2_RX_BUF1); break; } USART2_RX_STA 0; } }3.3 PWM调速实现使用定时器TIM3的通道1和通道2生成PWM信号void TIM3_PWM_Init(u16 arr, u16 psc) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // PA6-TIM3_CH1, PA7-TIM3_CH2 GPIO_InitStructure.GPIO_Pin GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); TIM_TimeBaseStructure.TIM_Period arr; TIM_TimeBaseStructure.TIM_Prescaler psc; TIM_TimeBaseStructure.TIM_ClockDivision 0; TIM_TimeBaseStructure.TIM_CounterMode TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, TIM_TimeBaseStructure); TIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OCPolarity TIM_OCPolarity_High; TIM_OC1Init(TIM3, TIM_OCInitStructure); TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); TIM_OC2Init(TIM3, TIM_OCInitStructure); TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); TIM_Cmd(TIM3, ENABLE); }4. 手机APP开发4.1 Android控制端设计使用Android Studio开发控制APP主要功能包括蓝牙设备搜索与连接方向控制按钮虚拟摇杆速度调节滑块连接状态显示关键实现代码// Bluetooth连接核心代码 private class ConnectThread extends Thread { private final BluetoothSocket mmSocket; private final BluetoothDevice mmDevice; public ConnectThread(BluetoothDevice device) { BluetoothSocket tmp null; mmDevice device; try { tmp device.createRfcommSocketToServiceRecord(MY_UUID); } catch (IOException e) { Log.e(TAG, Socket创建失败, e); } mmSocket tmp; } public void run() { BluetoothAdapter.getDefaultAdapter().cancelDiscovery(); try { mmSocket.connect(); } catch (IOException connectException) { try { mmSocket.close(); } catch (IOException closeException) { Log.e(TAG, 无法关闭socket, closeException); } return; } manageConnectedSocket(mmSocket); } }4.2 控制界面优化为提高操作体验我们采用了以下设计虚拟摇杆通过触摸位置计算方向向量速度曲线非线性映射低速段更精细自动重连连接断开后自动尝试重连状态反馈实时显示连接状态和电池电量4.3 常见问题解决在实际测试中遇到的一些问题及解决方案问题现象可能原因解决方法蓝牙无法连接模块未进入配对模式长按HC-05按键直到指示灯快闪电机不转电源功率不足更换更大容量电池或检查接线控制延迟大蓝牙信号干扰远离WiFi路由器等2.4GHz设备APP闪退蓝牙权限未开启检查AndroidManifest.xml权限设置5. 项目进阶与扩展完成基础功能后可以考虑以下扩展方向5.1 功能增强速度PID控制实现更平滑的加减速自动避障增加超声波传感器路线记忆存储并复现行驶路径5.2 性能优化低功耗设计空闲时进入睡眠模式协议优化改用二进制协议提高传输效率OTA升级通过蓝牙更新固件5.3 外观改造3D打印外壳设计个性化车体LED装饰增加可编程灯带摄像头扩展实现FPV第一人称视角// PID控制算法示例 typedef struct { float Kp, Ki, Kd; float integral, prev_error; } PIDController; float PID_Update(PIDController* pid, float setpoint, float measurement) { float error setpoint - measurement; pid-integral error; if(pid-integral 100) pid-integral 100; if(pid-integral -100) pid-integral -100; float derivative error - pid-prev_error; pid-prev_error error; return pid-Kp * error pid-Ki * pid-integral pid-Kd * derivative; }在完成这个小项目后最深的体会是硬件开发远比纯软件开发更具挑战性。一个小小的接触不良就可能导致数小时的调试但当看到小车按照指令精准运动时那种成就感也是无与伦比的。建议初学者在焊接时多检查几遍连接使用万用表测试关键点电压这样可以节省大量调试时间。