深圳市航顺芯片技术研发有限公司
直播中

世态薄凉

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

如何利用51单片机制作简易的光电小车?

如何利用51单片机制作简易的光电小车?

回帖(1)

王秀兰

2021-9-26 15:28:10
  前言
  应学校暑期课程要求,也作为和小组成员完成一次对51单片机的练手,制作了简易的光电小车,完成了循迹功能,下面包括较为详细的小车搭建过程以及完整代码。
  硬件部分准备
  电源
  可充电的电池组是智能车的唯一动力来源。一般要求额定电压在7.2—9.6V 之间。可充电电池按化学组成分类,有铅酸、镍镉、镍氢、锂离子、锂聚合物等不同类型,其主要指标为电压、容量等。然而在选择可充电电池时,除考虑电压和容量,还应根据应用着重考虑电池的放电能力。电池放电能力习惯上以 C 为单位进行评价,C 即电池容量。智能车竞速的特点要求充电电池要有大容量、高放电能力的特点。常见的可充电电池有镍镉充电电池、镍氢充电电池、锂离子充电电池等
  1)镍镉充电电池的单个电压较低,仅有 1.2V;而且镍镉金属会污染环境,电池的记忆效应严重,能量密度较低,现在基本已经被淘汰,因此不适合使用。
  2)镍氢充电电池的单个电压也为 1.2V,它的记忆效应稍微比镍镉充电电池轻微,但是自放电现象严重,能量密度中等;好处是价格便宜,应用广泛。
  3)锂离子充电电池,单个电压为 3.6V,无记忆效应,能量密度高。
  综上,我们选择型号为 18650 的锂离子电池作为电源,能量密度高,而且只需两块即可达到额定电压为 7.2V 的要求。
  降压模块
  因为供电需求不同,我们还需要使用降压模块实现7.2V到5V的电压转换,此次我们采用了LM2596S(一定注意正负极)
  控制模块
  对于智能车的控制模块,我们选择最为熟悉的 STC89C51 单片机,它是一款基于 8 位单片机处理芯片 STC89C51RC 的系统。采用STC89C51 单片机作为系统的主控芯片,通过预先写入 STC89C51 中的控制程序来控制小车的运动,进而达到对智能小车的控制。另外,STC89C51 的供电电压为 5V,可通过 7.2V 电源经过降压模块来给单片机进行供电。
  驱动模块
  在智能小车两个前轮上各安装一个直流电机(小黄电机),分别控制小车的两个轮子的转速。当两个轮子的转速不同时,根据惯性,小车会转弯;当两个轮子的转速相同时,小车将直行。我们采用LM298N 实现对直流电机的驱动,其内部设有两个 H 桥高电压大电流全桥式驱动器。通过单片机将 PWM 脉冲信号传输给 L298N 电机驱动芯片,从而达到控制直流电机的速度、停止和正反转向,保证小车能够实现沿着预先设置的轨道行走、躲避障碍物以及自动纠正偏离。
  检测模块
  智能车的检测模块主要分为三种:摄像头、电磁、光电。本次课设中我们选择 TCRT5000 光电传感器作为检测模块。TCRT5000 是一款红外反射式光电开关。传感器采用高发射功率红外光电二极管和高灵敏度光电晶体管组成,常用于黑白线检测的场合。
  整体实现框图
  
  程序部分准备
  定时器部分
  v
