#include <REGX52.H>
#include <intrins.h>
#include <QXA51.H>
sbit DU = P2^6;//数码管段选
sbit RX = P2^0;//ECHO超声波模块回响端
sbit TX = P2^1;//TRIG超声波模块触发端
sbit LCM_RW = P3^6; //定义LCD引脚
sbit LCM_RS = P3^5;
sbit LCM_E = P3^4;
#define LCM_Data P0 //定义液晶屏数据口
#define Busy 0x80 //用于检测LCM状态字中的Busy标识
unsigned char pwm_left_val = 180;//左电机占空比值 取值范围0-170,0最快
unsigned char pwm_right_val = 180;//右电机占空比值取值范围0-170 ,0最快
unsigned char pwm_t;//周期
unsigned int time = 0;//传输时间
unsigned long S = 0;//距离
bit flag = 0;//超出测量范围标志位
unsigned char code Range[] ="==Range Finder==";//LCD1602显示格式
unsigned char code ASCII[13] = "0123456789.-M";
unsigned char code table[]="Distance:000.0cm";
unsigned char code table1[]="!!! Out of range";
unsigned char disbuff[4] = { 0,0,0,0};//距离显示缓存
void delay(unsigned int z)//毫秒级延时
{
unsigned int x,y;
for(x = z; x > 0; x--)
for(y = 114; y > 0 ; y--);
}
void Delay10us(unsigned char i) //10us延时函数 启动超声波模块时使用
{
unsigned char j;
do{
j = 10;
do{
_nop_();
}while(--j);
}while(--i);
}
void cmg88()//关数共阴极码管
{
DU=1;
P0=0X00;//共阴极数码管阳极给低电平,全部熄灭
DU=0;
}
/************************************LCD1602液晶屏驱动函数************************************************/
//*******************读状态*************************//
unsigned char ReadStatusLCM(void)
{
LCM_Data = 0xFF;
LCM_RS = 0;
Delay10us(1);
LCM_RW = 1;
Delay10us(1);
do{
LCM_E = 0;
Delay10us(1);
LCM_E = 0;
Delay10us(1);
LCM_E = 1;
Delay10us(1);
}
while (LCM_Data & Busy); //检测忙信号
return(LCM_Data);
}
/****************写数据************************/
void WriteDataLCM(unsigned char WDLCM)
{
ReadStatusLCM(); //检测忙
LCM_Data = WDLCM;
LCM_RS = 1;
Delay10us(1);
LCM_RW = 0;
Delay10us(1);
LCM_E = 0; //若晶振速度太高可以在这后加小的延时
Delay10us(1);
LCM_E = 0; //延时
Delay10us(1);
LCM_E = 1;
Delay10us(1);
}
//****************写指令*************************//
void WriteCommandLCM(unsigned char WCLCM,BuysC) //BuysC为0时忽略忙检测
{
if (BuysC) ReadStatusLCM(); //根据需要检测忙
LCM_Data = WCLCM;
LCM_RS = 0;
Delay10us(1);
LCM_RW = 0;
Delay10us(1);
LCM_E = 0;
Delay10us(1);
LCM_E = 0;
Delay10us(1);
LCM_E = 1;
Delay10us(1);
}
//*******************LCM初始化**********************//
void LCMInit(void)
{
LCM_Data = 0;
WriteCommandLCM(0x38,0); //三次显示模式设置,不检测忙信号
delay(5);
WriteCommandLCM(0x38,0);
delay(5);
WriteCommandLCM(0x38,0);
delay(5);
WriteCommandLCM(0x38,1); //显示模式设置,开始要求每次检测忙信号
WriteCommandLCM(0x08,1); //关闭显示
WriteCommandLCM(0x01,1); //显示清屏
WriteCommandLCM(0x06,1); // 显示光标移动设置
WriteCommandLCM(0x0c,1); // 显示开及光标设置
}
//*********************按指定位置显示一个字符***********************//
void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData)
{
Y &= 0x1;
X &= 0xF; //限制X不能大于15,Y不能大于1
if (Y) X |= 0x40; //当要显示第二行时地址码+0x40;
X |= 0x80; //算出指令码
WriteCommandLCM(X, 1); //发命令字
WriteDataLCM(DData); //发数据
}
//**********************按指定位置显示一串字符*************************//
void DisplayListChar(unsigned char X, unsigned char Y, unsigned char code *DData)
{
unsigned char ListLength;
ListLength = 0;
Y &= 0x1;
X &= 0xF; //限制X不能大于15,Y不能大于1
while (DData[ListLength]>0x19) //若到达字串尾则退出
{
if (X <= 0xF) //X坐标应小于0xF
{
DisplayOneChar(X, Y, DData[ListLength]); //显示单个字符
ListLength++;
X++;
}
}
}
/***************************************************************************/
/*定时器0中断*/
void timer0() interrupt 1 //T0中断用来计数器溢出,超过测距范围
{
flag=1; //中断溢出标志
}
void StartModule() //启动超声波模块
{
TX=1; //启动一次模块
Delay10us(2);
TX=0;
}
/*小车前进*/
void forward()
{
left_motor_go; //左电机前进
right_motor_go; //右电机前进
}
/*PWM控制使能 小车后退*/
void backward()
{
left_motor_back; //左电机后退
right_motor_back; //右电机后退
}
/*小车停止*/
void stop()
{
right_motor_stops;//右电机停止
left_motor_stops; //左电机停止
}
/*PWM控制使能 小车高速左转*/
void left_rapidly()
{
left_motor_back;
right_motor_go;
}
/*定时器1中断输出PWM信号*/
void timer1() interrupt 3
{
pwm_t++;//周期计时加
if(pwm_t == 255)
pwm_t = EN1 = EN2 = 0;
if(pwm_left_val == pwm_t)//左电机占空比
EN1 = 1;
if(pwm_right_val == pwm_t)//右电机占空比
EN2 = 1;
}
/*判断S2是否被按下*/
void keyscan()
{
for(;;) //死循环
{
if(key_s2 == 0)// 实时检测S2按键是否被按下
{
delay(5); //软件消抖
if(key_s2 == 0)//再检测S2是否被按下
{
while(!key_s2);//松手检测
beep = 0; //使能有源蜂鸣器
delay(200);//200毫秒延时
beep = 1; //关闭有源蜂鸣器
break; //退出FOR死循环
}
}
}
}
/*计算超声波所测距离并显示*/
void Conut(void)
{
time=TH0*256+TL0;
TH0=0;
TL0=0;
S=(float)(time*1.085)*0.17; //算出来是MM
if((S>=7000)||flag==1) //超出测量范围
{
flag=0;
DisplayListChar(0, 1, table1);//1602显示数组table1
}
else
{
disbuff[0]=S/1000; //距离数值千位
disbuff[1]=S%1000/100;//距离数值百位
disbuff[2]=S%100/10;//距离数值十位
disbuff[3]=S%10; //距离数值个位
DisplayListChar(0, 1, table); //显示:Distance:000.0cm
DisplayOneChar(9, 1, ASCII[disbuff[0]]); //显示千位
DisplayOneChar(10, 1, ASCII[disbuff[1]]);
DisplayOneChar(11, 1, ASCII[disbuff[2]]);
DisplayOneChar(12, 1, ASCII[10]); //显示 .
DisplayOneChar(13, 1, ASCII[disbuff[3]]);
}
}
/*超声波避障*/
void Avoid()
{
if(S < 400)//设置避障距离 ,单位毫米 刹车距离
{
beep = 0;//使能蜂鸣器
stop();//停车
backward();//后退
delay(100);//后退时间越长、距离越远。后退是为了留出车辆转向的空间
do{
left_rapidly();//高速左转
delay(70);//时间越长 转向角度越大,与实际行驶环境有关
stop();//停车
delay(200);//时间越长 停止时间越久长
StartModule(); //启动模块测距,再次判断是否
while(!RX); //当RX(ECHO信号回响)为零时等待
TR0=1; //开启计数
while(RX); //当RX为1计数并等待
TR0=0; //关闭计数
Conut(); //计算距离
}while(S < 280);//判断前面障碍物距离
beep = 1;//关闭蜂鸣器
}
else
{
forward();//前进
}
}
void main()
{
cmg88();//关数码管
LCMInit(); //LCM初始化
delay(5);//延时片刻
DisplayListChar(0, 0, Range);//1602第一行显示Range数组内容
DisplayListChar(0, 1, table);//1602第二行显示table数组内容
keyscan();//等待按下S2启动小车
delay(1000);//延时1秒
TMOD |= 0x20;//定时器1工作模式2,8位自动重装。用于产生PWM
TMOD |= 0x01;//定时器0工作模块1,16位定时模式。T0用测ECH0脉冲长度
TH1 = 220; //
TL1 = 220; //100HZ T1
TH0 = 0;
TL0 = 0;//T0,16位定时计数用于记录ECHO高电平时间
ET1 = 1;//允许T1中断
ET0 = 1;//允许T0中断
TR1 = 1;//启动定时器1
EA = 1;//启动总中断
while(1)
{
StartModule(); //启动模块测距
while(!RX); //当RX(ECHO信号回响)为零时等待
TR0=1; //开启计数
while(RX); //当RX为1计数并等待
TR0=0; //关闭计数
Conut(); //计算距离
Avoid(); //避障
delay(65); //测试周期不低于60MS
}
}
#ifndef __QXA51_H__
#define __QXA51_H__
/*电机驱动IO定义*/
sbit IN1=P1^2; //为1 左电机反转
sbit IN2=P1^3; //为1 左电机正转
sbit IN3=P1^6; //为1 右电机正转
sbit IN4=P1^7; //为1 右电机反转
sbit EN1=P1^4; //为1 左电机使能
sbit EN2=P1^5; //为1 右电机使能
sbit left_led1=P3^3;//左寻迹信号 为0没有识别到黑线 为1识别到黑线
sbit right_led1=P3^2;//右寻迹信号 为0没有识别到黑线 为1识别到黑线
sbit left_led2=P3^4;//左避障信号 为0识别到障碍物 为1没有识别到障碍物
sbit right_led2=P3^5;//右避障信号 为0识别到障碍物 为1没有识别到障碍物
sbit beep=P2^3;
sbit key_s2=P3^0;
sbit key_s3=P3^1;
#define left_motor_en EN1=1 //左电机使能
#define left_motor_stops EN1=0 //左电机停止
#define right_motor_en EN2=1 //右电机使能
#define right_motor_stops EN2=0 //右电机停止
#define left_motor_go IN1=0,IN2=1 //左电机正转
#define left_motor_back IN1=1,IN2=0 //左电机反转
#define right_motor_go IN3=1,IN4=0 //右电机正转
#define right_motor_back IN3=0,IN4=1 //右电机反转
#endif
这里运用了LCD1602的显示数据,按键启动,超声波测距,蜂鸣器,定时器,中断功能,
避障原理:运用超声波测距来检测距离如果距离小于指定距离的话,蜂鸣器开始响,然后停车开始向后退,高速左转后停车,然后继续运用超声波模块测距,如果大于指定距离继续前进