⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dpj.txt

📁 单片机 驱动小车自动寻迹 实现家庭只能清洁机的功能
💻 TXT
📖 第 1 页 / 共 2 页
字号:
#include "reg52.h"
#include "stdio.h"
#include "intrins.h"
#define uchar unsigned char
#define uint unsigned int
sfr		T2MOD	= 0xc9;

sbit	DIN7219	= P2^0;
sbit	CS7219	= P2^1;
sbit	CLK7219	= P2^2;

sbit	yhwfs	= P0^0;	//前方红外检测发送控制口
sbit	qhwfs	= P0^1;	//左方红外检测发送控制口
sbit	zhwfs	= P0^2;	//右方红外检测发送控制口

sbit	CS1543	= P0^3;	//TLC1543片选,低电平有效
sbit	DT1543	= P0^4;	//TLC1543数字量数据输出口
sbit	AD1543	= P0^5;	//TLC1543模拟通道地址输入口
sbit	CK1543	= P0^6;	//TLC1543工作时钟输入口
//TLC1543模拟通道0,1,2,3,4,5分别为红外检测的右方0,前方1,左方2,光敏电阻的右寻迹3,左寻迹4,中寻迹5

sbit	HWK		= P0^7;	//红外遥控接收口
sbit	D18b20	= P1^0;	//18B20数据口
sbit	FMQ		= P2^7;	//蜂鸣器控制口	   低电平蜂鸣器响

sbit	LED1	= P2^3;	//低电平点亮
sbit	LED2	= P2^4;
sbit	LED3	= P2^5;
sbit	LED4	= P2^6;

sbit	ztsk	= P3^0;	//左电机调速输出口
sbit	ytsk	= P3^1;	//右电机调速输出口
sbit	zjsk	= P3^2;	//左电机测速脉冲输入口,INT0中断,边缘触发
sbit	yjsk	= P3^3;	//右电机测速脉冲输入口,INT1中断,边缘触发
sbit 	zin		= P3^4;	//左电机正反转控制口
sbit	yin		= P3^5;	//右电机正反转控制口
sbit	zen		= P3^6;	//左电机供电允许控制口
sbit	yen		= P3^7;	//右电机供电允许控制口
//sbit    	= P1^5;
//sbit    	= P1^6;
//系统剩余端口:P10到P14及P27共6个
bit		hwkjz;			//红外口禁止
bit		sxjz;			//刷新显示禁止
bit		zxrwt,kk,zxrwtt;			//执行任务状态,工作用位变量,即将完成执行任务状态
bit		lszt=0;
bit     lll=0;
bit		dwdjz=0;		//读温度禁止
bit		fmqzt=0;		//蜂鸣器状态
bit     wtjct=0;		//前进物体检验状态
bit		zanting;		//小车暂停/取消暂停
//bit		onoff;

uchar	idata xcq[9]={0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f};		  //显示存储区
uint	idata adsj[11];		//A/D转换数据存储区,二进制数
uchar	idata adsjc[11];		//A/D转换数据存储区,已转为十进制数
uchar	idata wendu[2];		//读18b20的温度数据,高字节ssssszzz   低字节zzzz.xxxx
uchar	idata wenduc[5];	//经处理后的温度数据,[4]为符号,[3][2][1]为整数字,[0]为小数
uchar 	code  wdxs[16]={0x00,0x01,0x01,0x03,0x03,0x04,0x04,0x05,0x06,0x06,0x07,0x08,0x08,0x09,0x09};
							//温度小数部分用查表法
float 	wenduf;
uchar	xsfs,jz,hwkjzys;	//显示方式,键值,红外口禁止延时
uchar	sxjzys;				//刷新显示禁止延时
uchar	tsjs,ztsds,ytsds;	//调速计数,左电机档数,右电机档数
uchar	hh,ss,mm;			//计时秒,分
uchar	sss,mmm;			//执行任务计时秒,分
uchar	gzhh,gzmm;			//定时启动小车工作的时间,小时,分钟
uchar	zxjs90;				//转向90度脉冲数
uchar	ccc,ll;				//临时
uchar	fmqxys;				//蜂鸣器发声延时

