一、系统概述
基于STC89C52RC单片机(12MHz晶振),实现三路超声波避障功能。通过HC-SR04超声波模块检测前、左、右三方向障碍物距离,结合L298N电机驱动模块控制小车转向/停止,实现自主避障。核心功能包括:三路超声波分时测距、距离阈值判断、电机PWM调速与转向控制。
二、硬件设计
2.1 核心组件
| 模块 | 型号/参数 | 功能说明 |
|---|---|---|
| 主控 | STC89C52RC(8位,12MHz) | 三路测距控制、避障逻辑、电机驱动 |
| 超声波 | 3×HC-SR04 | 前(Trig→P1.0,Echo→P1.1)、左(Trig→P1.2,Echo→P1.3)、右(Trig→P1.4,Echo→P1.5) |
| 电机驱动 | L298N | 驱动2路直流电机(正转/反转/调速) |
| 电机 | 2×直流减速电机(6V) | 小车动力(左/右轮) |
| 电源 | 7.4V锂电池+LM7805(5V) | 为单片机、超声波、L298N供电 |
2.2 硬件连接
| 模块 | 引脚(STC89C52RC) | 说明 |
|---|---|---|
| 超声波前 | Trig→P1.0,Echo→P1.1 | 检测正前方障碍物 |
| 超声波左 | Trig→P1.2,Echo→P1.3 | 检测左侧障碍物 |
| 超声波右 | Trig→P1.4,Echo→P1.5 | 检测右侧障碍物 |
| L298N | IN1→P2.0,IN2→P2.1 | 左电机正转/反转控制 |
| IN3→P2.2,IN4→P2.3 | 右电机正转/反转控制 | |
| ENA→P2.4(PWM),ENB→P2.5(PWM) | 电机调速(PWM占空比控制) |
三、软件设计(Keil C51)
3.1 核心原理
超声波测距:
Trig引脚发送10us高电平触发测距;
Echo引脚接收高电平,用定时器计数高电平持续时间
t(单位:us);距离
d = (t × 0.034) / 2(声速340m/s=0.034cm/us,往返距离÷2)。
避障逻辑(三路阈值):
前方(Trig1/Echo1):
d < 20cm停止,20~50cm减速,>50cm前进;左侧(Trig2/Echo2):
d > 30cm可左转;右侧(Trig3/Echo3):
d > 30cm可右转;综合判断:前方障碍→优先右转(若右侧空旷)→否则左转→仍不行则后退。
3.2 核心代码实现
3.2.1 头文件与宏定义
#include <reg52.h>
#include <intrins.h>
// ==================== 引脚定义(三路超声波) ====================
#define TRIG1 P1_0 // 前超声波Trig
#define ECHO1 P1_1 // 前超声波Echo
#define TRIG2 P1_2 // 左超声波Trig
#define ECHO2 P1_3 // 左超声波Echo
#define TRIG3 P1_4 // 右超声波Trig
#define ECHO3 P1_5 // 右超声波Echo
// ==================== 电机驱动引脚(L298N) ====================
#define IN1 P2_0 // 左电机正转
#define IN2 P2_1 // 左电机反转
#define IN3 P2_2 // 右电机正转
#define IN4 P2_3 // 右电机反转
#define ENA P2_4 // 左电机PWM(PWM占空比控制)
#define ENB P2_5 // 右电机PWM
// ==================== 宏定义 ====================
#define uchar unsigned char
#define uint unsigned int
#define THRESHOLD_FRONT_NEAR 20 // 前方近距离阈值(cm)
#define THRESHOLD_FRONT_FAR 50 // 前方远距离阈值(cm)
#define THRESHOLD_SIDE 30 // 侧向安全距离(cm)
#define PWM_DUTY_MAX 80 // PWM最大占空比(80%)
3.2.2 延时函数(微秒/毫秒级)
// 微秒延时(12MHz晶振,1us≈12周期,误差±1us)
void DelayUs(uint us) {
while (us--) {
_nop_(); _nop_(); _nop_(); _nop_(); // 4个_nop_≈1us
_nop_(); _nop_(); _nop_(); _nop_();
}
}
// 毫秒延时
void DelayMs(uint ms) {
uint i, j;
for (i=0; i<ms; i++)
for (j=0; j<110; j++); // 110次循环≈1ms
}
3.2.3 定时器初始化(用于Echo高电平计时)
// 定时器0初始化(16位模式,用于计时Echo高电平时间)
void Timer0_Init() {
TMOD |= 0x01; // T0模式1(16位计数)
TH0 = 0; TL0 = 0; // 初始值0
ET0 = 0; // 关闭T0中断(查询模式)
TR0 = 0; // 初始停止计数
}
3.2.4 单路超声波测距函数
// 测量单路超声波距离(返回cm,-1表示超时)
uint Measure_Distance(uchar trig_pin, uchar echo_pin) {
uint time = 0;
uint timeout = 25000; // 超时阈值(25000us=25ms,对应4m距离)
// 1. 触发测距(Trig发送10us高电平)
trig_pin = 1;
DelayUs(15); // 15us(>10us即可)
trig_pin = 0;
// 2. 等待Echo变高(启动计时)
while (echo_pin == 0 && timeout--); // 等待Echo变高
if (timeout == 0) return 0xFFFF; // 超时返回错误
// 3. 启动定时器计数Echo高电平时间
TR0 = 1; // 启动T0计数
TH0 = 0; TL0 = 0;
timeout = 25000;
while (echo_pin == 1 && timeout--); // 等待Echo变低
TR0 = 0; // 停止计数
if (timeout == 0) return 0xFFFF; // 超时返回错误
// 4. 计算时间(us)= TH0<<8 | TL0
time = (TH0 << 8) | TL0;
// 距离(cm) = (time × 0.034) / 2 ≈ time × 0.017
return (uint)(time * 0.017); // 简化计算(0.034/2=0.017)
}
3.2.5 电机控制函数
// 电机停止
void Motor_Stop() {
IN1 = 0; IN2 = 0; IN3 = 0; IN4 = 0;
ENA = 0; ENB = 0;
}
// 电机前进(PWM调速)
void Motor_Forward(uchar duty) {
IN1 = 1; IN2 = 0; IN3 = 1; IN4 = 0; // 正转
ENA = (duty > PWM_DUTY_MAX) ? PWM_DUTY_MAX : duty; // 限幅
ENB = ENA; // 左右电机同速
}
// 电机左转(右轮前进,左轮停止)
void Motor_TurnLeft(uchar duty) {
IN1 = 0; IN2 = 0; IN3 = 1; IN4 = 0; // 左轮停,右轮转
ENA = 0; ENB = (duty > PWM_DUTY_MAX) ? PWM_DUTY_MAX : duty;
}
// 电机右转(左轮前进,右轮停止)
void Motor_TurnRight(uchar duty) {
IN1 = 1; IN2 = 0; IN3 = 0; IN4 = 0; // 左轮转,右轮停
ENA = (duty > PWM_DUTY_MAX) ? PWM_DUTY_MAX : duty;
ENB = 0;
}
// 电机后退
void Motor_Backward(uchar duty) {
IN1 = 0; IN2 = 1; IN3 = 0; IN4 = 1; // 反转
ENA = (duty > PWM_DUTY_MAX) ? PWM_DUTY_MAX : duty;
ENB = ENA;
}
3.2.6 避障逻辑主函数
void Obstacle_Avoidance() {
uint dist_front, dist_left, dist_right;
// 1. 分时测量三路距离(避免干扰)
dist_front = Measure_Distance(TRIG1, ECHO1); // 前
DelayMs(50); // 间隔50ms
dist_left = Measure_Distance(TRIG2, ECHO2); // 左
DelayMs(50);
dist_right = Measure_Distance(TRIG3, ECHO3); // 右
// 2. 异常处理(超时视为无障碍)
if (dist_front == 0xFFFF) dist_front = 100;
if (dist_left == 0xFFFF) dist_left = 100;
if (dist_right == 0xFFFF) dist_right = 100;
// 3. 避障决策
if (dist_front > THRESHOLD_FRONT_FAR) {
// 前方安全(>50cm):前进(70%速度)
Motor_Forward(70);
} else if (dist_front > THRESHOLD_FRONT_NEAR) {
// 前方中等距离(20~50cm):减速前进(50%速度)
Motor_Forward(50);
} else {
// 前方近距离(<20cm):停止并转向
Motor_Stop();
DelayMs(200);
// 优先右转(右侧空旷)
if (dist_right > THRESHOLD_SIDE) {
Motor_TurnRight(60); // 右转(60%速度)
DelayMs(300); // 转300ms
}
// 其次左转(左侧空旷)
else if (dist_left > THRESHOLD_SIDE) {
Motor_TurnLeft(60); // 左转(60%速度)
DelayMs(300);
}
// 两侧均障碍:后退(50%速度)
else {
Motor_Backward(50);
DelayMs(500); // 退500ms
}
}
}
3.2.7 主函数
void main() {
Timer0_Init(); // 初始化定时器0(计时用)
EA = 1; // 开总中断(如需中断可启用)
while (1) {
Obstacle_Avoidance(); // 循环执行避障逻辑
DelayMs(100); // 每100ms检测一次
}
}
参考代码 基于51单片机超声波避障程序(三路) www.youwenfan.com/contentali/182711.html
四、关键问题与解决方案
4.1 三路干扰问题
原因:同时触发三路超声波会导致信号串扰。
解决:分时触发(每路间隔50ms),确保前一路线束Echo处理完毕再触发下一路线束。
4.2 测距误差大
原因:定时器精度不足(12MHz晶振下,16位定时器最大计时65ms,对应11m距离)。
解决:HC-SR04量程仅4m(约23ms),超时阈值设为25ms足够,误差主要来自声速温度补偿(常温下0.034cm/us可接受)。
4.3 电机抖动
原因:PWM占空比突变或电源不稳。
解决:PWM占空比渐变过渡(如每次增减10%),电源端并联100μF电容滤波。
五、测试与验证
硬件连接:按2.2节连接三路超声波与电机驱动,确保Trig/Echo引脚无虚焊。
功能测试:
前方无障碍物(>50cm):小车前进;
前方放置障碍物(<20cm):小车停止→右转→前进;
单侧有障碍(如左侧<30cm):小车优先右转避开。
六、总结
基于51单片机实现了三路超声波避障,核心是分时测距、定时器计时与电机联动控制。通过模块化设计(测距、电机、逻辑分离),可扩展为多路检测或加入红外传感器融合避障。