迷宫电脑鼠(51单片机)

功能分析:

(1)迷宫小车能够在迷宫中随意穿行(寻找终点)。
五个传感器,左外和右外传感器用来修正小车,其中无论哪一个检测到障碍,小车就向另一边转动一定角度,使其尽可能地在路径中心行走。前、左、右传感器用来判断这三个方向是否有障碍,并根据设计的右手法则使小车可以左右转弯和向前走防止其撞墙。
(2)迷宫小车能够在迷宫中记忆路径(遍历迷宫)。
建立一个二维数组,用坐标来表示相应迷宫格子的下标,通过绝对方向与小车相对方向的转换,利用位运算将左、右、前三个传感器记录的挡板信息放在低四位,0无1有,小车从迷宫格子的哪个绝对方向进入放在高四位。通过小车进入每一个迷宫格子的绝对方向来记忆路径。
(3)迷宫小车遇到死胡同或周围路径已走过无路可走能够回溯到上一个岔路口(回溯)。
通过建立的二维数组中记录的数据,每个数据的高四位记录的是小车进入该迷宫格子的绝对方向,通过小车现在在这个迷宫格子的绝对方向和之前进入该迷宫格子的绝对方向相对比,来选择是向左转、向右转、转180度还是不转,只要保证与进入的绝对方向相反就能回溯到上一个岔路口。

mouse.h

sfr P4=0xe8;
//红外地址接口定义
sbit A0=P4^0;
sbit A1=P2^0;
sbit A2=P2^7;
//红外传感器接收信号口定义(接收到信号值为0)
sbit irR1=P2^1; //前
sbit irR2=P2^2; //左外
sbit irR3=P2^3; //左
sbit irR4=P2^4; //右
sbit irR5=P2^5; //右外
bit irC=0 ,irL=0,irR=0,irLU=0,irRU=0;//定义红外传感器检测状态全局位变量,为0无障碍
//红外发射控制宏定义(传入传感器组号)
#define MOUSE_IR_ON(GROUP_NO) \
do\
{	\
	A0=(GROUP_NO)&0x01; \
	A1=(GROUP_NO)&0x02; \
	A2=(GROUP_NO)&0x04; \
}while(0)

主代码

//八位,低四位挡板情况,高四位方位代码,0、1、2、3分别来表示上、右、下、左
//遍历;冲刺//200个字节
#include "reg52.h"
#include "mouse.h"

unsigned char code forward[]={0x11,0x33,0x22,0x66,0x44,0xcc,0x88,0x99};
unsigned char code reverse[]={0x11,0x99,0x88,0xcc,0x44,0x66,0x22,0x33};
unsigned char code go[]={0x11,0x93,0x82,0xc6,0x44,0x6c,0x28,0x39};
unsigned char i=0,j=0;
sbit tube1 = P4^3;
sbit tube2 = P4^2;
sbit beep = P3^7;
xdata unsigned char map[8][8];//地图数据
xdata unsigned char stack_x[20]={-1};//堆栈,记录岔路口
xdata unsigned char stack_y[20]={-1};
unsigned int direction=0;//小车前进方向上的绝对方向
unsigned int x=0;
unsigned int y=0;
unsigned int top=0;
unsigned int move_x[4] = {0,1,0,-1};
unsigned int move_y[4] = {1,0,-1,0};
unsigned char target_x = 7;//目标地点
unsigned char target_y = 7;

void xiuzheng();//函数声明
void delay(unsigned int ms);//延时函数
void initTime2();//时间初始化
void setTime2(int us);
void turnleft();
void turnright();
void turn();
void bianli();
void all();
void go_back();
unsigned int jugment(unsigned int k);
void init();

