基于单片机智能循迹壁障小车

更新时间:2024-05-25 09:00:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

届 别 .. 学 号

毕业设计

基于单片机智能循迹壁障小车

姓 名 系 别、 专 业 导 师 姓 名、职 称 完 成 时 间

摘 要

智能循迹壁障小车是移动式机器人的重要组成部分,本设计通过不断检测各个模块的传感器的输入信号。循迹模块实时检测5路循迹模块在黑线跑道上的状态,当小车跑出所设置的范围时,智能小车自主调整小车的方向位置。并且具有循迹的跑道上检测前方的距离,当前方距离小于25厘米时,小车避开障碍物往回继续循迹。小车把前方障碍物的距离显示在LCD1602液晶上,小车的驱动是采用L298驱动芯片驱动循迹壁障小的行走。

关键词:循迹壁障小车;STC89C52单片机;驱动芯片(L298)

Abstract

Intelligent tracking walls car is an important part of the mobile robot, this design through continuous testing each module of the input signal of the transducer.Tracking module 5 road tracking real-time detection module in the state of the black line on the runway, when the range of the car ran out of the set, the direction of the intelligent car independently adjust the car position.And a tracking on the runway detection distance ahead, the current party distance less than 25 cm, the car back to avoid obstacles continue to tracking.The car distance obstacles in front of the display on the LCD1602 LCD, the car driver is driven by L298 drive chip tracking small walls of walking.

Key words:Tracking walls car;STC89C52 single-chip microcomputer;Drive chip (L298)

1

1 绪论

1.1国内外研究动态

智能小车方面:智能小车,也称轮式机器人,是一种以汽车电子为背景,涵盖控制、模式识别、传感技术、电子、电气、计算机、机械等多学科的科技创意性设计。智能汽车作为一种智能化的交通工具,体现了车辆工程、人工智能、自动控制、计算机等多个学科领域理论技术的交叉和综合,是未来汽车发展的趋势。

机器人技术方面:目前已经开发出了多种类型机器人机构,其结构有串联、并联及垂直关节和平面关节多种。目前研究重点是机器人新的结构、功能及可实现性,其目的是使机器功能更强、柔性更大、满足不同目的的需求。同时机器人机构向着模块化、可重构方向发展。机器人控制技术现已实现了机器人的全数字化控制,基于传感器的控制技术已取得了重大进展。目前重点研究开放式、模块化控制系统,人机界面更加友好,具有良好的语言及图形编辑界面。同时机器人的控制器的标准化和网络化以及基于PC机网络式控制器已成为研究热点。机器人已经实现了全数字交流伺服驱动控制,绝对位置反馈。目前正研究利用计算机技术,探索高效的控制驱动算法,提高系统的响应速度和控制精度;同时利用现场总线技术,实现的分布式控制。

单片机方面:单片机的应用在后PC时代得到了前所未有的发展,但对处理器的综合性能要求也越来越高。综观单片机的发展,以应用需求为目标,市场越来越细化,充分突出以“单片”解决问题。单片机系统作为嵌入式系统的一部分,主要集中在中、低端应用领域。

1.2 课题的目的和意义

在国外机器人的发展有如下趋势。一方面机器人在制造业应用的范围越来越广阔,其标准化、模块化、网络化和智能化的程度越来越高,功能也越来越强,并向着技术和装备成套化的方向发展;另一方面,机器人向着非制造业应用以及微小型方向发展,如表演型机器人,服务机型器人,机器人玩具等。国外研究机构正试图将机器人应用于人类活动的各个领域。

在我国机器人主要应用于工业制造领域,我国工业机器人现在的总装机量约为120000台,其中国产机器人占有量约为 1/3,即40000多台。与世界机器人总装机台数7500万台相比,中国总装机量仅占万分之十六[1]。对中国这样一个拥有13亿人口的大国来说,仅在机器人数量上就和发达国家有着很明显的差距。因此大力发展我国的机器人事业刻不容缓。

智能循迹避障小车可以理解为机器人的一种特例,它是一种能够通过编程手段完成特定任务的小型化机器人。与普遍意义上的机器人相比智能小车制作成本低廉,电路结

1

构简单,程序调试方便,具有很强的趣味性,为此其深受广大机器人爱好者以及高校学生的喜爱。全国大学生电子设计竞赛每年都设有智能小车类的题目,由此可见国家对高校机器人研究工作的重视程度。

