一、系统概述
基于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 核心原理
-
超声波测距:
-
Trig引脚发送10us高电平触发测距;
-
Echo引脚接收高电平,用定时器捕获高电平持续时间
t; -
距离
d = (t × 340m/s) / 2 = t × 0.017cm/us(声速340m/s=0.034cm/us,除以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
五、调试与优化
-
超声波测距校准 :用直尺测量实际距离,调整
0.017系数(如实际2cm时测得1.8cm,系数改为0.019); -
电机转向测试:单独测试IN1/IN2/IN3/IN4电平,确保正转/反转方向正确;
-
避障阈值调整 :根据小车速度调整
DISTANCE_THRESHOLD,避免急转; -
抗干扰:Echo引脚加10kΩ下拉电阻,减少环境噪声影响。
六、总结
本程序基于STM32标准库3.5实现了超声波避障小车,核心是超声波测距+电机PWM控制+阈值避障逻辑。通过模块化设计(测距、电机、控制分离),便于移植和扩展(如添加红外避障、蓝牙遥控)。