//设置T2自动重载寄存器和计数器初值
void setTime2(int us)
{
	TH2=(65536-us)/256;
	RCAP2H=(65536-us)/256;
	TL2=(65536-us)%256;
	RCAP2L=(65536-us)%256;
}
//定时计数器T2初始化
void initTime2()
{
	EA=1;//总中断允许
	//T2CON默认配置为16位自动重载计数模式
	//T2MOD默认不使能减计数和时钟输出
	ET2=1;
	setTime2(5000);//设置为5ms中断一次(可自定义,不可太短)
	TR2=1;
}
void delay(unsigned int ms)//延时
{
	unsigned int a=0,b=0;
	for(a=0;a<ms;a++)
	{
		for(b=0;b<123;b++);
	}
}
void turnleft()//向左转
{
	for(i=0;i<51;i++)
	{
		for(j=0;j<8;j++)
		{
			P1 = reverse[j];
			delay(2);
		}
	}
	direction=(direction+3)%4;
}
void turnright()//向右转
{
	for(i=0;i<51;i++)
	{
		for(j=0;j<8;j++)
		{
			P1 = forward[j];
			delay(2);
		}
	}
	direction=(direction+1)%4;
}
void turn()//转180
{
	for(i=0;i<105;i++)
	{
		for(j=0;j<8;j++)
		{
			P1 = forward[j];
			delay(2);
		}
	}
	direction=(direction+2)%4;
}
//irC=0 ,irL=0,irR=0,irLU=0,irRU=0
void bianli()//遍历迷宫,左手法则
{
		if((0x0F&map[x][y])==0x0F)
		{
			all();
		}
		if(irL==1&&jugment(3))//左边无挡板且未走过
		{
			delay(300);
			turnleft();
			xiuzheng();
		}
		else if(irC==1&&jugment(0))//左边有挡板,前边无且未走过
		{
			delay(300);
			xiuzheng();
		}
		else if(irR==1&&jugment(1))//左边有挡板前边有,右边无
		{
			delay(300);
			turnright();
			xiuzheng();
		}
		else//死胡同
		{
			go_back();
		}
}
unsigned int jugment(unsigned int k)  //判断的第二个条件,及是否已经走过
{
	int happy = 0;
	k = (k+direction)%4;
	happy = (x + move_x[k])*10 + y+move_y[k];
	if(happy<0)
	{
		return 0;
	}
	if((0xf0&map[happy/10][happy%10])==0xf0)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}
void xiuzheng()//走一格修正
{
		for(i=0;i<106;i++)
		{
			for(j=0;j<8;j++)
			{
				P1 = go[j];
				delay(2);
			}
			if(irLU==0)
			{
				if(irC!=0)
				{
					for(j=0;j<8;j++)
					{
						P1 = forward[j];
						delay(2);
					}
				}
			}
			if(irRU==0)
			{
				if(irC!=0)
				{
					for(j=0;j<8;j++)
					{
						P1 = reverse[j];
						delay(2);
					}
				}
			}
		}
		x+=move_x[direction];
		y+=move_y[direction];
}
void go_back()
{
	unsigned char happy;
	unsigned int nice=0;
	while(1)
	{
		happy = map[x][y]&0xf0;
		switch(happy)
		{
			case 0x70:nice = 0;break;
			case 0xb0:nice = 1;break;
			case 0xd0:nice = 2;break;
			case 0xe0:nice = 3;break;
			default:break;
		}
		if(nice == direction) //绝对方向相同
		{
			turn();
			delay(500);
			xiuzheng();
		}
		else if ((nice+direction)%2==0) //绝对方向相反,直接直行
		{
			delay(500);
			xiuzheng();
		}
		else  //右转左转的情况
		{
			if(direction==0)
			{
				if(nice==3) 
				{
					turnright();
				}
				else  
				{
					turnleft();
				}
				delay(500);
				xiuzheng();
			}
			else if(direction==1)
			{
				if(nice==0)  
				{
					turnright();
				}
				else  
				{
					turnleft();
				}
				delay(500);
				xiuzheng();
			}
			else if(direction==2)
			{
				if(nice==1)  
				{
					turnright();
				}
				else  
				{
					turnleft();
				}
				delay(500);
				xiuzheng();
			}
			else if(direction==3)
			{
				if(nice==2) 
				{
					turnright();
				}
				else  
				{
					turnleft();
				}
				delay(500);
				xiuzheng();
			}
		}
		if(x==stack_x[top]&&y==stack_y[top])
		{
			top--;
			beep = 0;
			delay(100);
			beep = 1;
			break;
		}
	}
}
void init()
{
	stack_x[0]=0;//起点压栈
	stack_y[0]=0;
	for(i=0;i<8;i++)//迷宫数据初始化
	{
		for(j=0;j<8;j++)
		{
			map[i][j]=0xFF;
		}
	}
}
void all()//记录迷宫中每一格所对应的挡板信息,用数码管表示坐标;绝对上右下左,0无1有
{
	unsigned char s;
	unsigned char sum =0;
	switch (direction)  //记录进入的绝对方向  上右下左
	{
		case 0:map[x][y]&=0x7f;break;  //上0111
		case 1:map[x][y]&=0xbf;break; //右1011
		case 2:map[x][y]&=0xdf;break;  //下1101
		case 3:map[x][y]&=0xef;break;//左1110
		default:break;
	}
	if(!(x==0&&y==0))  //初始节点的时候是不记录后方的,其他情况都要记录来的方向
	{
		s = (direction + 2)%4;
		switch(s)
		{
				case 0: map[x][y]&=0xf7;break;//上0111
				case 1: map[x][y]&=0xfe;break;//右1110
				case 2: map[x][y]&=0xfb;break;//下1011
				case 3: map[x][y]&=0xfd;break;//左1101
				default:break;
		}
	}
	if(irR==1)   //记录小车右方是否无墙    
	{
		sum++;
		s = (direction + 1)%4;
		switch(s)
		{
			case 0: map[x][y]&=0xf7;break;//低四位记录挡板信息,0无1有
			case 1: map[x][y]&=0xfe;break;
			case 2: map[x][y]&=0xfb;break;
			case 3: map[x][y]&=0xfd;break;
			default:break;
		}
	}
	if(irC==1)  //记录前方是否无墙
	{   
		sum++;
		s = direction;
		switch(s)  //上右下左
		{
			case 0: map[x][y]&=0xf7;break;
			case 1: map[x][y]&=0xfe;break;
			case 2: map[x][y]&=0xfb;break;
			case 3: map[x][y]&=0xfd;break;
			default:break;
		}
	}
	if(irL==1)  //记录左方是否无墙
	{
		sum++;
		s = (direction+3)%4;
		switch(s)
		{
			case 0: map[x][y]&=0xf7;break;
			case 1: map[x][y]&=0xfe;break;
			case 2: map[x][y]&=0xfb;break;
			case 3: map[x][y]&=0xfd;break;
			default:break;
		}
	}
	if(sum>=2)//是否为岔路口
	{
		top++;
		stack_x[top] = x;
		stack_y[top] = y;
	}
}
void main()
{
	initTime2();
	delay(1000);
	init();
	while(1)
	{
		bianli();
		if(x==0&&y==0)
			break;
	}
}
//T2中断服务函数
void time2() interrupt 5
{
	static bit tagsend = 1;
	static unsigned char irnum = 0;
	TF2 = 0;
	if(tagsend==0)//接收
	{
		switch(irnum)
		{
			case 0:
				irC = irR1;//前
				break;
			case 1:
				irLU = irR2;//左外
				break;
			case 2:
				irL = irR3;//左
				break;
			case 3:
				irR = irR4;//右
				break;
			case 4:
				irRU = irR5;//右外
				break;
		}
	}
	if(tagsend==1)//发送
	{
		if(++irnum>4)
			irnum=0;
		A0 = irnum&0x01;
		A1 = irnum&0x02;
		A2 = irnum&0x04;
	}
	else
	{
		A0 = A1 = A2 = 1;
	}
	tagsend = ~tagsend;
}

可以尝试在该代码基础上自行修改完善加上小车最短路径冲刺功能。

  • 18
    点赞
  • 112
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值