基于STM32标准库3.5的小车超声波避障程序

一、系统概述

基于STM32标准库3.5实现小车超声波避障功能,通过HC-SR04超声波模块检测前方障碍物距离,结合L298N电机驱动模块控制小车转向/停止,实现自主避障。核心功能包括:超声波测距、距离阈值判断、电机PWM调速与转向控制。

二、硬件设计

2.1 核心组件

模块 型号/参数 功能说明
主控 STM32F103C8T6(库3.5) 系统控制、测距计算、电机驱动
超声波 HC-SR04 测距(2cm~400cm,精度±3mm)
电机驱动 L298N 驱动2路直流电机(正转/反转/调速)
电机 2路直流减速电机(6V) 小车动力(左/右轮)
电源 7.4V锂电池+LM7805(5V) 为STM32、超声波、L298N供电

2.2 硬件连接

模块 引脚(STM32) 说明
HC-SR04 Trig → PA0 触发信号(输出,高电平≥10us)
Echo → PA1 回响信号(输入,高电平持续时间=距离×2/声速)
L298N IN1 → PB0 左电机正转控制
IN2 → PB1 左电机反转控制
IN3 → PB5 右电机正转控制
IN4 → PB6 右电机反转控制
ENA → PA6(TIM3_CH1) 左电机PWM调速(TIM3输出)
ENB → PA7(TIM3_CH2) 右电机PWM调速(TIM3输出)

三、软件设计(STM32标准库3.5)

3.1 核心原理

  1. 超声波测距

    • Trig引脚发送10us高电平触发测距;

    • Echo引脚接收高电平,用定时器捕获高电平持续时间t

    • 距离d = (t × 340m/s) / 2 = t × 0.017cm/us(声速340m/s=0.034cm/us,除以2为往返距离)。

  2. 避障逻辑

  • 距离d > 30cm:前进(左右电机正转,PWM占空比70%);

  • 20cm ≤ d ≤ 30cm:减速前进(PWM占空比50%);

  • 10cm ≤ d < 20cm:左转(左电机停,右电机正转);

  • d < 10cm:右转(右电机停,左电机正转);

  • 超时(无回响):停止并后退(左右电机反转)。

3.2 程序结构

c 复制代码
/* 头文件与宏定义 */
#include "stm32f10x.h"
#define TRIG_PIN    GPIO_Pin_0
#define TRIG_PORT   GPIOA
#define ECHO_PIN    GPIO_Pin_1
#define ECHO_PORT   GPIOA
#define LEFT_FWD    GPIO_Pin_0, GPIOB  // IN1
#define LEFT_REV    GPIO_Pin_1, GPIOB  // IN2
#define RIGHT_FWD   GPIO_Pin_5, GPIOB  // IN3
#define RIGHT_REV   GPIO_Pin_6, GPIOB  // IN4
#define ENA_PIN     GPIO_Pin_6, GPIOA  // TIM3_CH1
#define ENB_PIN     GPIO_Pin_7, GPIOA  // TIM3_CH2
#define DISTANCE_THRESHOLD_NEAR 10   // 近距阈值(cm)
#define DISTANCE_THRESHOLD_MID   20   // 中距阈值(cm)
#define DISTANCE_THRESHOLD_FAR   30   // 远距阈值(cm)

/* 函数声明 */
void RCC_Configuration(void);    // 时钟配置
void GPIO_Configuration(void);   // GPIO配置
void TIM3_PWM_Init(u16 arr, u16 psc);  // TIM3 PWM初始化(电机调速)
void Ultrasonic_Trigger(void);   // 触发超声波测距
u16 Ultrasonic_GetDistance(void); // 获取距离(cm)
void Motor_Control(u8 left, u8 right); // 电机控制(0=停,1=正转,2=反转,PWM占空比)
void Delay_us(u32 us);            // 微秒延时
void Delay_ms(u32 ms);            // 毫秒延时

3.3 核心代码实现

3.3.1 时钟与GPIO配置
c 复制代码
void RCC_Configuration(void) {
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | 
                          RCC_APB2Periph_AFIO | RCC_APB2Periph_TIM1, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);  // TIM3时钟(PWM)
}

