基于51单片机的超声波避障小车设计

摘要

本研究题目中设计应用的是一台具有自动倒车避除障功能的智能小车,其总体设计及思想可与雷达测距跟踪机器人、搜索定位机器人、管道腐蚀探伤定位机器人系统等类似。本实验小车主要使用了一片STC89C51单片机作为其主
控的芯片,通过超声波多普勒测距机来实现检测其周围道路是否遇有障碍物及获取该障碍物间的相对距离,当实际检
测到的与障碍物距离远远小于所设定好的最小安全制动距离时,小车系统便可能会进行自动应急转弯,避开该障碍物
后再继续其沿直线运动。与小车配套的上位机使用 LABVIEW 开发,可以通过串口与小车进行通信,控制小车的运动速
度、运动方向,改变障碍物检测范围。障碍物的检测范围也可以通过小车上的按钮来调节。障碍物的检测电压范围也
会直接存入51单片机中的一个EEPROM程序存储器中,确保第一次断电自检后该数据也不会随之丢失,并保证在下一次
上电工作时自动读取出该检测数据。小车系统的车辆运动的状态数据和与障碍物距离也会实时在大屏幕彩色LCD液晶
显示屏画面上得以实时地显示。避障小车系统控制器的电路设计均采用到了模块化控制的最新设计思想方法,电路结
构极为简单,程序编写调试灵活方便,具有着很大的设计扩展开发空间。
关键词:单片机;障碍物检测;串口数据传输软件;EEPROM;

1绪论

近年来,智能车的不断发展,使得人们的生活方式也不停的得到了改善。人们在他们不断的探讨、认识、改造着
自然现象的发展过程中,制造出一种能彻底替代人的劳动行为的机器一直认为是人类的梦想。很多学校为了培养学生
的动手、编程能力以及培养学生们的兴趣,为智能小车在控制领域内也提供了环境。同时还参加过一些国际较高大型
设计比赛中的设计比赛和其他一些设计课程学习与实践毕业设计阶段的开始采用这类的题目。避障小车最适合在那
些人类无法工作的环境中工作,该技术目前也还可以被广泛地应用于无人和可辅助驾驶系统的机动车,无人生产线,仓
库,服务机器人等方面领域。在一些危险的环境情况下,机器人非常地适合使用。在这些复杂险恶多变的社会环境影
响下的工作,人类必需特别采取更加严密细致的安全保护管理措施。而机器人就可以快速进入或安全穿过对这些潜在
危险的区域并进行自动维护控制和跟踪探测工作,且你不需要得到像对人一样的保护。随着目前智能机器人系统的技
术应用与领域范围迅速地扩大,人们更加希望看到智能机器人出现在今后越来越多高科技的应用领域为人们服务,代
替人类完成许多繁重的工作。智能车是智能机器人的一个重要方向,它集中运用了计算机、传感器、通讯、程序控制
及自动控制等技术,是重要的高科技新技术综合体。近年来对智能车研究的重要方向是提高汽车的安全性、舒适性,
以及提供了全面丰富的智能人车一体交互控制界面。当下在不断的提高科学技术,不断的完善研发技术的环境下,智
能车得到了飞速的发展,并且已在越来越广泛的行业中得到应用,智能车与其相关产品的生产已经日渐成熟。目前,智
能车己经变成世界车辆工程方面研究的重要板块和汽车工业产值增长的重要动力,汽车的智能化已经成为各大汽车产
业的竞争焦点,很多工业国家都已经将其纳入到了自己重点发展的智能交通项目中。
  “工欲善其事,必先利其器”。人类都在试图认识到自然、改造自然、推动着社会向前进步的成长过程中,不断地
发明创造研制出的各种各样能够为未来人类发展服务的先进工具,其中还有许多发明创造具有着划时代深远的革命意
涵义。作为在20世纪人类自动化科学技术领域获得的第一项重大突破性成就,机器人自动化已经开始和改变人类社会
日常的人类生产。
1.1.2 未来发展
  人类科学上的各种探索或研究的实践活动都已在世界上基本已摆脱抛去了地球生物圈及其本身存在的种种束缚
而正日益地广泛和快速深入地向前发展并进入到太阳系外层空间海洋中深处和行星际海洋的中深处。对那些诸如对
月球表面和其他一些除了太阳系天体外的其他的太阳系行星天体的探测,对其他一些除太阳系行星体以外所有的所有
其他的宇宙星球体进行深入的地质考察,对数千米宇宙深处以下所有的星际海底天体的深度探测与研究,都是目前人
们在目前阶段还仅仅单的是仅仅靠一些机械人力工具所达远远都不能及的。自动航行的控制系统也已经正在逐步渐
渐地代替了以前人们去完成所有上述所有这些深度探测任务。在我们未来现实战场平台上将要开展进行的其他许多
现代军事活动领域任务中,在未来许多需要恶劣或复杂气候环境条件作用状态下进行实施任务的许多特殊社会生产技
术与特殊劳动实践项目活动中,凡属某些已不宜完全单独的由自行动人驾驶员能直接驾车去完成承担的某些复杂环境
任务,均可尝试逐步的由智能车载自动环境控制系统去予以代替,如智能小车驾驶员就可以实现快速去适应各类车辆
不同的复杂工况环境,不受各种恶劣如温度、湿度环境变化等自然各种条件因子造成的人为干扰及影响,完成在各种
环境危险恶劣的复杂地段、人类交通工具无法进行快速的介入控制等的各类特殊和危险恶劣情况环境条件下才能进
行完成的大型特种任务。高科技的自动智能控制系统软件设备及相应配套硬件装置设施等都已是在日益成熟发展并
成为了各种复杂现代和大型复杂社会活动环境条件中人类越来越多离不开用到的一项重要高科技自动监控智能设
备。
  未来在智能汽车领域上的高度的智能化技术发展无疑是伴随现代汽车产业的快速地发展而发展必然的带来深远
