基于51单片机的多功能小车

头文件

#ifndef __PWM_H__
#define __PWM_H__
 
/*电机驱动IO定义*/
sbit EN1=P1^6; //为1 左电机使能
sbit EN2=P1^7; //为1 右电机使能
 
//循迹模块 
#define Left_1_led        P3_7	 //左循迹传感器    
	
#define Right_1_led       P3_6	 //右循迹传感器 
//避障模块	
#define LeftIRBZ          P3_5	 //左避障传感器	  
	
#define RightIRBZ         P3_4	 //右避障传感器	    
//超声波
#define  TX  P2_1

#define  RX  P2_0

unsigned char disbuff[4]={0,0,0,0};//用于分别存放距离的值0.1mm、mm、cm和m的值

sbit SB1=P2^3;                            //定义蜂鸣器端口
sbit IRIN=P3^3;                           //定义红外接收端口

#define ShowPort P0                                   //定义数码管显示端口

sbit LeftLed=P2^0;                                    //定义前方左侧指示灯端口
sbit RightLed=P0^7;                                   //定义前方右侧指示灯端口 

sbit nose=P2^7;

#define left_motor_en     EN1=1 //左电机使能
#define left_motor_stops  EN1=0 //左电机停止
#define right_motor_en    EN2=1 //右电机使能
#define right_motor_stops EN2=0 //右电机停止
 
 
#endif

主函数

#include<AT89x51.H>
#include <intrins.h>
#include<PWM.H>    

unsigned char code  LedShowData[]={0x03,0x9F,0x25,0x0D,0x99,  //定义数码管显示数据
                                   0x49,0x41,0x1F,0x01,0x19};//0,1,2,3,4,5,6,7,8,9
unsigned char code  RecvData[]={0x19,0x46,0x15,0x43,0x44,0x40,0x0D,0x0E,0x00,0x0F};
unsigned char IRCOM[7];

unsigned char pwm_left_val=100;
unsigned char pwm_right_val=100;
unsigned char pwm_t;

unsigned int  time=0;//用于存放定时器时间值
unsigned long S=0;//用于存放距离的值
bit  flag =0; //量程溢出标志位
bit  turn_right_flag;

unsigned char temp = 1;
sbit M1A=P1^2;                                        //定义电机1正向端口
sbit M1B=P1^3;                                        //定义电机1反向端口
sbit M2A=P1^4;                                        //定义电机2正向端口
sbit M2B=P1^5;                                        //定义电机2反向端口
void Delay10us(unsigned char i) 
{ 
   unsigned char j; 
do{ 
  j = 10; 
  do{ 
   _nop_(); 
   }while(--j); 
}while(--i); 
}  
void Delay1ms(unsigned int i) 
{ 
	unsigned char j,k; 
	do{ 
			j = 10; 
		do{ 
			k = 50; 
			do{ 
			_nop_(); 
				}while(--k);     
			}while(--j); 
		}while(--i); 
} 

void delay_nus(unsigned int i)  //延时:i>=12 ,i的最小延时单12 us
{ 
  i=i/10;
  while(--i);
}   
void delay_nms(unsigned int n)  //延时n ms
{ 
  n=n+1;
  while(--n)  
  delay_nus(900);         //延时 1ms,同时进行补偿
  
}  

void delayms(unsigned char x)                         //0.14mS延时程序
{
  unsigned char i;                                    //定义临时变量
  while(x--)                                          //延时时间循环
  {
    for (i = 0; i<13; i++) {}                         //14mS延时
  }
}

void Delay()                                          //定义延时子程序
{ 
  unsigned int DelayTime=30000;                       //定义延时时间变量
  while(DelayTime--);                                 //开始进行延时循环
  return;                                             //子程序返回
}
void stop()//停止
{
   M1A=0;                                   //将M1电机A端初始化为0
   M1B=0;                                   //将M1电机B端初始化为0
   M2A=0;                                   //将M2电机A端初始化为0
   M2B=0;

}

void run()//前进
{

   M1A=1;                                   
   M1B=0;                                   
   M2A=1;                                   
   M2B=0;
}

void back()//后退
{
   M1A=0;                                   
   M1B=1;                                   
   M2A=0;                                   
   M2B=1;
}

void rightrun()//右转
{
   M1A=1;                                   
   M1B=0;                                   
   M2A=0;                                   
   M2B=1;

}

void leftrun()//左转
{

   M1A=0;                                   
   M1B=1;                                   
   M2A=1;                                   
   M2B=0;

}


