基于 STM32F103ZET6 的循轨避障蓝牙小车

一、系统总体方案

1.1 功能定义

  • 循迹:红外对管 / 灰度传感器,沿黑线自动行驶
  • 避障:超声波 + 红外,遇到障碍物自动减速 / 转向
  • 蓝牙遥控:手机 APP(SPP 串口协议)远程控制
  • 自动 / 手动模式切换

1.2 系统框图

复制代码
        ┌─────────────┐
        │ 蓝牙 APP    │
        │ (Android)   │
        └─────▲───────┘
              │ UART
        ┌─────┴───────┐
        │ STM32F103ZET6│
        │ 主控 MCU     │
        └─────▲───────┘
              │ PWM / GPIO
   ┌──────────┼──────────┐
   │          │          │
┌──▼───┐  ┌──▼───┐  ┌──▼───┐
│ 左电机 │  │ 右电机 │  │ 舵机 │
│ TB6612 │  │ TB6612 │  │ SG90 │
└──────┘  └──────┘  └──────┘
   ▲          ▲
   └────┬─────┘
        │
┌───────┴───────┐
│ 循迹 / 避障   │
│ 红外 / 超声   │
└───────────────┘

二、硬件设计(可直接打板)

2.1 核心器件选型

模块 型号 说明
MCU STM32F103ZET6 512KB Flash,足够复杂逻辑
电机驱动 TB6612FNG 双路直流,PWM调速
循迹 TCRT5000 × 5 模拟/数字均可
避障 HC-SR04 + IR 超声测距 + 红外防跌落
蓝牙 HC-05 / JDY-31 串口 SPP
电源 18650 × 2 7.4V → 5V/3.3V
稳压 LM2596 + AMS1117 7.4→5V→3.3V

2.2 引脚分配

电机控制
c 复制代码
/* 左电机 */
#define MOTOR_L_IN1  GPIO_PIN_0  // PA0
#define MOTOR_L_IN2  GPIO_PIN_1  // PA1
#define MOTOR_L_PWM  TIM2_CH1    // PA0

/* 右电机 */
#define MOTOR_R_IN1  GPIO_PIN_2  // PA2
#define MOTOR_R_IN2  GPIO_PIN_3  // PA3
#define MOTOR_R_PWM  TIM2_CH2    // PA1
循迹传感器(5路)
c 复制代码
#define TRACK_S1  GPIO_PIN_4  // PA4
#define TRACK_S2  GPIO_PIN_5  // PA5
#define TRACK_S3  GPIO_PIN_6  // PA6
#define TRACK_S4  GPIO_PIN_7  // PA7
#define TRACK_S5  GPIO_PIN_0  // PB0
避障传感器
c 复制代码
#define US_TRIG   GPIO_PIN_8   // PB8
#define US_ECHO   GPIO_PIN_9   // PB9
#define IR_LEFT   GPIO_PIN_10  // PB10
#define IR_RIGHT  GPIO_PIN_11  // PB11
蓝牙(UART1)
c 复制代码
#define BT_TX  GPIO_PIN_9   // PA9
#define BT_RX  GPIO_PIN_10  // PA10

三、STM32CubeMX 配置

3.1 时钟

  • HSE:8 MHz
  • PLL:×9 → 72 MHz

3.2 TIM 定时器

TIM 用途 频率
TIM2 电机 PWM 10 kHz
TIM3 舵机 PWM 50 Hz
TIM4 超声波计时 1 MHz

3.3 USART

  • USART1:蓝牙(115200, 8N1)
  • DMA:接收(减少中断)

四、核心软件实现(C 语言)

4.1 电机驱动(motor.c

c 复制代码
#include "motor.h"

void Motor_Init(void)
{
    HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
    HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
}

void Motor_SetSpeed(uint8_t left, uint8_t right)
{
    __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, left);
    __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, right);
}