影响的,在我们当今汽车这种发展新技术情况环境条件下研究超声波探头技术在我们未来在智能车的碰撞及避障安全
功能技术上的创新及应用将也必将具有着很有深远的地发展意义,这无疑就又将会直接地对保证我国对于我国未来开
展的新一代智能汽车关键技术应用基础的前瞻性基础的研究开发以及其在今后整个汽车世界高科技领域里能够所占
据一定的行业领先地位等也均具有着了十分重要地作用。
  本套智能小车系统的设计最具有其诱人与魅力的一个市场前景应该来说就是在其可用于驾驶员未来日常驾驶使
用的智能汽车系统设计应用上体现的出来了,当有一些普通驾驶员在稍后因工作一时而疏忽了驾车时间或经常打瞌睡
觉时在这样的一套智能汽车系统应用的系统设计应用中我们就能更明显地体现出的显示出它了以及它的应有发挥的
一个积极的作用。如果驾驶者发现其汽车驶有可能偏离了正常驾驶车道时或正常行驶距有周围没有障碍物时或远远
小于威胁其驾驶员安全行车的直线距离时,汽车控制系统也就会主动提前地发出这一声紧急警报,提醒其所有驾驶员
减速停车的注意,如果这时其他任何驾驶员都并没有能够很及时正确地并作出任何适当地反应,汽车驾驶员也自然就
会被提前并自动的进行紧急减速停车操作或自动安全的停靠和行驶于路边。这样的微型小车在今后我们还将应该也
可以继续作为专门用于发射载人的月球探测器卫星等技术方面研究的宇航员专用和无人卫星遥控的探月飞船专用车,帮助宇航员为今后我们的驾驶员及时传达我们来自于月球轨道面上的更多的宝贵可靠的卫星信息,让以后的我们这些
宇航员们更加深入准确快速的更全面的了解到月球,为将来人类在将来能够成功载人登月做好最后一个更充分地技术
准备。这样一个小巧便携的微型智能小车即使只是在普通科学车和科学考察车辆和科学探测车上进行使用时也有它
相当的广阔的潜在现实与应用与推广的前景,在全球许多大科学探索或科学考察等领域活动中,有很多是相当的危险
的且那些通常人们也根本都无法去随意去涉足到的一些小的地方,这时,智能科学小车或智能考察和探测车也就这样
正好地能够被人们派上实际用场,在这时它的上面又能被装上一台微型智能摄像机,代替那些普通的人们来进行过去
许多是人类所无法轻易地进行到的操作。

第2章 总体设计

2.1 总体结构
  使用51单片机来搭建一个避清障小车,通过超声波模块的数据反馈计算从而直接得到与障碍物的距离与小车之间
的最小距离。得到距离之后通过判断预置数与距离的大小来判断是否需要进行避障操作。预置数需要存储到单片机
EEPROM 中,每次上电自动从特定存储单元读取。小车使用L298N 驱动直流电机,通过单片机输出的高低电平组合控制
电机的方向,通过改变方波信号的占空比控制电机转动的速度。车辆实时信息需要通过LCD 模块显示,包括车辆运行
状态,障碍物距离。
  下位机和上位机之间通过串口通讯,上位机发送控制字符段控制小车运行速度和方向,超声波检测障碍物的范
围;下位机将实时检测到的距离数据传输给上位机并通过图形化界面进行显示。
上位机使用 LABVIEW 搭建,通过 VISA 控件搭建串口通讯软件,实现数据的发送与接收。在这里插入图片描述

图 1-1 系统结构图
在这里插入图片描述

图 1-2 系统总体电路图
2.1.1设计的思路
  本系统设计是采用了C语言来设计编译的程序。模块化的结构程序模块化的软件设计,可以直接使整个系统软件
变得便于设计调试实现与程序优化,也会使软件其他人者更好地理解程序和快速阅读该系统相关的程序与设计。因
此,软件程序开发的软件设计程序上,运用到了模块化设计程序的结构方式对整个软件环境进行结构化设计,使得编写
程序可以变得更加清晰直观简单易懂。
  为了要保证同时完成的所有的上述的这些功能任务,在我们具体在进行单片机过程软件程序的设计或操作时,通
常都先会把每一整个的单片机过程软件分成为若干个小程序部分,每小一部分往往也会叫做其中某的一个功能模块。
所谓模块的代码"模块"的代码,实质含义大致上来讲也应该就是该模块代码所实际包含并完成并实现某一定目的功
能,相对于其他独立地运行起来的模块程序段,这种对模块程序功能的抽象设计实现的程序方法也通常又叫模块程序
设计法。模块程序设计法它包含的其它一些的主要程序设计法优点有之一主要是:单个的程序模块代码比起专门设计
了一个独立模块而完整可运行的多模块程序来说较更易的实现其编写的功能条件及编程及调试等能力需求;且各程序
模块间又可以同时互相共存,一个独立程序模块同时也是可以被分别或者被同时设计成为多个的功能任务以便满足在
需要其他各种不同的功能条件的支持状态下程序的正常调用;模块程序可直接允许软件系统设计者进行重新分割已有
模块任务代码和有效整合利用已有的模块程序,为软件设计者工作中提供一个巨大的方便。[5]。因此,主程序主要能
起到决策导向机制和辅助决策等作用,决定在何时小车就该如何做如何的动作,小车上的其它各种控制功能都主要可
以通过程序调用这些具体操作的子程序。
2.1.2软件工具的简单介绍
  单片机系统在开发工作环境系统中除需提供所必要而使用的一些基础硬件系统环境外,同样它还应离不开提供各
种功能软件。在系统软件的开发及设计开发的整个过程中,涉及要使用到的Keil软件编译程序、STC_ISP_V480下载程
序软件、Protues仿真及分析等软件,下文面对开发需要具体用到的哪些软件来做作了作一比较简单实用的介绍。随
着世界当代计算机科技工业应用的技术日益的发展,"计算机仿真技术"系统已日益开始的成为目前国外及许多中国企
业的设计研究开发生产部门系统中最重要和应用最大的一个计算机辅助工业前期的分析及设计研究方法手段。它本
身也同时具有实现了设计分析方式的灵活,结果、过程之间有机合理的相互结合及统一的完整系统的功能特点。可使
半导体集成芯片电路系统设计及研究工作时间都可被大有为度的缩短、耗资更可以被大为地的减少,也就因而也可大
大显著的降低了半导体工程芯片开发制造技术方面的种种潜在的风险。相信在未来在单片机系统设计开发制造的实
际应用研究工程中使用PROTUES也是必定的能在从中获得愈来的愈多的广泛的实际应用。

