基于51单片机的超声波避障小车:HC-SR04与SG90舵机配合实现
+
一、HC-SR04超声波模块
HC-SR04时序图
触发信号输入端(Trig)输入一个10微秒以上的高电平信号,超声发送口收到信号自动发送8个40Hz方波,同时启动 定时器 ,待传感器接收到回波则停止 计时 并输出回响信号,回响信号脉冲宽度与所测距离正比。. 根据时间间隔可以计算距离,公式:距离=(高电平时间*声速)/2。【来自】
由于Trig端要输入一个10微秒以上的函数所以要使用 intrins.h中的函数 nop();
引入函数如下
#include <intrins.h>
整体测量距离函数
void hcsr04_Init()
{
Trig=1;//Trig端置1
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();//等待10us以上
Trig=0;//Trig端置0
while(!Echo); //当Echo端为0时等待
TR0=1; //定时器0置1 开始计时
while(Echo); //当Echo为1时 计时并等待
TR0=0; //关闭定时器0 结束计时
}
void distance(void) //超声波模块计算距离
{
time=TH0*256+TL0; //将计时器记录的时间存入time中
TH0=0; //计时器清零
TL0=0;
Distance=(time*1.8)/100;//计算距离
}
二、SG90舵机
sg90舵机的三根线买回来是连在一起的可将塑料头拆开方便接入单片机
SG90舵机时序图
该舵机的控制信号为周期是20ms 的脉宽调制(PWM)信号,脉冲宽度从0.5ms-2.5ms,相对应舵盘的位置为0—180度。
如上图可知
当脉冲宽度为0.5ms舵机旋转0度
当脉冲宽度为1ms舵机旋转45度
当脉冲宽度为1.5ms舵机旋转90度
当脉冲宽度为2ms舵机旋转135度
当脉冲宽度为2.5ms舵机旋转180度
接线说明
红线为vcc端接入单片机5v端
橙线为pwm信号线参考程序定义接入
棕线为gnd端接入单片机GND端
#include <REG51.H>
typedef unsigned char uchar; //偷懒 只为少敲些键盘
typedef unsigned int uint;
uchar angle;
sbit PWM = P3^5; //pwm信号端也就是舵机的黄色线
uchar count = 0; //计算周期
void delay_ms(uint c) //延迟函数 延迟1ms
{
uint a,b;
for(;c>0;c--)
for(b=102;b>0;b--)
for(a=3;a>0;a--);
}
void Time0_Init() //定时器初始化
{
TMOD = 0x01; //定时器0工作在方式1
TH0 = 0xfe; //装入初值 0.5ms中断一次
TL0 = 0x33;
EA = 1;
ET0 = 1;
TR0=1; //定时器置1打开
}
void main()
{
Time0_Init();
while (1)
{
count = 0;
angle = 1; //归零 1--0 2--45 3--90 4--135 5--180
delay_ms(1000);
count = 0;
angle = 2; //旋转45度
delay_ms(1000);
count = 0;
angle = 3; //旋转90度
delay_ms(1000);
count = 0;
angle = 4; //旋转135度
delay_ms(1000);
count = 0;
angle = 5; //旋转180度
delay_ms(1000);
}
}
void timer0() interrupt 1
{
TR0 = 0; //关闭计时器0
TH0 = 0xfe;
TL0 = 0x33; //11.0592MZ晶振,0.5ms
if(count<=angle)
{
PWM = 1;
}
else
{
PWM = 0;
}
if(count==40) //一个周期为20ms
{
count = 0; //周期达到20ms 清零重新计时
}
count ++;
TR0 = 1; //开启计时
}
三.总程序编写
#include <reg51.h>
#include <intrins.h> //用于使用了_nop()_函数
#define uchar unsigned char
#define uint unsigned int
sbit IN1 =P1^0;
sbit IN2 =P1^1;
sbit IN3 =P1^2;
sbit IN4 =P1^3;
sbit Echo = P2^5; //超声波模块 Echo端接单片机P2.5
sbit Trig = P2^6; //超声波模块 Trig端接单片机P2.6
sbit pwm= P2^4; //舵机信号端定义
void turnleft();
void turnright();
void straight();
void stop();
void count();
void run();
void hcsr04();
void delayms(uint ms);
uint time = 0; //测距数据,距离所用时间变量
uint Distance = 0; //距离
uchar flag =0; //定时器0溢出标志
uchar angle;
uint counter=0;
void main()
{
TMOD|=0x11; //定时器0定时器1,工作方式1
TH0=0; //定时器0用于超声波测距
TL0=0;
TH1=0xFE; //定时器1用于控制舵机 0.5ms定时
TL1=0x33;
ET0=1; //定时器0中断使能
ET1=1; //定时器1中断使能
TR1=1; //定时器1开始计时
EA=1; //开启总中断
angle = 3;
while(1)
{
hcsr04();
count(); //计算距离
run();
}
}
void delay_ms(uint c) //延迟函数 延迟1ms
{
uint a,b;
for(;c>0;c--)
for(b=102;b>0;b--)
for(a=3;a>0;a--);
}
void run() //测定距离为15cm 当大于小于15cm是舵机的转向和小车的前进方向
{
if(angle ==3 && Distance >= 15)
{
straight();
hcsr04();
count();
}
else if(angle ==3 && Distance < 15)
{
stop();
angle = 2;
delay_ms(20);
hcsr04();
count();
}
if(angle == 2 && Distance >=15)
{
turnright();
delay_ms(50);
angle=3;
delay_ms(20);
hcsr04();
count();
}
else if(angle == 2 && Distance < 15)
{
angle = 4;
delay_ms(20);
hcsr04();
count();
}
if(angle == 4 && Distance >=15)
{
turnleft();
delay_ms(50);
angle =3;
delay_ms(200);
hcsr04();
count();
}
else if(angle == 4 && Distance <15)
{
angle =3;
delay_ms(20);
hcsr04();
count();
}
}
void straight()
{
IN1 = 1;
IN2 = 0;
IN3 = 0;
IN4 = 1;
}
void turnleft()
{
IN1 = 1;
IN2 = 0;
IN3 = 1;
IN4 = 0;
}
void turnright()
{
IN1 = 0;
IN2 = 1;
IN3 = 0;
IN4 = 1;
}
void hcsr04()
{
Trig=1;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_(); //等待大于10us
Trig=0;
while(!Echo); //当Echo为零时等待
TR0=1; //开启计数
while(Echo); //当Echo为1时,计时并等待
TR0=0; //关闭计时
}
void count(void)
{
time=TH0*256+TL0; //定时器的值放在time中
TH0=0;
TL0=0; //清零定时器0
Distance=(time*1.8)/100; //计算距离
}
void Tmr0_isr() interrupt 1 //T0中断用来计数器溢出,超过测距范围
{
flag=1; //中断溢出标志
}
void Tmr1_isr() interrupt 3 //T1中断用来控制舵机
{
TR1 = 0; //关闭计时器0
TH1 = 0xfe;
TL1 = 0x33; //11.0592MZ晶振,0.5ms
if(counter<=angle)
{
pwm = 1;
}
else
{
pwm = 0;
}
if(counter==40) //一个周期为20ms
{
counter = 0; //周期达到20ms 清零重新计时
}
counter ++;
TR1 = 1; //开启计时
}
对于小车方向程序及烧录问题可转【基于51单片机的遥控小车】
-------------------------- END!!!----------------------------