void ControlCar_yaokong(unsigned char ConType)    //定义电机控制子程序	(红外遥控单独设置一个 switch  case  语句  )
{
 
  stop();
	switch(ConType)                          //判断用户设定电机形式
  {
		case 1:  //前进                         //判断用户是否选择形式1
	 { 
    stop();						      //进入前进之前 先停止一段时间  防止电机反向电压冲击主板 导致系统复位
	  Delay1ms(150);
	  LeftLed = 0 ;
	  run();
    break;
   }
   case 2: //后退                          //判断用户是否选择形式2
   { 
    stop();								      //进入后退之前 先停止一段时间  防止电机反向电压冲击主板 导致系统复位
    Delay1ms(150);
    LeftLed = 1 ; 	 
	  back();                                 //M2电机反转
    break;
   }
	 case 3: //右转                          //判断用户是否选择形式3
   { 
     stop();								  //进入左转之前 先停止一段时间  防止电机反向电压冲击主板 导致系统复位
		 Delay1ms(150); 
		 rightrun();                                //M2电机正转
		 break;
   }
  case 4: //左转                          //判断用户是否选择形式4
  { 
     stop();								  //进入右转之前 先停止一段时间  防止电机反向电压冲击主板 导致系统复位
	   Delay1ms(150);
     leftrun();                                  //M1电机正转  //M2电机反转
 	   break;
  }
  case 8: //停止                          //判断用户是否选择形式8
  {
    stop();
	  break;                                //退出当前选择
  }
 }
}
/********距离计算程序***************/
void Conut(void)
{
	 time=TH1*256+TL1;
	 TH1=0;
	 TL1=0;
	 S=time*2;//先算出一共的时间是多少微秒。
   S=S*0.17;//此时计算到的结果为毫米,并且是精确到毫米的后两位了,有两个小数点 
	 if(S<=400)	 //
	 {	
	    if(turn_right_flag!=1)
		  {
		    Stop();
		    Delay1ms(5);//发现小车自动复位的时候,可以稍微延长一点这个延时,减少电机反向电压对电路板的冲击。
		  }
		  turn_right_flag=1;
		
		  SB1=0;

		  Delay1ms(50);
		
		  SB1=1;
	    back();
	    Delay1ms(300); 	// 关键点  延时5MS  
	    leftrun();
	    Delay1ms(400); 	  //左转800MS

	 }
	 else
	 {
	    turn_right_flag=0;
		  run();
	 }
	 //=======================================
	 if((S>=5000)||flag==1) //超出测量范围
	 {	
	   flag=0;
	 }
	 else
	 {
      disbuff[0]=S%10;
	    disbuff[1]=S/10%10;
	    disbuff[2]=S/100%10;
	    disbuff[3]=S/1000;
	 }
}
void Robot_Avoidance()                   //机器人避障子程序
{
  	  
	      if(LeftIRBZ==1&&RightIRBZ ==1)	  //LeftIRBZ RightIRBZ 

		    {	 
		          run();
              delay_nms (10);
			        SB1=1;
			  }
			  else
			  {			  
				      if(LeftIRBZ==1&&RightIRBZ ==0)	    //右边检测到红外信号
			 	      {
				 	        rightrun();                            //右转
                  delay_nms (300);					   //停止300MS   防止电机反相电压冲击  导致系统复位

			        }
			   
				 	    if(RightIRBZ ==1&&LeftIRBZ==0)		//左边检测到红外信号
				     {	  
				      
					         leftrun();                        //左转
                   delay_nms (300);					   //停止300MS   防止电机反相电压冲击  导致系统复位
				      }
							if(RightIRBZ==0&&LeftIRBZ==0)		//两边传感器同时检测到红外
							{	  
								SB1=0;
								stop();                     //停止
                delay_nms (300);			//停止300MS   防止电机反相电压冲击  导致系统复位
								back(); 		        //调用电机后退函数
								delay_nms (300);		//后退50毫秒
								rightrun();  		   //调用电机右转函数
								delay_nms (400);
							}			
				}
	
			run();
		  
}
//小车循迹子程序
void Robot_Traction()                     //机器人循迹子程序
{
  
   //SB1=1;
   if(Left_1_led  == 0 && Right_1_led == 0)    //三个红外检测到黑线,就前进	 Left_1_led 	  Right_1_led
   {
      run();                     //左侧没有信号时,开始向右转一定的角度
      delay_nms (10);
			SB1=0;
   }
   
   else if(Left_1_led  == 0 && Right_1_led == 1)
   {
      rightrun();                       //右侧检测到黑线,开始向右转一定的角度
      delay_nms (10);
   }

   else if(Left_1_led  == 1 &&  Right_1_led == 0)
   {
      leftrun();                         //左侧检测到黑线,开始向左转一定的角度
	  
      delay_nms (10);
   }
   else if(Left_1_led  == 1 &&  Right_1_led == 1)
   {
      SB1=1;
	    stop();                         //左侧检测到黑线,开始向左转一定的角度
      delay_nms (10);
   }
     
}
//小车循迹加避障合体程序
void Robot_com()
{
		Robot_Traction();
	  if(RightIRBZ==0&&LeftIRBZ==0)		//两边传感器同时检测到红外
		{
			SB1=0;
      stop();
		}
		else
			run();
}
//PWM调速中断
void timer0() interrupt 1
{
  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;
}
void PWM_init()
{
	TMOD|=0x02;//八位重装模块
  TH0=220;
  TL0=220;//11.0592M晶振下最大比值是256,输出100HZ
  TR0=1;//启动定时器0
  ET0=1;//允许定时器0中断
}

