做这个超声波避障小车的原因是因为单片机课程设计
一、硬件部分
1、电机驱动
电机驱动四个输入端IN1、IN2、IN3和IN4,四个输出端OUT1、OUT2、OUT3和OUT4,一个接地端GND,单片机的P2.1~P2.4端口分别与 引脚IN1、IN2、IN3、IN4相连通过电平变化控制电机在持续高速状态下的转向,L298N的四个输出端直接与两个电机相连驱动电机,采用电池供电。
2、超声波
超声波模块采用的HC–SR04超声波模块,该模块可提供 2cm-400cm 的非接触式距离感测功能,测距精度可达高到 3mm,测量角度小于15度。模块包括超声波发射器、接收器与控制电路。基本工作原理:采用 IO 口 TRIG 触发测距,给至少20us 的高电平信号;模块自动发送 8个40khz 的方波,自动检测是否有信号返回;有信号返回,通过 IO 口 ECHO 输出一个高电平,高电平持续的时间就是超声波从发射到返回的时间。测试距离=(高电平时间*声速(340M/S))/2。其中VCC 供5V 电源,GND 为地线,TRIG 触发控制信号输入,ECHO 回响信号输出等四支线。
程序中测试功能主要由两个函数完成,即openHc()负责启动一次模块的测距,然后由getDistance()确定前方是否有障碍物。
3、舵机
舵机是一种位置(角度)伺服的驱动器,适用那些需要角度不断变化并可以保持的控制系统。舵机只是一种通俗的叫法,其实质是一个伺服马达。舵机又分为模拟舵机和数字舵机,模拟舵机需要不断的发送目的地PWM信号,才能旋转到指定位置,而数字舵机只需给一个目的地PWM信号,即可旋转到指定位置。
PWM(脉冲宽度调制)是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。而高电平(或者低电平)占整个周期的时间就叫作占空比,PWM频率是指每秒钟信号从高电平到低电平再到高电平的次数。
接线方法:
红-------------------------VCC
棕色----------------------GND
橙色----------------------信号线
在项目中黄色的信号线接单片机的P1.0引脚,红色的电源线和GND接单片机的5V电源引脚和GND。
二、代码部分
#include<reg52.h>
#include<intrins.h>
#define uchar unsigned char
#define obstructionDis 20 //到障碍物距离
sbit LED = P0^0; //距离小于20就亮
sbit Trig = P1^1; //TRIG用来发送方波
sbit Echo = P1^2; //ECHO用来接收方波
sbit Motor_1 = P2^1; //控制第一个电机正反转
sbit Motor_2 = P2^2;
sbit Motor_3 = P2^3; //控制第二个电机正反转
sbit Motor_4 = P2^4;
sbit servoMotors = P1^0; //PWM控制舵机引脚
float L = 0;
uchar sum;
uchar Motor_pwm = 0;
uchar Servor = 5; //设置舵机占空比
uchar servorTime = 0;
uchar ifLeft = 0; //左方向是否有障碍物
uchar ifRight = 0; //右方向是否有障碍物
void delay(uchar time) //延时函数
{
uchar i;
for(;time > 0;time--){
for(i = 0;i < 255;i++);
}
}
void turnLeft() //左
{
Motor_1 = 1;
Motor_2 = 0;
Motor_3 = 0;
Motor_4 = 0;
}
void turnRight() //右
{
Motor_1 = 0;
Motor_2 = 0;
Motor_3 = 1;
Motor_4 = 0;
}
void turnUp() //前
{
Motor_1 = 1;
Motor_2 = 0;
Motor_3 = 1;
Motor_4 = 0;
}
void turnDown() //后
{
Motor_1 = 0;
Motor_2 = 1;
Motor_3 = 0;
Motor_4 = 1;
}
//发射超声波测距波形
void openHc()
{
Trig = 1;
_nop_(); //1us,一共20us
_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();
_nop_();
Trig = 0;
}
//超声波
uchar getDistance()
{
TH0 = 0;
TL0 = 0;
openHc(); //发送一个方波信号,
while(!Echo); //等于0一直循环,直到Echo为高电平,信号反弹回来
TR0 = 1; //开启定时器
while(Echo);
TR0 = 0;
sum = TH0*256 + TL0; //高八位加低八位组成16位
L = (sum*1.78)/100; //L为距离
if(L < obstructionDis){ //如果距离小于20
LED = 1;
return 0;
}else{
LED = 0;
return 1;
}
}
//控制舵机方向
void control()
{
Servor = 21; //舵机向左摆动
servorTime = 0; //从0开始计数
TR1 = 1; //开启T1,舵机开始工作
delay(200); //等待
TR1 = 0;
delay(3000);
if(getDistance() == 0){
turnLeft();
delay(200);
delay(200);
}
Servor = 13; //超声波正对前方
servorTime = 0;
TR1 = 1; //定时器T1开始工(T1用来控制舵机)
delay(200); //等待中断
TR1 = 0; //关闭定时器
delay(3000);
if(getDistance() == 0){
turnDown();
delay(200);
delay(200);
delay(100);
turnRight();
delay(200);
delay(200);
}
Servor = 5; //舵机向右
servorTime = 0;
TR1 = 1;
delay(200);
TR1 = 0;
delay(3000);
if(getDistance() == 0){
turnRight();
delay(200);
delay(200);
}
Servor = 13; //超声波正对前方
servorTime = 0;
TR1 = 1; //定时器T1开始工(T1用来控制舵机)
delay(200); //等待中断
TR1 = 0; //关闭定时器
delay(3000);
if(getDistance() == 0){
turnDown();
delay(200);
delay(200);
delay(100);
turnRight();
delay(200);
delay(200);
}
}
//初始化
void Init()
{
LED = 1; //LED先亮
EA = 1;
ET1 = 1;
TMOD |= 0x10; //00000001,方式1
TH1 = (65536 - 100)/256; //65436,100us
TL1 = (65536 - 100)%256;
}
//主程序
void main()
{
Init();
servorTime = 0;
while(1){ //如果返回的是1,则说明没有障碍物所以一直向前
turnUp();
if(getDistance() == 1){
control();
}else{
turnDown();
delay(200);
delay(200);
delay(100);
control();
break;
}
}
}
//T1中断
void T1_int() interrupt 3 //产生舵机所用脉常(输出PWM信号)
{
TH1 = 0xff; //重新赋值
TL1 = 0x9c;
servorTime++; //用来计数中断次数,加一次就代表100us
if(servorTime <= Servor){
servoMotors = 1; //舵机旋转
}else{
servoMotors = 0; //舵机停止
}
if(servorTime >= 100){ //加到100舵机就停止
servorTime = 0; //舵机停
}
}
三、实物图
因为小车是一直在向前走,舵机又在左右旋转,所以需要小车的速度足够慢,避障效果才比较明显,即使用了一个降压模块,让小车的速度慢下来。