基于单片机的循迹小车实验报告.docx
《基于单片机的循迹小车实验报告.docx》由会员分享,可在线阅读,更多相关《基于单片机的循迹小车实验报告.docx(28页珍藏版)》请在冰豆网上搜索。
基于单片机的循迹小车实验报告
课程设计报告
(嵌入式技术实践
(二))
学院:
电气工程与自动化学院
题目:
基于P89V51RB2单片机寻迹小车
专业班级:
学号:
学生XX:
指导老师:
2013年06月07日
附录30
第1章绪论
1.1引言
我们所处的这个时代是信息革命的时代,各种新技术、新思想层出不穷,纵观世界X围内智能汽车技术的发展,每一次新的进步无不是受新技术新思想的推动。
随着汽车工业的迅速发展,传统的汽车的发展逐渐趋于饱和。
伴随着电子技术和嵌入式技术的迅猛发展,这使得汽车日渐走向智能化。
智能汽车由原先的驾驶更加简单更加安全更加舒适,逐渐的向智能驾驶系统方向发展。
智能驾驶系统相当于智能机器人,能代替人驾驶汽车。
它主要是通过安装在前后保险杠及两侧的红外线摄像机,对汽车前后左右一定区域进行不停地扫描和监视。
计算机、电子地图和光化学传感器等对红外线摄像机传来的信号进行分析计算,并根据道路交通信息管理系统传来的交通信息,代替人的大脑发出指令,指挥执行系统操作汽车。
1.2课题任务要求
应用P89V51RB2微控制器中的端口、外部中断、定时器等基本模块,实现核心控制,再结合电源板、电机驱动板来控制电机的转向,最后加上传感检测模块,实现小车的智能寻迹。
这次课程实践要求每一同学都要动手都制作出一辆循迹小车,真正实现从听中学到做中学,提高同学们的动手能力。
这次实践最基本的功能底线就是能够实现循迹,附加的有超声波测距,蜂鸣器报警及液晶屏显示。
1.3本论文研究的内容
本论文是基于P89V51RB2单片机开发,主要是研究3轮小车的路径识别及其控制算法以及超声波测距及LCD1602显示距离。
第2章系统总体设计
2.1小车的机械特性
小车采用的是一辆三轮车车模。
后轮控件前进或转弯,前轮根据后轮驱动左右摆动即可以实现左右转。
该种车模控制简单。
小车可通过PWM控制后轮电机转动的速度来控制前轮电机的转动幅度从而控制小车的转弯幅度,实现小车的前进与转弯操作。
小车可通过对DIR控制后退。
2.2寻迹小车基本原理
探测路面黑线的基本原理:
光线照射到路面并反射,由于黑线和白纸对光的反射系数不同,可以根据接收到的反射光强弱来判断是否是黑线。
利用这个原理,可以控制小车行走的路迹。
这里的循迹是指小车在白色地板上循黑线行走,通常采取的方法是红外探测法。
红外探测法,即利用红外线在不同颜色的物体表面具有不同的反射性质的特点,在小车行驶过程中不断地向地面发射红外光,当红外光遇到白色纸质地板时发生漫反射,反射光被装在小车上的接收管接收;如果遇到黑线则红外光被吸收,小车上的接收管接收不到红外光。
处理器就根据是否收到反射回来的红外光为依据来确定黑线的位置和小车的行走路线。
红外探测器探测距离有限,一般最大不应超过3cm。
智能小车系统以处理器为核心,为了使智能小车能够快速行驶,处理器必须把路径的迅速判断、相应的转向电机控制以及直流驱动电机的控制精密地结合在一起。
如果传感器部分的数据没有正确地采集和识别,转向电机控制的失当,都会造成模型车严重抖动甚至偏离赛道;如果直流电机的驱动控制效果不好,也会造成直线路段速度上不去,弯曲路段入弯速度过快等问题。
其系统结构如所图2.2示。
本次红外探测采用的是反射式探测。
2.3智能小车超声波测距原理
利用超声波连续发出10us以上的高电平,就可以在接口有高电频输出,等待接受到返回的高电频信号时,通过定时器电波对被控对象进行时间检测。
就可以计算相应的时间了。
图2.2系统结构图
80C51处理器通过引脚读出超声波信号管脚
80C51处理器向红外线传感器供5V电压,通过采集其高低电平可以控制小车的转弯。
80C51处理器通过DATA引脚向键盘显示板发送要显示的数据,还可以通过KEY引脚读取键盘的按键,实现相应的功能。
第3章系统硬件设计
3.1控制器的选择
本次设计采用的是80C51单片机。
3.1.1概述
P89V51RB2是一款由美国NXP半导体公司提供的增强型80C51微控制器,包括16KBFlash程序存储器和1KB数据RAM,且功能上完全覆盖标准80C51单片机系列
3.1.2P89V51RB2开发工具特性
1.80C51内核,5V工作电压,操作频率0~40MHZ;
2.16KB片内Flash存储器,1KB片内SRAM;
3.SPI串行通信接口和增强型UART;
4.PCA(可编程计数器列阵),具有PWM和捕获、比较功能;
5.4个8位I/O口,含有三个高电流P1口(每个I/O口的电流为16mA);
6.8个中断源,4个中断优先级,3个16位定时器/计数器和可编程看门狗定时器(WDT);
7.2个DPTR寄存器;
3.2硬件电路设计
本次项目采用的电路板从画电路原理图开始,到PCB板的布线以及电路板的焊接与检测一系列工作都是自己在大一下学期课程实践期间制作的。
3.2.1系统电源电路
交流电经过全波电路在经过电容滤波,在经过稳压电源芯片做成稳压电路,输出电压5V、7.2V的直流电源。
其电源电路原理图如图3.2所示。
图3.2系统电源电路原理图
小车的驱动电机的供电电压为7.2V,经过电容滤波后接7805进行稳压,稳压输出5V的电压。
提供单片机所需5V电压。
3.2.2电机驱动模块
1.驱动实现与原理
本项目驱动两路直流电机,实现电机的正反转与测速和遥控。
输入输出逻辑表真值表3.2。
表3.2L298N输入输出逻辑真值表
通道1
通道2
输入
输出控制电机1
输入
输出控制电机2
EnA
In1
In2
OUT1
OUT2
转向
EnB
In3
In4
OUT3
OUT4
转向
1
0
0
0
0
停止
1
0
0
0
0
停止
0
1
0
1
反传
0
1
0
1
反传
1
0
1
0
正转
1
0
1
0
正转
1
1
0
0
停止
1
1
1
1
停止
0
X
X
0
0
停止
0
X
X
0
0
停止
其中“0”为低电平;“1”为高电平;“X”为任何状态。
驱动原理图
3.2.3光电编码器/测速
2.光电编码器原理
光电编码器,是一种通过光电转换将输出轴上的机械几何位移量转换成脉冲或数字量的传感器。
这是目前应用最多的传感器,光电编码器是由光栅盘和光电检测装置组成。
光栅盘是在一定直径的圆板上等分地开通若干个长方形孔。
由于光电码盘与电动机同轴,电动机旋转时,光栅盘与电动机同速旋转,经发光二极管等电子元件组成的检测装置检测输出若干脉冲信号,通过计算每秒光电编码器输出脉冲的个数就能反映当前电动机的转速。
3.光电编码器的实现
光电编码器的发光装置一般由发光二极管来实现。
光敏元件则由光敏三极管接上了上拉电阻来完成。
光电式旋转编码器是转速或转角的检测元件,旋转的编码器与电动机相连,当电机转动时,带动码盘旋转,便发出转速或转角信号。
其示意图如图3.5所示。
图3.5光电编码器的实现示意图
当电机旋转时,码盘随之一起转动。
通过光栅的作用,使得光敏三极管随着光栅透出的光而导通。
接收的频率和转速成正比。
在接收端可以输出一系列的方波,80C51内核可以通过采集方波的频率从而可以计算出电机的速度。
3.2.4红外线检测电路
红外线检测电路原理其实很简单,就是利用红外线在不同颜色的物体表面具有不同的反射性质的特点,在小车行驶过程中不断地向地面发射红外光,当红外光遇到白色纸质地板时发生漫反射,反射光被装在小车上的接收管接收,Cortex-M0内核采集到的电压就是高电平;如果遇到黑线则红外光被吸收,小车上的接收管接收不到红外光,然后80C51内核采集到的电压就是低电平。
其基本原理图如图3.6所示。
图3.6红外线检测电路原理图
鉴于本项目设计需实现的功能比较简单,故只要两路红外线检测电路即可,分别位于小车中心轴的两测即可。
3.2.5超声波蔽障/测距
3.2.5.1超声波测距模块简介
超声波检测设计小车避障是利用超声波测距,并根据测出离障碍物不同距离而做出不同反应。
检测距离:
5CM-4M
分辨率:
5MM
数字电平信号,可直接接单片机,无需任何辅助电路,也无需单片机产生任何信
号辅助,距离和模块输出信号脉冲长度成正比。
尺寸:
43.5*20.5毫米
高度:
13.8毫米
3.2.5.2超声波测距模块的引脚功能
图3.2.5.3超声波实物
3.2.5.3超声波测距原理
你只需要提供一个短期的10uS脉冲触发信号。
该模块内部将发出8个40kHz
周期电平并检测回波。
一旦检测到有回波信号则输出回响信号。
回响信号是一个脉冲的宽度成正比的距离对象。
可通过发射信号到收到的回响信号时间间隔可以计算得到距式:
uS/58=厘米或者uS/148=英寸。
建议测量周期为60ms以上,以防止发射信号对回响信号的影响
3.2.5.4超声波测距时序图
图3.2.5超声波测距时序图
3.2.6LCD显示设计
加液晶显示是为了弥补在超声波蔽障及测距是,对于具体我们不知道的距离显示出来,有助于我们更好的预知路程蔽障的X围及距离障碍物的距离。
通过1602的显示,让我们更加清楚小车隔障碍物的距离。
图3.2.6液晶显示实物图
3.2.7.1液晶工作原理
在数字电路中,所有的数据都是以0和1保存的,对LCD控制器进行不同的数据操作,可以得到不同的结果。
对于显示英文操作,由于英文字母种类很少,只需要8位(一字节)即可。
而对于中文,常用却有6000以上,于是我们的DOS前辈想了一个办法,就是将ASCII表的高128个很少用到的数值以两个为一组来表示汉字,即汉字的内码。
而剩下的低128位则留给英文字符使用,即英文的内码。
那么,得到了汉字的内码后,还仅是一组数字,那又如何在屏幕上去显示呢?
这就涉及到文字的字模,字模虽然也是一组数字,但它的意义却与数字的意义有了根本的变化,它是用数字的各位信息来记载英文或汉字的形状,从而通过扫描,显示在液晶屏幕上
3.2.7.1液晶显示原理
液晶显示其实就是对屏幕的每个点的扫描,带字库的液晶内部自带控制芯片,直接对它操作就可以显示出汉子字符,需要读写命令和数据,才能达到对液晶控制器的操作,具体的如何显示,有兴趣者可以自己查阅资料,进一步理解并学会使用。
第4章系统软件设计
4.1编译环境
TKStudio集成开发环境(又称TKStudioIDE)是XX致远电子XX开发的一个微处理器软件开发平台,是一款具有强大内置编辑器的多内核编译调试环境,支持8051、ARM、AVR等多种微控制器,可以完成从工程建立和管理,编译,,目标代码的生成,到软件仿真,硬件仿真(挂接TKS系列仿真器等硬件)等完整的开发流程。
TKStudio集成开发环境包括工程管理器、代码编辑器、编译工具链、源码级调试器和外部工具等。
4.2模块的驱动
4.2.1红外线传感器模块
红外线模块只要M0处理器向其供5V电压就能工作,然后通过引脚采集其电平高低就可以根据不同情况做出相应的处理。
其具体程序控制见程序清单4.1.
程序清单4.1读取红外传感器的高低电平
voidTrack(void)
{
if((IN1==0&&IN2==0)||(IN1==1&&IN2==1))
{
Forward();//调用前进函数
}
if(IN1==1&&IN2==0)
{
Lift();//调用左转函数
}
if(IN1==0&&IN2==1)
{
Right();//调用右转函数
}
}
4.2.2电机模块的驱动
首先,通过设置L298N芯片的输入方向RIGHT_FANZHUAN,RIGHT_ZHENGZHUAN,RIGHT_STOP,LEFT_ZHENGZHUAN,LEFT_FANZHUAN,LEFT_STOP,从而控制电机的正反转。
详见程序清单4.3.
程序清单4.3直流电机驱动与路径识别
voidForward()//电机前进
{
PWM1=1;
PWM2=1;
}
voidLift()//电机左转
{
PWM1=0;
PWM2=1;
}
voidRight()//电机右转
{
PWM1=1;
PWM2=0;
}
voidTrack(void)
{
if((IN1==0&&IN2==0)||(IN1==1&&IN2==1))
{
Forward();//调用前进函数
}
if(IN1==1&&IN2==0)
{
Lift();//调用左转函数
}
if(IN1==0&&IN2==1)
{
Right();//调用右转函数
}
}
前轮为方向轮,只有在需要转弯的时候才需要后边电机驱动其左右转动,在常态下则由后轮的推力使前轮向前转动。
具体实现是通过控制前面产生的两路PWM波的占空比和L298N芯片的In1、In2的方向来实现小车的前进寻迹与后退寻迹,其程序流程图详见图4.1所示。
图4.1直流电机控制流程图
根据图4.1可以看到程序一开始就进行读取红外线传感器,如果左右两边都遇到黑线则停止前进;如果左边遇到黑线而且右边没有遇到黑线,小车则左转;如果右边遇到黑线而且左边没有遇到黑线,小车则右转;如果两边都没有遇到黑线小车则直行。
具体程序控制详见程序清单4.4。
4.2.3转速捕获
本项目采用16位定时器1和32位定时器1的捕获功能来实现两直流电机的转速捕获。
由于主轮与后面光码盘扇叶转速的比例是1:
80,而且有两片扇叶。
所以测主轮的转速公式为:
转速=((FAHBCLK/((CAP1_2-CAP1_1)/(N2-1))))*3/8/TMR16B1PR,程序控制详见程序清单4.5.
程序清单4.5直流电机转速的测量
voidTimeNew1()//光栅捕获并记录
{R1=R2;
//捕获左电机光栅并记录
if(R_Mcp2==0){R2=1;}
if(R_Mcp2==1){R2=0;}
if(R1==1){if(R2==0){rm2++;}}
if(rm2==1){rm2=0;Count2++;}
if(Count2==10000){Count2=0;}
if(R_Mcp1==0){r2=1;}//捕获右电机光栅并记录
if(R_Mcp1==1){r2=0;}
if(r1==1){if(r2==0){rm1++;}}
if(rm1==1){rm1=0;Count1++;}
if(Count1==10000){Count1=0;}
r1=r2;
}
m1=lucheng1/1000,//转换成路程并分解成BCD码
dm1=(lucheng1-1000*m1)/100,
cm1=(lucheng1-1000*m1-100*dm1)/10,
mm1=lucheng1-1000*m1-100*dm1-10*cm1,
m2=lucheng2/1000,
dm2=(lucheng2-1000*m2)/100,
cm2=(lucheng2-1000*m2-100*dm2)/10,
mm2=lucheng2-1000*m2-100*dm2-10*cm2
if(Count3==4000)//定时一秒//{lucheng1=Count2*2200/1580;lucheng2=Count1*2200/1580;Count3=0;Count1=0,Count2=0;}//路程计算
4.2.4LCD1602液示显示模块
1602通过超声波产生的中断进行计数,在液晶屏上显示出来。
程序清单4.2.4
#defineLCM_RWP3_4//定义LCD引脚
#defineLCM_RSP3_3
#defineLCM_EP3_5
#defineLCM_DataP1
#defineBusy0x80//用于检测LCM状态字中的Busy标识
voidLCMInit(void);
voidDisplayOneChar(unsignedcharX,unsignedcharY,unsignedcharDData);
voidDisplayListChar(unsignedcharX,unsignedcharY,unsignedcharcode*DData);
voidDelay5Ms(void);
voidDelay400Ms(void);
voidDecode(unsignedcharScanCode);
voidWriteDataLCM(unsignedcharWDLCM);
voidWritemandLCM(unsignedcharWCLCM,BuysC);
unsignedcharReadDataLCM(void);
unsignedcharReadStatusLCM(void);
unsignedcharcodemcustudio[]={"ZDH-122ban-33hao"};
unsignedcharcodeemail[]={"distance-display"};
unsignedcharcodeCls[]={""};
unsignedcharcodeASCII[15]={'0','1','2','3','4','5','6','7','8','9','.','-','M'};
staticunsignedcharDisNum=0;//显示用指针
unsignedinttime=0;
unsignedlongS=0;
bitflag=0;
unsignedchardisbuff[4]={0,0,0,0,};
//写数据
voidWriteDataLCM(unsignedcharWDLCM)
{
ReadStatusLCM();//检测忙
LCM_Data=WDLCM;
LCM_RS=1;
LCM_RW=0;
LCM_E=0;//若晶振速度太高可以在这后加小的延时
LCM_E=0;//延时
LCM_E=1;
}
//写指令
voidWritemandLCM(unsignedcharWCLCM,BuysC)//BuysC为0时忽略忙检测
{
if(BuysC)ReadStatusLCM();//根据需要检测忙
LCM_Data=WCLCM;
LCM_RS=0;
LCM_RW=0;
LCM_E=0;
LCM_E=0;
LCM_E=1;
}
//读数据
unsignedcharReadDataLCM(void)
{
LCM_RS=1;
LCM_RW=1;
LCM_E=0;
LCM_E=0;
LCM_E=1;
return(LCM_Data);
}
//读状态
unsignedcharReadStatusLCM(void)
{
LCM_Data=0xFF;
LCM_RS=0;
LCM_RW=1;
LCM_E=0;
LCM_E=0;
LCM_E=1;
while(LCM_Data&Busy);//检测忙信号
return(LCM_Data);
}
voidLCMInit(void)//LCM初始化
{
LCM_Data=0;
WritemandLCM(0x38,0);//三次显示模式设置,不检测忙信号
Delay5Ms();
WritemandLCM(0x38,0);
Delay5Ms();
WritemandLCM(0x38,0);
Delay5Ms();
WritemandLCM(0x38,1);//显示模式设置,开始要求每次检测忙信号
WritemandLCM(0x08,1);//关闭显示
WritemandLCM(0x01,1);//显示清屏
WritemandLCM(0x06,1);//显示光标移动设置
WritemandLCM(0x0F,1);//显示开及光标设置
}
//按指定位置显示一个字符
voidDisplayOneChar(unsignedcharX,unsignedcharY,unsignedcharDData)
{
Y&=0x1;
X&=0xF;//限制X不能大于15,Y不能大于1
if(Y)X|=0x40;//当要显示第二行时地址码+0x40;
X|=0x80;//算出指令码
WritemandLCM(X,1);//发命令字
WriteDataLCM(DData);//发数据
}
//按指定位置显示一串字符
voidDisplayListChar(unsignedcharX,unsignedcharY,unsignedcharcode*DData)
{
unsignedcharListLength;
ListLength=0;
Y&=0x1;
X&=0xF;//限制X不能大于15,Y不能大于1
while(DData[ListLength]>0x19)//若到达字串尾则退出
{
if(X<=0xF)//X坐标应小于0xF
{
DisplayOneChar(X,Y,DData[ListLength]);//显示单个字符
ListLength++;
X++;
}
}
}
//5ms延时
voidDelay5Ms(void)
{
unsignedintTempCyc=5552;
while(TempCyc--);
}
//400ms延时
voidDelay400Ms(void)
{
unsignedcharTempCycA=5;
unsignedintTempCycB;
while(TempCycA--)
{
TempCycB=7269;
while(TempCycB--);
};
}
/********************************************************/
voidConut(void)
{
time=TH0*256+TL0;
TH0=0;
TL0=0;
S=(time*1.7)/100;//算出来是CM
if((S>=700)||flag==1)//超出测量X围显示“-”
{
flag=0;
DisplayOneChar(0,1,'D');
DisplayOneChar(1,1,'i');
DisplayOneChar(2,1,'s');