void Motor_Forward(uint8_t speed)
{
    HAL_GPIO_WritePin(GPIOA, MOTOR_L_IN1, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOA, MOTOR_L_IN2, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOA, MOTOR_R_IN1, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOA, MOTOR_R_IN2, GPIO_PIN_RESET);
    Motor_SetSpeed(speed, speed);
}

void Motor_TurnLeft(uint8_t speed)
{
    HAL_GPIO_WritePin(GPIOA, MOTOR_L_IN1, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOA, MOTOR_L_IN2, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOA, MOTOR_R_IN1, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOA, MOTOR_R_IN2, GPIO_PIN_RESET);
    Motor_SetSpeed(speed, speed);
}

4.2 循迹算法(track.c

c 复制代码
#include "track.h"

uint8_t Track_Read(void)
{
    uint8_t status = 0;
    status |= HAL_GPIO_ReadPin(GPIOA, TRACK_S1) << 0;
    status |= HAL_GPIO_ReadPin(GPIOA, TRACK_S2) << 1;
    status |= HAL_GPIO_ReadPin(GPIOA, TRACK_S3) << 2;
    status |= HAL_GPIO_ReadPin(GPIOA, TRACK_S4) << 3;
    status |= HAL_GPIO_ReadPin(GPIOB, TRACK_S5) << 4;
    return status;   // bit0~4:1=黑线
}

void Track_Control(void)
{
    uint8_t track = Track_Read();

    switch(track)
    {
        case 0b00100:  // 正中
            Motor_Forward(70);
            break;
        case 0b01100:  // 偏右
            Motor_TurnLeft(60);
            break;
        case 0b00011:  // 偏左
            Motor_TurnRight(60);
            break;
        case 0b11111:  // 十字路口
            Motor_Forward(80);
            HAL_Delay(500);
            break;
        default:
            Motor_Stop();
            break;
    }
}

4.3 避障算法(avoid.c

c 复制代码
#include "avoid.h"

float Ultrasonic_GetDistance(void)
{
    uint32_t time_us;

    HAL_GPIO_WritePin(GPIOB, US_TRIG, GPIO_PIN_SET);
    HAL_Delay(1);
    HAL_GPIO_WritePin(GPIOB, US_TRIG, GPIO_PIN_RESET);

    while(HAL_GPIO_ReadPin(GPIOB, US_ECHO) == GPIO_PIN_RESET);
    __HAL_TIM_SET_COUNTER(&htim4, 0);
    while(HAL_GPIO_ReadPin(GPIOB, US_ECHO) == GPIO_PIN_SET);
    time_us = __HAL_TIM_GET_COUNTER(&htim4);

    return (time_us / 58.0f);  // cm
}

void Avoid_Control(void)
{
    float dist = Ultrasonic_GetDistance();
    uint8_t ir_left = HAL_GPIO_ReadPin(GPIOB, IR_LEFT);
    uint8_t ir_right = HAL_GPIO_ReadPin(GPIOB, IR_RIGHT);

    if(dist < 20 || ir_left == 0 || ir_right == 0)
    {
        // 后退 + 转向
        Motor_Backward(60);
        HAL_Delay(300);
        Motor_TurnLeft(70);
        HAL_Delay(400);
    }
}

4.4 蓝牙协议(bluetooth.c

c 复制代码
#include "bluetooth.h"

uint8_t bt_rx_buf[32];
uint8_t bt_rx_len = 0;

void Bluetooth_Parse(uint8_t *data, uint8_t len)
{
    if(len < 2) return;

    if(data[0] == 0xA5 && data[len-1] == 0x5A)
    {
        uint8_t cmd = data[1];
        uint8_t val = data[2];

        switch(cmd)
        {
            case 0x01:  // 前进
                Motor_Forward(val);
                break;
            case 0x02:  // 后退
                Motor_Backward(val);
                break;
            case 0x03:  // 左转
                Motor_TurnLeft(val);
                break;
            case 0x04:  // 右转
                Motor_TurnRight(val);
                break;
            case 0x05:  // 自动模式
                system_mode = MODE_AUTO;
                break;
            case 0x06:  // 手动模式
                system_mode = MODE_MANUAL;
                break;
        }
    }
}

void USART1_IRQHandler(void)
{
    uint8_t ch;
    if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE))
    {
        ch = USART1->DR;
        if(bt_rx_len < sizeof(bt_rx_buf))
            bt_rx_buf[bt_rx_len++] = ch;
    }
}

五、主循环逻辑(main.c

c 复制代码
int main(void)
{
    HAL_Init();
    SystemClock_Config();

    MX_GPIO_Init();
    MX_TIM2_Init();
    MX_USART1_UART_Init();

    Motor_Init();
    Bluetooth_Init();

    while(1)
    {
        if(system_mode == MODE_AUTO)
        {
            Track_Control();
            Avoid_Control();
        }
        else if(system_mode == MODE_MANUAL)
        {
            // 蓝牙控制已在中断中处理
        }

        HAL_Delay(10);
    }
}

参考代码 基于STM32F103ZET6实现循轨避障蓝牙小车 www.youwenfan.com/contentcsv/115832.html

六、手机蓝牙 APP(通用协议)

功能 发送数据 说明
前进 A5 01 64 5A 速度 100
后退 A5 02 64 5A 速度 100
左转 A5 03 50 5A 速度 80
自动 A5 05 01 5A 进入自动
手动 A5 06 01 5A 进入手动

可用 蓝牙串口助手App Inventor 自制 APP。


七、调试与常见问题

7.1 电机抖动

  • PWM 频率太低 → 设为 10 kHz
  • 电源不足 → 18650 单独供电

7.2 循迹不准

  • 传感器间距 2~3 cm
  • 黑线宽度 1.5~2 cm
  • 增加软件滤波(连续 3 次确认)

7.3 蓝牙断连

  • 波特率 115200
  • 远离电机电源线
相关推荐
炸膛坦客8 小时前
单片机/C/C++八股:(二十六)IIC 专题(I²C)---- 上集
c语言·c++·单片机
华清远见IT开放实验室12 小时前
实验室建设案例 | 石家庄科技信息职业学院嵌入式实验室——从底层硬件到系统应用,一所应用型高校的嵌入式人才培养这样落地
linux·arm开发·stm32·嵌入式硬件·高校·实验室建设
AI的探索之旅15 小时前
AI辅助原理图评审:电源去耦、BOOT引脚、VCAP——19项逐一核查,遗漏?不存在的
人工智能·vscode·嵌入式硬件
茯苓gao15 小时前
嵌入式开发笔记:EtherCAT协议从硬件到软件完整配置指南——从零搭建一套EtherCAT通信系统
笔记·嵌入式硬件·学习
GeekArch15 小时前
第24讲:Vibe模式代码风格控制——适配Keil/STM32工程规范
人工智能·stm32·单片机·嵌入式硬件·mcu·决策树·ai编程
Freedom_my16 小时前
STM32项目3
stm32·单片机·嵌入式硬件
国科安芯17 小时前
星间光链路:AS32S601型抗辐射MCU在空间激光通信终端控制中的技术实现
服务器·网络·单片机·嵌入式硬件·物联网·安全·信息与通信
小李不困还能学18 小时前
基于 51 单片机的8 路抢答器设计教程
单片机·嵌入式硬件·mongodb·抢答器
CedarQR18 小时前
万字长文:从零在 RK3588 上部署 PaddleSpeech 中文 TTS 全流程(FastSpeech2 + HiFiGAN)
开发语言·c++·嵌入式硬件·ubuntu·json
萌动的小火苗19 小时前
嵌入式开发中的栈与队列:任务调度为什么依赖数据结构
数据结构·c++·单片机·嵌入式硬件