51智能小车超声波避障

该博客介绍了基于超声波传感器的避障小车系统,包括LCD1602显示屏、按键启动、超声波测距、蜂鸣器提示和定时器中断等功能。小车通过检测到的距离进行避障操作,当障碍物距离小于预设值时,会停车、后退并高速左转,直至检测到安全距离后继续前进。此外,还涉及到了电机控制和PWM调速技术。
摘要由CSDN通过智能技术生成
#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的显示数据,按键启动,超声波测距,蜂鸣器,定时器,中断功能,

避障原理:运用超声波测距来检测距离如果距离小于指定距离的话,蜂鸣器开始响,然后停车开始向后退,高速左转后停车,然后继续运用超声波模块测距,如果大于指定距离继续前进

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值