基于51单片机实现红外循迹

红外循迹外观:

 红外循迹原理:

        红外循迹模块原理还是很简单的,和许多光电传感器原理一样,当发射器发射出去的光被接收器接收到后,模块上对应的LED灯点亮,此时相应的输出引脚输出低电平;如果发射器发射的光没有被接收器接收到的话,那么LED灯不点亮,此时相应的输出引脚输出高电平。

 PWM调速:

这里必须要有PWM来控制小车的速度,不然的话太快容易脱离轨道,具体多少速度还是需要看硬件和软件的配合,需要多次实验试错。PWM可以参考我前面写的关于舵机的代码,原理是一样的,只需要加些变量即可使用。

电机驱动模块:

这里就不再多说,一般都是拿L298N驱动模块来做小车,可以一个驱动模块控制四个轮子,也可以两个控制四个,具体还是需要看硬件是否被满足。

 程序设计:

在程序设计过程中,最难的还是走直线的情况下,因为小车如果速度太快的话,会直接脱离轨道,太慢的话,玩的时候感觉又有点不得劲,所以要尽力写出最高效的程序还是有点挑战的。如果循迹模块检测到低电平,就直走,检测到高电平,因为我刚开始是在前面装了两个,但是后来觉得走直线的时候太快,冲出了轨迹,所以后来又加了一个,放在了前一排的后面。

这里注意一下,此代码只是往右旋转的,不支持左转,它会一直右转右转。

代码:

代码有两个,前一个是走椭圆的,后一个是走直角的,有点差别,但差别不大,注意区分。

前一个;:

#include <reg52.h>   //此文件中定义了单片机的一些特殊功能寄存器

typedef unsigned int u16;	  //对数据类型进行声明定义
typedef unsigned char u8;

sbit leftA=P2^1;
sbit leftB=P2^2;
sbit leftC=P2^3;
sbit leftD=P2^4;

sbit rightA = P1^4; 
sbit rightB = P1^3; 
sbit rightC = P1^2; 
sbit rightD = P1^1; 

sbit Left_moto_pwmA=P2^0 ;
sbit Left_moto_pwmB=P2^5 ;
sbit Right_moto_pwmA=P1^0;
sbit Right_moto_pwmB=P1^6;

bit Left_moto_stop =1;
bit Right_moto_stop =1;

extern unsigned char pwm_val_left =0;  //脉冲变量
unsigned char push_val_left =0; 
extern unsigned char pwm_val_right =0; //脉冲变量
unsigned char push_val_right=0;

//调节速度
unsigned char Left_Speed_Ratio;
unsigned char Right_Speed_Ratio;								

#define Right_1_led         P3^2	   //四路寻迹模块接口第一路
#define Left_2_led        	P3^3	   //四路寻迹模块接口第二路

void delay(u16 n);

void delay(u16 n)   //1ms   (误差 -0.651041666667us)
{
   u16 i ;
    unsigned char a,b;
	for(i=1;i<=n;i++)
	{
    for(b=102;b>0;b--)
        for(a=3;a>0;a--);
	}
}

void pwm_out_left_moto(void)     //左电机调速
{ 				
		if(pwm_val_left>=10) pwm_val_left=0; 
		if(Left_moto_stop) 
		{ 
					if(pwm_val_left<=push_val_left) 
					{
							Left_moto_pwmA=1; 
							Left_moto_pwmB=1; 
					}
					else 
					{
							Left_moto_pwmA=0; 
							Left_moto_pwmB=0; 
					}
		} 
		else 
		{
				Left_moto_pwmA=0; 
				Left_moto_pwmA=0; 
		}
} 	

void pwm_out_right_moto(void)   //右电机调速
{ 
		if(pwm_val_right>=10) pwm_val_right=0; 
		if(Right_moto_stop) 
		{ 
				if(pwm_val_right<=push_val_right) 
				{
							Right_moto_pwmA=1; 
							Right_moto_pwmB=1;
				}
				else 
				{
						Right_moto_pwmA=0; 
						Right_moto_pwmB=0;
				}

		} 
		else 
		{
				Right_moto_pwmA=0; 
				Right_moto_pwmB=0;
		}			
} 

//pwm中断
void Timer0Init()    //定时器初始化函数
{
			TMOD|=0X01;//选择为定时器0模式,工作方式1,仅用TR0打开启动。

			TH0=0XFC;	//给定时器赋初值,定时1ms
			TL0=0X18;	
			ET0=1;//打开定时器0中断允许
			EA=1;//打开总中断
			TR0=1;//打开定时器			
}

