详解51单片机循迹小车设计原理

硬件部分

  1. 控制芯片

我使用的是STC89C52。

  1. 车体

可以购买车体套件,套件包含了车轮,电机,底盘以及连接的小零件。

不建议购买金属底盘,小车所使用的部件大多在底部有裸露引脚,金属底盘会导致短路。

3.L298N电机驱动模块

输出A/B:连接左右电机。

通道A/B使能:把跳线帽拔下后就可以通过PWM调速对电机进行调速。

逻辑输入:与最小系统板引脚连接,IN1和IN2控制左侧电机,IN3和IN4控制右侧电机。

12V供电:连接电源正极。

供电GND:连接电源正极以及单片机GND。

5V供电:连接单片机VCC。

建议加装稳压模块,因为L298N输出电压不稳定。

  1. 红外循迹模块

可以选用四路,二路,五路。

红外循迹模块由探头和主控板组成。当感应器接收到返回的红外光时,主控板上的指示灯会熄灭,同时输出高电平;若感应器为接收到返回的红外光,则指示灯亮,同时输出低电平。

主控板上有四个旋钮,可调节四个探头的灵敏度,在小车组装完成后,上电调节灵敏度。调节至指示灯处于亮灭边界即可。

  1. 电池

推荐使用12V可充电锂电池组,可以反复使用,不建议使用车体套件附带的电池盒,因为使用电池盒时电压不够大,电机动力不足。购买的电池组需要一个DC转接头。

5.51最小系统板

也可以直接使用51学习板,但其体积较大,不便于安装。

注:还需要一些其余零件,例如黑色电工胶布,杜邦线,螺丝,根据个人需求购买电烙铁,电机上有两个小铜环用于接电,可以直接用线搭上去,但是容易断裂,建议焊接。

程序部分

我的程序采用了模块化编程,也可以不用,但是代码会比较长。

编写程序前需要学习PWM调速以及定时器。

小车的转弯靠左右轮的差速,在转弯时一个轮子正转,一个反转效果比较好。

主函数

//驱动主函数
#include<REGX52.H>

#include"timer.h"
#include"Delay.h"
#include"MOTIONCONTROL.h"

#include"drive.h"

#include"direction.h"

void main()
{
    Timer0_Init();
    EA=1;
    while(1)
    {

    CONTROL();

    }
    
}

定时器

#include <REGX52.H>

sbit ENA=P1^1;
sbit ENB=P1^0;
unsigned int PWML,PWMR,t=0;//PWML控制左轮,PWMR控制右轮,t为比较值

void Timer0_Init()
{
    TMOD &= 0xF0;    
    TMOD |= 0x01;        
    TL0 = 65436%256;        
    TH0 = 65436/256;        
    TF0 = 0;        
    TR0 = 1;
    ET0=1;
    EA=1;
    PT0=0;
}//100us


void Timer0_Rountinue() interrupt 1
{
    TL0 = 65436%256;
    TH0 = 65436/256;
    t++;
    if(t<PWML)  ENA=1;
    else  ENA=0;
    if(t<PWMR)  ENB=1;
    else  ENB=0;
    t%=100;
}

循迹函数

#include<REGX52.H>

#include"timer.h"

#include"direction.h"

#include"drive.h"

#include"Delay.h"

sbit D1=P2^3;
sbit D2=P2^2;
sbit D3=P2^1;
sbit D4=P2^0;