第3 章 硬件设计

3.1 电机控制模块在这里插入图片描述

图 2-1 L298N 原理图
  电机驱动器控制模块使用到的型号是L298N,这款是其中一款能够接受极高交流电压要求的步进电机驱动器,直流
电机和三相步进电机也都一样可以进行驱动。一片驱动控制芯片可用来同时控制两个直流减速电机分别做各种不同
减速动作,在一个6V电压到三个46V电流之间的电压范围内,提供最大2个安培的工作电流,并且同时具有电机过热电流
自断报警和温度反馈等检测监控功能。技术参数
  L298N控制器还可做到通过微处理器对直流步进电机直流输出电平进行比较直接简单的控制,通过电脑对电机主
控芯片驱动芯片电路内相应的直流I/O电路参数进行输入运算后并对其设定的输出控制直流输入的电平值参数进行设
定,就可控制芯片为直流步进电机自动选择进行的直流的正转输入或者是反转直流输出的驱动,操作十分方便而简
单、稳定性又比较好,可以很轻松地满足大直流电机输出需要的大直流电压大直输出大电流输出等驱动条件,同时价
格相对便宜,是一种高性价比的电机驱动模块。
  上图为一部分L298N 原理图,当使能端ENABLE 为1 时,与门才能受到INT1,INT2 的控制,当INT1=0,INT2=0
时,OUT1,OUT2 都为低电平;当INT1=1,INT2=0时,OUT1 为高电平,OUT2 都为低电平;当INT1=0,INT2=1 时,
OUT1 为低电平,OUT2 位高电平;当 INT1=1,INT2=1 时,OUT1,OUT2 都为高电平。只有存在电位差的时候,电机
发生转动。
  根据原理图分析可得,可以对使能端进行 PWM 控制进行调速,INT1,2 的状态不发生改变,也可以对INT1 或者
INT2 进行PWM 控制,使能端不变同样可以完成对速度的控制。
  上图为一部分L298N 原理图,当使能端ENABLE 为1 时,与门才能受到INT1,INT2 的控制,当INT1=0,INT2=0
时,OUT1,OUT2 都为低电平;当INT1=1,INT2=0时,OUT1 为高电平,OUT2 都为低电平;当INT1=0,INT2=1 时,
OUT1 为低电平,OUT2 位高电平;当 INT1=1,INT2=1 时,OUT1,OUT2 都为高电平。只有存在电位差的时候,电机
发生转动。根据原理图分析可得,可以对使能端进行 PWM 控制进行调速,INT1,2 的状态不发生改变,也可以对
INT1 或者INT2 进行PWM 控制,使能端不变同样可以完成对速度的控制。在这里插入图片描述

图2-2 L298N与系统连线图
  单片机将I/O口连接到L298N的控制信号输入端,由于51单片机并没有提供PWM脉冲输出控制功能,所以我们可以尝
试通过单片机改变单片机I/O口的输出的高低电平的持续工作时间而改变其占片空比,从而实现速度控制。
3.2 超声波模块
  HC-SR04超声波模块还包括可直接提供的从2cm到~400cm范围内测量的超声波距离自动感测仪等功能,测量结果的
显示精度一般也可以很准确的达到3mm。技术参数模块的内部构造包括超声波发射器,接收器模块电路与控制单元电
路。超声波模块系统的最简单基本模块的内部工作原理大致也可大致被分为如下这三步:
(1)采用Trig引脚触发,给以频率至少要大于每秒10个us的高电平脉冲信号
(2)超声波模块将可以自动连续地接收发送出的8个40kHz和以上频域的方波,自动实时的地检测出是否已经有反射了
信号并且反射信号返回(3)若是有一个反射的信号被反射后返回,通过一个Echo引脚将会被输出接收到了一个高电平
频率的反射脉冲,高电平脉冲所需要持续的时间也同样就是一个超声波模块从连续接收发射方波开始到连续接收到反
射信号脉冲并返回为止的时间。距离=(高电平脉冲时间*340)/2
在这里插入图片描述

图2-3 超声波模块与系统连线
单片机系统需要判断计数器数值来计算时钟长短,进而算出障碍物距离。
3.3 LCD 模块
  LCD1602液晶显示屏是主要指是一种工业领域专用的字符型显示控制液晶,能够真正实现同时连续最大能显示到
16行*02行即最大为显示32个字符LCD1602液晶显示系统中的显示控制的原理主要都是指通过利用了该类液晶器件特
有的一些基本物理特性,通过其输出控制电压输出来达到对其能够显示出来的图形区域宽度来进行显示控制,即可以
做到直接的显示图形。1602液晶显示器采用有两个标准规格的引脚,其中:第1号引脚:GND为负电源的接地端子;第2号
引脚:VCC为可接地到5位电压V型的正负电源上的正极端子;第3个引脚:V0为液晶显示器中的显示对比度信号的调整的
输入信号端,接在正极的电源时是显示对比度信号的最低极弱,接地于正极的电源时则显示的对比度信号为最高较强
信号(对比度过高时会产生"鬼影",使用时可以通过一个10K的电位器调整对比度)等。第4引脚:RS为对数据寄存器类
型的选择,高电平1时可选择数据寄存器、低电平为0时可以再选择数据指令寄存器。第5引脚:RW为对数据的读写操作
信号线,高电平1时需先进行数据的读写取操作,低电平为0时需要后进行数据读写取的操作。第6个引脚:为对数据的
使用能端,高电平1时须先执行读取信息,0时后才会执行读写指令。第714位引脚:D0D7为第8位的双向数据输出端。
第15~第16位引脚:背灯电源。第15位引脚背光电源的正极,第16位引脚背光负极。
  LCD1602工作时电压特性:3.3V或远低于标准5V电压的最高额定工作时电压,对比度可调;内含复位控制保护电路
