









这是整个清扫系统的大脑。Cortex-M3 内核 @72MHz,负责运行所有控制逻辑:接收蓝牙命令、输出 4 路 PWM 控制双电机+舵机、管理 10ms 系统节拍、处理按键/编码器中断。程序仅占用 8.5KB Flash,资源余量充足(64KB 总量)。板载 PC13 LED 用于心跳指示,无需外接显示屏也能判断工作状态。
这是系统的肌肉。内含两路独立 H 桥,每路可输出 1.2A 持续电流,同时驱动左右两个 130 直流电机。通过 AIN1/AIN2 + PWM 三线控制每路电机的转速(0-100%)和方向(正/反转)。PWM 频率 20kHz 高于人耳听觉范围,运转安静无啸叫。VM 接 5V 独立供电,STBY 使能引脚接 3.3V 常开。
两个 3.7V 额定电压的小型直流电机,各自带动一个圆形毛刷盘旋转清扫。通过 TB6612 实现双路独立 PWM 调速,左右刷盘可分别控制转速(命令 A:50 / B:80)。支持正反转——反转用于处理刷盘被异物卡住的异常情况。5V 短期测试可用,长期建议 3.7V 供电。
手机与清扫小车之间的无线桥梁。通过 USART1 串口(PA9/PA10)与 STM32 通信,波特率 9600bps。手机安装任意蓝牙串口助手 APP 即可发送 ASCII 命令遥控。支持的命令包括:ON/OFF(启停)、S0-100(调速)、A:N/B:N(单路控制)、UP/DN(刷臂升降)、REV(反转防卡)、?(状态查询)。
系统采用双电源架构:ST-Link 通过 SWD 接口提供 3.3V 逻辑电源(给 STM32、TB6612 逻辑侧、HC-05 供电),USB Type-C 提供 5V 电机电源(给 TB6612 VM 引脚和 SG90 舵机供电)。两个电源的 GND 必须共地,确保信号参考电平一致。
两轮差速驱动底盘,搭载所有硬件模块。底板提供统一的安装平面,TB6612、STM32 核心板、蓝牙模块均固定其上。车轮由独立电机驱动(非本清扫系统控制),清扫刷盘通过支架安装于车头/车侧,刷臂角度由 SG90 舵机调节。
小车底盘的两个驱动轮,由独立的行走电机控制(通过另一块 STM32 板或同一主控的其他 GPIO 控制)。通过两轮差速实现前进、后退、原地旋转。清扫作业时小车慢速前进,刷盘旋转清扫路面,刷臂角度根据路面情况由 SG90 动态调整。
用于固定 STM32 核心板和 TB6612 模块的塑料/金属支架,确保电路板在运动过程中不会松动或短路。支架通过螺丝或卡扣安装在底板上,核心板可直接插拔方便调试和更换。
套件包含母对母、母对公各 20 根杜邦线(21cm),用于连接 STM32 引脚与各模块。面包板跳线和飞线用于原型验证阶段快速搭建电路。正式安装在小车上后建议用扎带整理走线,避免运动时松动。
用于固定电机支架、刷盘连接件、舵机臂等机械部件。配合螺丝使用,确保清扫机构在震动环境下保持稳定连接。
STM32F103C8T6 主控芯片上电后,依次初始化 TIM2(SG90 舵机 50Hz PWM)、TIM3(Motor A 20kHz PWM)、 TIM1(Motor B 20kHz PWM)、TIM4(10ms 系统节拍定时器)及 USART1(蓝牙串口 9600bps)。 开机执行 3 秒自检确认双电机通路正常后进入主循环。主循环以 TIM4 10ms 中断为节拍驱动清扫状态机, 同时 USART1 中断接收蓝牙串口数据,当检测到换行符(\r 或 \n)时触发命令解析。命令经去空格、转大写、 字符串匹配后执行对应操作。TB6612 双 H 桥以 20kHz PWM 驱动两个 130 直流电机,占空比可 0%~100% 连续可调, 支持正反转。SG90 舵机以 50Hz PWM 控制刷臂角度(5°抬起 ~ 60°强力下压)。
┌─────────────────────────────────┐
│ 📱 手机蓝牙串口 APP │
│ 命令: ON / OFF / S50 │
└─────────────┬───────────────────┘
│ HC-05 BLE (9600)
┌─────────────┴───────────────────┐
│ 🧠 STM32F103C8T6 │
│ Cortex-M3 @ 72MHz │
│ │
│ PA0→SG90 │ PA6→MotorA │ PA8→MotorB │
│ PA9/10→HC-05 │ PB0/1/13/14→DIR │
└──┬──────────┬──────────┬──────────┘
│ │ │
┌────────┴──┐ ┌───┴──────────┴───┐ ┌───┴───┐
│ SG90 舵机 │ │ TB6612FNG │ │ HC-05 │
│ 刷臂 0~60° │ │ Motor A │ Motor B│ │ 蓝牙 │
│ 50Hz PWM │ │ 🧹左刷 │ 🧹右刷 │ └───────┘
└───────────┘ └──────────────────┘
| 项目名称 | 清扫小车 — 蓝牙遥控双刷盘嵌入式控制系统 |
| 适用场景 | 室内路面自动清扫,可安装于智能小车底盘,手机蓝牙遥控 |
| 开发语言 | C (ARMCC V5.06),基于 STM32 标准外设库 V3.5.0 |
| 核心依赖 | STM32F10x_StdPeriph_Driver、CMSIS Core-M3、startup_stm32f10x_md.s |
| MCU 平台 | STM32F103C8T6,Cortex-M3 内核,72MHz,64KB Flash,20KB SRAM |
| 编译工具 | Keil MDK-ARM V5 (ARMCC V5.06),优化 -O1,C99 + --gnu |
| 程序规模 | Code=6292B RO-data=2368B RW-data=68B ZI-data=1636B,~8.5KB Flash |
/* TB6612 双 H 桥电机驱动 - 20kHz PWM,双路独立 */
void TB6612_Init(void) {
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
// Motor A: PB0(AIN1) PB1(AIN2) + PA6(TIM3_CH1 PWM)
// Motor B: PB13(BIN1) PB14(BIN2) + PA8(TIM1_CH1 PWM)
// TIM1 需 BDTR 配置(高级定时器必须)
TIM_BDTRInitTypeDef bdtr; TIM_BDTRStructInit(&bdtr);
TIM_BDTRConfig(TIM1, &bdtr); TIM_CtrlPWMOutputs(TIM1, ENABLE);
}
void TB6612_MotorA(int16_t speed) {
if (speed > 100) speed = 100;
if (speed < -100) speed = -100;
if (speed > 0) { AIN1=1;AIN2=0;TIM_SetCompare1(TIM3,speed*36); }
else if (speed < 0) { AIN1=0;AIN2=1;TIM_SetCompare1(TIM3,(-speed)*36); }
else { AIN1=0;AIN2=0;TIM_SetCompare1(TIM3,0); }
}
/* SG90 舵机 - 50Hz PWM */
void SG90_SetAngle(uint8_t angle) {
uint16_t pulse = 500 + (uint16_t)((uint32_t)angle * 2000 / 180);
TIM_SetCompare1(TIM2, pulse); // 500(0°)-2500(180°)
}
/* USART1 中断接收(HC-05 蓝牙, 9600bps)*/
void USART1_IRQHandler(void) {
if (USART_GetITStatus(USART1, USART_IT_RXNE)) {
char ch = USART_ReceiveData(USART1);
if (ch == '\n' || ch == '\r') {
if (uart_idx) { uart_buf[uart_idx]=0; uart_cmd_ready=1; }
} else if (uart_idx < 63) uart_buf[uart_idx++] = ch;
}
}
/* 命令解析: 去空白→转大写→分支匹配 */
static void UART_ParseCmd(char *cmd) {
/* strip \r\n + leading spaces */
while (*cmd == ' ') cmd++; strupr(cmd);
if (!strcmp(cmd,"ON")) TB6612_BrushRun(65);
else if (!strncmp(cmd,"S",1)) { int v=atoi(cmd+1); TB6612_BrushRun(v); }
else if (!strcmp(cmd,"UP")) SG90_ArmUp();
else if (!strcmp(cmd,"DN")) SG90_ArmDown();
}
/* 按键扫描 - 每10ms调用 */
void Button_Scan(void) {
for (uint8_t i=0; i<3; i++) {
uint8_t cur = GPIO_ReadInputDataBit(pins[i]);
if (cur==0&&last[i]==1) cnt[i]=0; // 按下沿, 开始计数
else if (cur==0) cnt[i]++; // 持续按下, 累加
else if (cur==1&&last[i]==0&&cnt[i]>=3) // 松开沿, 判断
event[i] = (cnt[i]<100) ? KEY_SHORT : KEY_LONG;
if (cnt[i]==100) event[i]=KEY_LONG; // 长按1s
last[i]=cur;
}
}
/* 编码器 EXTI11 下降沿中断 */
void EXTI15_10_IRQHandler(void) {
if (EXTI_GetITStatus(EXTI_Line11)) {
if (GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_12)) enc_cnt++; else enc_cnt--;
EXTI_ClearITPendingBit(EXTI_Line11);
}
}
| PWM 频率 | Motor A: TIM3 20kHz / Motor B: TIM1 20kHz / SG90: TIM2 50Hz |
| 默认转速 | 65%(三档:LOW=40 / MID=65 / HIGH=100),编码器 ±20% 微调 |
| 反转防卡 | 转速 -80% 持续 3 秒(300×10ms),自动恢复正转 |
| 蓝牙波特率 | 9600-8-N-1,USART1 中断接收,缓冲区 64 字节 |
| 系统节拍 | TIM4 10ms 中断(PSC=71, ARR=9999) |
| 按键消抖 | 3 次确认 (30ms),短按 <1s,长按 ≥1s |
| LED 闪烁 | IDLE=500ms / RUNNING=100ms / PAUSED=常亮 |
| 开机自检 | 双电机 50% 正转 3 秒 → 停止 |
| MCU 资源 | Flash ~8.5KB/64KB (13%),SRAM ~1.7KB/20KB (8%) |
| STM32 引脚 | 功能 | 连接设备 | 技术参数 |
|---|---|---|---|
| PA0 | TIM2_CH1 | SG90 舵机 信号 | 50Hz PWM, 0~180°, 刷臂5°~60° |
| PA6 | TIM3_CH1 | TB6612 PWMA | 20kHz PWM, Motor A 转速 |
| PA8 | TIM1_CH1 | TB6612 PWMB | 20kHz PWM, Motor B 转速 |
| PA9 / PA10 | USART1_TX/RX | HC-05 RXD/TXD | 9600-8-N-1, 蓝牙串口 |
| PB0 / PB1 | GPIO Out | TB6612 AIN1/2 | Motor A 方向 (10=正 01=反) |
| PB8~PB10 | GPIO In (IPU) | KEY1/2/3 | 内部上拉, 接GND触发 |
| PB11 / PB12 | EXTI11 / GPIO | 编码器 CLK / DT | 下降沿中断 + 方向判断 |
| PB13 / PB14 | GPIO Out | TB6612 BIN1/2 | Motor B 方向 |
| PC13 | GPIO Out | 板载 LED | 心跳指示 (低点亮) |