void GPIO_Configuration(void) {
    GPIO_InitTypeDef GPIO_InitStructure;
    
    // 超声波Trig(PA0,推挽输出)
    GPIO_InitStructure.GPIO_Pin = TRIG_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(TRIG_PORT, &GPIO_InitStructure);
    
    // 超声波Echo(PA1,上拉输入)
    GPIO_InitStructure.GPIO_Pin = ECHO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(ECHO_PORT, &GPIO_InitStructure);
    
    // 电机控制引脚(PB0/PB1/PB5/PB6,推挽输出)
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_5 | GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    // 初始状态:电机停
    GPIO_ResetBits(GPIOB, GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_5 | GPIO_Pin_6);
}
3.3.2 超声波测距函数
c 复制代码
// 触发测距(发送10us高电平)
void Ultrasonic_Trigger(void) {
    GPIO_SetBits(TRIG_PORT, TRIG_PIN);
    Delay_us(15);  // 10~20us触发
    GPIO_ResetBits(TRIG_PORT, TRIG_PIN);
}

// 获取距离(cm),超时返回0
u16 Ultrasonic_GetDistance(void) {
    u32 timeout = 0;
    u16 distance = 0;
    
    Ultrasonic_Trigger();  // 触发测距
    
    // 等待Echo变高(启动计时)
    while (GPIO_ReadInputDataBit(ECHO_PORT, ECHO_PIN) == RESET) {
        timeout++;
        if (timeout > 10000) return 0;  // 超时(无回响)
        Delay_us(1);
    }
    
    // 测量Echo高电平持续时间(us)
    u32 t = 0;
    while (GPIO_ReadInputDataBit(ECHO_PORT, ECHO_PIN) == SET) {
        t++;
        Delay_us(1);
        if (t > 30000) {  // 最大测距4m(约23500us),超时返回0
            t = 0;
            break;
        }
    }
    
    // 计算距离:d = t × 0.017cm/us(声速340m/s=0.034cm/us,除以2)
    distance = t * 0.017;
    return (distance > 400) ? 400 : distance;  // 限幅400cm
}
3.3.3 电机PWM控制(TIM3)
c 复制代码
// TIM3 PWM初始化(arr=周期,psc=预分频,控制PWM频率=72MHz/(psc+1)/(arr+1))
void TIM3_PWM_Init(u16 arr, u16 psc) {
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_OCInitTypeDef TIM_OCInitStructure;
    
    // 时基配置
    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);
    
    // PWM模式配置(通道1:PA6,通道2:PA7)
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = 0;  // 初始占空比0
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    
    TIM_OC1Init(TIM3, &TIM_OCInitStructure);  // 通道1(ENA)
    TIM_OC2Init(TIM3, &TIM_OCInitStructure);  // 通道2(ENB)
    
    TIM_Cmd(TIM3, ENABLE);  // 使能TIM3
    TIM_CtrlPWMOutputs(TIM3, ENABLE);  // 高级定时器需使能,此处F103C8T6无需
}

// 设置电机PWM占空比(0~100%)
void Motor_PWM_Set(u8 channel, u8 duty) {
    u16 pulse = (TIM3->ARR + 1) * duty / 100;  // 计算脉冲值
    if (channel == 1) TIM_SetCompare1(TIM3, pulse);  // 左电机(ENA)
    if (channel == 2) TIM_SetCompare2(TIM3, pulse);  // 右电机(ENB)
}
3.3.4 电机控制与避障逻辑
c 复制代码
// 电机控制:left/right=0(停)/1(正转)/2(反转),duty=占空比(0~100)
void Motor_Control(u8 left, u8 right, u8 duty) {
    // 左电机
    if (left == 0) {  // 停
        GPIO_ResetBits(GPIOB, LEFT_FWD);
        GPIO_ResetBits(GPIOB, LEFT_REV);
    } else if (left == 1) {  // 正转
        GPIO_SetBits(GPIOB, LEFT_FWD);
        GPIO_ResetBits(GPIOB, LEFT_REV);
    } else if (left == 2) {  // 反转
        GPIO_ResetBits(GPIOB, LEFT_FWD);
        GPIO_SetBits(GPIOB, LEFT_REV);
    }
    
    // 右电机
    if (right == 0) {  // 停
        GPIO_ResetBits(GPIOB, RIGHT_FWD);
        GPIO_ResetBits(GPIOB, RIGHT_REV);
    } else if (right == 1) {  // 正转
        GPIO_SetBits(GPIOB, RIGHT_FWD);
        GPIO_ResetBits(GPIOB, RIGHT_REV);
    } else if (right == 2) {  // 反转
        GPIO_ResetBits(GPIOB, RIGHT_FWD);
        GPIO_SetBits(GPIOB, RIGHT_REV);
    }
    
    // 设置PWM占空比
    Motor_PWM_Set(1, duty);  // 左电机
    Motor_PWM_Set(2, duty);  // 右电机
}