等;还能同时提供屏幕上显示的各种功能控制程序及操作命令,如:清屏、字符闪烁、光标闪烁、显示移位等多种功能
控制显示功能(本项目重点使用常规字符显示功能)等;内建有大容量达80兆字节容量的数字显示内存和数据存储器
DDRAM存储器;同时内建了包含有可多达192个由5X7点阵字符组成的字型的字符发生器CGROM存储器;同时还有多达8个
可完全可由用户自定义设置的5X7点阵字型组成的字符发生器CGRAM。由于其微功耗、体积小、显示的字符内容又极
为丰富,足够完成项目所需要的所有数据显示功能。其余51单片机连接方式如下:
在这里插入图片描述

在单片机上的编程语句中还可以直接的用字符型常量或变量来代替赋值,如’A’。因为 CGROM 储存的字符代码与我们
的PC版中的字符代码都是基本都是一致的,因此我们在向DDRAM 写C51字符代码程序时甚至你也还可以选择直接用
P1='A’这样简单的方法。PC在编译时就必须先把’A’先转换为41H
代码。
3.4 串口通信模块
51单片机的器件内部一般都加有了这样一个全双工控制的数字串行通信的接口,能做到确保计算机同时独立地进行接
收发送数字指令和发送数字指令发送的两种二进制数据。串行异步通信控制系统是指一种指数据信号一位一位的连
续串行地或同时的按特定逻辑顺序的连续的传送各种信息数据的异步计算机移动通信或控制系统方式,其各自的技术
突出处和基本优点之一都是只需同时使用同一根计算机数字传输线,大大上可以显著降低用户计算机硬件成本,适合
实现各种计算机远距离移动通信。其最突出技术缺点处之一主要是数字信号移动传输时的运算速度效率通常均较串
行计算机要低,所以在编写程序的时候要注意延时函数的使用,否则会无法读取到完整的距离数据。
首先介绍串口通信所需的寄存器:
  (1)SBUF寄存器:它实际上本身又是指具有正负两个在同一个逻辑物理单元基础上起到完全互相独立控制作用功
能的负责数据同时接收、发送操作的一个缓冲器,可用来进行同时的处理同时发送、接收正负两种的数据,可用于同
时处理通过两个指令进行对正负一个寄存器SBUF寄存器数据上的读写操作功能来分别进行的区别就是它实际上是指
负责在对接数据存收的缓冲器进行上数据的读写操作功能还是指负责在对数据的发送处理的缓冲器进行的操作。
(2)SCON 串行口控制寄存器:
(3)重点关注方式控制位和中断标志位。SM0和SM1:串并行口工作方式控制位;本次设计采用方式一工作方式控制
位;TI :串行口发送的中断消息或请求的标志。当指向一个CPU发送刚处理加载完的一串并行的数据的请求后,此时的
SBUF寄存器为一个空,硬件使其TI值置于1,请求标志为一个中断,CPU在响应中断标志请求结束后,由软件进行自动地
对该空寄存器TI值进行的清零运算;RI清零:串行口接收到的中断标志或请求的中断标志。当每一个串执行口都接收
读到读完的每一帧的所有串行数据时,此时若判断其的SBUF寄存器位为已加满,硬件则可以直接使其的RI值置于1,请
求中断。CPU可在响应到中断信号结束后,用软件自动进行对其的RI值进行自动清零。根据硬件对其中断点标志位为
的自动判断,进行读取或发送数据。在使用串口时还应注意波特率,一般设置小于时钟源的十二分之一,所以应用的
(4)是波特率4800Hz。在这里插入图片描述

图 2-6 串行口与单片机连接
(5)在这里使用了 MAX232芯片,由于计算机上的串口是具有 RS-232标准的串行
  (6)接口,而在RS-232协议的标准中也定义出了其主要电气特性:高电平信号电压范围的温度范围约为-15V~-3V,
  (7)低电平信号电压的变化范围约为+3V~+15V,这样灵活的电压配置也提高了数据信号传输设备的供电可靠性。
由于单片机中的管脚电平转换为了TTL,单片机当与满足RS-232标准接口的串行通讯口进行异步通信编程时,首先必须
要认真解决好的一点便是电平转换精度的确定问题。
3.5 EEPROM 使用
  (8)STC89C51内部的芯片一般都是自带了一个有2K个字节的EEPROM,STC的单片机一般都是利用了IAP技术进行实
现的EEPROM,内部的Flash擦写次数最高时可达每日达100,000万次或以上。STC单片机的内部主要是有以下这样的几
个功能寄存器
有一个是专门设计了的一个特殊类型的功能寄存器就是用来负责管理ISP/IAP等的特殊的功能的。
在这里插入图片描述

图 2-7 STC89C51RC 单片机 EEPROM 相关寄存器
  (9)程序在用户访问系统数据ISP程序区数据时可以同时对用户应用程序区数据/用户数据Flash程序区数据
(EEPROM)进行字处理节读/字节编程/扇区擦除;程序在访问用户应用程序区数据时,仅按需就可以完成对数据在Flash
内存区数据驱动器(EEPROM)存储器上所进行的字节重读操作/字节编程操作/扇区字节的擦除。STC89C51RC单片机的
内部数据存储器上可用的DataFlash存储器(EEPROM)存储器的地址如图所示。在这里插入图片描述

图 2-8 STC89C51RC 单片机内部 EEPROM 详细地址表

第4 章 软件设计

4.1 单片机控制程序
4.1.1 电机控制程序
  电机控制程序需要控制小车五种运行状态,分别是前进,后退,左转,右转和停止,根据不同的高低电平组合
输入到L298N 上,观察小车运行状态,调试出正确的高低电平组合。
对于小车的运行速度控制,需要先写好延时函数,通过不同的高低电平持续间
的组合,控制小车的运行速度。本程序为小车设置三种速度,分别是全速,占空比100%,中速,占空比70%,慢速,
占空比50%。
4.1.2 超声波测距模块
(1)设计思路
  初始化端口时首先应先将所有的trig端端口电流和echo端的端口电压值都应适当地置设为最低,首先应至少给所
有的trig端发送一次至少为每秒10个us的高电平时脉冲
  (模块自动向外发送8个40K的方波),然后等待,捕捉echo端的输出波形的上升或下上沿,捕捉取到一个上升沿的同