2、循迹壁障小车总体方案设计

本设计采用由STC89C52单片机最小系统、电机驱动电路模块、超声波壁障模块、5路循迹模块、液晶显示模块和电源模块块组成。单片机实时检测5路循迹模块在黑线跑道上的状态,并自主调整小车的方向。在循迹的跑道上检测前方的距离,当前方距离小于20厘米时,小车避开障碍物往回继续循迹。小车把前方障碍物的距离显示在LCD1602液晶上,小车的驱动是采用L298驱动芯片驱动循迹壁障小的行走。系统总体框图如图3-1所示:

3-1总体结构框图

5路循迹模块 超声波壁障 单片机 STC89C52 L298驱动 减速电机 电源部分 液晶显示 3、系统方案比较、设计与论证

该系统主要由单片机主控模块、循迹模块、壁障模块电路,液晶显示模块、电机驱动模块和电源模块电路组成,下面介绍实现此系统功能的方案。

3.1主控制器模块选择

方案1:

采用可编程逻辑器件CPLD 作为控制器。CPLD可以实现各种复杂的逻辑功能、规模大、密度高、体积小、稳定性高、IO资源丰富、易于进行功能扩展。采用并行的输入输出方式,提高了系统的处理速度,适合作为大规模控制系统的控制核心。但本系统不需要复杂的逻辑功能,对数据的处理速度的要求也不是非常高。且从使用及经济的角度考虑我们放弃了此方案。 方案2:

2

采用STC89C52单片机作为整个系统的核心,用其控制水温测量控制系统,以实现其既定的性能指标。充分分析我们的系统,其关键在于实现水温的自动控制,而在这一点上,单片机就显现出来它的优势——控制简单、方便、快捷。这样一来,单片机就可以充分发挥其资源丰富、有较为强大的控制功能及可位寻址操作功能、价格低廉等优点。STC89C52单片机具有功能强大的位操作指令,I/O口均可按位寻址,程序空间多达8K,对于本设计也绰绰有余,更可贵的是STC89C52单片机价格非常低廉。

3.2循迹壁障小车车体的选择

方案1:

购买玩具电动车。购买的玩具电动车具有组装完整的车架车轮、电机及其驱动电

路。但是一般的说来,玩具电动车具有如下缺点:首先,这种玩具电动车由于装配紧凑,使得各种所需传感器的安装十分不方便。其次,这种电动车一般都是前轮转向后轮驱动,不能方便迅速的实现原地保持坐标转90度甚至180度的弯角。再次,玩具电动车的电机多为玩具直流电机,力矩小,空载转速快,负载性能差,不易调速。而且这种电动车一般都价格不扉。因此我们放弃了此方案。 方案2:

买现成的车模。经过反复考虑论证,我们制定了买左右两轮分别驱动,后万向轮转向的车模方案。即左右轮分别用两个转速和力矩基本完全相同的直流减速电机进行驱动,后装一个万向轮。这样,当两个直流电机转向相反同时转速相同时就可以实现电动车的原地旋转,由此可以轻松的实现小车坐标不变的90度和180度的转弯。

综上考虑,我们选择了方案2。

3.3电机驱动芯片的选择

方案1:

采用SM6135W电机遥控驱动模块控制直流电机,SW6135W是专为遥控车设计的大规模集成电路,能实现前进、后退、向右、向左、加速五个功能,但是其采用的是编码输入控制,而不是电平控制,这样在程序中实现比较麻烦,而且该电机模块价格比较高。 方案2:

采用电阻网络或数字电位器调节电动机的分压,从而达到分压的目的。但电阻网络只能实现有级调速,而数字电阻的元器件价格比较昂贵。更主要的问题在于一般的电动机电阻很小,但电流很大,分压不仅会降低效率,而且实现很困难。 方案3:

采用功率三极管作为功率放大器的输出控制直流电机。线性型驱动的电路结构和原理简单,加速能力强,采用由达林顿管组成的 H型桥式电路(如图2)。用单片机控制达林顿管使之工作在占空比可调的开关状态下,精确调整电动机转速。这种电路由于工作

3

数字、专用符号和图形。在单片机的人机交流界面中,一般的输出方式有以下几种:发光管、LED数码管、液晶显示器。发光管和LED数码管比较常用,软硬件都比较简单。

在单片机系统中应用晶液显示器作为输出器件有以下几个优点:

