设计背景:
本次设计主要是为了学校的一个电子竞赛才做的这一个小项目,这也是我刚学习51单片机以来做的第一个大制作。其实这个制作的原理很简单,但实际做出来却花了一些时间,下面就简单地给大家介绍一下我们的制作,也为各位网友作为一个参考。
使用到的模块:
51单片机 L298N电机驱动模块 红外传感器模块 hc05蓝牙模块 普通直流电机
实现的原理:
电路设计:
成品展示:
程序设计:
L298N驱动直行转向程序,这里用的是定时器0作为PWM输出。关于L298N和定时器可以在网上查找资料,知道如何使用,这里就不给大家详细介绍了。
#include "xunji.h"
#include "reg52.h"
uchar PWMCnt1;
uchar PWMCnt2;
uchar cntPWM1;
uchar cntPWM2;
//uchar PWMA;
//uchar PWMB;
void Delay(int xms) //@12.000MHz
{ while(xms--)
{unsigned char i, j;
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
void Timer0_init()
{
TMOD &=0xF0;
TMOD |=0X01;//使用定时器0
TH0 = 0xFF;
TL0 = 0xA3;
EA=1;//全局中断位
ET0=1;//定时器0中断允许位
TR0=1;//定时器0运行允许位
}
void turnright1() //右转
{
IN1 = 0; //右轮反转
IN2 = 1;
IN3 = 0; //左轮正转
IN4 = 1;
cntPWM1 = 50;
cntPWM2 = 45;
}
void turnRight2() //右转
{
IN1 = 0; //右轮反转
IN2 = 1;
IN3 = 0; //左轮正转
IN4 = 1;
cntPWM1 = 45;
cntPWM2 = 40;
}
void turnleft1() //左转
{
IN1 = 1;
IN2 = 0; //右轮正转
IN3 = 1;
IN4 = 0; //左轮反转
cntPWM1 = 45;
cntPWM2 = 50;
}
void turnLeft2() //左转
{
IN1 = 1;
IN2 = 0; //右轮正转
IN3 = 1;
IN4 = 0; //左轮反转
cntPWM1 = 40;
cntPWM2 = 45;
}
void forward() //前进
{
IN1 = 1;
IN2 = 0; //右轮正转
IN3 = 0; //左轮正转
IN4 = 1;
cntPWM1 = 26;
cntPWM2 = 25;
}
void backward() //后退
{
IN1 = 0; //右轮反转
IN2 = 1;
IN3 = 1;
IN4 = 0; //左轮反转
cntPWM1 = 26;
cntPWM2 = 25;
}
void Stop() //停止
{
IN1 = 0;
IN2 = 0;
IN3 = 0;
IN4 = 0;
}
void interrupttimer0() interrupt 1
{
TH0 = (65536 - 50)/256;
TL0 = (65536 - 50)%256;
PWMCnt1++;
PWMCnt2++;
PWMCnt1%=100;
PWMCnt2%=100;
if(PWMCnt1<=cntPWM1)
{
ENA=1;
}
else
ENA=0;
if(PWMCnt2<=cntPWM2)
{
ENB=1;
}
else
ENB=0;
//
// if(PWMA<=cntPWM1)
// {
// ENA=1;
// }
// else
// ENA=0;
//
// if(PWMB<=cntPWM2)
// {
// ENB=1;
// }
// else
// ENB=0;
}
循迹模块程序,这里利用是4个红外传感器返回的高低电平来判断黑线的位置,从而驱使小车的直行与转向。程序比较繁杂,其实有很多是多余的,还可以进行一些简化,不需要4个传感器都要判断是否输出高低,另外直行的程序最好放在前面,并且再加上else,这样的话,前面判断成功了就不用再去执行后面的程序,可以缩短cpu消耗的时间。
void XunJi()
{
unsigned char flag = 0;
if((left1 == 0)&&(left2 == 0)&&(right1 == 0)&&(right2 == 0)) //0 0 0 0
flag = 0;
if((left1 == 0)&&(left2 == 0)&&(right1 == 0)&&(right2 == 1)) //0 0 0 1
flag = 1;
if((left1 == 0)&&(left2 == 0)&&(right1 == 1)&&(right2 == 0)) //0 0 1 0
flag = 0;
if((left1 == 0)&&(left2 == 0)&&(right1 == 1)&&(right2 == 1)) //0 0 1 1
flag = 2;
if((left1 == 0)&&(left2 == 1)&&(right1 == 0)&&(right2 == 0)) //0 1 0 0
flag = 0;
if((left1 == 0)&&(left2 == 1)&&(right1 == 0)&&(right2 == 1)) //0 1 0 1
flag = 4;
if((left1 == 0)&&(left2 == 1)&&(right1 == 1)&&(right2 == 0)) //0 1 1 0
flag = 0;
if((left1 == 0)&&(left2 == 1)&&(right1 == 1)&&(right2 == 1)) //0 1 1 1
flag = 1;
if((left1 == 1)&&(left2 == 0)&&(right1 == 0)&&(right2 == 0)) //1 0 0 0
flag = 3;
if((left1 == 1)&&(left2 == 0)&&(right1 == 0)&&(right2 == 1)) //1 0 0 1
flag = 0;
if((left1 == 1)&&(left2 == 0)&&(right1 == 1)&&(right2 == 0)) //1 0 1 0
flag = 2;
if((left1 == 1)&&(left2 == 0)&&(right1 == 1)&&(right2 == 1)) //1 0 1 1
flag = 0;
if((left1 == 1)&&(left2 == 1)&&(right1 == 0)&&(right2 == 0)) //1 1 0 0
flag = 4;
if((left1 == 1)&&(left2 == 1)&&(right1 == 0)&&(right2 == 1)) //1 1 0 1
flag = 0;
if((left1 == 1)&&(left2 == 1)&&(right1 == 1)&&(right2 == 0)) //1 1 1 0
flag = 3;
if((left1 == 1)&&(left2 == 1)&&(right1 == 1)&&(right2 == 1)) //1 1 1 1
flag = 6;
switch(flag)
{
case 0:forward();break;
case 1:turnright1();break;
case 2:turnright2();break;
case 3:turnleft1();break;
case 4:turnleft2();break;
case 5:backward();break;
default:stop();break;
}
}
避障模块程序,这里是利用的小车上边的3个红外传感器来识别前方障碍物,根据障碍物位置来做如何的转向,从而实现避障。
void bizhan() //循迹+避障
{
if((bizh1==1)&&(bizh2==1)&&(bizh3==1))
XunJi();
if((bizh1==0)||(bizh2==0)||(bizh3==0))
{
stop();
Delay (500);
turnright2();
Delay (60);
}
}
void bizh() //避障
{
if((bizh1==1)&&(bizh2==1)&&(bizh3==1))
forward();
if((bizh1==0)&&(bizh2==1)&&(bizh3==1))
turnleft2();
if((bizh1==1)&&(bizh2==0)&&(bizh3==1))
turnright2();
if((bizh1==1)&&(bizh2==1)&&(bizh3==0))
turnright2();
if((bizh1==0)&&(bizh2==0)&&(bizh3==0))
turnleft2();
if((bizh1==0)&&(bizh2==0)&&(bizh3==1))
turnleft1();
if((bizh1==1)&&(bizh2==0)&&(bizh3==0))
turnright1();
}
蓝牙控制程序
#include "reg52.h"
#include "bluetooth.h"
uchar temp;
uchar speedA;
uchar speedB;
void uart_init()//这是对蓝牙串口进行初始化,不是定时器1
{
TMOD &=0xF0;
TMOD |=0x21;//定时器1采用方式2 8位初值自动重装
SCON=0x50;
TL1=0xFD;
TH1=0xFD;
PCON=0x00;//电源控制寄存位
ES=1;//串口通信运行允许位
TR1=1;//定时器1运行
}
//void sendbyte(uchar c)
//{
// SBUF=c;//发送数据
//
// while(!TI);//没有发送完一直执行这个空语句
// /*发送字节完成后TI 变成1,则需要最后把他置零;RI也一样*/
// TI=0;//发送串口中断判断位
//}
void uart_interrupt() interrupt 4
{
if(RI)//串口中断允许位
{
temp=SBUF;//取出数据
RI=0;//取出数据后RI变为1,需要最后把他置零
quick();
slow();
}
}
void quick()//蓝牙加速
{
speedA*=2;
speedB*=2;
}
void slow()//蓝牙减速
{
speedA%=2;
speedB%=2;
}
小车的主程序
#include "reg52.h"
#include "xunji.h"
#include "bluetooth.h"
extern uchar temp;//用于切换模式和蓝牙指令
void start();
void main()
{
Timer0_init();
uart_init();
while(1)
{
start();
}
}
void start()
{
switch(temp)
{
case 'e':bizhan();break;
case 'f':forward1(); break;
case 'a':quick();break;
case 'b':backward2(); break;
case 'c':slow();break;
case 'r':turnleft(); break;
case 'l':turnright(); break;
case 's':stop(); break;
case 'k':bizh();break;
default :stop();break;//如果传输了一个这些之外的字母,则stop()
}
}
最后
程序只是作为一个参考,真正调试还需要根据实际情况为准。比如PWM的调试,循迹模块程序的简化等。另外上边展示的主要是一些重要的模块程序,详细的可以点击下面的连接自己提取。最后,希望大家都能做出自己满意的小车。
链接:https://pan.baidu.com/s/11-6rN-bxYrJlRpDWrP0K4g
提取码:armc