uchar	xczt;	//小车状态字,0,1,2,3,4,5,分别为停车0,前进1,倒退2,左转3,右转4,转向完成临时停车5,6
				//任务时:任务1寻线前进11,任务2寻线后退12,任务3垂直前进13,任务4垂直后退14,
				//检测块:tq2时为21,tq5时为22,
				
uchar	zjs,yjs;			//转向时左右轮临时脉冲计数
uchar	z0,zh0,y0;			//左中右寻迹比较阈值电平
							//实测各路最小(黑带内)/最大(白底)为z:3.3V/4.5V,y:2.3V~4.2V,zh:2.1V~4.5V
uchar   qy0,qz0;			//前左右寻迹比较阈值电平
uchar	tq20,tq50;			//气敏元件电压阈值
uchar	qfwt;
uchar	s,lm,l;				//水平横线长度(脉冲数),横线条数,小车当前寻迹线数
uchar	xjqk,xjqk0,xjqkq,xjqkn,jpt;	//寻迹情况,寻迹情况上次值,前方寻迹情况,寻迹情况连续相同值次数,纠偏状态
uint	zjsn,yjsn;			//左右轮前进累计脉冲计数
uint	n1000;				//T2定时中断1000次计数(1秒)
uint	n500;				//T2定时中断500次计数(半秒)-蜂鸣器使用
	
//uint	t0n,t0n0,nn;

void 	xtcsh(void);							  //系统初始化
void 	init_Max7219(void);
void 	Write_Max7219(uchar address,uchar dat);	  //
void 	Write_Max7219_byte(uchar kk);
uchar 	dhwk(void);								  //读红外遥控口
uchar 	dhwsj(void);							  //读红外遥控键值
void 	zxml(uchar jz);							  //
void 	sxxs(uchar fs);							  //刷新显示_LED数码管显示
void 	delay(uchar l);							  //
void 	delay2(uint l);
uint 	adzh(uchar adtd);						  //A/D转换_TLC1543
void 	zxrw(void);								  //执行任务
uchar 	xjqkfx(void);							  //寻迹情况分析
uchar 	ezhs(uint sj);							  //二进制转换十进制
void	tq2(void);								  //TQ-2气体传感器
void	tq5(void);								  //TQ-5气体传感器
void	wdcg(void);								  //温度传感器
void 	dwd(void);								  //读18b20温度
void 	fw18b20(void);							  //复位18b20
void 	write18b20_byte(uchar val);		//写18b20一字节
uchar 	read18b20_byte(void);			//读18b20一字节
void 	wdsjcl(void);					//温度数据处理

/*************************************************/

