自动循迹小车
旦检测到某个I/O口有信号,即进入判断处理程序,先确定4个探测器中的哪一个探测到了黑线,如果左面第一级传感器或者左面第二级传感器探测到黑线,即小车左半部分压到黑线,车身向右偏出,此时应使小车向左转;如果是右面第一级传感器或右面第二级传感器探测到了黑线,即车身右半部压住黑线,小车向左偏出了轨迹,则应使小车向右转。在经过了方向调整后,小车再继续向前行走,并继续探测黑线重复上述动作。循迹流程图如图4-2所示
启动循迹模式 探测黑线 N 是否检测到黑线 Y 判断处理程序 向左转 Turn _left2 向左转 Turn _left1 向右转 Turn_ right1 向右转 Turn_ Lright2 继续前进
图4-2循迹流程图
由于第二级方向控制为第一级的后备,则两个等级间的转向力度必须相互配合。第二级通常是在超出第一级的控制范围的情况下发生作用,它也是最后一层保护,所以它必须要保证小车回到正确轨迹上来,则通常使第二级转向力度大于第一级,即Turn_left2 > Turn_left1,Turn_right2 > Turn_right1 (其中
20
自动循迹小车
Turn_left2,Turn_left1, Turn_right2 , Turn_right1为小车转向力度,其大小通过改变单片机输出的占空比的大小来改变),具体数值在实地实验中得到。
4.4中断程序流程图
这里利用的是51单片机的T0定时计数器,从而让单片机P0口的P0.4和P0.5引脚输出占空比不同的方波, 然后经驱动芯片放大后控制直流电机。定时计数器若干时间(比如0.1ms)比如中断一次, 就使P0.4或P0.5产生一个高电平或低电平。中断程序流程图如图4-3所示
开始 定时器赋初值 技术变量赋值t=0 Y 计数值t<占空比? N P0.4和P0.5 输出高电平 P0.4和P0.5 输出低电平 计数变量t加1
结束 图4-3中断程序流程图
21
自动循迹小车
4.5单片机测序
#include
#define uchar unsigned char #define uint unsigned int
unsigned char zkb1=0 ; //**左边电机的占空比**// unsigned char zkb2=0 ; //**右边电机的占空比**// unsigned char t=0; //**定时器中断计数器**// sbit RSEN1=P1^0; sbit RSEN2=P1^1; sbit LSEN1=P1^2; sbit LSEN2=P1^3; sbit IN1=P0^0; sbit IN2=P0^1; sbit IN3=P0^2; sbit IN4=P0^3; sbit ENA=P0^4; sbit ENB=P0^5;
//****************延时函数****************// void delay(int z) { while (z--); }
//**********初始化定时器,中断***********// void init() { TMOD=0x01;
TH0=(65536-100)/256; TL0=(65536-100)%6; EA=1; ET0=1; TR0=1; }
22
自动循迹小车
//***********中断函数+脉宽调制***********// void timer0() interrupt 1 { if(t t++; if(t>=100) {t=0;} } //******************直行******************// void qianjin() { zkb1=30; zkb2=30; } //***************左转函数1***************// void turn_left1() { zkb1=0; zkb2=50; } //***************左转函数2***************// void turn_left2() { zkb1=0; zkb2=60; } //***************右转函数1***************// void turn_right1() 23 自动循迹小车 { zkb1=50; zkb2=0; } //***************右转函数2***************// void turn_right2() { zkb1=60; zkb2=0; } //***************循迹函数*****************// void xunji() { uchar flag; if((RSEN1==1)&&(RSEN2==1)&&(LSEN1==1)&&(LSEN2==1)) { flag=0; }//*******直行*******// else if((RSEN1==0)&&(RSEN2==1)&&(LSEN1==1)&&(LSEN2==1)) { flag=1;} //***左偏1,右转1***// else if((RSEN1==0)&&(RSEN2==0)&&(LSEN1==1)&&(LSEN2==1)) { flag=2;} //***左偏2,右转2***// else if((RSEN1==1)&&(RSEN2==1)&&(LSEN1==0)&&(LSEN2==1)) { flag=3; }//***右偏1,左转1***// else if((RSEN1==1)&&(RSEN2==1)&&(LSEN1==0)&&(LSEN2==0)) { flag=4; }//***右偏2,左转2***// switch (flag) { case 0:qianjin(); break; case 1:turn_right1(); break; case 2:turn_right2(); break; case 3:turn_left1(); break; case 4:turn_left2(); 24