void Timer1_10ms(void)
{
TMOD |= 0x10 ; //使用模式 1
TH0 = (65536 - 10000)/256; //取高 8 位
TL0 = (65536 - 10000)%256; //取低 8 位 共定时 10ms
TR1 = 1; //打开定时器 1 开关
EA = 1; //打开中断总开关
ET1 = 1; //打开定时器中断 1 的开关
}
void Timer1_Isr(void) interrupt 3
{
static unsigned char i = 0;
TH0 = (65536 - 10000)/256; //重载初值
TL0 = (65536 - 10000)%256;
i++;
if(i == 11) //100ms 反转一次
{
//所需控制内容——PWM 定时
}
  原理
  电机本质上是一个电感元件,那么数字信号表现在电机上就是平均值。平均电压越大,电机转的越快。而通过 PWM 输出不同占空比数字电压信号,即不同电压值的模拟信号,便能控制电机在不同转速下转动。
  电机输出端引脚是高电平电机就可以转动,当输出端高电平时,电机会转动,但是是一点一点的提速,在高电平突然转向低电平时,电机由于电感有防止电流突变的作用是不会停止的,会保持这原有的转速,以此往复,电机的转速就是周期内输出的平均电压值,所以实质上我们调速是将电机处于一种,似停非停,似全速转动又非全速转动的状态。
  功能框图
  
  后期
  成品及局部展示
  整体造型
  
  主控和驱动
  
  光电管检测部分
  
  电源管理
  
  黑胶带制作简易车道
  
  调试及效果
  初始调试建议光电小车时,采用了差速控制的方法,在模拟车道上能够实现较好的转弯的功能,但问题是无法很好的通过急弯。为此,想到了使一侧的车轮反转,另一侧车轮正转以获得最大程度的转速差,至此小车能够比较好的通过所有模拟的弯道。在一次次调试的过程中,将电机驱动引脚的占空比提高,并将周期缩小,小车获得了更高的车速,与此同时小车的过弯性能降低了,为了解决这个问题,经过大量依赖程序的调试并没有获得很好的效果。于是我们想到了改变小车光电管的位置,以提前感知弯道,将两对光电管改为“八”字构,并将最外侧的一对光电管向前伸展,最终获得了比较好的效果。
  CODE
  最后附上所有代码
 
#主程序部分
#include"stc15.h"
#include"start_set.h"
#include"motor.h"
#include"time.h"
void main()
{
time_start();
while(1)
        {
        if(left2==0&&left1==0&&right1==0&&right2==0)//Ö±ÐÐ
                straight(count1,650,count2,650);
        else if(left2==0&&left1==1&&right1==0&&right2==0)//×óСת
                straight(count1,1,count2,1000);
        else if(left2==0&&left1==0&&right1==1&&right2==0)//ÓÒСת
                straight(count1,1000,count2,1);
        else if(left2==1&&left1==1&&right1==0&&right2==0)//×ó´óת
                acute_left(count1,800,count2,800);
        else if(left2==0&&left1==0&&right1==1&&right2==1)//ÓÒ´óת
                acute_right(count1,800,count2,800);
        else if(left2==1&&left1==0&&right1==0&&right2==0)//×ó¼±×ª
                {
                        acute_left(count1,1000,count2,1000);
                }
        else if(left2==0&&left1==0&&right1==0&&right2==1)//ÓÒ¼±×ª
                {
                        acute_right(count1,1000,count2,1000);
                }
        }
}


# 电机控制部分
#include"stc15.h"
void left_motor(int count1,int time1)
{
        IN1=1;
        IN2=0;
        if ( count1         ENA=1;
        else
        ENA=0;
}
void right_motor(int count2,int time2)
{
        IN3=0;
        IN4=1;
        if ( count2                 ENB=1;
        else
                ENB=0;
}
void back_left(int count1,int time1)
{
        IN1=0;
        IN2=1;
        if(count1                 ENA=1;
        else
                ENA=0;
}
void back_right(int count2,int time2)
{
        IN3=1;
        IN4=0;
        if ( count2                 ENB=1;
        else
                ENB=0;
}
void straight(int count1,int time1,int count2,int time2)
{
        right_motor(count2,time2);
        left_motor(count1,time1);
}
void acute_left(int count1,int time1,int count2,int time2)
{
        back_left(count1,time1);
        right_motor(count2,time2);
}
void acute_right(int count1,int time1,int count2,int time2)
{
        left_motor(count1,time1);
        back_right(count2,time2);
}


# 初始化
#include"stc15.h"
***it ENA=P0^0;
***it IN1=P0^1;
***it IN2=P0^2;
***it ENB=P1^0;
***it IN3=P1^1;
***it IN4=P1^2;
***it left1=P2^3;
***it left2=P2^4;
***it right1=P2^1;
***it right2=P2^2;
int count1=0;
int count2=0;
void time_start(void)
{
        TMOD=0x00;
        TH0=(65536-120)/256;
        TL0=(65536-120)%256;
        EA=1;
        ET0=1;
        TR0=1;
        TH1=(65536-120)/256;
        TL1=(65536-120)%256;
        EA=1;
        ET1=1;
        TR1=1;
}


# 定时中断
#include"stc15.h"
#include"intrins.h"
void timer0()interrupt 1
{
        TH0=(65536-120)/256;
        TL0=(65536-120)%256;
        count1++;
        if(count1>1000)
                count1=0;
}
void timer1()interrupt 3
{
        TH1=(65536-120)/256;
        TL1=(65536-120)%256;
        count2++;
        if(count2>=1000)
                count2=0;
}
举报

更多回帖

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