时,打开了超声波定时器并再次开始等待计时,再次重新开始计时等待时捕捉取echo来的是一个下降的上升沿,当再次
打开捕捉取得到上升的第一个下降沿,读出到超声波计时器持续的运行的时间,这一点实际上也就是读取到超声波计
数器在空气介质过程中的持续的运行的时间的时间。测试障碍物的距离=(高电平时间*声速(340M/S))/2,就等于可以
通过推算测出的超声波到障碍物间距离的距离得到超声波测量计算得的障碍物距离后,与设置的障碍物检测范围相
比。若是所测距离超出障碍物检测范围,则认为小车前方没有障碍区,继续直线运动。若是所测距离小于障碍物检测
距离,则控制小车自动左转,避开障碍物,然后继续直线行驶。
(2)流程图
在这里插入图片描述

图 3-1 超声波模块流程图
1.3 LCD 液晶显示模块
(1)设计思路
  先试将1602的初始数据化为上下两行来分别显示,5x8点阵,第1行主要是用来直接显示出小车所检测的到前方的
最大障碍物距离,第2行则完全可以是用来直接地显示出该小车的最小正常的运动的轨迹方向和其最小的运动的轨迹
速度。显示窗口开启时,光标指针既不向下移动显示,也即不向移动闪烁。当写入到一条新的数据信息中后,光标会将
左右方向下移而使显示时光标位置不随移动。
  初始化完1602 后,读取此时超声波模块测得的障碍物距离,以及小车的运动方向和运动速度。然后将障碍物距
离对应的字符进行编码,转换为 1602 的输入信号,在1602 的第1 行居中实时显示的障碍物距离。小车运动状态对
应的字符也会进行编码,然后输入1602 进行显示。从1602 第2 行第3 个字符点阵开始显示小车的运动方向,从第
8 个字符点阵开始显示小车的运动速度。
(2)流程图在这里插入图片描述

图 3-2 LCD 液晶显示模块流程图
4.1.4 EEPROM 存取模块
(1)设计思路
每次上电时,先从单片机的EEPROM 中读取之前设置的障碍物检测范围。然后
检测按钮1、按钮2 的状态,若按钮1 按下,将障碍物检测范围设置为50cm;若是
按钮 2 按下,则将障碍物检测范围设置成 100cm。其次上位机通过串口发送的控制
  指令,若上位机向单片机发送字符‘E’,将障碍物检测范围设置为50cm;若上位机向单片机发送字符‘F’,
则将障碍物检测范围设置为100cm。每次更改障碍物检测范围后,都要将修改后的检测范围重新存入EEPROM 中。
(2)流程图
在这里插入图片描述

图 3-3 EEPROM 模块流程图
4.1.5 串口通信程序
(1)设计思路
1、声明串口初始化程序。
2、配置定时器设置定时器1 工作在模式2。
3、设置SCON 串口控制寄存器,使串行口工作在方式1,并允许接收。
4、先为定时器1 高8 位赋初值,再为定时器1 低8 位赋初值,使波特率设置为4800b/s
5、启动定时器,之后开始死循环,将由超声波模块读取的数据存储到数组中,再一位一位地将数据放到SBUF 寄存
器中,进行发送,注意插入延时函数,否则可能会出现数据接收错误,查询是否发送完毕,对发送标志位清0。
6、如果接收到数据。接收到的数据赋给定义的变量 UART_buff, 通过对此变量的判断,进行小车状态的相关控制。
之后对接收标志位清0,准备再次接收。
4.1.6 上位机设计
  上位机设计使用 LabVIEW 做串口通信调试程序,首先要安装 VISA 驱动,LabVIEW 对串口的操作主要是读操作
和写操作。本项目主要是通过串口程序对下位机进行读写操作。
  使用VISA 串口通信模块,需要对串口进行初始化设置,包括波特率,端口号,数据位,校验位的初始化;第二
步是配置VISA 读取和VISA 关闭函数,VISA 读取函数的功能是从 VISA 资源名称所指定的设备或接口中读取指定数
量的字节,并将数据返回至读取缓冲区,并通过设计字符显示模块显示在上位机中,通过字符串转十进制数进而使
用图像的方法进行图像绘制。VISA 关闭函数的功能是关闭VISA 资源名称指定的设备。VISA 写入模块通过不同的按
钮选择要发送的控制字符,下位机通过对字符的匹配进行相应的设置。根据一系列的逻辑运算判断输出信号,点亮
响应的显示灯显示车辆运行状态。

第5 章 综合分析

5.1 项目整体介绍
  本避障小车使用一片 STC89C51 单片机作为主控芯片,可以通过车头安装的超声波测距模块来检测周围是否有
障碍物及获取障碍物的距离,当障碍物距离小于设定的距离时,小车便会自动转弯,避开障碍物后继续沿直线运动
。上位机使用LABVIEW 开发,可以通过串口与小车进行通信,控制小车的运动状态,改变障碍物检测范围。障碍物
的检测范围也可以通过小车上的按钮来调节。障碍物检测范围会存入 51 单片机的 EEPROM 中,确保断电后数据不
会丢失,并在下一次上电时读取该数据。小车的运动状态和障碍物距离会在LCD 液晶屏上实时显示。
5.2 各模块介绍
5.2.1 下位机
  本避障小车使用一片 STC89C51 单片机作为主控芯片,用来控制小车各模块之间协同工作,实现智能小车的自
动避障。车头安装的超声波测距模块可以检测周围是否有障碍物及获取障碍物的距离,当障碍物距离小于设定的距
离时,小车便会自动转弯,避开障碍物后继续沿直线运动。障碍物的检测范围可以通过小车上的按钮来调节。按下
按钮 1 时,障碍物检测范围会设置成50cm。按下按钮2 时则将障碍物检测范围设置成100cm。每次更改障碍物的检
测范围后,新的检测范围会存入51 单片机的EEPROM 中,确保断电后数据不会丢失,并在下一次上电时读取该数
据,确保小车断电重启后仍能实现自动避障。LCD 液晶屏会实时显示超声波检测到的障碍物距离和小车运行状态。
第1 显示的障碍物距离。第2 行会先显示小车的运动状态,‘Run’代表前进,‘Down’代表后退,‘Stop’代表停
止,‘Left’代表左转,‘Right’代表右转。然后显示的是小车的运动速度,‘High’代表全速,‘Medium’代表
中速,‘Slow’则代表低速,‘Stop’代表停止。
5.2.2 上位机在这里插入图片描述

