基于 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
  • 远离电机电源线
相关推荐
FreakStudio8 天前
W55MH32L-EVB 上手测评:硬件 TCP/IP 加持的以太网单片机,MicroPython 零门槛开发
python·单片机·嵌入式·大学生·面向对象·并行计算·电子diy·电子计算机
✎ ﹏梦醒͜ღ҉繁华落℘13 天前
单片机基础知识---stm32单片机的优先级
stm32·单片机·mongodb
u1521096484913 天前
S.S.Audio PRO A2音频隔离器
嵌入式硬件·音视频·实时音视频·视频编解码·视频
zd84510150013 天前
RS485 总线详解
单片机·嵌入式硬件
半条-咸鱼13 天前
【STM32】I2C协议原理、HAL读写与OLED显示操作
嵌入式硬件·c·信息与通信
牛根生同志13 天前
SPI数据收发的时候 TXE与RXNE标志位置位的时机
stm32·spi·transfer
wohoo_wangzi13 天前
苏州晟雅泰电子:关于W25Q128JVSIQ这个芯片物料的参数,规格及应用领域
嵌入式硬件
goldenrolan13 天前
学习型红外控制系统稳定性挂测工装专项总结
软件测试·python·stm32·嵌入式·红外
✎ ﹏梦醒͜ღ҉繁华落℘13 天前
编程基础 --高内聚,低耦合
c语言·单片机
科芯创展13 天前
1A,1MHz,30VIN,XZ4115,降压恒流LED驱动芯片
单片机·嵌入式硬件