由于液晶显示器每一个点在收到信号后就一直保持那种色彩和亮度,恒定发光,而不像阴极射线管显示器(CRT)那样需要不断刷新新亮点。因此,液晶显示器画质高且不会闪烁。

液晶显示器都是数字式的,和单片机系统的接口更加简单可靠,操作更加方便。 液晶显示器通过显示屏上的电极控制液晶分子状态来达到显示的目的,在重量上比相同显示面积的传统显示器要轻得多。

相对而言,液晶显示器的功耗主要消耗在其内部的电极和驱动IC上,因而耗电量比其它显示器要少得多。

字符型液晶显示模块是一种专门用于显示字母、数字、符号等点阵式LCD,目前常用16*1,16*2,20*2和40*2行等的模块。下面以长沙太阳人电子有限公司的1602字符型液晶显示器为例,介绍其用法。

一般1602字符型液晶显示器实物如图3-10和3-11所示:

图3-10 液晶屏正面

图3-11 液晶屏背面

(1)引脚说明:

第1脚:VSS为地电源。

9

第2脚:VDD接5V正电源。

第3脚:VL为液晶显示器对比度调整端,接正电源时对比度最弱,接地时对比度最高,对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度。

第4脚:RS为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。 第5脚:R/W为读写信号线,高电平时进行读操作,低电平时进行写操作。当RS和R/W共同为低电平时可以写入指令或者显示地址,当RS为低电平

R/W为高电平时可以读忙信号,当RS为高电平R/W为低电平时可以写入数据。 第6脚:E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。 第7~14脚:D0~D7为8位双向数据线。 第15脚:背光源正极。 第16脚:背光源负极。

(2)1602LCD的RAM地址映射以及标准字库表

LCD1602液晶模块内部的字符发生存储器已经存储了160个不同的点阵字符图形,这些字符图有:阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码,比如大写的英文字母“A”的代码是01000001B(41H),显示时模块把地址41H中的点阵字符图形显示出来,我们就能看到字母。

它的读写操作、屏幕和光标的操作都是通过指令编程来实现的(说明:1为高电平,0为低电平)。

指令1:清显示,指令码01H,光标复位到地址00H位置。 指令2:光标复位,光标返回到地址00H 。

指令3:光标和显示模式设置 I/D:光标移动方向,高电平右移,低电平左移 。S:屏幕上所有文字是否左移或者右移。高电平表示有效,低电平则无效 。

指令4:显示开关控制。 D:控制整体显示的开与关,高电平表示开显示,低电平表示关显示。 C:控制光标的开与关,高电平表示有光标,低电平表示无光标。 B:控制光标是否闪烁,高电平闪烁,低电平不闪烁 。

指令5:光标或显示移位 S/C:高电平时移动显示的文字,低电平时移动光标 。 指令6:功能设置命令 DL:高电平时为4位总线,低电平时为8位总线。 N:低电平时为单行显示,高电平时双行显示。 F:低电平时显示5X7的点阵字符,高电平时显示5x10的点阵字符 (有些模块是 DL:高电平时为8位总线,低电平时为4位总线)。

指令7:字符发生器RAM地址设置 。 指令8:DDRAM地址设置 。

指令9:读出忙信号和光标地址。 BF为忙标志位,高电平表示忙,此时模块不能接收命令或者数据,如果为低电平表示不忙,模块就能接收相应的命令或者数据。

10

指令10:写数据 。 指令11:读数据 。

液晶显示模块是一个慢显示器件,所以在执行每条指令之前一定要确认模块的忙标志为低电平,表示不忙,否则此指令失效。要显示字符时要先输入显示字符地址,也就是告诉模块在哪里显示字符。

1602 内部显示地址如图3-12所示:

图3-12 1602内部显示地址

例如第二行第一个字符的地址是40H,那么是否直接写入40H 就可以将光标定位在第二行第 一个字符的位置呢?这样不行,因为写入显示地址时要求最高位D7恒定为高电平

1,所以实际写入的数据应该是

01000000B(40H)

+10000000B(80H)=11000000B(C0H) 。在对液晶模块的初始化中要先设置其显示模式,在液晶模块显示字符时光标是自动右移的,无需人工干预。每次输入指令前都要判断液晶模块是否处于忙的状态。1602 液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,如下图所示,这些字符有:阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码,比如大写的英文字母“A”的代码是01000001B(41H),显示时模块把地址41H 中的点阵字符图形显示出来,我们就能看到字母“A”。