图 4-2 避障小车上位机
上位机使用labview 开发,可以控制小车的运动状态、更改小车的障碍物检测范
围,小车的运动状态和障碍物距离也都会在上位机界面上显示。
上位机界面左上方是串口设置模块,可以对串口进行一些设置,如选择串口更
改数据位等。右上方则用来设置障碍物检测距离和显示障碍物距离,障碍物的距离可以显示当前的具体距离,也可
以通过曲线图形象的显示障碍物距离。
  上位机界面右下方是用来控制小车状态的,可以控制小车的前进、后退、左转、右转和停止,还可以控制小车
前进时的运动速度。
5.3 检测数据分析
  避障小车的避障范围设置成不同范围,在多种情况下对小车的避障效果进行检测。试验发现,当障碍物距离比
较近,小于80cm 时,超声波模块的距离检测比较准确,小车的避障效果就比较好,可以实现自动避障。当障碍物距
离比较远,大于100cm时,超声波的测距精度就开始降低,所以小车有时会不能准确判断是否应该转向来避开障碍
物。

第6章 程序

#include <reg52.h> //51头文件
#include <intrins.h> //包含nop等系统函数
#include <..\CONFIG\QXA51.h>//QX-A51智能小车配置文件
sbit DU = P2^6;//数码管段选
sbit RX = P2^0;//ECHO超声波模块回响端
sbit TX = P2^1;//TRIG超声波模块触发端
sbit LCM_RW = P3^6; //定义LCD引脚
sbit LCM_RS = P3^5;
sbit LCM_E = P3^4;
#define LCM_Data P0 //定义液晶屏数据口
#define Busy 0x80 //用于检测LCM状态字中的Busy标识
unsigned char pwm_left_val = 100;//左电机占空比值 取值范围0-170,0最快
unsigned char pwm_right_val = 110;//右电机占空比值取值范围0-170 ,0最快
unsigned char pwm_t;//周期
unsigned int time = 0;//传输时间
14
15
unsigned long S = 0;//距离
bit flag = 0;//超出测量范围标志位
  unsigned char code Range[] ="==Range Finder==";//LCD1602显示格式
unsigned char code ASCII[13] = "0123456789.-M";
unsigned char code table[]="Distance:000.0cm";
unsigned char code table1[]="!!! Out of range";
unsigned char disbuff[4] = { 0,0,0,0};//距离显示缓存
void delay(unsigned int z)//毫秒级延时
{
unsigned int x,y;
for(x = z; x > 0; x--)
for(y = 114; y > 0 ; y--);
}
  void Delay10us(unsigned char i) //10us延时函数 启动超声波模块时使用
{ 
unsigned char j; 
do{ 
j = 10; 
do{ 
_nop_(); 
}while(--j); 
}while(--i); 
}
void cmg88()//关数共阴极码管
{
DU=1; 
P0=0X00;//共阴极数码管阳极给低电平,全部熄灭
DU=0;
}
  /************************************LCD1602液晶屏驱动函数
************************************************/
  //*******************读状态*************************//
unsigned char ReadStatusLCM(void)
{
LCM_Data = 0xFF; 
LCM_RS = 0;
Delay10us(1); 
LCM_RW = 1;
Delay10us(1); 
do{
LCM_E = 0;
Delay10us(1); 
LCM_E = 0;
Delay10us(1); 
LCM_E = 1;
Delay10us(1); 
}
while (LCM_Data & Busy); //检测忙信号
return(LCM_Data);
}
/****************写数据************************/
void WriteDataLCM(unsigned char WDLCM) 
{
ReadStatusLCM(); //检测忙
LCM_Data = WDLCM;
LCM_RS = 1;
Delay10us(1); 
LCM_RW = 0;
Delay10us(1); 
LCM_E = 0; //若晶振速度太高可以在这后加小的延时
Delay10us(1); 
LCM_E = 0; //延时
Delay10us(1); 
LCM_E = 1;
Delay10us(1); 
}
//****************写指令*************************//
#define uint unsigned int
#define uchar unsigned char
#define ulong unsigned long
sbit IN1=P1^0;
sbit IN2=P1^1;
sbit IN3=P1^2;
sbit IN4=P1^3;
sbit Sevro_Motor=P2^0;
sbit Echo=P2^3;
sbit Trig=P2^4;
sbit Left_val=P2^1;
sbit Right_val=P2^2;
uchar PWM_val;
uchar Set_val; 
uint x,y,time,timer;
ulong S;
void delay(uint z)
{
for(x=z;x>0;x--)
for(y=1000;y>0;y--);
}
  void MeasureDistance() //启动测距信号
{
Trig=1; 
_nop_();
_nop_();
_nop_();
16
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
Trig=0;
}
void head()
{
IN1=1;
IN2=0;
IN3=1;
IN4=0;
}
void back()
{
IN1=0;
IN2=1;
IN3=0;
IN4=1;
}void stop()
{
IN1=0;
IN2=0;
IN3=0;
IN4=0;
}
void CountDistance()
{
while(!Echo); 
TR0=1; 
while(Echo); 
TR0=0; 
time=TH0*256+TL0; 
TH0=0;
17
TL0=0;
S=(time*1.7)/100; 
}
void Servo_PWM()
{
if(PWM_val<=Set_val)
Sevro_Motor=1;
else
Sevro_Motor=0;
if(PWM_val>=50)
PWM_val=0;
}
void time1()interrupt 3 
{ 
TH1=(65536-100)/256; 
TL1=(65536-100)%256; 
timer++;
PWM_val++;
Servo_PWM();
}
void timer0()interrupt 1
{ 
}
void init()
{
P2=0xff;
TMOD=0x11;
TH1=(65536-100)/256; 
TL1=(65536-100)%256;
TH0=0;
TL0=0;
TR1=1;
ET1=1;
ET0=1;
EA =1; 
time=0;
timer=0;
S=0;
PWM_val=0;
delay(50);
Set_val=21;
}
  //21是中,19是左,23是右 