// 主避障逻辑
void Obstacle_Avoidance(void) {
    u16 distance = Ultrasonic_GetDistance();
    if (distance == 0) {  // 超时(无回响)
        Motor_Control(2, 2, 50);  // 后退
        Delay_ms(500);
        Motor_Control(0, 0, 0);   // 停
    } else if (distance < DISTANCE_THRESHOLD_NEAR) {  // <10cm:右转
        Motor_Control(1, 0, 60);  // 左电机正转,右电机停
        Delay_ms(300);
    } else if (distance < DISTANCE_THRESHOLD_MID) {  // 10~20cm:左转
        Motor_Control(0, 1, 60);  // 左电机停,右电机正转
        Delay_ms(300);
    } else if (distance < DISTANCE_THRESHOLD_FAR) {  // 20~30cm:减速前进
        Motor_Control(1, 1, 50);  // 双电机正转,50%占空比
    } else {  // >30cm:前进
        Motor_Control(1, 1, 70);  // 双电机正转,70%占空比
    }
}
3.3.5 主函数
c 复制代码
int main(void) {
    RCC_Configuration();    // 时钟配置
    GPIO_Configuration();   // GPIO配置
    TIM3_PWM_Init(999, 71);  // TIM3初始化:72MHz/(71+1)=1MHz,周期=1000us(1ms),PWM频率1kHz
    
    while (1) {
        Obstacle_Avoidance();  // 避障逻辑
        Delay_ms(100);         // 每100ms测距一次
    }
}

四、关键函数补充(延时函数)

c 复制代码
// 微秒延时(基于SysTick,需先配置SysTick时钟)
void Delay_us(u32 us) {
    SysTick->LOAD = 72 * us;  // 72MHz时钟,1us=72个周期
    SysTick->VAL = 0x00;     // 清空计数器
    SysTick->CTRL = 0x00000005;  // 使能SysTick,无中断
    while (!(SysTick->CTRL & 0x00010000));  // 等待计数完成
    SysTick->CTRL = 0x00000004;  // 关闭SysTick
}

// 毫秒延时
void Delay_ms(u32 ms) {
    while (ms--) Delay_us(1000);
}

参考代码 基于stm32库3.5编写的小车超声波避障程序 www.youwenfan.com/contentcss/56282.html

五、调试与优化

  1. 超声波测距校准 :用直尺测量实际距离,调整0.017系数(如实际2cm时测得1.8cm,系数改为0.019);

  2. 电机转向测试:单独测试IN1/IN2/IN3/IN4电平,确保正转/反转方向正确;

  3. 避障阈值调整 :根据小车速度调整DISTANCE_THRESHOLD,避免急转;

  4. 抗干扰:Echo引脚加10kΩ下拉电阻,减少环境噪声影响。

六、总结

本程序基于STM32标准库3.5实现了超声波避障小车,核心是超声波测距+电机PWM控制+阈值避障逻辑。通过模块化设计(测距、电机、控制分离),便于移植和扩展(如添加红外避障、蓝牙遥控)。

相关推荐
dashizhi20153 小时前
服务器共享管理之设置共享文件访问权限、记录共享文件访问行为日志?
运维·网络·stm32·安全·电脑
深圳市雅欣控制技术有限公司3 小时前
室内 KTV 灯控方案:STM32 主控与电源芯片(FP6195 + FP7208)应用方案
stm32·单片机·嵌入式硬件·智能照明·灯光控制·单节锂电池·ktv氛围灯
飘忽不定的bug3 小时前
RK3588 linux+rtos(mcu)串口适配
linux·单片机·elasticsearch
Suifqwu13 小时前
rk3576(6)之设备树下GPIO驱动
单片机·嵌入式硬件
三佛科技-1873661339714 小时前
国产替代新选择|替代STM32/APM32型号推荐(32位MCU)
stm32·单片机·嵌入式硬件
要不枉此行15 小时前
BLE 性能调优全攻略:MTU 配置、DLE 开启与干扰优化
单片机
llilian_1615 小时前
信号失真度测试仪 自动失真测试仪 低失真度自动测量仪为各行业精准赋能 自动失真仪
网络·功能测试·单片机·测试工具
jghhh0116 小时前
基于TMS320F28033的20MHz手持式双踪袖珍示波器设计与实现
stm32·嵌入式硬件·51单片机
zmj32032416 小时前
KW45芯片的安全启动
单片机·嵌入式开发·安全启动