void timer0()interrupt 1  //定时器中断函数,此处配置为1ms产生一次中断,对PWM的输出进行控制
{ 
		TH0=0XFC;	//给定时器赋初值,定时1ms
		TL0=0X18;
		//time++; 
		pwm_val_left++; 
		pwm_val_right++; 
		pwm_out_left_moto(); 
		pwm_out_right_moto(); 
} 

void stop()
{
	leftA=0;
	leftB=0;
	leftC=0;
	leftD=0;
	rightA=0;
	rightB=0;
	rightC=0;
	rightD=0;
}

void forward() //前进
{
	push_val_left =Left_Speed_Ratio; 
	push_val_right =Right_Speed_Ratio; 
	leftA=1;
	leftB=0;
	leftC=1;
	leftD=0;
	rightA=1;
	rightB=0;
	rightC=1;
	rightD=0; 
}

void back() //后退
{
	push_val_left =Left_Speed_Ratio; 
  push_val_right =Right_Speed_Ratio; 
	leftA=0;
	leftB=1;
	leftC=0;
	leftD=1;
	rightA=0;
	rightB=1;
	rightC=0;
	rightD=1;
}

void left() //左转
{
	push_val_left =Left_Speed_Ratio; 
	push_val_right =Right_Speed_Ratio; 
	leftA=0;
	leftB=1;
	leftC=0;
	leftD=1;
	rightA=0;
	rightB=0;
	rightC=0;
	rightD=0;
}

void right() //右转
{
	push_val_left =Left_Speed_Ratio; 
	push_val_right =Right_Speed_Ratio; 
	leftA=0;
	leftB=0;
	leftC=0;
	leftD=0;
	rightA=0;
	rightB=1;
	rightC=0;
	rightD=1;
}
void main()
{
	Timer0Init();
	while(1)
	{		 

	    switch(P3&0x0f)
		{
			//说明一下,速度很关键,开始的时候尽量慢一点。
            //我写的时候,右转把左边的轮子停住了,左边的轮子是不动的,而右边的轮子是加速的。
            //注意两个传感器检测到都是往右转的。
			case 0x03:	Left_Speed_Ratio=2;Right_Speed_Ratio=2;forward();break;// 
			case 0x07:	Left_Speed_Ratio=0;	Right_Speed_Ratio=3;right();delay(10);break;	
			case 0x0b:	Left_Speed_Ratio=0;	Right_Speed_Ratio=3;right();delay(7);break;
			case 0x0f:	Left_Speed_Ratio=0;	Right_Speed_Ratio=3;right();delay(8);break;
			default	 : 	break;		
	             }
		}	

}



 后一个:

#include <reg52.h>   //此文件中定义了单片机的一些特殊功能寄存器

typedef unsigned int u16;	  //对数据类型进行声明定义
typedef unsigned char u8;

sbit leftA=P2^1;
sbit leftB=P2^2;
sbit leftC=P2^3;
sbit leftD=P2^4;

sbit Left_moto_pwmA=P2^0 ;
sbit Left_moto_pwmB=P2^5 ;
sbit Right_moto_pwmA=P1^0;
sbit Right_moto_pwmB=P1^6;


sbit rightA = P1^4; 
sbit rightB = P1^3; 
sbit rightC = P1^2; 
sbit rightD = P1^1; 

bit Left_moto_stop =1;
bit Right_moto_stop =1;


extern unsigned char pwm_val_left =0;  //脉冲变量
unsigned char push_val_left =0; 
extern unsigned char pwm_val_right =0; //脉冲变量
unsigned char push_val_right=0;

//调节速度
unsigned char Left_Speed_Ratio;
unsigned char Right_Speed_Ratio;			

#define Right_1_led         P3^2	   //四路寻迹模块接口第一路
#define Left_1_led        	P3^3	   //四路寻迹模块接口第二路
#define Right_2_led         P3^4	   //四路寻迹模块接口第一路

void delay(u16 n);

void delay(u16 n)   //1ms   (误差 -0.651041666667us)
{
   u16 i ;
    unsigned char a,b;
	for(i=1;i<=n;i++)
	{
    for(b=102;b>0;b--)
        for(a=3;a>0;a--);
	}
}

void pwm_out_left_moto(void)     //左电机调速
{ 				
		if(pwm_val_left>=10) pwm_val_left=0; 
		if(Left_moto_stop) 
		{ 
					if(pwm_val_left<=push_val_left) 
					{
							Left_moto_pwmA=1; 
							Left_moto_pwmB=1; 
					}
					else 
					{
							Left_moto_pwmA=0; 
							Left_moto_pwmB=0; 
					}
		} 
		else 
		{
				Left_moto_pwmA=0; 
				Left_moto_pwmA=0; 
		}
} 	

