寻迹小车代码

#include<reg52.h>
#include<intrins.h>   
#include<string.h>
#define uint unsigned int
#define uchar unsigned char


//停车
#define stop();    { IN31=0; IN32=0; IN33=0; IN34=0;}
//后退
#define back();    { IN31=0; IN32=1; IN33=0; IN34=1;}
//前进
#define go();      { IN31=1; IN32=0; IN33=1; IN34=0;}
//前进时左转
#define left_g();  { IN31=0; IN32=0; IN33=1; IN34=0;}
//前进时右转
#define right_g(); { IN31=1; IN32=0; IN33=0; IN34=0;}
//后退时左转
#define left_b();  { IN31=0; IN32=1; IN33=0; IN34=0;}
//后退时右转
#define right_b(); { IN31=0; IN32=0; IN33=0; IN34=1;}
//原地打转180
#define turn_round(); { IN31=1; IN32=0; IN33=0; IN34=1;}


sfr T2MOD=0xc9; //使用定时器2时必须
sbit IN31= P2^0;//直流电机输入端IN1
sbit IN32= P2^1;//直流电机输入端IN2
sbit IN33= P2^2;//直流电机输入端IN3
sbit IN34= P2^3;//直流电机输入端IN4
sbit EN12= P2^4;//直流电机输入端IN3
sbit EN34= P2^5;//直流电机输入端IN4
sbit rw=P3^1;  //1602端口定义
sbit en=P3^0;  //1602端口定义
sbit rs=P3^7;  //1602端口定义
sbit Test_Black_tape=P3^3; //小车车轮检测黑带条纹数
sbit bing=P3^6; //蜂鸣器
sbit Test_left=P0^0;  //黑线左检测端口定义
sbit Test_Middle_left=P0^1;  //黑线中检测端口定义
sbit Test_Middle_right=P0^2;  //黑线右检测端口定义
sbit Test_right=P0^3;  //黑线右检测端口定义
uchar PWM12=47,PWM34=49;//PWM12控制EN12,PWM34控制EN34
uchar PWM_i=0;//调速脉冲进行计时
uchar Test_flag =0;//低四位表黑线情况,第四,三,二,一位表示左,左中,右中,右侧探测结果,1表示在黑线上
uchar detector=8;  //4-左侧探测器,2-中间探测器,1-右侧探测器
uchar left_flag=0; //首先检测到黑线时被标记为1;
uchar right_flag=0; //首先检测到黑线时被标记为1;
uchar count=0; // 对黑条进行计数
uchar correction_flag=0;//方位矫正函数标志位,为1时可执行矫正函数
uchar Control_rotation_angle=0; //控制矫正函数转角大小
uchar Control_bing=0;//控制蜂鸣器位,为1时蜂鸣器按一定频率响
uchar bing_i=0;//控制蜂鸣器频率
uchar flag=1;//控制两边边ST188开关,flag为1时开
uint Timing=0;//控制两边边ST188开关,Timing(定时器中)等于300时(600ms),flag置为1
uint mstcnt=0;//定时器重时间计数,每1ms加1
uint  time=0;//全程时间
uint Time_delay=0;//延时时间(2ms)
uchar Time_delay_flag=0;//启动延时计时的标志位,1时启动
uint Time_interval=0;//中间两个传感器检测的黑线相差的时间(ms)
uchar Time_interval_flag=0;//启动中间两个传感器检测的黑线相差的时间(ms)的标志位,1时启动
uchar Control_count=1;  //为1时允许flag开始计时
uchar turn_round_flag=1; //转弯标志位
uint distance=0,Subsection_distance=0;//全程,每一段时间所行使的路程
uint cycle_number=0;// 记录小车车轮的圈数
uchar open_interrupt0=0;//当Close_interrupt=1时,外部中断1s后打开
uint  interrupt0_i=0;//1s打开中断进行计时
uchar stop_flag=0; //终点起点停车标志位
uchar disbuf[4]={0};   //存放路程
uchar seconde[3]={0};  //存放时间
uchar number[2]={0};  //存放黑条数目
uchar code table1[]={"S: 0.0 m  t:  0s"};
uchar code table2[]={"    count:00"    };
/***************延时子函数1us*******************/
 void delay1us(uint us)
  {
    while(us--) ;


  }
/***************延时子函数1ms*******************/
void delay1ms(uint ms)
  { 
    uchar j;
    while(ms--)
     {
       for(j=0;j<120;j++);
     }
  }