//----------红外遥控-------------------------------------------------------------
void IR_IN() interrupt 2 using 0                      //定义INT2外部中断函数
{
  unsigned char j,k,N=0;                              //定义临时接收变量
   
  EX1 = 0;                                            //关闭外部中断,防止再有信号到达   
  delayms(15);                                        //延时时间,进行红外消抖
  if (IRIN==1)                                        //判断红外信号是否消失
  {  
     EX1 =1;                                          //外部中断开
	 return;                                          //返回
  } 
                           
  while (!IRIN)                                       //等IR变为高电平,跳过9ms的前导低电平信号。
  {
      delayms(1);                                     //延时等待
  }

  for (j=0;j<4;j++)                                   //采集红外遥控器数据
  { 
    for (k=0;k<8;k++)                                 //分次采集8位数据
    {
       while (IRIN)                                   //等 IR 变为低电平,跳过4.5ms的前导高电平信号。
       {
         delayms(1);                                  //延时等待
       }
       
       while (!IRIN)                                  //等 IR 变为高电平
       {
         delayms(1);                                  //延时等待
       }
   
       while (IRIN)                                   //计算IR高电平时长
       {
         delayms(1);                                  //延时等待
         N++;                                         //计数器加加
         if (N>=30)                                   //判断计数器累加值
	     { 
           EX1=1;                                     //打开外部中断功能
	       return;                                    //返回
         }                   
       }
                                       
      IRCOM[j]=IRCOM[j] >> 1;                         //进行数据位移操作并自动补零
     
      if (N>=8)                                       //判断数据长度 
      {
         IRCOM[j] = IRCOM[j] | 0x80;                  //数据最高位补1
      } 
      N=0;                                            //清零位数计录器
    }
  }
   
  if (IRCOM[2]!=~IRCOM[3])                            //判断地址码是否相同
  { 
     EX1=1;                                           //打开外部中断
     return;                                          //返回
  }

  for(j=0;j<10;j++)                                   //循环进行键码解析
   {
      if(IRCOM[2]==RecvData[j])                       //进行键位对应
      {
        ControlCar_yaokong(j);                                          //数码管显示相应数码
      }
   }
   EX1 = 1;                                           //外部中断开 
} 
void zd0() interrupt 3 		 //T0中断用来计数器溢出,超过测距范围(超声波)
{
  flag=1;			 //中断溢出标志
	RX=0;
}
/********超声波高电平脉冲宽度计算程序***************/
void Timer_Count(void)
{
	 TR1=1;			    //开启计数
	 while(RX);			//当RX为1计数并等待
	 TR1=0;				//关闭计数
   Conut();			//计算
}
/********************************************************/
void  StartModule() 		         //启动模块
{
	 TX=1;			                     //启动一次模块
   Delay10us(2);
	 TX=0;
}
void ultrasonic()
{
	unsigned int a;
	Delay1ms(5);//延时片刻
  TMOD=TMOD|0x10;//设T0为方式1,GATE=1;
  EA=1;
  TH1=0;
  TL1=0;          
  ET1=1;             //允许T0中断
	turn_right_flag=0;
	RX=1;
	StartModule();
  for(a=951;a>0;a--)
	{	   
	  if(RX==1)
		{
       Timer_Count();
		}
  }
}
/********************************************************/ 
//------------------------------------------------------------------------------------------------------- 
void main()                               //主程序入口
{
  EA = 1;			   //开总中断
  EX1=1;                                               //同意开启外部中断1
  IT1=1;                                               //设定外部中断1为低边缘触发类型
  PWM_init();
  while(1)                                //程序主循环
  {
	  if(P3_2 == 0)
	  {
	   delay_nms(10);
	   if(P3_2 == 0)
	   {
	   	  temp++;
		  while(!P3_2);
	   }
	  }
	  if(temp > 5)
	  {
	    temp = 1;
	  }
	  switch(temp)
	  {
	    case 1:	ShowPort = LedShowData[1];Robot_Traction();EX1 = 0;break;
		  case 2: ShowPort = LedShowData[2];Robot_Avoidance();EX1 = 0;break;
			case 3: ShowPort = LedShowData[3];Robot_com();EX1 = 0;break;
			case 4: ShowPort = LedShowData[4];SB1 = 1; EX1 = 1;break;
			case 5: ShowPort = LedShowData[5];ultrasonic();EX1 = 1;break;
	  } 
  }
}

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值