4.3STC89C52单片机的简介

51系列单片机最初是由Intel 公司开发设计的,但后来Intel 公司把51 核的设计方案卖给了几家大的电子设计生产商,譬如 SST、Philip、Atmel 等大公司。因此市面上出现了各式各样的均以51 为内核的单片机。这些各大电子生产商推出的单片机都兼容51 指令、并在51 的基础上扩展一些功能而内部结构是与51一致的。

STC89C52有40个引脚,4个8位并行I/O口,1个全双工异步串行口,同时内含5个中断源,2个优先级,2个16位定时/计数器。STC89C52的存储器系统由4K的程序存储器(掩膜ROM),和128B的数据存储器(RAM)组成。

STC89C52单片机的基本组成框图见图3-1。

11

XTAL2时钟电路XTAL1RAM128BSFR 21个定时个/计数器2VccCPUROM/EPROM/Flash 4KB总线控制中断系统5个中断源2个优先级串行口全双工1个4个并行口VssRSTEAPSENALEP0P1P2P3

图3-1 STC89C52单片机结构图

4.3.1 STC89C52单片机主要特性

1. 一个8 位的微处理器(CPU)。

2. 片内数据存储器RAM(128B),用以存放可以读/写的数据,如运算的中间结果、最终结果以及欲显示的数据等,SST89 系列单片机最多提供1K 的RAM。

3. 片内程序存储器ROM(4KB),用以存放程序、一些原始数据和表格。但也有一些单片机内部不带ROM/EPROM,如8031,8032,80C31 等。目前单片机的发展趋势是将RAM 和ROM 都集成在单片机里面,这样既方便了用户进行设计又提高了系统的抗干扰性。SST 公司推出的89 系列单片机分别集成了16K、32K、64K Flash 存储器,可供用户根据需要选用。

4. 四个8 位并行I/O 接口P0~P3,每个口既可以用作输入,也可以用作输出。 5. 两个定时器/计数器,每个定时器/计数器都可以设置成计数方式,用以对外部事件进行计数,也可以设置成定时方式,并可以根据计数或定时的结果实现计算机控制。为方便设计串行通信,目前的52 系列单片机都会提供3 个16 位定时器/计数器。

6. 五个中断源的中断控制系统。现在新推出的单片机都不只5 个中断源,例如SST89E58RD 就有9 个中断源。

7. 一个全双工UART(通用异步接收发送器)的串行I/O 口,用于实现单片机之间或单机与微机之间的串行通信。

8. 片内振荡器和时钟产生电路,但石英晶体和微调电容需要外接。最高允许振荡频率为12MHz。SST89V58RD 最高允许振荡频率达40MHz,因而大大的提高了指令的执行速度。

12

图3-2 STC89C52单片机管脚图

部分引脚说明:

1.时钟电路引脚XTAL1 和XTAL2:

XTAL2(18 脚):接外部晶体和微调电容的一端;片内它是振荡电路反相放大器的输出端,振荡电路的频率就是晶体固有频率。若需采用外部时钟电路时,该引脚输入外部时钟脉冲。

要检查振荡电路是否正常工作,可用示波器查看XTAL2 端是否有脉冲信号输出。 XTAL1(19 脚):接外部晶体和微调电容的另一端;在片内它是振荡电路反相放大器的输入端。在采用外部时钟时,该引脚必须接地。

2.控制信号引脚RST,ALE,PSEN 和EA:

RST/VPD(9 脚):RST 是复位信号输入端,高电平有效。当此输入端保持备用电源的输入端。当主电源Vcc 发生故障,降低到低电平规定值时,将+5V 电源自动两个机器周期(24个时钟振荡周期)的高电平时,就可以完成复位操作。RST 引脚的第二功能是VPD,即接入RST 端,为RAM 提供备用电源,以保证存储在RAM 中的信息不丢失,从而合复位后能继续正常运行。

ALE/PROG(30 脚):地址锁存允许信号端。当8051 上电正常工作后,ALE 引脚不断向外输出正脉冲信号,此频率为振荡器频率fOSC 的1/6。CPU 访问片外存储器时,ALE 输出信号作为锁存低8 位地址的控制信号。

