基于 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
  • 远离电机电源线
相关推荐
蹊黎10 小时前
Linux 下用 C 语言实现进度条
linux·c语言·单片机
Zw-awa13 小时前
从 CPU 搬运到自动搬运:DMA、空闲中断和两块缓冲
stm32
无敌贵点大王13 小时前
从寄存器层面重学STM32(6)——串口USART实战部分
stm32·单片机·嵌入式硬件
庙堂龙吟奈我何14 小时前
二进制和十六进制
stm32·单片机
国科安芯15 小时前
长期在轨的计算底座:商业空间站与在轨服务飞行器健康管理中的抗辐射MCU—— 面向可维护空间平台的分层容错与安全通信综述
人工智能·单片机·嵌入式硬件·安全·低轨卫星·抗辐射
TST-魚爷15 小时前
小型视频会议室音频踩坑:一体化拾音扩音方案实测分享(易视讯)
stm32·电脑·音视频·钉钉·腾讯会议·zoom会议
不昀17 小时前
RMII切到10Mbps,50MHz参考时钟也要降到5MHz吗?
单片机·嵌入式硬件·硬件设计·以太网接口
路上有只喵18 小时前
认识元器件 · 单片机(MCU/MPU/SOC) · 实战篇6
单片机·嵌入式硬件
国科安芯19 小时前
核电站蒸汽发生器传热管在役无损检测模拟前端的低噪声供电研究
嵌入式硬件·ldo·低压差线性稳压器·无损检测·核电站·蒸汽发生器·传热管
集芯微电科技有限公司19 小时前
40V/24A高频率增强型GaN HEMT功率开关管/高频DC转换/电动工具/GaN充电器 方案首选
人工智能·科技·单片机·嵌入式硬件·深度学习·神经网络·生成对抗网络