void write_com(uchar com)//1602写指令
 {
  rs=0;
  P1=com;
  delay1us(4);
  en=1;
  en=0;
 }


void write_data(uchar data0)//1602写数据
 {
  rs=1;
  P1=data0;
  delay1us(4);
  en=1;
  en=0;
 }
void display1( ) //显示时间路程程序
{
  disbuf[0] = ((distance/1000)%10)+0x30;  //路程(cm)千位
  disbuf[1] = ((distance/100)%10)+0x30; //路程(cm)百位
  disbuf[2] = ((distance/10)%10)+0x30; //路程(cm)十位
  disbuf[3] = (distance%10)+0x30; //路程(cm)个位
  seconde[0] = (time/100)+0x30; //时间百位
  seconde[1] = ((time%100)/10)+0x30; //时间十位
  seconde[2] = (time%10)+0x30; //时间个位  
 if(disbuf[0]==0x30)
   {
disbuf[0]=0x20;//如果百位为0,不显示(显示空格)
   }
 if(seconde[0]==0x30)
   {
seconde[0]=0x20;//如果百位为0,不显示(显示空格)
if(seconde[1]==0x30)
{
seconde[1]=0x20;//如果百位为0,十位为0也不显示(显示空格)
}
   }  
write_com(0x80+2);  //显示路程十位
delay1us(2);
write_data(disbuf[0]); 
delay1us(2);  
    write_com(0x80+3);  //显示路程个位
delay1us(2);
write_data(disbuf[1]);
delay1us(2);
write_com(0x80+5);  //显示路程十分位位
delay1us(2);
write_data(disbuf[2]);
delay1us(2);
write_com(0x80+6); //显示路程百分位
delay1us(2);
write_data(disbuf[3]);
delay1us(2);


write_com(0x80+12);  //显示时间百位
delay1us(2);
write_data(seconde[0]); 
delay1us(2);  
    write_com(0x80+13);  //显示时间十位
delay1us(2);
write_data(seconde[1]);
delay1us(2);
write_com(0x80+14);  //显示时间个位
delay1us(2);
write_data(seconde[2]);
delay1us(2);
}
void display2( ) //显示黑带函数
{
  number[0] = (count/10)+0x30; //黑带数目十位
  number[1] = (count%10)+0x30; //黑带数目个位   
 if(number[0]==0x30)
   {
number[0]=0x20;//如果十位为0,不显示(显示空格)
   }  
write_com(0x80+0x40+10);  //显示黑条数目十位
write_data(number[0]);
delay1us(2);
write_com(0x80+0x40+11);  //显示黑条数目个位
delay1us(2);
write_data(number[1]);
}
/**************计算路程,并把结果放入lcd1602缓冲区**************/
void count_distance()
{
  Subsection_distance=cycle_number*5;
  distance=distance+Subsection_distance;
  cycle_number=0;
 }
/*************小车前进转弯函数*********************/
void search_back_small( )   //后退小步,缓冲作用
{
  back();
  Time_delay_flag=1;
  while(Time_delay<130);   //定时器2延时130x2=260ms
  Time_delay_flag=0;
  Time_delay=0;
  stop();
}
void search_back( )           //后退
{
  back();
  Time_delay_flag=1;
  while(Time_delay<200);   //定时器2延时200x2=400ms
  Time_delay_flag=0;
  Time_delay=0;
  stop();
}


void search_right_g_5( ) //前进实现右转
{
  right_g();
  Time_delay_flag=1;
  while(Time_delay<30);   //定时器2延时30x2=60ms
  Time_delay_flag=0;
  Time_delay=0;
  stop();
}
void search_right_g_10( ) //前进实现右转
{
  right_g();
  Time_delay_flag=1;
  while(Time_delay<70);   //定时器2延时70x2=140ms
  Time_delay_flag=0;
  Time_delay=0;
  stop();
}
void search_right_g_20( ) //前进实现右转
{
  right_g();
  Time_delay_flag=1;
  while(Time_delay<100);   //定时器2延时100x2=200ms
  Time_delay_flag=0;
  Time_delay=0;
  stop();
}
void search_right_g_30( ) //前进实现右转
{
  right_g();
  Time_delay_flag=1;
  while(Time_delay<130);   //定时器2延时130x2=260ms
  Time_delay_flag=0;
  Time_delay=0;
  stop();
}
void search_right_g_40( ) //前进实现右转
{
  right_g();
  Time_delay_flag=1;
  while(Time_delay<170);   //定时器2延时170x2=340ms
  Time_delay_flag=0;
  Time_delay=0;
  stop();
}