平时不访问片外存储器时,ALE 端也以振荡频率的1/6 固定输出正脉冲,因而ALE 信号可以用作对外输出时钟或定时信号。如果想确定8051/8031 芯片的好坏,可用示波器查看ALE端是否有脉冲信号输出。如有脉冲信号输出,则8051/8031 基本上是好的。

13

输出电压稳定在5V,正负误差不超过0.2V。基于这样的情况再结合电机的工作电压,选取了6节干电池9V作为7805的输入电源,搭建的电源部分电路如图10所示:

图10电源接口电路

6、系统软件设计

6.1程序结构分析

智能循迹壁障小车的软件设计采用模块化的设计思想,这样就把一个复杂的软件设

计分成几个相对简单的部分分别予以解决。本论文完成的功能是循迹壁障小车,单片机实时检测5路循迹模块在黑线跑道上的状态,当前方距离小于25厘米时,小车避开障碍物往回继续循迹,并在液晶上显示距离。先初始化超声波和液晶,读取超声波检测的距离并在液晶上把距离显示出来。利用红外传感器检测小车循迹的位置,判断是否调整小车的位置。在循迹的路上检测前方的距离,判断前方障碍物是否小于25cm,如果小于则小车壁障障碍物原路返回继续循迹。流程图如图7-1所示:

6.2系统程序流图

19

开始 液晶、超声波初始化 读出前方的距离 显示当前检测的距离 循迹是否调整 否 是否有障碍物 结束 是 小车调整相应角度回到跑道上 是 小车后退避开障碍物 图7-1 主程序流程图

7、系统的安装与调试

小车在调试的时候遇到了很多问题,经过努力问题都解决了。

7.1调试的步骤

第一步为目测,单片机应用系统电路全部手工焊接在洞洞板上,因此对每一个焊点都要进行仔细的检查。检查它是否有虚焊、是否有毛剌等。

第二步为万用表测试,先用万用表复核目测中认为可疑的连线或接点,查看它们的通断状态是否与设计规定相符,再检查各种电源线与地线之间是否有短路现象。

第三步为加电检查。当系统加电时,首先检查所有插座或器件引脚的电源端是否有符合要求的电压值,接地端电压值是否接近零,接固定电平的引脚端是否电平正确。

第四步是联机检查。

20

7.2遇到的问题

电路焊接完后进行进行上电测试,发现电源指示灯都没有亮,然后就闻到一股焦味,用手一摸稳压电源芯片发现很烫,于是赶紧拔掉电源。用外用表测量电源的正负极,发现电阻很小。仔细检查一看原来是单片机供电的稳压芯片7805接反了。1脚本来是电压输入端,结果接成了1脚输出端。把稳压芯片取下,换上新的,并且把引脚接对后,通电电源指示灯也亮了,测量电压符合要求5.01V。并且芯片也不发热

结论

经过近一个月的毕业设计,使我对集成电路的使用有了更进一步的认识和了解,要想学好它要重在实践,通过实践,我也发现我的很多不足之处,把所学习到的知识融合到一块还不是想象中的那么简单,其中涉及了单片机、数字电子技术、模拟电子技术、protel 99se等学科知识,要学好这门课程还需要更多的努力。

通过实践的学习,使我对整体的电路设计有了一个更全面的了解,锻炼了重全局考虑局部的能力。深刻体会了理论联系实际的重要性,从老师提出设计要求到完成设计报告,不断的完善自己的设计和电路。在图书馆查资料到写出具体的实施方案、画出电路图都要认真考虑,寻找最优的设计方案。经过多次修改最终于实现了设计要求。 在大学四年的学习和课题研究期间,老师们给予我许多悉心的指导和帮助,教给我知识和为人处世的道理。尤其是这次毕业论文设计,在这里非常感谢老师在设计中给我的建议、支持和帮助,非常感谢老师在我写论文期间对我的引导和启发。在整个论文的选题、理论研究、需求分析、总体设计、详细设计的过程中,自始至终得到了导师老师的悉心指导和深切关怀。感谢导师对我论文不厌其烦的精心修改,多次耐心地审阅了论文全稿,提出了许多宝贵的意见。还有一只在身边支持的同学,在我遇到问题时,他们都尽心为我解答,如果遇到我们都不熟悉的问题,他们都和我一起动手解决。由于老师的支持和同学的各方配合使我的课题能顺利的完成。

致谢