void xtcsh(void)		   //系统初始化
{
	zen=0;yen=0;
	zin=1;yin=1;
	xczt=0;
	zhwfs=qhwfs=yhwfs=0;
	ztsds=40;ytsds=40;tsjs=0;
	LED1=1;LED2=1;LED3=1;LED4=1;
 	TMOD=0x11;
	T2CON=0x00; 
	TH2=0xfc;		   //定时1ms
	TL2=0x67;
	RCAP2H = 0xfc;	   //自动重装初值寄存器
	RCAP2L = 0x67;
	TR2=1;
	ET2=1;
	TF2=0;
	IT0=1;EX0=1;	   //允许int0外部中断,边沿触发
	IT1=1;EX1=1;	   //允许int1外部中断,边沿触发
	EA=1;
	xsfs=0;
	hwkjz=0;
//	xwz=0x01;
	hwkjz=0;
	sxjz=0;
	sxjzys=200;
	ss=10;mm=59;hh=23;
	sss=mmm=0;
	zxjs90=16;
	s=50;lm=6;	  //水平横线长度(脉冲数),横线条数
	z0=zh0=y0=38;//实测各路最小(黑带内)/最大(白底)为z:3.3V/4.5V,y:2.3V~4.2V,zh:2.1V~4.5V,此均取3.8V为判断阈值
	qy0=qz0=35;	 //前寻线阈值
	tq20=10;		 //TQ-2气体传感器的阈值
	tq50=10;		 //TQ-5气体传感器的阈值
	fmqzt=0;	//蜂鸣器状态,静声
	zxrwt=0;
	qfwt=20;	//红外检测前方物体阈值电平
	FMQ=0;
	fw18b20();
	write18b20_byte(0xcc);
	write18b20_byte(0x44);
	delay(10);
	ccc=0xff;
	zanting=0;	 //预置小车非暂停状态
	gzhh=23;gzmm=0;		//预置小车定时自动启动工作的时间
}
/*************************************************/
void Write_Max7219_byte(uchar kk)
{
		uchar i;
		CLK7219=0;
		for(i=0;i<8;i++)
		{
			DIN7219=(bit)(kk & 0x80);
			kk<<=1;
			CLK7219=1;
			_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
			CLK7219=0;
		} 
}
/*************************************************/
void Write_Max7219(uchar address,uchar dat)
{
		DIN7219=0;
		CLK7219=0;
		CS7219=0;
		Write_Max7219_byte(address);
		Write_Max7219_byte(dat);
		CS7219=1;
}
/*************************************************/
void init_Max7219(void)
{
		Write_Max7219(0x0c,0x01);	//关断模式寄存器(0ch),开启正常工作模式(0xX1)		
		Write_Max7219(0x09,0xff);	//译码控制寄存器(09h),选用全译码模式(0xff)
		Write_Max7219(0x0b,0x07);	//扫描界限寄存器(0bh),8位全用
		Write_Max7219(0x0a,0x06);	//亮度控制寄存器(0ah),最大亮度0fh,设置初始亮度06h
		Write_Max7219(0x0f,0x00);	//测试控制寄存器(0fh),选择工作模式(0xX0)
}
/*
;测试寄存器地址为0FH,数据01H为测试,00H为正常工作
;7219的8个数码管的地址为01H(最低位)到08H(最高位)
;发送子程序,数据由R3(地址)和R4(数据)带来,共发16位
;B译码为BCD码,0AH~0EH为-,E,H,L,P,OFH为消隐,小数点为8XH
*/
/*************************************************/
void delay(uchar l)				  //延时125*11=1375微秒
{	uchar i;
	while(l--)
	{
		for(i=0;i<125;i++)
		{ ; } 
	}
}
/*************************************************/
void delay2(uint l)				  //延时11微秒
{	
	for(;l>0;l--)
	{ ; } 
}
/*************************************************/
uint adzh(uchar adtd)
{
	uchar i,j,ah,al;
	uint ad;
	j=adtd;ah=0;al=0;
	if(j==0) yhwfs=1;
	if(j==1) qhwfs=1;
	if(j==2) zhwfs=1;
	CS1543=0;					//选中1543芯片
	_nop_();
	for(i=1;i<5;i++)			//先发A/D通道地址(4bit)					  //添加
	{
	 	AD1543=(bit)(j&0x08);	//从高位发起,送1543数据线
		CK1543=1;				//发正脉冲到1543时钟线
		CK1543=0;
		j<<=1;					//发下一位
	}
	for(i=1;i<7;i++)			//再发6位空地址为
	{
		CK1543=1;
		CK1543=0;
	}
	CS1543=1;			//拉起1543CS电平,1543开始A/D转换
	for(i=0;i<15;i++)	//等待转换完成
	{	_nop_();}
	CS1543=0;			//再选中1543,准备读取转换数据
	for(i=1;i<3;i++)	//先读高2位(共10位)存在高字节
	{
	 	CK1543=1;DT1543=1;	 	//拉起时钟线,数据线电平
		ah<<=1;				 	//准备接收下一位(预先填0)
		if(DT1543) 	ah|=0x01; 	//如果数据线为高电平则改为1
		CK1543=0;		//降下时钟线电平,完成1bit的读取
	}
	for(i=1;i<9;i++)	//再读取数据的低8位,存在低字节
	{
	 	CK1543=1;DT1543=1;
		al<<=1;
		if(DT1543) 	al|=0x01;
		CK1543=0;
	}
	CS1543=1;			//完成数据读取,结束对1543的访问
	ad=(uint)(ah);ad<<=8;ad|=al;	//将高低字节组合
	ad*=5;		   	//乘基准电压5V,低10位应为小数部分
	zhwfs=0;qhwfs=0;yhwfs=0;
	return(ad);		
}
/*************************************************/
void sxxs(uchar fs)				//刷新显示
{	uchar i,j,b,c;
//	float x;
	switch(fs)
	{
	 	case 0:	{			   //fs=0时显示时间
					xcq[0]=ss%10;xcq[1]=ss/10;
					xcq[2]=(mm%10)|0x80;    //分钟个位数和小数点
					xcq[3]=mm/10;
					xcq[4]=(hh%10)|0x80;    //小时个位数和小数点
					xcq[5]=hh/10;
					xcq[6]=xcq[7]=0x0f;
					break;
				}
		case 1:	{			  //fs=1时显示路程,前进的累计计数
					xcq[0]=yjsn%10;			  //左轮脉冲数写入显存区
					xcq[1]=(yjsn%100)/10;
					xcq[2]=(yjsn%1000)/100;
					xcq[3]=yjsn/1000;
					xcq[4]=(zjsn%10)|0x80;	  //左轮脉冲数写入显存区
					xcq[5]=(zjsn%100)/10;
					xcq[6]=(zjsn%1000)/100;
					xcq[7]=zjsn/1000;
					break;
				}
		case 2:	{			  //fs=2时显示左右电机设置的调速档数
					xcq[0]=ytsds%10;		  //右轮档数写入显存区
					xcq[1]=(ytsds%100)/10;
					xcq[2]=(ytsds%1000)/100;
					xcq[3]=ytsds/1000;
					xcq[4]=(ztsds%10)|0x80;	  //左轮档数写入显存区
					xcq[5]=(ztsds%100)/10;
					xcq[6]=(ztsds%1000)/100;
					xcq[7]=ztsds/1000;
					break;
				}
		case 3:	{			  //显示左前右三路红外检测A/D转换的电压值,显示z.z q.q y.y
					if(sxjz==0)
					{	for(i=0;i<3;i++)		  	//分别为TL1543的模拟通道0,1,2  
						{	j=i*3;
	 						c=adsjc[i]/10;		//取整数部分
							b=adsjc[i]%10;	 	//取十分位数字
							xcq[j]=b;xcq[j+1]=c|0x80;xcq[j+2]=0x0f;	//分别送显存区待显 X.X
						}
						sxjz=1;
					}
					break;
				}
		case 7:	{			  //显示底盘左右红外检测A/D转换的电压值,显示z.z q.q y.y
					if(sxjz==0)
					{	for(i=7;i<9;i++)		  	//分别为TL1543的模拟通道1,2  
						{	j=(i-7)*3;
	 						c=adsjc[i]/10;		//取整数部分
							b=adsjc[i]%10;	 	//取十分位数字
							xcq[j]=b;xcq[j+1]=c|0x80;xcq[j+2]=0x0f;	//分别送显存区待显 X.X
						}
						sxjz=1;
						xcq[6]=xcq[7]=0x0f;
					}
					break;
				}

		case 8:	{				//显示18b20所测温度值,szzz.x
					xcq[0]=wenduc[0];	   	//十分位
					xcq[1]=wenduc[1]|0x80;	//个位,后加小数点
					xcq[2]=wenduc[2];		//十位
					xcq[3]=wenduc[3];		//百位
					if(xcq[3]==0) 
					{	xcq[3]=0x0f;
						if(xcq[2]==0) xcq[2]=0x0f;
					}
					xcq[4]=0x0f;					   //符号位
					if(wenduc[4]==1) xcq[4]=0x0a;	   //为负号
					xcq[5]=xcq[6]=xcq[7]=0x0f;
				 	break;
				}
		case 9:	{				//显示执行任务时间,mm.ss
					xcq[0]=sss%10;xcq[1]=sss/10;
					xcq[2]=(mmm%10)|0x80;    //分钟个位数和小数点
					xcq[3]=mmm/10;
					xcq[4]=xcq[5]=xcq[6]=xcq[7]=0x0f;
				 	break;
				}
		case 4:	{			  //显示底盘左中右三路光敏电阻寻迹检测A/D转换的电压值
					if(sxjz==0)
					{	for(i=3;i<6;i++)		  //分别为TL1543的模拟通道中5,左4,右3
						{	j=(i-3)*3;
	 						c=adsjc[i]/10;	//取整数部分
							b=adsjc[i]%10;	 	//取十分位数字
							xcq[j]=b;xcq[j+1]=c|0x80;xcq[j+2]=0x0f;	//分别送显存区待显 X.X
						}
						sxjz=1;
					}
					break;
				}
		case 5:	{			  //fs=5时显示左右转向时的临时计数
					xcq[0]=yjs%10;			  //右轮脉冲数写入显存区
					xcq[1]=(yjs%100)/10;
					xcq[2]=(yjs%1000)/100;
					xcq[3]=0x0f;
					xcq[4]=(zjs%10)|0x80;	  //左轮脉冲数写入显存区
					xcq[5]=(zjs%100)/10;
					xcq[6]=(zjs%1000)/100;
					xcq[7]=0x0f;
					break;
				}
		case 6:	{			  //fs=6时显示qkfx实时值
					b=ccc/10;
					xcq[0]=ccc%10;
					xcq[1]=b%10;
					xcq[2]=ccc/100;
					xcq[3]=0x0f;
					xcq[4]=0x0f;	  
					xcq[5]=0x0f;
					xcq[6]=xjqkq;
					xcq[7]=0x0f;
					break;
				}
		default:{	break;  }
	}
	for(j=0;j<8;j++) { Write_Max7219(j+1,xcq[j]); }	 //将显存数据送7219显示
}
/*************************************************/
void zxrw(void)							 //	执行任务
{	uchar zh,qy,qz;
	xjqk=xjqkfx();
	zh=adsjc[5];						//中寻线标志
	qy=adsjc[0];						//前右寻线标志
	qz=adsjc[2];						//前左寻线标志
	switch(xczt)
	{
	 	case 11:{		//寻线前进
					if((zjsn>s)|(yjsn>s))		//走到线左端,应后退返回
					{	zen=0;yen=0;zin=0;yin=0;
						zjsn=yjsn=s;
						delay(100);
						zen=yen=1;xczt=12;
					}
					else
					{	
						if((xjqkq==0x02)&(jpt!=1))	//左偏
						{	ztsds=49;ytsds=5;
//							if(ztsds>49)	ztsds=49;
							jpt=1;				//纠左偏状态
						}
						if((xjqkq==0x01)&(jpt!=2))	//右偏
						{	ztsds=5;ytsds=49;
//							if(ytsds>49)	ytsds=49;
							jpt=2;				//纠右偏状态
						}
/*						if((qy<qy0)&(jpt!=10))	   //左微偏
						{	ztsds+=5;ytsds-=5;
							jpt=10;				   //纠左微偏状态
						}  
						if(((xjqk==4)|(xjqk==6))&(jpt!=1))	//左偏
						{	ztsds+=9;ytsds-=9;
							if(zh>40) {ztsds+=5;ytsds-=5;}	//左偏严重
							if(ztsds>49)	ztsds=49;
							jpt=1;				//纠左偏状态
						}
						if((qz<qz0)&(jpt!=20))	   //右微偏
						{  ztsds-=5;ytsds+=5;
						   jpt=20;				 //纠右微偏状态
						}  
						if(((xjqk==1)|(xjqk==3))&(jpt!=2))	//右偏
						{	ztsds-=9;ytsds+=9;
							if(zh>40) {ztsds-=5;ytsds+=5;}	//右偏严重
							if(ytsds>49)	ytsds=49;
							jpt=2;				//纠右偏状态
						}
*/
						if(xjqkq==0x03)	{jpt=0;ztsds=ytsds=40;}	//不偏
					}
					if((adsjc[1]>qfwt)&(!fmqzt)&(!wtjct))
					{	
						FMQ=1;fmqzt=1;fmqxys=2;				   //启动蜂鸣器发声2次
						wtjct=1;	 						  //前进物体检测状态
					}
					break; 
				}
		case 12:{		//寻线后退
					if((zjsn==0)|(yjsn=0))		//已退到线左端,本线寻完,应左转向后垂直运行
					{							//
						zen=0;yen=0;zin=0;yin=1; 	//准备左转
						zjsn=yjsn=0;
						delay(100);
						zjs=yjs=0;ztsds=ytsds=40;zen=yen=1;xczt=3;	//左转	
					}
					else
/*					{	
						if((xjqkq==0x02)&(jpt!=1))	//尾巴右偏
						{	ytsds+=9;ztsds=10;
							if(ytsds>49)	ytsds=49;
							jpt=1;				//纠右偏状态
						}
						if((xjqkq==0x01)&(jpt!=2))	//尾巴左偏
						{	ytsds=10;ztsds+=9;
							if(ztsds>49)	ztsds=49;
							jpt=2;				//纠左偏状态

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -