嵌入式迷宫小车

嵌入式迷宫小车

仅供参考
https://download.csdn.net/download/weixin_50722482/85826485

调试的方法

1.左前,右前小车与墙的感应距离为一个指姆的大小
2.左,前,右的感应距离可以远一些,只要该方向正常有障碍就应该感应的到
3.注释纯属娱乐
4.只为记录自己的学习

代码的实现

#include<reg52.h>
#include<intrins.h>
sfr P4 = 0xe8;
//3——8译码器的三个输入端
sbit A0 = P4^0;
sbit A1 = P2^0;
sbit A2 = P2^7;
//红外传感器的五个方向
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; //规定C为1,左前2,左3,右前5,右4

//红外发射控制宏定义(传入传感器组号)
#define MOUSE_IR_ON(GROUP_NO)\
do\
{\
    A0=(GROUP_NO)&0X01;\
    A1=(GROUP_NO)&0X02;\
    A2=(GROUP_NO)&0X04;\
} while (0);

sbit wel1 = P4^3;//数码管的位选
sbit wel2 = P4^2;
sbit Beep = P3^7; //蜂鸣器

unsigned code tabal[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};  //数码管显示的0-9

unsigned char l1=0,l2=0; //用做转向修正(减小前进步数)

//堆柞,记录岔路口坐标
xdata unsigned char stack_x[20] = {-1};
xdata unsigned char stack_y[20] = {-1};
unsigned char top = 0;//堆柞指针

//单元格目标记录
unsigned char x =0,y =0;
//地图数据
unsigned char map[8][8]; //地图数据  最后都会初始化

xdata unsigned char maze[8][8];  //登高表记录

//方向记录,参考书上 绝对方向与相对方向的和与4的余数
unsigned int dir = 0,dirs = 0; //记录绝对方向  //规定0为上,1为右,2为下,3为左
//对数值进行运算
unsigned int move_x[4] = {0,10,0,-10};
unsigned int move_y[4] = {1,0,-1,0};

//目标单元格坐标
unsigned char target_x = 7;
unsigned char target_y = 7;


//转向数组
unsigned char code turn_right[]={0x11,0x33,0x22,0x66,0x44,0xcc,0x88,0x99};   //左右电机同时右转
unsigned char code turn_left[]={0x11,0x99,0x88,0xcc,0x44,0x66,0x22,0x33};    //左右电机同时左转
unsigned char code turn_right_2[] ={0x01,0x03,0x02,0x06,0x04,0x0c,0x08,0x09};  //左步机右转函数
unsigned char code turn_left_2[] ={0x10,0x90,0x80,0xc0,0x40,060,0x20,0x30};			//右步机左转函数
unsigned char code forward[] ={0x11,0x93,0x82,0xc6,0x44,0x6c,0x28,0x39};

xdata unsigned char path[20]={5};
//初始化函数
void init();
void delay_ms(unsigned int z);
void display(unsigned int k);
void setTime2(unsigned int us);
void initTime2();
void nice_go();
void turn_Right1();
void turn_Left1();
void go_straight();
void nice_modify();
void flash_back();
unsigned int jugment(unsigned int k);
int arrive();
int ending();
void cool_ergodic();
void target();
void cool_findshort();//找到最短路径

unsigned int jugment(unsigned int k)  //判断的第二个条件,及是否已经走过
{
	int happy = 0;
	k = (k+dir)%4;
	happy = dirs + move_x[k] + move_y[k];
	if(happy<0)
	{
		return 0;
	}
	if((0xf0&map[happy/10][happy%10])==0xf0)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

void flash_back()  //回溯到上一个岔路口
{
	unsigned char happy;
	unsigned int nice=0;
	while(1)
	{
		happy = map[dirs/10][dirs%10]&0xf0;
		switch(happy)
		{
			case 0x70:nice = 0;break;
			case 0xe0:nice = 1;break;
			case 0xc0:nice = 2;break;
			case 0xd0:nice = 3;break;
			default:break;
		}
		if(nice == dir) //绝对方向相同
		{
			turn_Right1();
			turn_Right1();//两次右转_掉头
			delay_ms(500);
			go_straight();
		}
		else if ((nice+dir)%2==0) //绝对方向相反,直接直行
		{
			delay_ms(500);
			go_straight();
		}
		else  //右转左转的情况
		{
			if(dir==0)
			{
				if(nice==3) turn_Right1();
				else  turn_Left1();
				delay_ms(500);
				go_straight();
			}
			else if(dir==1)
			{
				if(nice==0)  turn_Right1();
				else  turn_Left1();
				delay_ms(500);
				go_straight();
			}
			else if(dir==2)
			{
				if(nice==1)  turn_Right1();
				else  turn_Left1();
				delay_ms(500);
				go_straight();
			}
			else if(dir==3)
			{
				if(nice==2) turn_Right1();
				else  turn_Left1();
				delay_ms(500);
				go_straight();
			}
		}
		if(arrive()||ending())  //达到最近的一个岔路口
		{
			Beep = 0;
			delay_ms(50);
			Beep = 1;
			break;
		}
	}
}
int arrive()
{
	unsigned char i =0;
	if(dirs==0) return 0;
	for(i=0;i<16;i++)
	{
		if((dirs/10)==stack_x[i]&&(dirs%10)==stack_y[i])
		{
			return 1;
		}
	}
	return 0;
}
void jilu()
{
	unsigned char s;
	unsigned char sum =0;
	x = dirs/10;y = dirs%10;
	switch (dir)  //记录进入的绝对方向  上右下左,上下左右
	{
		case 0:map[x][y]&=0x7f;break;  //上
		case 1:map[x][y]&=0xef;break; //右
		case 2:map[x][y]&=0xcf;break;  //下
		case 3:map[x][y]&=0xdf;break;//左
		default:break;
	}
	if(!(dirs==0))  //初始节点的时候是不记录后方的,其他情况都要记录来的方向
	{
		s = (dir + 2)%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(!irR)   //记录右方是否无墙    
	{
	sum++;
	s = (dir + 1)%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(!irC)  //记录前方是否无墙
	{   
	sum++;
	s = dir;
	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)  //记录左方是否无墙
	{
	sum++;
	s = (dir+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)
	{
		stack_x[top] = dirs/10;
		stack_y[top] = dirs%10;
		top++;
	}
	//display(map[x][y]&0x0f);
}

void nice_modify()   //针对偏移的修正函数
{
	unsigned char i=0;
	if((irLu||irRu)&&!irC)
	{
		if(irLu)
		{
			
			for(i=0;i<8;i++)
			{
				P1 = turn_right_2[i];
				delay_ms(3);
			}
		}
		if(irRu)
		{
			for(i=0;i<8;i++)
			{
				P1 = turn_left_2[i];
				delay_ms(3);
			}
		}
		l1++;
	}
}

void go_straight()  //前进函数
{
	unsigned char i=0,j=0;
	l1 = 0;
	l2 = 0;
	for ( j = 0; j < 108-l2; j++)
	{                          //由于修正会导致电机前进,所以可以通过减少前进的n来控制小车前进的距离
			for ( i = 0; i < 8; i++)
			{
					P1 = forward[i];
					delay_ms(3);
			}
			nice_modify(); 
			l2 += l1/2;
			l1 = l1%2;
	}
	dirs = dirs+move_x[dir]+move_y[dir];
	display(dirs);
}

void turn_Left1()
{
	unsigned char i=0,j=0;
	for ( j = 0; j < 50; j++)
	{
		 for ( i = 0; i < 8; i++)
			{
					P1 = turn_left[i];
					delay_ms(3);
			}		
	}
	dir =(dir + 3)%4;  
}
void turn_Right1()
{
	unsigned char i=0,j=0;
	for ( j = 0; j < 50; j++)
	{
		 for ( i = 0; i < 8; i++)
			{
					P1 = turn_right[i];
					delay_ms(3);
			}
			
	}
	dir =(dir + 1)%4;    //右转之后绝对方向改变
}

void nice_go() //右转法则,进行判断前进
{
	if(!arrive())jilu();				//如果是已经走过的岔路口就不记录信息
	if(!irR&&jugment(1))  //右方无墙
	{  
		turn_Right1();
		delay_ms(500);
		go_straight();
	}
	else if (!irC&&jugment(0))
	{
		delay_ms(500);
		go_straight();
	}
	else if (!irL&&jugment(3))
	{
		turn_Left1();
		delay_ms(500);
		go_straight();
	}
	else 
	{
		flash_back();
	}
}

void display(unsigned int k)//显示函数
{
	unsigned char a,b;
	a = k/10;b = k%10;
  wel1 = 1;wel2 = 0;//开启数码管一的循环
	P0 = tabal[a];
	wel1 = 0;wel2 = 1;
  P0 = tabal[b];
	wel1 = 0;wel2 = 0;	
}

void setTime2(unsigned int us)//设置T2自动重载寄存器和计数器初值
{
    TH2    = (65536-us)/256;
    RCAP2H = (65536-us)/256;
    TL2    = (65536-us)%256;
    RCAP2L = (65536-us)%256;
}
void initTime2()//初始化中断函数
{
    EA = 1;//所有中断的总开关
    ET2 = 1; //T2 中断
    setTime2(5000);
    TR2 = 1; //启动定时器2
}

void init() //初始化迷宫函数
{
	unsigned char i,j;
    for(i=0;i<8;i++)
	{
		for(j=0;j<8;j++)
		{
				map[i][j]=0xff;
		}
	}
}
void delay_ms(unsigned int z)//软件延时
{
    unsigned char u, o;
    while(--z)
    {
    _nop_();
    u = 2;
    o = 199;
    do
    {
    while (--o);
    } while (--u);
    }
}
void target()  //判断是否到达目标结点
{
	if(dirs == target_x*10 + target_y )
	{
		Beep = 0;
		delay_ms(1000);//判断到终点就响
		Beep = 1;
	}
}
int ending()  //判断是否回到起点
{
	if(dirs==0)
	{
		return 1;
	}
	else 
		return 0;
}
void main()
{	
    init(); //初始化迷宫数据
		initTime2();//初始化中断函数
		while(1)
		{
			delay_ms(1000);
			x = dirs/10;
			y = dirs%10;
			nice_go();
			target();    //走完判断是否是中点,终点就响一秒
			if(ending())  //每走一格或者回溯到了岔路口,或者回到了起点都会进行一次判断
			{
				break;
			}
		}
		//delay_ms(1000);
		//cool_ergodic(); //构建登高表
		//display(99); //
		//cool_findshort();//找到最短路径
		//Beep = 0;
		//display(88);
		//delay_ms(1000);
		//Beep = 1;
		while(1);
}


void time2() interrupt 5 //T2中断
{       
	static unsigned int temp =0;
	static bit ir = 0;
	TF2 = 0;
	if(!ir)             //防止判定为改变后的方向
	{   
			MOUSE_IR_ON(temp);
	}     
	else
	{
	switch (temp++)
	{
	case 0://前
			if (!irR1)
			{
					irC = 1;
					//display(1);
			}
			else           
			{
					irC = 0;
					Beep = 1;
			}
			MOUSE_IR_ON(5);break;
	case 1://左前
			if(!irR2)
			{
					irLu = 1;
				Beep = 0;
					//display(2);
					
			}
			else
			{
					irLu = 0;
					Beep = 1;
			}
			MOUSE_IR_ON(5);break;
	case 2://左
			if(!irR3)
			{
					irL = 1;
				display(3);
			}
			else
			{
					irL = 0;
			Beep = 1;
			}
			MOUSE_IR_ON(5);break;
	case 3://右
			if(!irR4)
			{
					irR  = 1;
					//display(4);
			}
			else
			{
					irR = 0;
				Beep = 1;
			}
			MOUSE_IR_ON(5);break;
	case 4://右前
			if(!irR5)
			{
					irRu = 1;
					//display(5);
					Beep = 0; 
			}
			else
			{
					irRu = 0;
					Beep = 1;
					Beep = 1;
			}
			MOUSE_IR_ON(5);break;
			default:break;
	}    
	} 
	ir = ~ir;
	if(temp == 5)
	{
		temp = 0;
	}
}
int cool_ending()  //判断登高表是否已经做完所有遍历
{
	unsigned char i=0,j=0;
	for(i=0;i<8;i++)
	{
		for(j=0;j<8;j++)
		{
			if(maze[i][j]== 55)
			{
				return 1;
			}
		}
	}
	return 0;
}
void init_maze() //初始化登高表
{
	unsigned char i,j;
	for(i=0;i<8;i++)
	{
		for(j=0;j<8;j++)
		{
			maze[i][j] = 55;
		}
	}
}	
xdata unsigned char quen_x[64];  //队列x坐标
xdata unsigned char quen_y[64];  //对列y坐标
void cool_ergodic() //使用广度优先构建登高表 //循环队列 尾部插入,头部取出,即head++,tail++
{
	unsigned char head =0,tail=0;    //头指针和尾部指针
	unsigned char i,j;               //记录当前出队列的单元格的x,y坐标
	unsigned char happy;             //用于对 i 或者 j 进行计算
	Beep = 0;
	delay_ms(5000);
	Beep = 1;
	init_maze();											//初始化登高表 开始全为-1
	quen_x[0] = 0; quen_y[0] = 0;     //起点入队
	tail++;                           //尾节点向后延伸
	maze[0][0] = 1;                    //起点为1步
	while(cool_ending())   //如果头结点追上了尾节点或者整个迷宫单元格已经全部有个步长,即都不在为1 就可以退出循环了
	{
		i = quen_x[head];            //取出头部单元格
		j = quen_y[head];
		head++;											//头结点向后延伸
		if(head==64)                //头结点向后延伸到20,即队列满的情况下会再回到起点开始继续加
		{
			head = 0;
		}
		if((map[i][j]&0x08) == 0x00)//上方无墙
		{
			happy = j+1;
			if(maze[i][happy]==55) //还没有走过
			{
				maze[i][happy] = maze[i][j]+1; //上方单元格加一
				quen_x[tail] = i;  //该单元个入队
				quen_y[tail] = happy;
				tail++; //尾部指正指向下一个空数组
				if(tail==64)
				{
					tail = 0; //循环指针,当已经记录到数组的尾部,就会回到起点开始记录。
				}
			}
		}
		if((map[i][j]&0x01) == 0x00) //右方无墙
		{
			happy = i+1;
			if(happy<8&&(maze[happy][j]==55)) //还没有走过
			{
				maze[happy][j] = maze[i][j]+1; //右方单元格加一
				quen_x[tail] = happy; //该单元格入队
				quen_y[tail] = j;
				tail++;//尾部指针指向下一个空数组
				if(tail==64)
				{
					tail = 0;循环指针,当已经记录到数组的尾部,就会回到起点开始记录。
				}
			}
		}
		if((map[i][j]&0x02)==0x00)  //左方无墙   有墙时不会进行下面的运算所以不会出现数组越界的情况
		{
			happy = i -1;
			if((happy>=0&&maze[happy][j]==55)) //还没有走过
			{
				maze[happy][j] = maze[i][j]+1; //左方单元格加一
				quen_x[tail] = happy; //该单元格入队
				quen_y[tail] = j;
				tail++;//尾部指针指向下一个空数组
				if(tail==64)
				{
					tail = 0;循环指针,当已经记录到数组的尾部,就会回到起点开始记录。
				}
			}
		}	
		if((map[i][j]&0x04)==0x00&&!(i==0&&j==0))  //下方无墙  因为初始化的时候默认都是有墙,所以单元格来的方向肯定是无墙的,因此在记录的时候应该把来的方向也记入单元格
		{
			happy = j-1;
			if(happy>=0&&maze[i][happy]==55) //还没有走过
			{
				maze[i][happy] = maze[i][j]+1; //下方单元格加一
				quen_x[tail] = i;  //该单元个入队
				quen_y[tail] = happy;
				tail++; //尾部指正指向下一个空数组
				if(tail==64)
				{
					tail = 0; //循环指针,当已经记录到数组的尾部,就会回到起点开始记录。
				}
			}
		} 
	}
} 
void cool_findshort()  //找到最短路径
{
	//查看下方gitHup
}	

githup链接

githup嵌入式迷宫

  • 11
    点赞
  • 91
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Afraidlight

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值