void main()
{
init();
while(1)
18
{
if(timer>=400)
{
timer=0; 
MeasureDistance(); //启动检测
CountDistance(); //计算距离
delay(10);
  if((S<35)&&(Left_val==1)&&(Right_val==0)) //距离小于20CM
{
stop();
Set_val=22;
delay(20);
back();
delay(80);
Set_val=21;
head();
}
  else if((S<35)&&(Left_val==0)&&(Right_val==1))
{
stop();
Set_val=19;
delay(20);
back();
delay(80);
Set_val=21; 
head();
}
  else if((S<35)&&(Left_val==0)&&(Right_val==0))
{
stop();
delay(20);
Set_val=22;
back();
delay(80);
Set_val=21;
head();
}
  else if((S<35)&&(Left_val==1)&&(Right_val==1))
{
Set_val=19;
back();
delay(80);
Set_val=21;
head();
}
/*else if(S>=30)
{
19
Set_val=21;
head();
}
  else if((S>=30)&&(Left_val==1)&&(Right_val==0))
{
Set_val=19;
head();
delay(50);
Set_val=21;
head();
}
  else if((S>=30)&&(Left_val==0)&&(Right_val==1))
{
Set_val=22;
head();
delay(50);
Set_val=21;
head();
}*/
if((Left_val==1)&&(Right_val==1))
{
head();
}else if((Left_val==0)&&(Right_val==1))
{
Set_val=22;
head();
delay(50);
Set_val=21;
head();
}else if((Left_val==1)&&(Right_val==0))
{
Set_val=20;
head();
delay(50);
Set_val=21;
head();
}else if((Left_val==0)&&(Right_val==0))
{
stop();
}
}
}
}
  void WriteCommandLCM(unsigned char WCLCM,BuysC) //BuysC为0时忽略忙检测
{
if (BuysC) ReadStatusLCM(); //根据需要检测忙
LCM_Data = WCLCM;
20
LCM_RS = 0;
Delay10us(1); 
LCM_RW = 0; 
Delay10us(1); 
LCM_E = 0;
Delay10us(1); 
LCM_E = 0;
Delay10us(1); 
LCM_E = 1;
Delay10us(1); 
}
  //*******************LCM初始化**********************//
void LCMInit(void) 
{
LCM_Data = 0;
WriteCommandLCM(0x38,0); //三次显示模式设置,不检测忙信号
delay(5); 
WriteCommandLCM(0x38,0);
delay(5); 
WriteCommandLCM(0x38,0);
delay(5);
WriteCommandLCM(0x38,1); //显示模式设置,开始要求每次检测忙信号
WriteCommandLCM(0x08,1); //关闭显示
WriteCommandLCM(0x01,1); //显示清屏
WriteCommandLCM(0x06,1); // 显示光标移动设置
WriteCommandLCM(0x0c,1); // 显示开及光标设置
}
  //*********************按指定位置显示一个字符***********************//
void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData)
{
Y &= 0x1;
X &= 0xF; //限制X不能大于15,Y不能大于1
if (Y) X |= 0x40; //当要显示第二行时地址码+0x40;
X |= 0x80; //算出指令码
WriteCommandLCM(X, 1); //发命令字
WriteDataLCM(DData); //发数据
}
  //**********************按指定位置显示一串字符*************************//
void DisplayListChar(unsigned char X, unsigned char Y, unsigned char code *DData)
{
unsigned char ListLength;
ListLength = 0;
Y &= 0x1;
X &= 0xF; //限制X不能大于15,Y不能大于1
while (DData[ListLength]>0x19) //若到达字串尾则退出
{
if (X <= 0xF) //X坐标应小于0xF
21
{
DisplayOneChar(X, Y, DData[ListLength]); //显示单个字符
ListLength++;
X++;
}
}
}
  /***************************************************************************/