在完成本设计的写作过程中,我十分感谢我的指导老师。从选题到完成设计,老师一直都是很悉心的给我讲解着在设计中遇到的各种问题,循循善诱,严格把关,帮助我开拓设计思路,并不断地鼓舞着我,使我感到信心倍增,让我非常积极地投入到设计中,不断地完成设计中的一个个部分。在此,再次感谢老师在设计上不断地给与我帮助,让我在大学里的最后一次的学习过程中,充分感受到了自己对学习的兴趣和热情,使我能够圆满地完成自己的毕业设计。

回想大学四年的时光,仿佛尽在昨天。最后,我还要感谢在我大学四年的学习期间

21

给我极大关心和支持的家人、各位老师以及我的同学和朋友。是你们在生活和学习上不断给与我支持、帮助和无微不至的关怀,是你们不断地给与了我信心,让我在人生中一次次坚强地走下去。

参考文献

[1]郭惠.吴迅.单片机C语言程序设计完全自学手册[M].电子工业出版社,2008.10:1-200.

[2]王东锋.王会良,董冠强. 单片机C语言应用100例[M]. 电子工业出版社,2009.3:145-300.

[3] 方佩敏.新编传感器原理应用电路详解。北京:电子工业出版社,1994

[4] 王晓明. 电动机的单片机控制[J]. 学术期刊,2002,13(15):1322-1755. [5]郭天祥.51单片机C程序教程[M].北京:电子工业出版社,2009.1. [6]陶红艳,余成波.传感器与现代检测技术[M].北京:清华大学出版社,2009. [7]康光华.电子技术基础—模拟部分(第五版)[M].北京:高等教育出版社,2006 [8] E18-D80NK反射式接近开关传感器说明书[Z].

[9]谭浩强.C程序设计[M].北京:清华大学出版社,1991.

[10]刘新杰.竞赛机器人小车设计的几个关键问题及解决[J].苏州科技学院学报.2004. Vol.24: 70-74.

22

4排针 Description 2排座 循迹接口 C5 C1 电源接口 Designator 电解电容 瓷片电容 瓷片电容 电解电容 发光二极管 发光二极管 J4 J3 C4 D14 附录2元器件清单

附录1整体电路原理图

P1, P2 J1, J2 C2, C3 D1, D6, D11, D12, D13 贴片二极管4007 D2, D3, D4, D5, D7, D8, D9, D10 IN4007 23

JP4 JP2 LED LED 20pf 10uf Power Comment 470uF 0.1uf Header 7 Quantity 1 1

2 1 1 2 1 8 5 1 2

超声波接口 电阻 电阻 电阻 电位器 触点按键 自锁按键 电机驱动芯片 电压比较器 循迹头 单片机 比较器 稳压芯片 直流减速电机 超声波模块 1602液晶显示 晶振

P3 R5, R8, R11, R14, R17,R20 R6, R9, R12, R15, R18 R3 RST1 SW1 U1 U2 U3, U4, U5, U6, U8 U7 U9 VR1 Y1 Header 4 10K 200 10k SW-PB sw-灰色 L298 LM339 ST178 STC89c52 lm393 LM7805 HC-SR04 LCD1 12M 1 7 6 5 1 1 1 1 1 5 1 1 1 2 1 1 1 R1, R2, R4, R10 R16,R21,R23 2k 附录3部分源程序

#include //单片机头文件 #include #include #include

#include //va_list 的头文件 #define uchar unsigned char #define uint unsigned int sbit RS = P3^5; sbit RW = P3^6; sbit EN = P3^7;

sbit RX = P3^3; //超声波接收 sbit TX = P3^2; //超声波发射 static bit flag = 0;

/********************寻迹模块IO口定义*********************************/ sbit xun_ll = P0^4; //从左到右第1个 sbit xun_l = P0^3; //从左到右第2个

24

sbit xun_z = P0^2; //从左到右第3个 sbit xun_r = P0^1; //从左到右第4个 sbit xun_rr = P0^0; //从左到右第5个

/********************LN298电机驱动IO口定义*********************************/ sbit qu_ll = P2^0; //左边电机控制IN1 sbit qu_zl = P2^1; //左边电机控制IN2 sbit qu_zr = P2^2; //右边电机控制IN1 sbit qu_rr = P2^3; //右边电机控制IN2 #define RS_H RS = 1 #define RS_L RS = 0

#define RW_H RW = 1 #define RW_L RW = 0

#define EN_H EN = 1 #define EN_L EN = 0