void search_right_b( ) //后退实现右转
{
  right_b();
  Time_delay_flag=1;
  while(Time_delay<105);   //定时器2延时105x2=210ms
  Time_delay_flag=0;
  Time_delay=0;
  stop();
}


void search_left_g_5( ) //前进实现左转
{
  left_g();
  Time_delay_flag=1;
  while(Time_delay<25);   //定时器2延时25x2=50ms
  Time_delay_flag=0;
  Time_delay=0;
  stop();
}
void search_left_g_10( ) //前进实现左转
{
  left_g();
  Time_delay_flag=1;
  while(Time_delay<45);   //定时器2延时45x2=90ms
  Time_delay_flag=0;
  Time_delay=0;
  stop();
}
void search_left_g_20( ) //前进实现左转
{
  left_g();
  Time_delay_flag=1;
  while(Time_delay<70);   //定时器2延时70x2=140ms
  Time_delay_flag=0;
  Time_delay=0;
  stop();
}
void search_left_g_30( ) //前进实现左转
{
  left_g();
  Time_delay_flag=1;
  while(Time_delay<90);   //定时器2延时90x2=180ms
  Time_delay_flag=0;
  Time_delay=0;
  stop();
}
void search_left_g_40( ) //前进实现左转
{
  left_g();
  Time_delay_flag=1;
  while(Time_delay<130);   //定时器2延时130x2=260ms
  Time_delay_flag=0;
  Time_delay=0;
  stop();
}
void search_left_b( ) //后退实现左转
{
  left_b();
  Time_delay_flag=1;
  while(Time_delay<115);   //定时器2延时115x2=230ms
  Time_delay_flag=0;
  Time_delay=0;
  stop();
}
void turn_round_180( )
{
  turn_round();
  Time_delay_flag=1;
  while(Time_delay<580);   //定时器2延时560x2=1160ms
  Time_delay_flag=0;
  Time_delay=0;
  stop();

/*************矫正小车方位函数*********************/
void rotation_angle( )
{
  if((Time_interval>=0)&&(Time_interval<=2))
    {Control_rotation_angle=0;} //不转角
  if((Time_interval>2)&&(Time_interval<=10))
    {Control_rotation_angle=1;} //转角5度
  if((Time_interval>10)&&(Time_interval<=25))
    {Control_rotation_angle=2;} //转角10度
  if((Time_interval>25)&&(Time_interval<=40))
    {Control_rotation_angle=3;} //转角15度
  if((Time_interval>40)&&(Time_interval<=60))
    {Control_rotation_angle=4;} //转角20度
  if((Time_interval>60)&&(Time_interval<=90))
    {Control_rotation_angle=5;} //转角25度
  if((Time_interval>90)&&(Time_interval<=150))
    {Control_rotation_angle=6;} //转角25度
  if(left_flag==1) //左边先检测到黑线
   {
    switch(Control_rotation_angle) 
 {
case 1:    search_left_g_5( );
  break;
case 2:    search_left_g_10( );
          break;
case 3:   search_left_g_20( );
          break;
case 4:    search_left_g_30( );
          break;
case 5:   search_left_g_40( );
  break;
case 6:   search_left_g_40( );
  break;
default:   break;          
      }
}
 else if(right_flag==1)
   {
    switch(Control_rotation_angle) 
 {
case 1:    search_right_g_5( );
  break;
case 2:    search_right_g_10( );
          break;
case 3:   search_right_g_20( );
          break;
case 4:    search_right_g_30( );
          break;
case 5:   search_right_g_40( ); 
          break;
case 6:    search_right_g_40( );
          break;
default:   break;          
      }
}
 right_flag=0;
 left_flag=0;
 Time_interval_flag=0;
 Time_interval=0;
}
/*************检测左中右三处黑线情况*********************/
void Testing ( )
{
  Test_flag=0; //标志位清零
  detector=8; //标志位清零
  while(detector)
    {
  switch(detector)
         {
  case 8: if((Test_left==0)&&(flag==1))//左侧红外传感器检测黑线情况(flag为0时对应为始终为0)
           {
 Test_flag=Test_flag|detector;
}//将Test_flag对应的标志为1,1表示检测到黑线}
          break;  
  case 4: if(Test_Middle_left==0)   //左侧红外传感器检测黑线情况
           {
 Test_flag= Test_flag|detector;
 flag=0;Control_count=1;
}//将Test_flag对应的标志为1,1表示检测到黑线}
          break;
  case 2: if(Test_Middle_right==0)   //左侧红外传感器检测黑线情况
           {
 Test_flag=Test_flag|detector;
 flag=0;Control_count=1;
}//将Test_flag对应的标志为1,1表示检测到黑线}
          break;
  case 1: if((Test_right==0)&&(flag==1))//左侧红外传感器检测黑线情况(flag为0时对应为始终为0)
           {
 Test_flag=Test_flag|detector;
}//将Test_flag对应的标志为1,1表示检测到黑线}
          break;
          default: break;
       }
 detector >>=1;
}
}


/*************根据检测到的黑线情况选择前进方式*********************/
void forward( )
{
    switch(Test_flag) 
 {
case 0x00: go();
          break;
case 0x01: search_back_small( );  //先后退小步
          search_left_b( );  //后退实现左转
  Control_bing=1;    //蜂鸣器响一声
          break;
case 0x02: Control_bing=1;    //蜂鸣器响一声
  if((left_flag==0)&&(right_flag==0))
    {
  right_flag=1;
  Time_interval_flag=1;
}
          break;
case 0x03: search_left_g_20( );  //后退实现左转
  Control_bing=1;    //蜂鸣器响一声
          break;
case 0x04: Control_bing=1;    //蜂鸣器响一声
  if((left_flag==0)&&(right_flag==0))
    {
  left_flag=1;
  Time_interval_flag=1;
}
          break;
case 0x06: go();
          break;
case 0x08: search_back_small( );  //先后退小步
          search_right_b( );   //后退实现右转
  Control_bing=1;    //蜂鸣器响一声
          break;
case 0x12: search_right_g_20( );   //后退实现右转
  Control_bing=1;    //蜂鸣器响一声
          break;
 default: search_back( );  //异常处理,后退
  Control_bing=1;    //蜂鸣器响一声
          break;          
      }
}
/*************终点,起点停车函数*********************/
void start_end( )
{
  uchar i=5;
  if(count==6)  //到达终点停留10s后原地打转180返回
{
 
 display2( ); //显示黑带数目
 stop();  
 while(i--)
  {
  bing=1;
delay1ms(200);
bing=0;
delay1ms(300);
  }
 delay1ms(6000);  
 search_back( );
 search_back( );
 delay1ms(500);
 EX0=0;  //关外部中断0
 EX1=0;
 turn_round_flag=0;
 turn_round_180( );
 EX0=1;  //开外部中断0
 EX1=1;
 turn_round_flag=1;
 delay1ms(200);
 display2( ); //显示黑带数目
}
  if(count==12)  //返回到起点,关闭总中断,响铃三声报警
{
 EA=0;
 stop();
 display2( ); //显示黑带数目
 while(i--)
  {
  bing=1;
delay1ms(200);
bing=0;
delay1ms(300);
  }
  while(1);
}
}
/*************外部中断0,计算中间黑条的数目*********************/
void INT_0() interrupt 0
{
  count++;
  EX0=0;
  if((count==6)||(count==12)) //起点,终点处理
{
  start_end( );

  if((count==3)||(count==9)) //减速行驶
    {
 PWM12=38;
 PWM34=40;
}
  else if((count==5)||(count==11)) //在距离终点0.5米时低速行驶至终点
    {
 PWM12=29;
 PWM34=30;
}
   else //正常速度
    {
 PWM12=47;
 PWM34=49;
}


  if(count>90)
    {
 count=0;
}
  open_interrupt0=1;
  display2( );//显示黑带数目
}
/*************外部中断1,计算车轮黑条数目*********************/
void INT_1() interrupt 2
{
  delay1us(500);
  if(Test_Black_tape==0)
{
    cycle_number++;
    IE1=0;  //清除中断标志位
    if(cycle_number==250)
    {
 cycle_number=0;
}
}
}
/*************定时计数器中断2,用于电机PWM调速,计时*********************/
void time_2() interrupt 5
 {


    TF2=0;   //定时器2必须由软件对溢出标志位清零,硬件不能清零,这里与定时器0和定时器不同
    PWM_i++;
mstcnt++;   //用于计算时间,每隔10ms加1
/*****以下为实时计时程序******/
    if(mstcnt>=500)//对小车行驶的时间进行计时,mstcnt满20即为一秒
     {
       time++;//秒+1
       mstcnt=0; //对计数单元的清零,重新开始计数
  if(time==500) 
    {
  time=0;
}
 if(turn_round_flag==1)
   {
count_distance();  //计算路程
   display1( ); //显示时间路程程序
}
     } 
/*****中间先过黑线时,两边黑线检测关闭400ms程序******/
if(Control_count==1)
{
   Timing++;
        if(Timing>=200)
         {
     Timing=0;
     flag=1;
 Control_count=0;
         }
}
/*****以下为蜂鸣器响铃控制程序******/
if(Control_bing==1)
{
   bing_i++;
   if(bing_i<200)
 {
 bing=1;
 }
else
{
bing=0;
   bing_i=0;
Control_bing=0;
}
}
/*****以下为中间两个传感器通过黑色胶带的时间差******/
    if(Time_interval_flag==1)
 {
  Time_interval++;
if(right_flag==1)   //此时右边传感器先接触黑线
 {
  if(Test_Middle_left==0)
 {
  Time_interval_flag=0;
correction_flag=1; //方位矫正标志位,为1时可执行矫正函数
 }
 }
if(left_flag==1)   //此时左边传感器先接触黑线
 {
  if(Test_Middle_right==0)
 {
  Time_interval_flag=0;
correction_flag=1; //方位矫正标志位,为1时可执行矫正函数
 }
 }
   if(Time_interval>=200)
  {
Time_interval_flag=0;
correction_flag=1;
Time_interval=0; 
  }
 }
/*****以下用于延时******/
    if(Time_delay_flag==1)
 {
  Time_delay++;
if(Time_delay>=2000)
 {
  Time_delay_flag=0;
  Time_delay=0;
 }
 }  
/*****定时1S打开外部中断0,防止抖动,黑条连续计数******/
    if(open_interrupt0==1)
 {
   interrupt0_i++;
if(interrupt0_i>=500)
 {
    open_interrupt0=0;
  EX0=1;
      IE0=0;  //清除中断标志位
  interrupt0_i=0;
 }
 }
/*****以下为PWM调速程序******/
if(PWM_i<=PWM12)  //控制EN12
{
 EN12=1;
}
else
{
 EN12=0;
}
if(PWM_i<=PWM34)  //控制EN34
{
 EN34=1;
}
else
{
 EN34=0;
}
if(PWM_i>=50)
{
 PWM_i=0;
}
  }


 /*************初始化函数*********************/
void int_int (void)
 {
   uchar i;
   bing=0;  //蜂鸣器初始化
   rw=0;
   write_com(0x38);//设置显示模式
   delay1ms(2);
   write_com(0x0c);
   delay1ms(2);
   write_com(0x06);
   delay1ms(2);
   write_com(0x01); //清零
   delay1ms(2);
   for(i=0;i<sizeof(table1)-1;i++)
     {
      write_data(table1[i]);
      delay1ms(1);  
     }
  write_com(0x80+0x40);
  delay1ms(1);
  for(i=0;i<sizeof(table2)-1;i++)
   {
     write_data(table2[i]);
     delay1ms(1);
   }


   TMOD=0x55;//确定时器工作方式
   IE0=0;  //清除中断标志位
   IE1=0;  //清除中断标志位 
   RCAP2H=0xf8;
   RCAP2L=0x30;       //定时器2自动重装
   T2CON=0x00;
   T2MOD=0x00;
   ET2=1; // 允许定时器2中断
   TR2=1;  //开启定时器2
   EX0=1;  //开外部中断0;
   IT0=1; //外部中断0负跳变触发
   EX1=1;  //开外部中断0;
   IT1=1; //外部中断0负跳变触发
   IP=0x20; //设置中断优先级(外部中断0,定时中断2为高优先级)
   EA=1; //开总中断
 }
/*************主函数*********************/
void main() 
 {  
   delay1ms(500);//按下电源给小车0.5S的缓冲时间
   int_int(  ); //系统初始化
   while(1)  //进入总循环
   {
     Testing ( ); //检测黑线情况
forward( ); //根据检测的黑线情况选择前进方式
if((correction_flag==1)&&(count!=7))   //执行矫正程序
  {
  rotation_angle( );
correction_flag=0;
  }  
   }
 }
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值