大家在做寻迹小车的时候可能会遇到许许多多的问题,比如小车该如何组装?组装之后该如何接线?接线之后又该如何编程,电源应该给多少右才能驱动电机呢?那么本次我将以三个方面给大家讲解(讲的不对可以辱骂,没必要放过)
(a) 四路寻迹模块 (b)L298N电机驱动模块
一、小车的组装&接线
我们会用到三个模块51单片机最小系统板、四路寻迹模块、L298N电机驱动模块,这些根据这些名字在淘宝上都能购买(窝没钱只能买两个轮的)线太杂,嫌麻烦就没理了。
(1)L298N常见问题讲解
(1.) L298N这款芯片,如果你跟我一样只玩这种两个轮的小电机话只需要7.4v的电压就可以了,通过L298N给单片机供5v的电,然后从单片机再供5v的电给寻迹模块。至于为什么是7v?因为7v是L298n的一个突破口,如果你低于这个电压电机也能驱动,但会有点问题比如用着用着电池就没电了需要换电池,驱动也不稳定,四个电池只能玩2个小时左右。所以我们用两个18650电池变成7.4v(记得买带充电的)
1.供电控制: 只需要在12V供电处接上7-12V电压,供电GND处与单片机共地即可,5V供电处会输出一个5V的电压,可以用于给单片机供电,做小车时最常用的就是这种方式。使用这种方式时,板载5V使能不用管。
2.引脚功能: 输出A、B:接受电流的输出使其前进后退(输出直流随便你怎么接)
12V供电:接7V~12V电压,最高可承受30多V的电压(你小子别接反就不会坏的那种)
供电GND:单片机接一根用于给单片机进行供地,给电源接一根用于造成电流回路
5V供电:给单片机接一根进行供电,可以输出一个相对较稳定5v的电压
通道使能端A、B:到这里你可能需要学习一个叫PWM的东西(会的话当我没说)
使能A控制左边电机反之则右边,只有当 “A或B使能” 为1的时候 “输出A或B” 才能输出所以你可以在适当的时间给他们“零”或者“一”来实现调速。(注意!每个使能都有两个插线口接前面一排就行了接单片机引脚)
逻辑输入IN1、2、3、4:1~2为左边 3~4为右边 1和3是前进 2和4是后退。接在单片机的引脚上面控制左转右转
(2.)四路寻迹模块
四路寻迹模块供3.5v~5v电压利用单片机供电,按下图接就完了(这个就不过多讲自己学习一下下) 红外循迹模块原理还是很简单的,和许多光电传感器原理一样,当发射器发射出去的光被接收器接收到后,模块上对应的LED灯点亮,此时相应的输出引脚输出低电平;如果发射器发射的光没有被接收器接收到的话,那么LED灯不点亮,此时相应的输出引脚输出高电平。
灯没亮就是检测到你的 “黑胶布” 了或者距离太远没检测到东西,通过旋钮调距离(嘿嘿,看到那个黑胶布了没?是的,光滑的黑胶布可以让你的红外寻迹返回不了数据,买一个吧~)
灯亮就是检测到东西(自己去看看就不细讲了还是很好理解的,链接在下面)
http://t.csdnimg.cn/irh4N
二.小车代码讲解
1.这是第一部分的代码这个代码是利用8421法去判断红外传感器他是不是检测到黑线。这里怕有的兄弟不是特别理解,那么我就举个栗子这个是重点自己看一下
if(count10us>=5)
{
if((accept_left==0) && (accept_far_left==0) &&(accept_right==0)&&(accept_far_right==0)) //全部为零
{
testnum=3;
}
else if((accept_left==0) && (accept_far_left==0) &&(accept_right==0)&&(accept_far_right==1))
{
testnum=6;
}
else if((accept_left==0) && (accept_far_left==0) &&(accept_right==1)&&(accept_far_right==0))
{
testnum=6;
}
else if((accept_left==0) && (accept_far_left==0) &&(accept_right==1)&&(accept_far_right==1))
{
testnum=2;
}
else if((accept_left==0) && (accept_far_left==1) &&(accept_right==0)&&(accept_far_right==0))
{
testnum=7;
}
else if((accept_left==0) && (accept_far_left==1) &&(accept_right==0)&&(accept_far_right==1))
{
testnum=7;
}
else if((accept_left==0) && (accept_far_left==1) &&(accept_right==1)&&(accept_far_right==0))
{
testnum=3;
}
else if((accept_left==0) && (accept_far_left==1) &&(accept_right==1)&&(accept_far_right==1))
{
testnum=2;
}
else if((accept_left==1) && (accept_far_left==0) &&(accept_right==0)&&(accept_far_right==0))
{
testnum=7;
}
else if((accept_left==1) && (accept_far_left==0) &&(accept_right==0)&&(accept_far_right==1))
{
testnum=3;
}
else if((accept_left==1) && (accept_far_left==0) &&(accept_right==1)&&(accept_far_right==0))
{
testnum=6;
}
else if((accept_left==1) && (accept_far_left==0) &&(accept_right==1)&&(accept_far_right==1))
{
testnum=2;
}
else if((accept_left==1) && (accept_far_left==1) &&(accept_right==0)&&(accept_far_right==0))
{
testnum=1;
}
else if((accept_left==1) && (accept_far_left==1) &&(accept_right==0)&&(accept_far_right==1))
{
testnum=1;
}
else if((accept_left==1) && (accept_far_left==1) &&(accept_right==1)&&(accept_far_right==0))
{
testnum=1;
}
else if((accept_left==1) && (accept_far_left==1) &&(accept_right==1)&&(accept_far_right==1))
{
testnum=3;
}
else
{
advance();
}
count10us=0;
}
return testnum;
}
以上这个代码就是利用8421法来编写的,剩下的就是利用定时器控制使能端
三、全部代码的过程
都封装好了自己拿过去用吧,使能端自己在调一下我全部改了。
#include
#include
//小车轮胎
sbit IN1=P1^0; //左轮 请进
sbit IN2=P1^1; //左轮 后退
sbit IN3=P1^2; //右轮 前进
sbit IN4=P1^3; //右轮 后退
sbit ENA=P1^4; //左使能端1
sbit ENA1=P1^5; //右使能端2
//传感器检测
sbit accept_left=P2^0; //左侧检测
sbit accept_far_left=P2^1; //极左边检测
sbit accept_right=P2^2; //右侧检测
sbit accept_far_right=P2^3; //极右侧检测
unsigned char num1;
unsigned int Count_ENA,Count_ENA1,count10us,countsete=65534;
//检测输入
void stop() //全部停止
{
Count_ENA=80;
Count_ENA1=80; //可以适当调节减少误差
IN1=0;
IN2=0;
IN3=0;
IN4=0;
Delay100us(1);
}
void min_left() //小转左边检测
{
Count_ENA=60;
Count_ENA1=60;
IN1=1;
IN2=0;
IN3=0;
IN4=0;
}
void min_right() //小转右边检测
{
Count_ENA=60;
Count_ENA1=60;
IN1=0;
IN2=0;
IN3=1;
IN4=0;
}
void left() //大转左边检测
{
Count_ENA=70;
Count_ENA1=70;
IN1=0;
IN2=1;
IN3=1;
IN4=0;
}
void right() //大转右边检测
{
Count_ENA=70;
Count_ENA1=70;
IN1=1;
IN2=0;
IN3=0;
IN4=1;
}
void advance() //前进检测
{
Count_ENA=80;
Count_ENA1=80;
IN1=1;
IN2=0;
IN3=1;
IN4=0;
Delay100us(1);
}
void retreat() //后退检测
{
Count_ENA=65;
Count_ENA1=65;
IN1=0;
IN2=1;
IN3=0;
IN4=1;
Delay100us(1);
}
unsigned char test_trolley(unsigned char testnum) //寻迹判断
{
if(count10us>=5)
{
if((accept_left==0) && (accept_far_left==0) &&(accept_right==0)&&(accept_far_right==0)) //全部为零
{
testnum=3;
}
else if((accept_left==0) && (accept_far_left==0) &&(accept_right==0)&&(accept_far_right==1))
{
testnum=6;
}
else if((accept_left==0) && (accept_far_left==0) &&(accept_right==1)&&(accept_far_right==0))
{
testnum=6;
}
else if((accept_left==0) && (accept_far_left==0) &&(accept_right==1)&&(accept_far_right==1))
{
testnum=2;
}
else if((accept_left==0) && (accept_far_left==1) &&(accept_right==0)&&(accept_far_right==0))
{
testnum=7;
}
else if((accept_left==0) && (accept_far_left==1) &&(accept_right==0)&&(accept_far_right==1))
{
testnum=7;
}
else if((accept_left==0) && (accept_far_left==1) &&(accept_right==1)&&(accept_far_right==0))
{
testnum=3;
}
else if((accept_left==0) && (accept_far_left==1) &&(accept_right==1)&&(accept_far_right==1))
{
testnum=2;
}
else if((accept_left==1) && (accept_far_left==0) &&(accept_right==0)&&(accept_far_right==0))
{
testnum=7;
}
else if((accept_left==1) && (accept_far_left==0) &&(accept_right==0)&&(accept_far_right==1))
{
testnum=3;
}
else if((accept_left==1) && (accept_far_left==0) &&(accept_right==1)&&(accept_far_right==0))
{
testnum=6;
}
else if((accept_left==1) && (accept_far_left==0) &&(accept_right==1)&&(accept_far_right==1))
{
testnum=2;
}
else if((accept_left==1) && (accept_far_left==1) &&(accept_right==0)&&(accept_far_right==0))
{
testnum=1;
else if((accept_left==1) && (accept_far_left==1) &&(accept_right==0)&&(accept_far_right==1))
{
testnum=1;
}
else if((accept_left==1) && (accept_far_left==1) &&(accept_right==1)&&(accept_far_right==0))
{
testnum=1;
}
else if((accept_left==1) && (accept_far_left==1) &&(accept_right==1)&&(accept_far_right==1))
{
testnum=3;
}
else
{
advance();
}
count10us=0;
}
return testnum;
}
unsigned char select(unsigned char num2)
{
num1=test_trolley(num1);
switch(num1)
{
case 1:left();break; //左转
case 2:right();break; //右转
case 3:advance();break;//前进
case 4:retreat();break;//后退
case 5:stop(); break; //停止
case 6:min_left(); break; //小左转检测
case 7:min_right();break; //小右转检测
}
return num2;
}
void Timer0Init(void) //1毫秒@11.0592MHz
{
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x66; //设置定时初值
TH0 = 0xFC; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1;
PT0=0;
EA=1;
}
void timer0_routine() interrupt 1 //定时器里面在加一个变量分别用来表示ENA1和ENA2
{
static unsigned int j,y,countnum;
TL0 = 0x66; //设置定时初值
TH0 = 0xFC; //设置定时初值
countnum++;
countsete++;
if(countnum>=2) //小车靠Pid误差运行 误差越大小车抖动的越快
{
j++;
y++;
if(j>=Count_ENA) {ENA=1;}
else {ENA=0;}
if(y>=Count_ENA1) {ENA1=1;}
else {ENA1=0;}
if(j==100)
{
j=0;
}
if(y==100)
{
y=0;
}
countnum=0;
}
if(countsete>=65535)
{
countsete=65525;
count10us++;
}
}