单片机交流
直播中

王彬

8年用户 1091经验值
私信 关注
[问答]

如何利用51单片机制作简单的循迹小车?

如何利用51单片机制作简单的循迹小车?

回帖(1)

陆焙兆

2021-11-3 10:01:44
  一、前言

因为自己对编程十分热爱,同时为了夯实竞赛班和大创项目的基础,我自学了51单片机,为了检验自己的学习成果,我制作了简易的寻迹小车。
  二、相关硬件

  


  • 芯片为STC89C52RC
  • 稳压模块
    由于电池选择的是18650锂电池,过放会导致电池永久损坏,就选择了带有示数的稳压模块;将电池盒的两根线接入VIN即可(注意正负极),利用螺丝刀旋转螺丝即可调压。



  • 电机驱动模块L298N
    非常常用的电机驱动模块,由稳压引出线给电机驱动供电,电机驱动自带5V调压引出线给单片机供电,注意要共地;逻辑输入后电机工作情况如下:










  • 四路循迹模块
    在装上小车前,调整好检测距离,当发射红外线遇到白色则会反射回来,输出低电平,同时主板上对应的灯亮起;遇到黑色会被吸收,输出高电平,同时主板上对应的灯熄灭。


  • 最后组装好的成品





三、软件实现

代码如下:

#include
typedef unsigned int u16;
typedef unsigned char u8;


***it right_ENA=P1^0;        //小车右侧电机驱动
***it right_ENB=P1^5;
***it right_IN1=P1^1;
***it right_IN2=P1^2;
***it right_IN3=P1^3;
***it right_IN4=P1^4;


***it left_ENA=P0^0;                //小车左侧电机驱动
***it left_ENB=P0^5;
***it left_IN3=P0^1;
***it left_IN4=P0^2;
***it left_IN1=P0^3;
***it left_IN2=P0^4;


***it left1=P2^4;                //四路红外
***it left2=P2^3;
***it right2=P2^2;
***it right1=P2^1;


u8 pwm_t=0;                                //计时器溢出统计
u8 pwm_right_val=0;                //右侧电机使能值
u8 pwm_left_val=0;                //左侧电机使能值


void forward()                        //前进
{
        right_IN1=1;
        right_IN2=0;
        right_IN3=1;
        right_IN4=0;


        left_IN1=1;
        left_IN2=0;
        left_IN3=1;
        left_IN4=0;


        pwm_left_val=185;
        pwm_right_val=185;
}


void turnLeft1()                //左转小弯
{
        right_IN1=1;
        right_IN2=0;
        right_IN3=1;
        right_IN4=0;


        left_IN1=0;
        left_IN2=1;
        left_IN3=0;
        left_IN4=1;


        pwm_left_val=120;
        pwm_right_val=100;
}


void turnLeft2()                //左转大弯
{
        right_IN1=1;
        right_IN2=0;
        right_IN3=1;
        right_IN4=0;


        left_IN1=0;
        left_IN2=1;
        left_IN3=0;
        left_IN4=1;


        pwm_left_val=100;
        pwm_right_val=80;                               
}


void turnRight1()                //右转小弯
{
        right_IN1=0;
        right_IN2=1;
        right_IN3=0;
        right_IN4=1;


        left_IN1=1;
        left_IN2=0;
        left_IN3=1;                                 
        left_IN4=0;


        pwm_left_val=100;
        pwm_right_val=120;
}


void turnRight2()                //右转大弯
{
        right_IN1=0;
        right_IN2=1;
        right_IN3=0;
        right_IN4=1;


        left_IN1=1;
        left_IN2=0;
        left_IN3=1;
        left_IN4=0;


        pwm_left_val=80;
        pwm_right_val=100;
}


void stop()                                //停止
{
        right_IN1=0;
        right_IN2=0;
        right_IN3=0;
        right_IN4=0;


        left_IN1=0;
        left_IN2=0;
        left_IN3=0;
        left_IN4=0;
}


void follow()                        //根据红外的不同情况循迹
{
        if((right2 == 0)&&(right1 == 0)&&(left1 == 0)&&(left2 == 0)
                ||(right2 == 1)&&(right1 == 1)&&(left1 == 1)&&(left2 == 1)
                ||(right2 == 1)&&(right1 == 0)&&(left1 == 0)&&(left2 == 1))
        {
                flag = 0;
        }
        if((right2 == 1)&&(right1 ==0)&&(left1 == 0)&&(left2 == 0))
        {
                flag = 1;
        }
        if((right2 == 0)&&(right1 == 0)&&(left1 == 0)&&(left2 == 1))
        {
                flag = 2;
        }
        if((right2 == 0)&&(right1 == 0)&&(left1 == 1)&&(left2 == 0)
                ||(right2 == 0)&&(right1 == 0)&&(left1 == 1)&&(left2 == 1))
        {
                flag = 3;
        }
        if((right2 == 0)&&(right1 == 1)&&(left1 == 0)&&(left2 == 0)
                ||(right2 == 1)&&(right1 == 1)&&(left1 == 0)&&(left2 == 0))
        {
                flag = 4;
        }


        switch(flag)
        {
                case 0:forward();break;
               
                case 1:stop();turnRight1();break;
               
                case 2:stop();turnLeft1();break;
               
                case 3:stop();turnLeft2();break;
               
                case 4:stop();turnRight2();break;


                default:stop();break;
        }


}


void main()
{
        TMOD=0x02;                        //定时器模式设置并赋初值,打开定时器和中断                                                       
        TH0=220;              
        TL0=220;
        TR0=1;
        ET0=1;
        EA=1;


        while(1)
        {
                follow();       
        }


}


void time0() interrupt 1
{
        if(pwm_t >=256)                                        //占空比分为256份,但最大200就不能转
                pwm_t=0;
        if(pwm_t < pwm_left_val)
                left_ENA=left_ENB=0;
        else
                left_ENA=left_ENB=1;
        if(pwm_t < pwm_right_val)
                right_ENA=right_ENB=0;
        else
                right_ENA=right_ENB=1;
        pwm_t++;
}
四、总结

  这次因为时间紧张,且传感器受光影响太大,规定时间内没有做出走内圈的程序,只有了大致思路;但这个循迹图总体来讲不是太难,十分适合练手。若有小伙伴借鉴了我的程序,可以适当更改占空比的份数,定时器的初值等让小车走的更稳定。 附录:循迹图



举报

更多回帖

发帖
×
20
完善资料,
赚取积分