/*定时器0中断*/
void timer0() interrupt 1 //T0中断用来计数器溢出,超过测距范围
{
flag=1; //中断溢出标志 
}
void StartModule() //启动超声波模块
{
TX=1; //启动一次模块
Delay10us(2);
TX=0;
}
/*小车前进*/
void forward()
{
left_motor_go; //左电机前进
right_motor_go; //右电机前进
}
/*PWM控制使能 小车后退*/
void backward()
{
left_motor_back; //左电机后退
right_motor_back; //右电机后退
}
/*小车停止*/
void stop()
{
right_motor_stops;//右电机停止
left_motor_stops; //左电机停止 
}
/*PWM控制使能 小车高速左转*/
void left_rapidly()
{
left_motor_back;
right_motor_go; 
}
/*定时器1中断输出PWM信号*/
void timer1() interrupt 3
{
pwm_t++;//周期计时加
22
if(pwm_t == 255)
pwm_t = EN1 = EN2 = 0;
if(pwm_left_val == pwm_t)//左电机占空比 
EN1 = 1; 
if(pwm_right_val == pwm_t)//右电机占空比
EN2 = 1; 
}
/*判断S2是否被按下*/
void keyscan()
{
for(;;) //死循环
{
if(key_s2 == 0)// 实时检测S2按键是否被按下
{
delay(5); //软件消抖
if(key_s2 == 0)//再检测S2是否被按下
{
while(!key_s2);//松手检测
beep = 0; //使能有源蜂鸣器
delay(200);//200毫秒延时
beep = 1; //关闭有源蜂鸣器
break; //退出FOR死循环
}
}
} 
}
/*计算超声波所测距离并显示*/
void Conut(void)
{
time=TH0*256+TL0;
TH0=0;
TL0=0;
S=(float)(time*1.085)*0.17; //算出来是MM
if((S>=7000)||flag==1) //超出测量范围
{ 
flag=0;
DisplayListChar(0, 1, table1);//1602显示数组table1
}
else
{
disbuff[0]=S/1000; //距离数值千位
disbuff[1]=S%1000/100;//距离数值百位
disbuff[2]=S%100/10;//距离数值十位
disbuff[3]=S%10; //距离数值个位
  DisplayListChar(0, 1, table); //显示:Distance:000.0cm
DisplayOneChar(9, 1, ASCII[disbuff[0]]); //显示千位
DisplayOneChar(10, 1, ASCII[disbuff[1]]); 
23
DisplayOneChar(11, 1, ASCII[disbuff[2]]);
DisplayOneChar(12, 1, ASCII[10]); //显示 . 
DisplayOneChar(13, 1, ASCII[disbuff[3]]);
}
}
/*超声波避障*/
void Avoid()
{
if(S < 400)//设置避障距离 ,单位毫米 刹车距离
{
beep = 0;//使能蜂鸣器
stop();//停车
backward();//后退
delay(100);//
do{
left_rapidly();//高速左转
delay(90);//时间越长 转向角度越大,与实际行驶环境有关
stop();//停车
delay(100);//时间越长 停止时间越久长
StartModule(); //启动模块测距,再次判断是否
while(!RX); //当RX(ECHO信号回响)为零时等待
TR0=1; //开启计数
while(RX); //当RX为1计数并等待
TR0=0; //关闭计数
Conut(); //计算距离
}while(S < 280);//判断前面障碍物距离
beep = 1;//关闭蜂鸣器
}
else
{
forward();//前进
} 
}
void main()
{
cmg88();//关数码管
LCMInit(); //LCM初始化
delay(5);//延时片刻
DisplayListChar(0, 0, Range);//1602第一行显示Range数组内容
DisplayListChar(0, 1, table);//1602第二行显示table数组内容
keyscan();//等待按下S2启动小车
delay(1000);//延时1秒
TMOD |= 0x20;//定时器1工作模式2,8位自动重装。用于产生PWM
TMOD |= 0x01;//定时器0工作模块1,16位定时模式。T0用测ECH0脉冲长度
TH1 = 220; //
TL1 = 220; //100HZ T1
TH0 = 0;
24
TL0 = 0;//T0,16位定时计数用于记录ECHO高电平时间 
ET1 = 1;//允许T1中断
ET0 = 1;//允许T0中断
TR1 = 1;//启动定时器1
EA = 1;//启动总中断
while(1)
{
StartModule(); //启动模块测距
while(!RX); //当RX(ECHO信号回响)为零时等待
TR0=1; //开启计数
while(RX); //当RX为1计数并等待
TR0=0; //关闭计数
Conut(); //计算距离
Avoid(); //避障
delay(65); //测试周期不低于60MS 
}
}
小车行驶驱动函数
/*PWM控制使能 小车前进*/
void forward()
{
left_motor_go; //左电机前进
right_motor_go; //右电机前进
}
/*PWM控制使能 小车后退*/
void backward()
{
left_motor_back; //左电机后退
right_motor_back; //右电机后退 
}
/*PWM控制使能 小车左转*/
void left_run()
{
left_motor_stops; //左电机停止
right_motor_go; //右电机前进 
}
/*PWM控制使能 小车右转*/
void right_run()
{
right_motor_stops;//右电机停止
left_motor_go; //左电机前进
}
/*小车停止*/
void stop()
{
right_motor_stops;//右电机停止
left_motor_stops; //左电机停止 
25
}
/*PWM控制使能 小车高速左转*/
void left_rapidly()
{
right_motor_go;
left_motor_back; 
}
/*PWM控制使能 小车高速右转*/
void right_rapidly()
{
left_motor_go;
right_motor_back; 
}
void delay(unsigned int z)//毫秒级延时
{
unsigned int x,y;
for(x = z; x > 0; x--)
for(y = 114; y > 0 ; y--);
}
/*小车前进*/
void forward()
{
left_motor_go; //左电机前进
right_motor_go; //右电机前进
}
//定时器0中断
void timer0() interrupt 1
{
pwm_t++;
if(pwm_t == 255)
pwm_t = EN1 = EN2 = 0;
if(pwm_motor_val == pwm_t)
EN2 = EN1 = 1; 
}
void main()
{
TMOD |= 0x02;//8位自动重装模块
TH0 = 220;
while(1)
{
forward();//前进
if(key_s2 == 0) //S2按下LED变暗
{
delay(5);
if(key_s2 == 0)
{
if(pwm_motor_val < 170)
26
{
pwm_motor_val++;
}
}
}
if(key_s3 == 0) //S3按键LED变亮
{
delay(5);
if(key_s3 == 0)
{
if(pwm_motor_val > 0)
{
pwm_motor_val--;
}
}
} 
}
}
1、智能小车云台避障程序
#define _MAIN_C
#include "config.h"
#include "motor.h"
#include "Delay.h"

第7章 结论

7.1.1设计调试中遇到的疑难问题及解决方法。
(1)问题:L298N 在连接单片机后,电机无法正常运动;
  解决方法:经过查阅L298N 原理,发现硬件电路连接错误,需要将L298N 的地和单片机的地向量,单片机5V 输
出应该连接到L298N 的5V 输入项。
(2)问题:上位机读取数据时数据显示错误,图像无法正常显示。
  解决方法:由于串口通信速度缺点之一是传输速度慢,所以在发送一个数据之后应该选取适当的延时,上位机
才能将数据完整的读取,读到的数据位字符串,需要在上位机加入一个字符转整形数据的模块,图像才能正常的显
示。
(3)问题:上位机无法通过串口更改小车的运动状态,LCD 屏也无法正常显示。
  解决方法:对串口通信模块和 LCD 显示模块的程序进行检查,发现 LCD 模块在显示时关闭了中断,在显示完
毕后却没有重新打开中断,使上位机和下位机无法通过串口正常通信。在更改LCD 模块的程序后,LCD 就能正常显
示了。
(4)问题:障碍物检测距离无法存入EEPROM。
  解决方法;检查 EEPROM 模块的程序,发现是再写入 ISP 命令后,没有先对ISP_TRIG 寄存器写入46H 和B9H,
ISP 命令无法生效。在EEPROM 模块程序中加入对应的代码,重新运行程序,障碍物距离就能存入EEPROM 中。
(5)问题:上位机labview 的程序无法运行。
  解决方法;检查labview 的程序组成框图,发现是串口数据读取模块的连线有问题。重新绘制串口读取模块的
框图,然后再运行labview 程序,程序就可以运行,实现对小车的控制。
7.2.2心得体会与建议。
  通过这次设计,使我对 51 单片机的使用有了更好的掌握,学习LCD1602A 液晶显示模块的使用,L298N 电机驱
动模块的使用,labview 制作人机交互界面等新知识。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值