#define READ_DATA P1

void DelayMs(unsigned int z) //1ms延时函数 {

unsigned int x; for(;z>0;z--)

for(x=110;x>0;x--); }

void LCDWriteCom(unsigned char com) { RS_L; RW_L; READ_DATA = com; EN_H; DelayMs(5); EN_L; }

void LCDWriteData(unsigned char dat) { RS_H; RW_L; READ_DATA = dat; EN_H; DelayMs(5); EN_L; }

/*******************************************************************************

25

**函数名称:LCD_Write_str()

**函数功能:在LCD上写入一串字符

**输 入 口:hang : 要写入的行,add 要写入列 *s要写入的指针数组 **输 出 口:无 **返 回 值:无

**备 注:strlen()是引用库函数string.h ,可以求出数组的长度 **日 期:2014.2.22

*******************************************************************************/ void LcdWriteStr(unsigned char hang,unsigned char add,char*s) {

unsigned char i;

unsigned char length = 0; if(hang==1) LCDWriteCom(0x80+add); else LCDWriteCom(0x80+0x40+add); length = strlen(s); for(i=0;i

LCDWriteData(*s++); //指针送完数据后自加一 }

/*void LcdWriteChar(unsigned char hang,unsigned char add,char Ch) { if(hang == 1)LCDWriteCom(0x80+add); else LCDWriteCom(0x80+0x40+add); LCDWriteData(Ch); }*/

//能像printf一样使用

void Lcd1602Printf( unsigned char x, unsigned char y, unsigned char *p,...) { char idata LcdBuf[17]; va_list ap; va_start(ap, p); vsprintf(LcdBuf,p,ap); va_end(ap);

LcdWriteStr(x,y,LcdBuf); }

void Init_1602(void) { LCDWriteCom(0x38); LCDWriteCom(0x0c); LCDWriteCom(0x06); LCDWriteCom(0x01);

26

DelayMs(2); // Lcd1602Printf(1,0,\ //测试液晶1602显示用 Normal:正常 }

//触发一个高电平时间

static void StartModule(void) //启动模块 { TX=1; //启动一次模块 _nop_();_nop_(); _nop_(); _nop_(); _nop_(); _nop_();_nop_(); _nop_();_nop_(); _nop_(); _nop_(); _nop_(); _nop_();_nop_(); _nop_();_nop_(); _nop_(); _nop_(); _nop_(); _nop_();_nop_(); TX=0; }

/******************************************************************************* * Function Name : Conut

* Description : 取出定时器的值,并通过计算得到距离,返回距离到调用函数 * Input : None * Output : None

* Return : 计算得到的距离 * Attention : 当距离大于5m时,返回3个8,表示超出量程

*******************************************************************************/ static int Conut(void) { uint S,time; time=TH0*256+TL0; TH0=0; TL0=0; S=(time*1.7)/100; //算出来是CM if((S>=500)||flag==1) //超出测量范围 , 亲测可以达到6M多一点点,不过 { //跳动的很厉厉害,现改为5M flag = 0; S = 888; } return S; }

/******************************************************************************* * Function Name : GetDis

* Description : 发出一个10us的高电平脉冲,得到超声波测出的距离 * Input : None * Output : None

* Return : S 测得的距离,Uint型变量,比如返回124,则表示为1.24M * Attention : 调用的函数有:StartModule,Conut

27

*******************************************************************************/ int GetDis(void) { StartModule(); //给一个高电平触发脉冲 while(!RX)xunnji(); //当RX为零时等待 TR0=1; //开启计数 while(RX)xunnji(); //当RX为1计数并等待 TR0=0; return Conut(); //计算 }

//定时器初始化

static void Timer0Init(void) { TMOD &= 0xf0; TMOD |= 0x01; //设T0为方式1, TH0=0; TL0=0; ET0=1; //允许T0中断 EA=1; //开启总中断 }

/******************************************************************************* * Function Name : CsbInit

* Description : 超声波初始化函数 * Input : None * Output : None * Return : None * Attention : 调用的函数有:Timer0Init ,只调用了一个定时器初始化

*******************************************************************************/ void CsbInit(void) { Timer0Init(); }

/************************** 定时器0中断服务函数 *******************************/ void zd0() interrupt 1 //T0中断用来计数器溢出,超过测距范围 { flag=1; //中断溢出标志 }

/***********************小车前进函数************************/ void go() { qu_ll = 1;

28

qu_zl = 0; qu_zr = 0; qu_rr = 1; }

// /***********************小车后退函数************************/ // void back() // {

// qu_ll = 0; // qu_zl = 1; // qu_zr = 1; // qu_rr = 0; // }

/***********************小车左转函数 只有一个轮子动************************/ void left() { qu_ll = 0; qu_zl = 0; qu_zr = 0; qu_rr = 1; }

/***********************小车左转函数 左边轮子后退 右边轮子前进************************/ void left_s() { qu_ll = 0; qu_zl = 1; qu_zr = 0; qu_rr = 1; }

/***********************小车停下函数************************/ void stop() { qu_ll = 0; qu_zl = 0; qu_zr = 0; qu_rr = 0; }

/***********************小车右转函数 只有一个轮子动************************/ void right() {

29

qu_ll = 1; qu_zl = 0; qu_zr = 0; qu_rr = 0; }

/***********************小车右转函数 左边轮子前进 右边轮子后退************************/ void right_s() { qu_ll = 1; qu_zl = 0; qu_zr = 1; qu_rr = 0; }

void che_90_180_break(uchar dat) { uchar i_z = 0; while(1) //循环等待中间寻迹传感器到黑线上 { if(xun_z == 0) //如果中间那寻迹传感器到了黑线上,要让小车停下来前进了 { i_z++; //消去干扰 if(i_z >= 10) //10次之后就确定寻迹模块的中间传感器到黑线上了 { if(dat == L) //如果是左转90度就让右转的方法制动 right_s(); else left_s(); //如果是右转90度就让左转的方法制动 DelayMs(50); go(); break; //break退出while(1)这个死循环 } } else //没有在黑钱上就给i_z变量清零 { i_z = 0; } } }

/***********************小车左转90度************************/ void left_s_90_while() //小车向左转90度

30

{ go(); //前进一小会让小车转90度时刚好让黑线在小车的中间 DelayMs(120); left_s(); //左转90度注意这个延时不能太长 只要能让寻迹模块中间的传感离开黑线就好 DelayMs(180); che_90_180_break(L); }

/***********************小车向右转90度************************/ void right_s_90_while() // { go(); //前进一小会让小车转90度时刚好让黑线在小车的中间 DelayMs(120); right_s(); //左转90度注意这个延时不能太长 只要能让寻迹模块中间的传感离开黑线就好 DelayMs(180); che_90_180_break(R); }

// 白线为 1 黑线为 0 void xunnji() { if((xun_ll==1) && (xun_l==1) && (xun_z==0) && (xun_r==1) && (xun_rr==1)) { go(); //小车前进 } if((xun_ll==0) && (xun_l==0) && (xun_z==0) && (xun_r==0) && (xun_rr==0)) { stop(); } if(((xun_ll==1) && (xun_l==1) && (xun_z==0) && (xun_rr==1)) || ((xun_ll==1) && (xun_l==1) && (xun_z==1) && (xun_rr==1)) || ((xun_ll==1) && (xun_z==1) && (xun_rr==0)) || ((xun_ll==1) && (xun_l==1) && (xun_z==1) && ( (xun_rr==0))) { right(); } if(((xun_ll==1) && (xun_l==0) && (xun_r==1) && (xun_rr==1)) || ((xun_ll==0) && (xun_l==0) && (xun_z==1) && (xun_rr==1)) || ((xun_ll==0) && (xun_l==1) && && (xun_r==1) && (xun_rr==1)))

31

{ left(); } if((xun_ll==1) && (xun_z==0) && (xun_rr==0)) { go(); DelayMs(1); if((xun_ll==1) && (xun_z==0)&& (xun_rr==0)) { right_s_90_while(); } } if((xun_ll==0) && (xun_l==0) && (xun_rr==1)) { go(); DelayMs(1); if((xun_ll==0) && (xun_l==0) && (xun_rr==1)) { left_s_90_while(); } } }

void main(void) { int Dis = 0; InitTimer(); Init_1602(); CsbInit(); Dis = GetDis(); while(1) { xunnji(); if(bTime_500Ms) { bTime_500Ms = 0 ; Dis = GetDis(); Lcd1602Printf(2,3,\ if(Dis < 24) { right_s(); DelayMs(500); }

32

}

}

}

33

本文来源:https://www.bwwdw.com/article/9ub7.html

Top