51单片机寻迹寻迹小车新手教程

大家在做寻迹小车的时候可能会遇到许许多多的问题,比如小车该如何组装?组装之后该如何接线?接线之后又该如何编程,电源应该给多少右才能驱动电机呢?那么本次我将以三个方面给大家讲解(讲的不对可以辱骂,没必要放过)

(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++;

}

}