void CONTROL()//识别到黑线,灯灭,输出1
{
    

    if(D1==0&&D2==0&&D3==0&&D4==0)//前进
    {
            PWML=14;
            PWMR=14;
            cargo();
    }    
    if(D1==0&&D2==1&&D3==1&&D4==0)//前进
    {
            PWML=15;
            PWMR=15;
            cargo();
    }    
    if(D1==1&&D2==1&&D3==1&&D4==1)//停止
    {
            PWML=0;
            PWMR=0;
            carstop();
    }
    if(D1==1&&D2==0&&D3==0&&D4==0)//右转大弯,左轮大
    {
            PWML=20;
            PWMR=9;
            carright();
    }    
    if(D1==0&&D2==0&&D3==0&&D4==1)//左转大弯,右轮大
    {
            PWML=9;
            PWMR=20;
            carleft();
    }        

    if(D1==0&&D2==0&&D3==1&&D4==0)//左转小弯,右轮大
    {
            PWML=14;
            PWMR=16;
            cargo();
    }    
    if(D1==0&&D2==1&&D3==0&&D4==0)//右转小弯,左轮大
    {
            PWML=16;
            PWMR=14;
            cargo();
    }    
    if(D1==1&&D2==1&&D3==0&&D4==0)//右转大弯,左轮大
    {
            PWML=20;
            PWMR=9;
            carright();
    }    
    if(D1==1&&D2==1&&D3==1&&D4==0)//右转大弯,左轮大
    {
            PWML=20;
            PWMR=9;
            carright();
    }    
    if(D1==0&&D2==1&&D3==1&&D4==1)//左转大弯,右轮大
    {
            PWML=9;
            PWMR=20;
            carleft();
    }    
    if(D1==1&&D2==0&&D3==1&&D4==0)//右转大弯,左轮大
    {
            PWML=20;
            PWMR=9;
            carright();
    }    
    if(D1==0&&D2==1&&D3==0&&D4==1)//左转大弯,右轮大
    {
            PWML=9;
            PWMR=20;
            carleft();
    }    
    if(D1==0&&D2==0&&D3==1&&D4==1)//左转大弯,右轮大
    {
            PWML=9;
            PWMR=20;
            carleft();
    }
}

方向相关函数

sbit IN1=P0^7;
sbit IN2=P0^6;
sbit IN3=P0^5;
sbit IN4=P0^4;
//    IN1=1;
//    IN2=0;
void Leftstop()
{
    IN1=0;
    IN2=0;
}
void Rightstop()
{
    IN3=0;
    IN4=0;
}
void Leftforward()
{
    IN1=0;
    IN2=1;
}
void Rightforward()
{
    IN3=1;
    IN4=0;
}
void Leftback()
{
    IN1=1;
    IN2=0;
}
void Rightback()
{
    IN3=0;
    IN4=1;
}
#include <REGX52.H>

#include"drive.h"

#include"timer.h"
void cargo()
{
    Leftforward();
    Rightforward();
}

void carstop()
{
    Rightstop();
    Leftstop();
}

void carleft()
{
    Leftback();
    Rightforward();
}

void carright()
{
    
    Leftforward();
    Rightback();
}

经验及错误总结

*定时器里面的TR0必须注意要置1,不然无法进入中断程序,占空比设置多少电机都是全速前进。

*若使用模块化编程,PWML和PWMR的值应设置为全局变量,不然其它文件不能使用PWML和PWMR的值。

*使用电烙铁一定要注意安全,最好找些教学视频后再上手。电烙铁长时间干烧会导致烙铁头氧化,不易上锡。

*电池组不能直接为单片机供电,不然芯片会被烧毁。

*小车最后虽然能完成要求,但因为程序上的不足并不能走好直线,如果想取得更好的结果,可以学习PID。

*循迹函数中有转小弯部分,若想使用该部分最好将中间两个探头分开些距离(具体取决于自己的实际需求),并且两个轮子的PWM值差不能太大。我最开始将两个探头紧挨在一起,想用来调节前进姿态,让小车走直线的轨迹更完美,但实际结果是小车反而更容易冲出轨道。

*小车循迹函数探头条件的if语句最好不要太简单,例如直接if(D1==1)就让小车进入右转,这样代码容易发生冲突,我在调试过程中因为循迹代码的冲突,导致车轮又正转又反转,最后的结果就是车轮无法运动。

*我的车最后要比较完美得走直线只能够把速度设置得很小,可能是受制于硬件。万向轮的存在让二驱的小车不是很适合走直线,地面不平整很容易使万向轮方向改变,即使两轮速度一致也会发生偏移。

小车速度很小的情况下需要外力才能正常运行。

*在编写代码过程中要注意自己设置的引脚是什么。我在编写调速函数时把左右轮设置反了,在调试过程中转向一直无法正常发生,甚至出现左转变右转,右转变左转的情况。定时器在从stc中复制下来的过程中,不知道是自己的原因还是stc的问题,TR0被置零,小车一直无法调速。

物联沃分享整理
物联沃-IOTWORD物联网 » 详解51单片机循迹小车设计原理

发表评论