基于单片机技术的智能小车.docx
《基于单片机技术的智能小车.docx》由会员分享,可在线阅读,更多相关《基于单片机技术的智能小车.docx(29页珍藏版)》请在冰点文库上搜索。
基于单片机技术的智能小车
基于单片机技术的智能小车
一、设计目的
1、通过本次创新设计项目的设计,培养良好的创新意识,拓宽创新视野;
2、关注最新科技前沿,不断更新自己的理论知识;
3、提高自己查阅专业学术论文的能力,并从中汲取所需要的知识,不断充实自己的理论水平;
4、通过实践提高自己的实际动手能力,在实践中检验理论。
二、设计要求
1、可实现比较平稳快速的寻迹功能;
2、实现简单的避障功能;
3、内置实时温度显示,且可以实现温度值上下限报警;
4、可进行远程红外遥控控制小车进行左右前后行进。
三、功能原理
总体功能概述
智能寻迹小车采用现在较为流行的8位单片机作为系统大脑。
以8051系列家族中的AT89S52为控制主芯片。
40脚的DIP封装使它拥有32个完全IO端口,通过对这些端口加以信号输入电路,控制电路,执行电路共同完成寻迹小车。
P0.0,P0.1,P0.2,P0.3分别通过LG9110电机驱动来驱动电机1和电机2。
由电机的正转与反转来完成小车的前进,后退,左转,右转,遇障碍物绕行,避悬崖等基本动作。
在小车前进时如果前方有障碍物,由红外发射管发射的红外信号被反射给红外接收管,红外接管将此信号经过P3.7传送入AT89S52中,主芯片通过内部的代码进行小车的绕障碍物操作,同时主芯片将P3.7的信号状态通过P2.5的LED指示灯显示出来。
小车行走时会通过P3.5与P3.6的红外接收探头来进行检测。
当走到悬崖处时,P3.5或P3.6将收到一个电平信号,此电平信号将通过相应端口传送入主芯片中,主芯片通过内部代码完成小车的避悬崖操作。
同时P3.5与P3.6的信号状态将通过P2.6/P2.7显示出来。
在小车的左转,右转,后退的过程,可以通过观看以P2.0/P0.7为指示灯的运行状态。
P3.0接
温度传感器,检测周围温度,并通过
接4位7段LED显示器实时显示。
两个按键以查询/中断两种不同的方式来展现按键操作。
你可以按下S1键来进行机器的停止。
再按下S2键来进行小车的运行。
这个按键的信息分别被P3.2,P3.4接收到。
IR1为红外遥控接收器,这就为小车进行远程遥控创造了可能。
这个红外遥控接收头接收到红外信号时将信号经过P3.3送入到主芯片,主芯片对其进行解密后以不同的方式对小车进行控制。
系统功能总体方框图
软件设计方框图
1、智能寻迹
智能小车之所以能够寻迹,主要是由前方的两对红外发射与接收探头来完成的。
我们知道光有反色的特性,所以当前方的红外发射探头发射出来的光线遇到物体时,就会形成发射的光线,而这个经反射的红外光线刚好被红外接收探头接收到。
当红外接收探头接收到信号后,再将信号送到单片机,由单片机内部程序来控制小车的运行情况。
至于如何知道是黑线还是白线,是利用红外光线的一个反射特性。
但对于不同的物体反射特性是不一样的,特别是对白色反光的物体,红外光线的反射量将会少一点。
而对于黑色不反光的物体,红外反射量将会大量的减少,则可以利用这一特性来完成黑与白的判断。
通过电路的合理安装,可以将这种接收到的红外光线变化量转换为电压值传送到单片机中。
而单片机就可以进行各种智能化的控制,完成黑线的寻迹功能。
红外光线是通过电阻将光信号转变为电信号的。
用15K的电阻,并且在进行寻迹时,将红外接收探头用黑色的套管套住,以免多余的光线进入,影响程序的正常判断。
如果需要对红外采集信号的灵敏度进行调整,可以将红外发射与接收的距离进行与地面距离的调整。
另一种方法可以将那个用于红外接收探头的15K电阻进行调整,以使灵敏度适合自己的需求。
在进行实际的智能寻迹时,第一次使用时,先将其他的软件功能关闭,只留寻迹功能来进行测试,完毕后在添加更多功能到寻迹框架中。
来发挥它更多的功能。
在寻迹功能不能很好完成时,应考虑到太阳光线或其他多余光线的影响。
经过测试可知,在光线较暗的室内测试效果较好。
2、
温度传感器
为单总线传感器,在本设计中,用
接
温度传感器,将
检测得到的、已经在
内部进行了
转换的数字量直接送入单片机。
1)
工作原理及应用
的温度检测与数字数据输出全集成于一个芯片之上,从而抗干扰力更强。
其一个工作周期可分为两个部分,即温度检测和数据处理。
在讲解其工作流程之前我们有必要了解
的内部存储器资源。
共有2种形态的存储器资源,它们分别是:
ROM 只读存储器,用于存放
ID编码,其前8位是单线系列编码(
的编码是19H),后面48位是芯片唯一的序列号,最后8位是以上56的位的CRC码(冗余校验)。
数据在出产时设置不由用户更改。
共64位ROM。
RAM 数据暂存器,用于内部计算和数据存取,数据在掉电后丢失,
共9个字节RAM,每个字节为8位。
第1、2个字节是温度转换后的数据值信息,第3、4个字节是用户EEPROM(常用于温度报警值储存)的镜像。
在上电复位时其值将被刷新。
第5个字节则是用户第3个EEPROM的镜像。
第6、7、8个字节为计数寄存器,是为了让用户得到更高的温度分辨率而设计的,同样也是内部温度转换、计算的暂存单元。
第9个字节为前8个字节的CRC码。
EEPROM 非易失性记忆体,用于存放长期需要保存的数据,上下限温度报警值和校验数据,
共3位EEPROM,并在RAM都存在镜像,以方便用户操作。
3、红外避障
红外探测避障是根据反射发出特定频率的红外线确定物体距离的,具体测量过程是这样的,在小车运动过程中先调节距离旋钮使其探测距离达到所用超声波探测器的盲区最大值,用程序控制探头发射信号,然后捕捉反射信号,若无反射信号说明无障碍,如有反射信号说明有障碍,信号从上拉电阻的OC门取出。
红外接管将此信号经过P3.7传送入AT89S52中,主芯片通过内部的程序,驱动电机进行小车的绕障碍物操作
4、红外遥控
在本设计中,使用
红外接收器,且与
端口连接。
特性有:
1、小型设计;
2、内置专用
;
3、宽角度及长距离接收;
4、抗干扰能力强;
5、能抵御环境光线干扰;
6、低电压工作;
通过遥控器远程发射信号,被
红外接收器接收,
红外接收器再把信号通过
端口将控制信号送入单片机,控制电机驱动,是小车完成前后左右的行驶的操作。
5、蜂鸣器
在本设计中,蜂鸣器主要作为温度上下限值报警提示报警。
蜂鸣器模块电路
四、本项目设计创新点
本项目采用以单片机系统开发制作,各项功能集于小车一身,可无需外部控制实现寻迹功能,也是人工智能技术。
亦可通过遥控控制,有手动与自动的选择。
1. 各部件相互独立又相互协同。
探测器、数据处理器、驱动电路相互独立,减轻了处理器的负担,能达到快速获取实时路况,分析路况,提供运行方案之目的。
处理器不负责控制探测器,减小了系统对软件的依赖,系统速度快,稳定性好。
2. 实时温度检测显示,同时可以设定上下限报警,有很高的实用价值。
3. 本小车的最大特色是各模块提供接口,可以随意拆卸,单片机采用了E2PROM,可以重复编程,修改代码,同时也预留了一些接口,便于日后的升级改进。
4. 本电路板采用布线和印制电路板相结合的策略,增大了修改硬件电路的灵活性。
综上所述,本项目的特点是采用模块化设计理念,有很大的升级空间,日后可方便的添加新功能。
五、作品实图
六、原理图
七、使用说明书
俯视图
·前视图
遥控器
九、总结
通过本次创新项目实践,使我们在学习理论知识之余,难得有机会得到一次理论知识的综合应用。
在动手的实践过程中,遇到过很多在之前觉得不是问题问题,比如焊接时不小心刮断电路板线路没发现,造成调试过程中的不小麻烦。
除了得到了知识的收获外,最可贵的是可以经历从一个项目构思立项到最终完成实物调试的整个过程。
同时也要感谢王涛老师、廖京盛老师在资金和技术上的支持与指导!
!
十、原程序
#include
#include
#include//包含51相关的头文件
typedefunsignedcharuchar;//重定义char数据类型
typedefunsignedintuint;//重定义int数据类型
sbitDQ=P3^0;//ds18b20端口
#definedataledP2//数码管接收数据口
staticunsignedintRecvData;//定义接收红外数据变量
staticunsignedcharCountData;//定义红外个数计数变量
staticunsignedcharAddData;//定义自增变量
staticunsignedintLedFlash;//定义闪动频率计数变量
unsignedcharHeardData;
uinttemp,tem;
ucharflag_get,count,num,minute,second;
ucharcodetab[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//7段数码管段码表共阴
ucharstr[4];
unsignedintReadTemperature(void);
voidInit_DS18B20(void);
unsignedcharReadOneChar(void);
voidWriteOneChar(unsignedchardat);
voiddelay(unsignedinti);
bitRunFlag=0;//定义运行标志位
bitEnableLight=0;//定义指示灯使能位
sbitLeftIR=P3^5;//定义前方左侧红外探头
sbitRightIR=P3^6;//定义前主右侧红外探头
sbitFontIR=P3^7;//定义前方红外探头
sbitSB1=P0^4;//定义蜂呜器
sbitS1=P3^2;//定义遥控红外接收探头
sbitLeftLed=P3^1;//定义前方左侧指示灯端口
sbitRightLed=P3^4;//定义前方右侧指示灯端口
/*************完成红外探头端口定义***********/
sbitM1A=P0^0;//定义电机1反向端口
sbitM1B=P0^1;//定义电机1正向端口
sbitM2A=P0^2;//定义电机2反向端口
sbitM2B=P0^3;//定义电机2正向端口
sbitIR1=P3^3;//定义红外接收端口
/*********完成红外接收端口的定义*************/
voidDelay()//定义延时子程序
{uintDelayTime=10000;//定义延时时间变量
while(DelayTime--);//开始进行延时循环
return;//子程序返回
}
voidControlCar(ucharCarType)//定义小车控制子程序
{
M1A=0;//将电机1正向电平置低
M1B=0;//将电机1反向电平置低
M2A=0;//将电机2正向电平置低
M2B=0;//将电机2反向电平置低
LeftLed=1;//关闭前方左侧指示灯
RightLed=1;//关闭前方右侧指示灯
Delay();//将此状态延时一段时间
switch(CarType)//判断小车控制指令类型
{case1:
//前进//判断是否是前进
{
M1A=1;//将电机1反向端口置高
M2B=1;//将电机2反向端口置高
break;//退出判断
}
case2:
//后退//判断是否是后退
{
M1B=1;//将电机1正向端口置高
M2A=1;//将电机2正向端口置高
break;//退出判断
}
case3:
//左转//判断是否是左转
{
M1B=1;//将电机1反向端口置高
//M2B=1;//将电机2正向端口置高
break;//退出判断
}
case4:
//右转//判断是否是右转
{
//M1A=1;//将电机1正向端口置高
M2A=1;//将电机2反向端口置高
break;//退出判断
}
case8:
//停转//判断是否是右转
{
M1A=0;//将电机1正向电平置低
M1B=0;//将电机1反向电平置低
M2A=0;//将电机2正向电平置低
M2B=0;//将电机2反向端口置高
break;//退出判断
}
default:
//默认情况下的判断
{
break;//直接退出判断
}
}
}
voidTimer0_IR1()interrupt1using3//定义红外定时器子程序
{
TH0=0xFF;//向定时器定时间寄存器填入高八位值
TL0=0x19;//向定时器定时间寄存器填入低八位值
AddData++;//自增变量加1
}
voidInt1_IR1()interrupt2//定义红外接收中断子程序
{
TR1=0;//将定时/计数器1关闭
if(4==AddData)//0//判断接收到的数据是0
{
RecvData=RecvData|0;//判断到0就将当前位写0
RecvData=RecvData<<1;//将当前位向左移动1位
}
elseif(8==AddData)//1//判断接收到的数据是1
{
RecvData=RecvData|1;//将当前位写1
RecvData=RecvData<<1;//将当前位向左移动1位
}
CountData++;//将红外接收位计数器加1
if(CountData==8)//判断是否接收到8位数据
{
HeardData=RecvData;//是8位数据时,则将数据暂存到高位变量中
}
elseif(CountData==16)//判断是否接收到16位数据
{
ET0=0;//关闭红外定时器0
EX1=0;//关闭红外外部中断1
TR1=1;//打开定时/计数器1
AddData=0;//定时时间间隔变量清零
if(HeardData==226||HeardData==112)//判断用户码是否正确
{
HeardData=RecvData;//取出接收到的低八位数据
switch(HeardData)//判断低八位数据的值下列那一位
{
case32:
//电源//说明按下了电源键
{
ControlCar(8);//将小车停止
break;//返回
}
case0:
//1//说明按下数字1键
{
ControlCar
(1);//将小车置于后退状态
break;//返回
}
case8:
//2//说明按下了数字2键
{
ControlCar
(2);//将小车置于前进状态
break;//返回
}
case4:
//3//说明按下了数字3键
{
ControlCar(3);//将小车置于左转状态
break;//返回
}
case12:
//4//说明按下了数字4键
{
ControlCar(4);//将小车置于右转状态
break;//返回
}
}
}
RecvData=0;//将接收到的数据清零
CountData=0;//将接收计数器清零
HeardData=0;//将接收高低数据变量清零
return;//返回
}
AddData=0;//将定时器计数器清零
ET0=1;//打开定时器中断
}
voidmain(void)//主程序入口
{
bitExeFlag=0;
unsignedcharTempH,TempL;
TMOD|=0x11;//定时器设置
TH1=0xef;
TL1=0xf0;
ET1=1;
TR0=1;
P2=0x00;
count=0;//定义可执行标志位变量
RecvData=0;//将接收变量数值初始化
CountData=0;//将计数器变量数值初始化
AddData=0;//将定时器计数器初始化
HeardData=0;//将高低计数器初始化
LedFlash=1000;//对闪灯数据进行初始化
TH0=0xFF;//对定时器进行计数值进行初始化
TL0=0x19;//同上,时间大约为25uS
TR0=1;//同意开始定时器0
EX1=1;//同意开启外部中断1
IT1=1;//设定外部中断1为低边缘触发类型
ET0=0;//开启接收中断标志
EA=1;//总中断开启
while
(1)//程序主循环
{
str[3]=0x39;//显示C符号
str[0]=tab[(TempH%100)/10];//十位温度
str[1]=tab[TempH%10]|0x80;//个位温度,带小数点
str[2]=tab[TempL];
if(flag_get==1)//定时读取当前温度
{
temp=ReadTemperature();
TempH=temp>>4;
tem=TempH%100;
TempL=(temp&0x0f)*6/10;//小数近似处理
flag_get=0;
}
while(LedFlash--)//闪灯总延时
{
if(IR1==0)//判断延时期间是否有红外信号输入
{
ExeFlag=1;//将可执行标志位置1
}
if(S1==0)//判断是否有S1按下
{
ControlCar(8);//将小车置于停止状态
gotoNextRun;//跳转到NextRun标签
}
LeftLed=LeftIR;//前方左侧指示灯指示出前方左侧红外探头状态
RightLed=RightIR;
if(LeftIR==0&&RightIR==1)//左侧红外探头没有接收到白色道路信号
{
ControlCar(4);//左侧没有信号时,开始向右转一定的角度
Delay();//修改这里进行转弯角度的调整
//Delay();//同上
//Delay();
//gotoNextRun;
ControlCar
(1);
}
if(LeftIR==1&&RightIR==0)
{
//ControlCar(8);//右侧没有信号时,开始向左转一定的角度
//Delay();
ControlCar(3);//右侧没有信号时,开始向左转一定的角度
Delay();//修改这里进行转弯角度的调整
//Delay();//同上
//Delay();
//gotoNextRun;
ControlCar
(1);
}
if(LeftIR==0&&RightIR==0)//左侧红外探头没有接收到白色道路信号
{
ControlCar
(2);//左侧没有信号时,开始向右转一定的角度
Delay();//修改这里进行转弯角度的调整
//Delay();//同上
//Delay();
//gotoNextRun;
ControlCar
(1);
}
if(FontIR==0)//判断正前方,前左侧,前右侧红外探头状态
{ControlCar
(2);//改变小车状态为后退
SB1=!
SB1;//将蜂鸣器取反
Delay();//调用延时子程序
Delay();
Delay();
SB1=!
SB1;//将蜂鸣器取反
Delay();//调用延时子程序
ControlCar(3);//改变小车左转状态
Delay();//调用延时子程序
Delay();
Delay();
SB1=!
SB1;//将蜂鸣器取反
Delay();//调用延时子程序
SB1=!
SB1;//将蜂鸣器取反
ControlCar
(1);//改变小车为前进状态
SB1=1;//关闭蜂鸣器声音
}
}
NextRun:
LedFlash=1000;//运行闪动时间重设定
if(ExeFlag==0)//判断可执行标志位
{
EX1=1;//开启外部中断1
TR1=1;//开启定时/计数器1
}
ExeFlag=0;//可执行标志位置0
}
}
/******************************************************************/
/*定时器中断*/
/******************************************************************/
voidtim(void)interrupt3using2//中断,用于数码管扫描和温度检测间隔
{
TH1=0xef;//定时器重装值
TL1=0xf0;
num++;
if(num==50)
{num=0;
flag_get=1;//标志位有效
}
count++;
if(count==1)
{P1=0;
dataled=str[0];
}
if(count==2)
{P1=1;
dataled=str[1];
}
if(count==3)
{P1=2;
dataled=str[2];
}
if(count==4)
{P1=3;
dataled=str[3];
count=0;}
}
/******************************************************************/
/*延时函数*/
/******************************************************************/
voiddelay(unsignedinti)//延时函数
{
while(i--);
}
/******************************************************************/
/*初始化*/
/******************************************************************/
voidInit_DS1