void pwm_out_right_moto(void)   //右电机调速
{ 
		if(pwm_val_right>=10) pwm_val_right=0; 
		if(Right_moto_stop) 
		{ 
				if(pwm_val_right<=push_val_right) 
				{
							Right_moto_pwmA=1; 
							Right_moto_pwmB=1;
				}
				else 
				{
						Right_moto_pwmA=0; 
						Right_moto_pwmB=0;
				}

		} 
		else 
		{
				Right_moto_pwmA=0; 
				Right_moto_pwmB=0;
		}			
} 

//pwm中断
void Timer0Init()    //定时器初始化函数
{
			TMOD|=0X01;//选择为定时器0模式,工作方式1,仅用TR0打开启动。

			TH0=0XFC;	//给定时器赋初值,定时1ms
			TL0=0X18;	
			ET0=1;//打开定时器0中断允许
			EA=1;//打开总中断
			TR0=1;//打开定时器			
}

void timer0()interrupt 1  //定时器中断函数,此处配置为1ms产生一次中断,对PWM的输出进行控制
{ 
		TH0=0XFC;	//给定时器赋初值,定时1ms
		TL0=0X18;
		//time++; 
		pwm_val_left++; 
		pwm_val_right++; 
		pwm_out_left_moto(); 
		pwm_out_right_moto(); 
} 

void stop()
{
	leftA=0;
	leftB=0;
	leftC=0;
	leftD=0;
	rightA=0;
	rightB=0;
	rightC=0;
	rightD=0;
}

void forward() //前进
{
	push_val_left =Left_Speed_Ratio; 
	push_val_right =Right_Speed_Ratio; 
	leftA=1;
	leftB=0;
	leftC=1;
	leftD=0;
	rightA=1;
	rightB=0;
	rightC=1;
	rightD=0; 
}

void back() //后退
{
	push_val_left =Left_Speed_Ratio; 
  push_val_right =Right_Speed_Ratio; 
	leftA=0;
	leftB=1;
	leftC=0;
	leftD=1;
	rightA=0;
	rightB=1;
	rightC=0;
	rightD=1;
}

void left() //左转
{
	push_val_left =Left_Speed_Ratio; 
	push_val_right =Right_Speed_Ratio; 
	leftA=0;
	leftB=1;
	leftC=0;
	leftD=1;
	rightA=0;
	rightB=0;
	rightC=0;
	rightD=0;
}

void right() //右转
{
	push_val_left =Left_Speed_Ratio; 
	push_val_right =Right_Speed_Ratio; 
	leftA=1;
	leftB=0;
	leftC=1;
	leftD=0;
	rightA=0;
	rightB=1;
	rightC=0;
	rightD=1;
}
void main()
{
	Timer0Init();
	while(1)
	{		 
		switch(P3&0xff)
		{			
case 0xe3:Left_Speed_Ratio=2;Right_Speed_Ratio=2;forward();break;
case 0xe7:back();delay(8);Left_Speed_Ratio=0;Right_Speed_Ratio=3;right();delay(10);break;					case 0xeb:back();delay(8);Left_Speed_Ratio=0;Right_Speed_Ratio=3;right();delay(8);break;
case 0xef:back();delay(8);Left_Speed_Ratio=0;Right_Speed_Ratio=3;right();delay(7);break;

case 0xf3:back();delay(8);Left_Speed_Ratio=2;Right_Speed_Ratio=2;forward();break;//部没
case 0xf7:back();delay(8);Left_Speed_Ratio=0;Right_Speed_Ratio=3;right();delay(10);break;	
case 0xfb:back();delay(8);Left_Speed_Ratio=0;Right_Speed_Ratio=3;right();delay(8);break; 
case 0xff:back();delay(8);Left_Speed_Ratio=0;Right_Speed_Ratio=3;right();delay(7);break;

case 0xdb:back();delay(350);Left_Speed_Ratio=0;Right_Speed_Ratio=4;right();delay(10);break;
case 0xdf:back();delay(450);Left_Speed_Ratio=0;Right_Speed_Ratio=4;right();delay(8);break
case 0xd7:back();delay(450);Left_Speed_Ratio=0;Right_Speed_Ratio=4;right();delay(7);break;
		}
	}	
}



总结:

写程序的过程和调试代码的过程是很辛苦的,需要坚持住,坚持就是胜利。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值