单片机应用-智能小车设计_第1页
单片机应用-智能小车设计_第2页
单片机应用-智能小车设计_第3页
单片机应用-智能小车设计_第4页
单片机应用-智能小车设计_第5页
已阅读5页,还剩32页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

智能小车设计所谓智能系统,应该是在没有人为因素干预下,能够完全的或者部分的对外部刺激因素做出适当响应的系统。通常这种系统无论复杂还是简单,其硬件结构都可以分为传感、控制以及执行三个部分,好比人的各种感官、大脑以及四肢。下面就从这三个方面进行智能小车的设计,该小车具备自动循迹能力(非人为控制下按照指定路线行走),并且随着不同传感器的加入,能够完成更多的功能,比如壁障、走迷宫、寻光、通过电脑及手机等上位机控制等等。一、控制部分:图1单片机最小系统原理图图2控制信号输入部分原理图图3控制部分电源输入开关图4显示接口图5DS18B20/1838一体化接口及ISP接口该智能小车整个控制部分电路原理如以上5个图所示,可分为主控芯片最小系统、控制信号输入、电源以及各类接口四个部分。1.主控芯片最小系统:在本设计中所使用的主控芯片为51系列单片机,为保证其正常工作所必需的外围电路包括晶振电路、复位电路以及P0口上拉电阻。当然以上三个部分只能保证单片机正常运转,但若只是这样基本没有什么实际意义,根据不同的任务要求,需要让单片机在适当的引脚上连接相应的设备。这里结合智能小车所需的功能以及未来方便扩展的需要,除了设置4个3头插针连接红外光电开关、舵机(距离探测时会用到)以及给其他传感器供电外,还将单片机P0、P1、P2、P3口用排针引出,其中P1使用双排针,一排与8个LED灯相连,可在日后测试时方便观察信号变化。具体连接如图1所示。2.控制信号输入部分:51系列单片机接收外部信号无非通过两个渠道,一个是其4个并行的I/O口,另一个就是其自带的串口,相较之下,串行口的拓展能力更强一些。如图2所示,在本设计中,利用单片机的I/O口设置了4个按键进行人机交互,同时在其串口上连接了一块USB/串口转换芯片PL2303。PL2303:是Prolific公司生产的一种高度集成的RS232-USB接口转换器,可提供一个RS232全双工异步串行通信装置与USB功能接口便利联接的解决方案。该器件内置USB功能控制器、USB收发器、振荡器和带有全部调制解调器控制信号的UART,只需外接几只电容就可实现USB信号与RS232信号的转换,能够方便嵌入到各种设备,该器件作为USB/RS232双向转换器,一方面从主机接收USB数据并将其转换为RS232信息流格式发送给外设;另一方面从RS232外设接收数据转换为USB数据格式传送回主机。这些工作全部由器件自动完成,开发者无需考虑固件设计。PL2303的高兼容驱动可在大多操作系统上模拟成传统COM端口,并允许基于COM端口应用可方便地转换成USB接口应用,通讯波特率高达6Mb/s。该器件具有以下特征:完全兼容USB1.1协议;可调节的3~5V输出电压,满足3V、3.3V和5V不同应用需求;支持完整的RS232接口,可编程设置的波特率:75b/s~6Mb/s,并为外部串行接口提供电源;512字节可调的双向数据缓存;支持默认的ROM和外部EEPROM存储设备配置信息,具有I2C总线接口,支持从外部MODEM信号远程唤醒;支持Windows98,Windows2000,WindowsXP等操作系统;28引脚的SOIC封装。PL2303引脚功能列表:引脚名字类型引脚描述1TXD输出数据输出到串口;2DTR_N输出数据终端准备好,低电平有效;3RST_N输出发送请求,低电平有效;4VDD_325电源RS232的电源,为串行端口信号的电源引脚;当串口为3.3V,这应该是3.3;当串行端口是2.5V,这应该是2.5V;5RXD输入串口数据输入;6RI_N输入/输出串行端口(环指示器);7GND电源接地;8NC无连接9DSR_N输入/输出串行端口(数据集就绪)10DCD_N输入/输出串行端口(数据载波检测)11CTS_N输入/输出串行端口(清除发送)12SHTD_N输出控制RS232收发器关机13EE_CLK输入/输出串行EEPROM时钟14EE_DATA输入/输出串行EEPROM数据15DP输入/输出USB端口D+信号16DM输入/输出USB端口D-信号17VO_33常规3.3V电源输出18GND接地19NC无连接20VDD_5电源USB端口的5V电压电源21GND接地22GP0输入/输出通用I/O引脚023GP1输入/输出通用I/O引脚124NC无连接25GND_A模拟地锁相环26PLL_TEST输入PLL锁相环测试模式控制27OSC1输入晶体振荡器输入28OSC2输入/输出晶体振荡器输出SSOP28封装以上是PL2303芯片的基本介绍,通俗的讲就是该芯片通过驱动可以在PC机上虚拟出一个COM口,使USB接口模拟串口的功能,一般使用情况下主要关心1、5、15、16四个引脚,具体连接参看图2。3.电源部分:电源部分设计为双供电方式,从图3中可以看到,当切换开关上方闭合时,控制板通过电源接头供电,当切换开关下方闭合时,控制板通过USB接口供电。 4.各类接口部分: 这里所提供的接口分别为1602、12864LCD标准接口、DS18B20/1838一体化接口、ISP接口以及图2中所示的由PL2303芯片扩展的USB接口,保证了基本的输出扩展及传感器信号源扩展。由于已将单片机的I/O口引出,不必担心接口是否够用的问题,日后根据需要通过杜邦线可以随时扩展新的接口。二、执行部分: 这里所说的执行部分指的是智能小车上能够表现出其对外部条件作出的反应的部分,这种反应可以是运动,也可以是声或者光。图6LED数码管显示1.LED数码管显示:图6所示为4位共阳极LED数码管显示电路,该部分可用于实时显示有关智能小车当前运行状态,比如速度、前方障碍物距离等等。如果根据实际需要进行相应的扩展,则可以用于显示更多类型的信息,比如加入A\D转换器可以显示当前电池的电压情况,加入温度传感器可以显示当前的工作温度等等。图7蜂鸣器2.蜂鸣器图7所示为简单的蜂鸣器电路,该蜂鸣器可用于对智能小车运行时的一些特定状况进行声音提示,如距离某物太近、转向、脱离轨道、电量过低等等,不同的状况可以使用不同的声音组合进行区分。3.运动部分:该智能小车的运动执行部分由减速直流电机、轮胎以及相应的驱动电路组成,具体如图8、9所示。该部分负责实时的执行小车所需的各种运动(左右转、前进、后退等),若将轮胎部分换成履带或者其它专用轮胎,则可以执行翻越等更为复杂的运动。下面就该部分原理做较为详尽的介绍。图8直流减速电机及轮胎图9双L298N驱动电路直流减速电机:直流减速电机相较于普通直流电机的最大区别就是加入了减速齿轮组,通过调整齿轮比可以在转速与扭矩之间进行权衡,降低转速则可以获得较大扭矩,带动更重的设备,反之扭矩则减少。本设计中整个小车质量相对于普通5V直流电机来说比较重,若选用较大功率的电机,则耗电量与驱动电路的负载将会增加,况且并不需要太高的速度,所以选用减速电机,在同样的功率下通过降低转速获得足够的扭矩。轮胎:最常见的轮胎如图8中所示的圆形轮胎,也是本设计中所使用的轮胎,其对于一般硬质平地来说非常适用,除此之外还有履带,适用于较软并且凹凸不平路面以及专门用于攀爬楼梯等特殊障碍物的异形轮胎等。驱动电路:小车直流电机工作电流一般是200-400mA有些更大,该设计中是四个轮子,那么总的电流在800-1600mA左右,这些电机轮子都是要接受单片机指令执行相应的动作,而单片机I/O口一般只能提供5mA到10mA的电流,直接驱动不了电机,所以需要一个驱动模块,该驱动模块的作用就是根据单片机的指令提供足够的电流。对于工作电压12V以下,功耗25W以内的设备可以选用专业的L298N,L293D驱动芯片。这里我们选用L298N驱动芯片,该芯片可以同时驱动两个电机,所以采用双L298N方案。L298N:图10LL298N是ST公司的L298系列的一款常见的15功能引脚Multiwatt15或PoweSO20封装的产品,如图11所示,内部包含4通道逻辑驱动电路,即内含两个H桥的高电压大电流双全桥式驱动器,如图10所示,可以方便的驱动两个直流电机,或一个四相步进电机。L298N可接受标准TTL逻辑电平信号,输入电压范围为+2.5~46V,输出电压最高可达50V,可以直接通过电源来调节输出电压,输出电流可达2.5A,可驱动电感性负载,可接入电流采样电阻形成电流传感信号,可以直接用单片机的IO口提供信号,而且L298N引脚功能表:引脚(MW15)引脚(PSO20)名称功能1;152;19SenseA;SenseB在该引脚与地之间连接一个用于电流采样的电阻,形成电流传感信号来控制负载电流。2;34;5Out1;Out2A桥的输出,并且这两端之间的负载电流受到1号管脚的监测。46VS供电电压输入端口,该端口的输入电压与桥的输出电压一致,范围为+2.5~+46V,使用时必须在其与地之间接上一个100nF的无感电容。5;77;9Input1;Input2A桥TTL逻辑电平输入端,与对应A桥输出一致(逻辑高则输出,低则停止输出)。6;118;14EnableA;EnableB逻辑电平使能端,为高则对应桥按照逻辑电平正常输出,为低时则停止。81;10;11;20GND接地912VSS逻辑参考电平输入端,使用时必须在其与地之间接上一个100nF的无感电容。10;1213;15Input3;Input4B桥TTL逻辑电平输入端,与对应A桥输出一致(逻辑高则输出,低则停止输出)。13;1416;17Out3;Out4B桥的输出,并且这两端之间的负载电流受到15号管脚的监测。3;18N.C.悬空图11在该驱动电路中,除了L298N驱动芯片外还包括LM2596S降压稳压芯片以及ULN2003L集成达林顿管,具体连接如图9所示。其作用分别为:LM2596S降压稳压芯片:该芯片可以稳定输出5V(可调)电压,用于给控制板以及传感器等较小功率设备提供一个稳定的电压,保证其的正常工作。ULN2003L集成达林顿管:将其所有管脚用排针引出,为了日后方便扩展更大功率器件。在图9中的16只二极管起到稳压保护作用,当输出电压过高或过低时,可以将其稳定在合理的范围之内。若在4个OUT之间加入发光二极管,则可以直观的看出当前驱动器的输出状态,即电机的工作状态,如图12所示图12驱动状态指示电路下面给出一路电机的控制逻辑表,其他三路电机逻辑类同。从表中可以更为直观的看出L298N驱动芯片几个关键引脚的功能,IN1和IN2之间高低电平切换可控制电机正反转,EN端高低变换可控制L298N输出端是否按照输入信号执行。用两个L298N连接前后左右4个电机,参照表中的逻辑给不同的IN输入逻辑电平,就可使小车完成前进、后退、左转、右转等动作,比如一块L298N芯片的OUT1、OUT2、OUT3、OUT4分别连接左侧前后电机的正极、负极、正极、负极,另一块L298N芯片的OUT1、OUT2、OUT3、OUT4分别连接右侧前后电机的正极、负极、正极、负极,此时两块L298N的IN端输入逻辑电平1010、1010则所有电机正转,小城前进;输入1010、0101则小车左侧前进,右侧后退实现右转等。当然此逻辑会随着实际的连接而改变,但原理相同。这里可以看到L298N中的EN端负责控制OUT端是否执行IN端的输入,使其在0、1之间按一定周期切换则可以实现小车的PWM控制,若想使小车全速运行,则需将EN端与逻辑高电位始终相连。电机控制逻辑表:IN1IN2ENA电机000不转010不转100不转110不转001不转101正转011反转111不转三、传感器部分:若要使小车智能化,就必须使其能够对外界环境的变化自行做出适当地反映,在这个过程中最为关键的因素就是如何感知外界的环境,完成这一任务的就是传感器。不同的传感器可以感知不同的环境因素,传感器越丰富,小车可获取到的因素种类就越多,这里将介绍几个常用的传感器。1.四路红外线探测系统:如图13所示该系统是为智能小车、机器人等自动化机械装置提供一种多用途的红外线探测系统。使用红外线发射和接收管等分立元器件组成探头,并使用LM339电压比较器(加入迟滞电路),防止临界输出抖动做为核心器件构成中控电路。此系统具有的多种探测功能能极大的满足各种自动化、智能化的小型系统的应用。图13四路红外线探测系统应用范围:1.智能化轮式车和智能化履带车循迹、避障、防跌落;2.智能化小型机械人和智能化小型机械手物料检测、色相检测灰度检测。特性:1.易于安装,使用简便;2.四路分别独立工作,工作时不受数量限制中控板与探头分开;3.安装位置不受限制模块高度≤4厘米;4.安全工作电压范围在4伏特至6伏特之间4路全开工作电流30毫安至40毫安之间;5.带校正调节功能,R17、R18、R19、R20对应比较电压调节输出端为集电极开路,板载4.7千欧上拉电阻。端口:+5、GND:电源接线端IN(1—4);OUT:探头与中控板连接端;OUT1、OUT2、OUT3、OUT4:对应输出端;LED3、LED4、LED6、LED7:对应输出指示;原理:图14所示为四路红外线探测系统中的一路原理图,其他三路与其一致,图中左半部份为发射,右半部份为接收,R17负责调整基准电压,加入迟滞电路,防止临界输出抖动。测试方法:如图15所示,左侧为传感器测试电路,右侧为传感器安装位置。1.测试探头:移开探头前面的所有物体,且探头不要指向阳光的方向。将探头板接上电源后用万用表测最输出端电压。此时的电压应当在1伏特左右。用白纸挡在探头前。用万用表测输出端电压应当接近电源电压。2.测试中探板:将测试好的探头按板上所标示的接入输入端子,移开探头前面的所有物体,且探头不要指向阳光的方向,将中探板接上电源后用万用表测输出端子,此时输出端输出的电压应当接近电源电压,用白纸挡在探头前,万用表测输出端电压应当接近0伏特,调整所在通道的电位器可以改变探测的距离。图14一路红外线探测系统原理图调试灵敏度:1.调节其四路寻迹的的电位器(调节其灵敏度以适合其环境)具体调试方法如下:先用手握住小车离地,左右晃动,从左到右第一对红外对管离开黑线时,中控板指示D3灯应会亮。当红外对管进入黑线时,中控板指示D3红灯应会灭,调节中控板R17使其工作在上述状态。同理,调节其它三对探头,使其正常工作。2.对应顺序:第二对红外对应灵敏度对应指示灯为中控板D4,调节灵敏度电位器R18;第三对红外对应灵敏度对应指示灯为中控板D5,调节灵敏度电位器R19;第四对红外对应灵敏度对应指示灯为中控板D6,调节灵敏度电位器R20。图15探头测试2.US-100超声波测距模块:US-100超声波测距模块可实现0~4.5m的非接触测距功能,拥有2.4~5.5V的宽电压输入范围,静态功耗低于2mA,自带温度传感器对测距结果进行校正(温度会影响超声波的测距精度),同时具有GPIO,串口等多种通信方式,内带看门狗,工作稳定可靠。外观如图16所示,左图为正面,右图为背面,模块的尺寸为45mm*20mm*1.6mm。板上有两个半径为1mm的机械孔。图16US-100超声波测距模块 主要技术参数: 工作电压:DC2.4V~5.5V; 静态电流:2mA; 工作温度:-20~+70度; 输出方式:电平或UART(跳线帽选择); 感应角度:小于15度; 探测距离:2cm-450cm 探测精度:0.3cm+1%; UART模式下串口配置:波特率9600,起始位1位,停止位1位,数据位8位,无奇偶校验,无流控制。 接口说明 本模块共有两个接口,即模式选择跳线(背面与电路板面垂直的两个引脚)和5Pin接口(正面图中向下的5个引脚)。 模式选择跳线接口: 间距为2.54mm,当插上跳线帽时为UART(串口)模式,拔掉时为电平触发模式。 5Pin接口: 正面图中从左到右依次编号1、2、3、4、5,功能如下表所示:1号Pin接VCC电源(供电范围2.4V~5.5V)2号Pin当为UART模式时,接外部电路UART的TX端;当为电平触发模式时,接外部电路的Trig端。3号Pin当为UART模式时,接外部电路UART的RX端;当为电平触发模式时,接外部电路的Echo端。4号Pin接外部电路的地。5号Pin接外部电路的地。电平触发测距工作原理:在模块上电前,首先去掉模式选择跳线上的跳线帽,使模块处于电平触发模式。图17表明:只需要在Trig/TX管脚输入一个10US以上的高电平,系统便可发出8个40KHZ的超声波脉冲,然后检测回波信号。当检测到回波信号后,模块还要进行温度值的测量,然后根据当前温度对测距结果进行校正,将校正后的结果通过Echo/RX管脚输出。在此模式下,模块将距离值转化为340m/s时的时间值的2倍,通过Echo端输出一高电平,可根据此高电平的持续时间来计算距离值。即距离值为:(高电平时间*340m/s)/2。注:因为距离值已经经过温度校正,此时无需再根据环境温度对超声波声速进行校正,即不管温度多少,声速选择340m/s即可。图17US-100电平触发测距时序图串口触发测距工作原理:图18US-100串口出发测距时序在模块上电前,首先插上模式选择跳线上的跳线帽,使模块处于串口触发模式。串口触发测距的时序如图18所示:在此模式下只需要在Trig/TX管脚输入0X55(波特率9600),系统便可发出8个40KHZ的超声波脉冲,然后检测回波信号。当检测到回波信号后,模块还要进行温度值的测量,然后根据当前温度对测距结果进行校正,将校正后的结果通过Echo/RX管脚输出。输出的距离值共两个字节,第一个字节是距离的高8位(HDate),第二个字节为距离的低8位(LData),单位为毫米。即距离值为(HData*256+LData)mm。串口触发测温工作原理:图19US-100串口测温时序在模块上电前,首先插上模式选择跳线上的跳线帽,使模块处于串口触发模式。串口触发测温的时序如图19所示:在此模式下只需要在Trig/TX管脚输入0X50(波特率9600),系统便启动温度传感器对当前温度进行测量,然后将温度值通过Echo/RX管脚输出。测量完成温度后,本模块会返回一个字节的温度值(TData),实际的温度值为TData-45。例如通过TX发送完0X50后,在RX端收到0X45,则此时的温度值为(0X45的10进制值)-45=24度。超声波测距模块主要用于实现智能小车及机器人壁障这一功能,其型号有很多,但从原理上和使用方法上来讲大同小异,这我们的设计中采用US-100这个型号的超声波测距模块,主要是因为该模块本身具备温度校正功能,在编写程序时较为方便。为了充分发挥超声波模块的作用,可给其配上一台舵机,使其能够实现多个方向的距离感应。舵机:在机器人机电控制系统中,舵机控制效果是性能的重要影响因素。舵机可以在微机电系统和航模中作为基本的输出执行机构,其简单的控制和输出使得单片机系统非常容易与之接口。

舵机是一种位置(角度)伺服的驱动器,适用于那些需要角度不断变化并可以保持的控制系统。目前在高档遥控玩具,如航模,包括飞机模型,潜艇模型;遥控机器人中已经使用得比较普遍。舵机是一种俗称,其实是一种伺服马达。图20舵机1)工作原理:控制信号由接收机的通道进入信号调制芯片,获得直流偏置电压。它内部有一个基准电路,产生周期为20ms,宽度为1.5ms的基准信号,将获得的直流偏置电压与电位器的电压比较,获得电压差输出。最后,电压差的正负输出到电机驱动芯片决定电机的正反转。当电机转速一定时,通过级联减速齿轮带动电位器旋转,使得电压差为0,电机停止转动。2)舵机的控制:舵机的控制一般需要一个20ms左右的时基脉冲,该脉冲的高电平部分一般为0.5ms~2.5ms范围内的角度控制脉冲部分。以180度角度伺服为例,那么对应的控制关系是这样的:

0.5ms--------------0度;

1.0ms------------45度;

1.5ms------------90度;

2.0ms-----------135度;

2.5ms-----------180度;3)用单片机作为舵机的控制单元:用单片机可以使PWM信号的脉冲宽度实现微秒级的变化,从而提高舵机的转角精度。单片机完成控制算法,再将计算结果转化为PWM信号输出到舵机,由于单片机系统是一个数字系统,其控制信号的变化完全依靠硬件计数,所以受外界干扰较小,整个系统工作可靠。单片机系统实现对舵机输出转角的控制,必须首先完成两个任务:首先是产生基本的PWM周期信号,本设计是产生20ms的周期信号;其次是脉宽的调整,即单片机模拟PWM信号的输出,并且调整占空比。当系统中只需要实现一个舵机的控制,采用的控制方式是改变单片机的一个定时器中断的初值,将20ms分为两次中断执行,一次短定时中断和一次长定时中断。这样既节省了硬件电路,也减少了软件开销,控制系统工作效率和控制精度都很高。图21单片机控制舵机基本流程具体的设计过程:例如想让舵机转向左极限的角度,它的正脉冲为2ms,则负脉冲为20ms-2ms=18ms,所以开始时在控制口发送高电平,然后设置定时器在2ms后发生中断,中断发生后,在中断程序里将控制口改为低电平,并将中断时间改为18ms,再过18ms进入下一次定时中断,再将控制口改为高电平,并将定时器初值改为2ms,等待下次中断到来,如此往复实现PWM信号输出到舵机。用修改定时器中断初值的方法巧妙形成了脉冲信号,调整时间段的宽度便可使伺服机灵活运动。为保证软件在定时中断里采集其他信号,并且使发生PWM信号的程序不影响中断程序的运行(如果这些程序所占用时间过长,有可能会发生中断程序还未结束,下次中断又到来的后果),所以需要将采集信号的函数放在长定时中断过程中执行,也就是说每经过两次中断执行一次这些程序,执行的周期还是20ms。具体流程如图21所示。以上介绍的传感器可以保证智能小车完成循迹、壁障、走迷宫等功能,若想完成更为复杂的功能,可以通过添加适当的传感器来实现,具体细节在未来系统扩展的在做介绍。前面,我们从硬件结构方面对智能小车做了一个较为全面的分析,但是以上所包括的所有器件电路只能算作一个运行平台,其包含了要实现功能所需的所有物质实体,却缺少智能系统所需的一个必要要素—“思想”,没有“思想”谈何智能。这里所指的“思想”在电子方面指的就是程序,要想让小车真正实现智能化,通过合理的程序来调动其各个部分协调工作是必不可少的。下面我们就来谈谈程序方面的设计。四、程序部分:对于51系列单片机来说,程序设计一般使用汇编和C两种语言。汇编语言接近底层,在时序控制方面可以做到十分精确,但缺点是可读性差,不容易实现模块化;C语言虽然精确度上稍稍不及汇编,但在其他方面均优于汇编语言,所以目前除了时序要求非常严格的接口驱动喜欢用汇编语言编写外,其余大部分越来越多的喜欢使用C语言。下面就以C语言作为程序编写语言,用模块化的思想设计智能小车各部分的程序。1.小车基本运动程序设计:顾名思义,该部分程序负责让主控部分协调小车各部分完成前进、后退、左右转向等基本动作。这里要说明一下,一个模块可以理解为一项任务,大任务可以分解为若干个小任务,也就是模块可分模块,一个任务包含若干功能,一个功能在C语言中我们习惯用一个子函数来描述,所以可以这样理解,一个模块就是由若干个子函数构成的,整个系统也可以理解为一个项目中最大的模块。硬件的连接方式会影响程序的编写,一般这种影响只局限于I/O口的变动,也就是说改变硬件连接后一般只需要将程序中的I/O口变量做适当的调整就可以实现原先的功能。下面我们参照图9,按照以下方式连接对小车基本运动程序进行设计,其他连接方式程序雷同。 根据前面描述,EN1EN2为驱动使能端,若给其PWM输入,则可以通过一起一停,调整起停所占时间比例的方式控制小车的运动速度。若要全速运行,只需直将使能端通过跳线帽接在+5V上即可。下面的程序只是基本运动,所以采用全速方式。然后P1_0P1_1接IN1IN2P1_2P1_3接IN3IN4P1_4P1_5接P1_6P1_7接IN7IN8IN5IN6;左上电机接驱动板子输出端(蓝色端子OUT1OUT2)、左下电机接驱动板子输出端(蓝色端子OUT3OUT4)、右上电机接驱动板子输出端(蓝色端子OUT5OUT6)、单片机I/O口输出电机运行状态P1_0=1,P1_1=0左上电机正转P1_0=0,P1_1=1左上电机反转P1_0=0,P1_1=0左上电机停转P1_0=1,P1_1=1左上电机刹停P1_2=1,P1_3=0左下电机正转P1_2=0,P1_3=1左下电机反转P1_2=0,P1_3=0左下电机停转P1_2=1,P1_3=1左下电机刹停P1_4=1,P1_5=0右上电机正转P1_4=0,P1_5=1右上电机反转P1_4=0,P1_5=0右上电机停转P1_4=1,P1_5=1右上电机刹停P1_6=1,P1_7=0右下电机正转P1_6=0,P1_7=1右下电机反转P1_6=0,P1_7=0右下电机停转P1_6=1,P1_7=1右下电机刹停根据上表,做以下宏定义,方便后面程序的编写,具体如下表所示:宏命令功能#defineLeft_moto_go{P1_0=1,P1_1=0,P1_2=1,P1_3=0;}左边两个电机正转(智能小车左半部分前进)#defineLeft_moto_back{P1_0=0,P1_1=1,P1_2=0,P1_3=1;}左边两个电机反转(智能小车左半部分后退)#defineLeft_moto_Stop{P1_0=0,P1_1=0,P1_2=0,P1_3=0;}左边两个电机停转(智能小车左半部分停止)#defineRight_moto_go{P1_4=1,P1_5=0,P1_6=1,P1_7=0;}右边两个电机正转(智能小车右半部分前进)#defineRight_moto_back{P1_4=0,P1_5=1,P1_6=0,P1_7=1;}右边两个电机反转(智能小车右半部分后退)#defineRight_moto_Stop{P1_4=0,P1_5=0,P1_6=0,P1_7=0;}右边两个电机停转(智能小车右半部分停止)如此一来就不难给出智能小车的4个基本运动函数的流程及代码:1)流程:图22小车基本运动流程图2)代码:全速前进:voidrun(void){ Left_moto_go; Right_moto_go;}全速后退:voidbackrun(void){ Left_moto_back; Right_moto_back;}左转:voidleftrun(void){ Left_moto_back; Right_moto_go;}右转:voidrightrun(void){ Left_moto_go; Right_moto_back;}若要让小车完成某个动作,只需在主函数MAIN中循环调用相应的运动子函数即可,比如让小车全速前进可实现如下: voidmain(void){ while(1) { run(); }}2.小车PWM运行程序设计:PWM运行,简而言之就是通过让电机一转一停,调整转停比来控制小车速度的运行方式。通过前面的介绍可以知道可以通过向L298N芯片的ENA、ENB端输入PWM信号来实现,缺点是会占用单片机的I/O口。另一种方法是直接向IN端输出PWM的方法,比如结合前面的单片机I/O输出与电机运行状态关系表,驱动端IN1=1IN2=0时全速前进IN1=1,IN2=1时电机刹停,由此可以看出先使小车处于某个运行状态,然后给4个电机的其中一端输入一个PWM信号,小车就会按照占空比由于左右转向无需以PMW方式运行,与之前基本运动程序一样,所以该部分程序主要针对小车的前进与后退进行设计,其均可分为三个部分:前进/后退函数;左右电机调速函数;定时器0中断函数,具体如下:前进/后退函数:1)流程:图23小车PWM运行中前进/后退函数流程2)代码:前进:voidrun(void){push_val_left=7; //占空比调节变量0-9。。。9最小,0最大 push_val_right=7; Left_moto_go; Right_moto_go;}后退:voidbackrun(void){push_val_left=3; //占空比调节变量0-9。。。0最小,9最大 push_val_right=3; Left_moto_back; Right_moto_back;}该函数的功能主要是确定小车的当前运行进本状态,类似于初始化函数,不循环调用,旨在给后面的PWM运行函数做运行前准备工作。左右电机调速函数:1)流程:图24左右电机调速函数流程2)代码:左电机调速: voidpwm_out_left_moto(void){if(Left_moto_stop)//左侧电机起停变量{if(pwm_val_left<=push_val_left) { Left_moto_pwm=1;//左前电机PWM输入变量,等同于P1.1 Left_moto_pwm1=1;//左后电机PWM输入变量,等同于P1.3 } else { Left_moto_pwm=0; Left_moto_pwm1=0; } if(pwm_val_left>=10) pwm_val_left=0;}else{Left_moto_pwm=0;Left_moto_pwm1=0; }}右电机调速:voidpwm_out_right_moto(void){if(Right_moto_stop)//右侧电机起停变量{if(pwm_val_right<=push_val_right) { Right_moto_pwm=1;//右前电机PWM输入变量,等同于P1.5 Right_moto_pwm1=1;//右后电机PWM输入变量,等同于P1.7 } else { Right_moto_pwm=0; Right_moto_pwm1=0; } if(pwm_val_right>=10) pwm_val_right=0;}else{Right_moto_pwm=0;Right_moto_pwm1=0; }}该函数负责给4个电机一端按照预设占空比进行PWM信号输出。定时器0中断函数:1)流程:图25定时器0中断函数流程 2)代码: voidtimer0()interrupt1using2{TH0=0XFc; //1Ms定时 TL0=0X18; time++; pwm_val_left++; pwm_val_right++; pwm_out_left_moto(); pwm_out_right_moto();} 该中断函数负责PWM信号输出所需的时间控制。使用以上3个子函数便可完成小车前进与后退的PWM运行,通过占空比变量的不同取值可以调整小车的运行速度。这里需要注意的是,在本设计中,前进时占空比变量越大,则小车向前跑的越慢,后退时则相反;运行停止变量在小车前进时只能起到预备停止的作用,若要使小车完全停止需在一开始调用停止函数,而在后退时则可以仅通过停止变量使小车停止。下面以小车PWM前进为例看看以上几个子程序是如何协调工作的。 voidmain(void){ TMOD=0X01; TH0=0XFc; //1ms定时 TL0=0X18; TR0=1; ET0=1; EA=1;run(); //PWM,调速前进 while(1) /*无限循环*/ { }}3.小车循迹程序设计:所谓小车循迹,就是让小车自行顺着预先设置好运动轨迹前进,效果好像小车自己跟人一样能够看到预设路线似的,但实际上有一部分小车是和人一样用“眼”看,而另一部分小车则是像蝙蝠一样用其它感官去“看”。上面提到的“眼”实际就是摄像头,俗称电子眼,通常使用的是CCD光学传感器件;其它感官则如我们前面提到的四路红外探测系统。电子眼的优点是定位精确,但后续数据处理工作量较为庞大,为保持实时性,需要配套类似于DSP等高速运算型MCU,整体成本较高,所以只应用于对精度有特殊要求的领域;四路红外探测系统在精度上无法和电子眼相提并论,但贵在其后续数据处理简单,51系列单片机就可以轻松胜任,整体成本低,能够胜任于一般精度要求的系统。在本设计中循迹过程中的“眼”采用的就是四路红外探测系统,有关该系统的原理前面已经做了详细介绍,下面主要进行小车循迹部分的程序设计。按照惯例,在做程序设计之前首先要将硬件部分连接确定下来。完成循迹功能首先要使小车具备运动能力,这部分仍按照之前的接法,不用PWM运行方式,除此之外就是四路红外探测系统了,这部分的接法如下(参照图1、9、13、14):四路寻迹传感器电源+5VGND取自于单片机板靠近液晶调节对比度的电源输出接口;P3_2接四路寻迹模块接口第一路输出信号即中控板上面标记为OUT1;P3_3接四路寻迹模块接口第二路输出信号即中控板上面标记为OUT2;P3_4接四路寻迹模块接口第三路输出信号即中控板上面标记为OUT3;P3_5接四路寻迹模块接口第四路输出信号即中控板上面标记为OUT4。按照前面对四路红外探测系统原理的分析,当某个探头遇白线时输出信号为0,遇黑线时输出信号为1。下面对关键的几个接口做如下宏定义,方便程序编写,四个探头至左向右分别命名为Left_1_led、Left_2_led、Right_1_led、Right_2_led。宏定义描述#defineLeft_1_ledP3_4P3_4接四路寻迹模块接口第一路输出信号即中控板上面标记为OUT1#defineLeft_2_ledP3_5P3_5接四路寻迹模块接口第二路输出信号即中控板上面标记为OUT2#defineRight_1_ledP3_6P3_6接四路寻迹模块接口第三路输出信号即中控板上面标记为OUT3#defineRight_2_ledP3_7P3_7接四路寻迹模块接口第四路输出信号即中控板上面标记为OUT4这里需要说明的是,一般完成循迹只需要两个与小车中轴线左右对称的探头即可,若轨迹线的宽度较小则选择使用内侧两个探头,反之选择外侧两个探头,轨迹线的最大宽度应限制在最外侧两个探头之间,否则无法完成循迹。不管使用那两个探头,剩下的两个探头均可换成向前突出型的,可用于避障,不过目前还是采用超声波避障更为方便,所以在这里不就此作过多的介绍。1)流程:图26小车循迹子函数流程2)代码:voidTracking(void){ if(Left_2_led==0&&Right_1_led==0) run(); else { if(Right_1_led==1&&Left_2_led==0) //右边检测到黑线 { Rightrun() } if(Left_2_led==1&&Right_1_led==0) //左边检测到黑线 { Leftrun(); } }}以上便是几个小车循迹的关键函数,若要真正实现功能,需包含头文件、宏定义、全局变量定义等形成完整可编译程序。小车循迹完整代码:#include<AT89x51.H>#defineLeft_1_ledP3_4 //P3_4接四路寻迹模块接口第一路输出信号即中控板上面标记为OUT1#defineLeft_2_ledP3_5 //P3_5接四路寻迹模块接口第二路输出信号即中控板上面标记为OUT2 #defineRight_1_ledP3_6 //P3_6接四路寻迹模块接口第三路输出信号即中控板上面标记为OUT3#defineRight_2_ledP3_7 //P3_7接四路寻迹模块接口第四路输出信号即中控板上面标记为OUT4#defineLeft_moto_go{P1_0=1,P1_1=0,P1_2=1,P1_3=0;}//左边两个电机向前走#defineLeft_moto_back{P1_0=0,P1_1=1,P1_2=0,P1_3=1;} //左边两个电机向后转#defineLeft_moto_Stop{P1_0=0,P1_1=0,P1_2=0,P1_3=0;}//左边两个电机停转#defineRight_moto_go{P1_4=1,P1_5=0,P1_6=1,P1_7=0;} //右边两个电机向前走#defineRight_moto_back{P1_4=0,P1_5=1,P1_6=0,P1_7=1;} //右边两个电机向前走#defineRight_moto_Stop{P1_4=0,P1_5=0,P1_6=0,P1_7=0;} //右边两个电机停转unsignedcharpwm_val_left=0;unsignedcharpush_val_left=1;//左电机占空比10/40unsignedcharpwm_val_right=0;unsignedcharpush_val_right=1;//右电机占空比10/40bitRight_moto_stop=1;bitLeft_moto_stop=1;/************************************************************************/ //延时函数 voiddelay(unsignedintk){ unsignedintx,y; for(x=0;x<k;x++) for(y=0;y<2000;y++);}/************************************************************************///前速前进voidrun(void){ Left_moto_go; Right_moto_go;}/************************************************************************///左转voidLeftrun(void){ Left_moto_back;//左电机往前走 Right_moto_go;//右电机往前走}/************************************************************************///右转voidRightrun(void){ Left_moto_go;//左电机往前走 Right_moto_back;//右电机往前走}/************************************************************************///循迹函数voidTracking(void){ if(Left_2_led==0&&Right_1_led==0) run(); else { if(Right_1_led==1&&Left_2_led==0) //右边检测到黑线 { Rightrun(); } if(Left_2_led==1&&Right_1_led==0) //左边检测到黑线 { Leftrun(); } }}/*********************************************************************/ /*--主函数--*/voidmain(void){ delay(100); //延时一段时间 run(); while(1) /*无限循环*/ { Tracking(); }}4.小车避障程序设计:所谓小车壁障,是指小车在有些许障碍无的区域内行进时时能够自行避开障碍,选择合适路线前进。若想实现此功能,用于测量距离的传感器必不可少,这里我们选用前面介绍的US-100型超声波测距模块。在安装方式上有以下两种:1)将此模块直接固定在小车车身上。这种安装方式只能使小车检测到相对于小车车身某个固定方向(取决于测距模块的朝向)的障碍物,小车可以据此调整行进方向,但是对于下一方向上是否仍有障碍物预先是不知道的,若区域障碍物布局较为复杂,则小车容易陷入原地循环转向的状态,使前进效率减低甚至无法前进,为避免此情况的发生,必须在程序运行过程中记录小车的运行轨迹,然后据此估算出没有障碍物的方向,所以程序设计较为复杂,无法根本解决效率低的问题,同时整个避障过程看起来比较“傻”。2)将此模块通过舵机固定在小车车身上。这种安装方式最大的好处就是在小车自身不改变方向的前提下,可以检测到以小车车身为圆心某个角度扇形范围(根据舵机型号的不同,一般为180度到360度)内的所有障碍物,小车可据此直接选择转向到无障碍物的方向继续前进,程序设计起来也较为方便,小车前进效率高,整个避障过程显得比较“智能”。由此,我们按照第二种安装方式进行程序设计。这里我们只取正前、正左、正右三个方向的检测结果。舵机控制程序设计:关于舵机的控制及工作原理前面已经做过详细介绍,连接上由单片机的P2.7口连接舵机的PWM控制信号输入端。程序方面可分为舵机控制,用于控制舵机旋转到设定角度;定时器中断部分,用于提供控制舵机所需的精确单位时间参考两个部分。舵机控制函数:1)流程:图27舵机控制函数流程2)代码:voidpwm_Servomoto(void){if(pwm_val_left<=push_val_left) Sevro_moto_pwm=1; else Sevro_moto_pwm=0; if(pwm_val_left>=200) pwm_val_left=0;}其中push_val_left为全局变量,用于设定舵机旋转角度,在本设计中一个时间单位为100us,所以5为0度(右转满),14为90度(归中),23为180度(左转满);pwm_val_left为单位时间计数变量;Sevro_moto_pwm为单片机P2.7关键新命名。定时器中断函数:1)流程:图28定时器中断函数流程这里的单位时间计数变量除了用于舵机角度控制的以外,还包括其他设备所需的变量,并不是唯一的,该函数的主要目的是提供一个100US的时间单位。2)代码:voidtime1()interrupt3using2{ TH1=(65536-100)/256; //100US定时 TL1=(65536-100)%256; //定时器100US为准。在这个基础上延时 pwm_val_left++;//此处加入其它所需计数变量 pwm_Servomoto();}若要实现舵机控制,除了用到以上两个函数外,还需要预先设定角度变量push_val_left,初始化定时器,打开中断等。下面以舵机归中为例来解释其具体用法,其他角度只是push_val_left变量赋值不同,具体数值与角度对应关系参看前面关于舵机介绍部分。舵机归中:voidmain(void){ TMOD=0X11; TH1=(65536-100)/256; //100US定时 TL1=(65536-100)%256; TH0=0; TL0=0; TR1=1; ET1=1; ET0=1; EA=1;push_val_left=14; //舵机归中while(timer<=4000); timer=0;}注意程序中加粗的部分:1)归中所需计数值14;2)timer是新加入的全局变量,添加到前面定时器中断函数中加粗部分,和pwm_val_left一起计数,作用是延迟足够的时间使舵机转到位;3)4000这个数值可延迟400MS,可根据实际情况进行增减。超声波测距程序设计:参考前面关于US-100型超声波测距模块的介绍,并将模块的ECHO端与单片机P2.4相连、TRIG端与单片机P2.5相连,则该部分流程及代码如下:1)流程:图29超声波测距流程2)代码:voidStartModule_Conut(void) { //启动测距信号TRIG=1; _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_(); _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_(); _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_(); TRIG=0;//计算距离 while(!ECHO); //当RX为零时等待 TR0=1; //开启计数 while(ECHO); //当RX为1计数并等待 TR0=0; //关闭计数 time=TH0*256+TL0; //读取脉宽长度 TH0=0; TL0=0; S=(time*1.7)/100;//算出来是CM disbuff[0]=S%1000/100;//更新显示 disbuff[1]=S%1000%100/10; disbuff[2]=S%1000%10%10;}其中S为全局变量,用来存储当前测得前方障碍物距离;disbuff[]为全局数组,用来存放用于显示距离的数据。小车避障函数设计:有了舵机以及超声波测距模块的程序,再结合前面小车基本运动程序就可以实现小城避障了,具体流程及代码如下:1)流程:图30小车避障程序流程2)代码:voidObs_Avoidance(void){ if(timer>=1000) //100MS检测启动检测一次 { timer=0; StartModule_Conut();//启动检测,计算距离 if(S<20) //距离小于20CM { stoprun(); //小车停止 push_val_left=5; //舵机向左转90度 timer=0; while(timer<=4000);//延时400MS让舵机转到其位置 StartModule_Conut();//启动检测,计算距离 S2=S; push_val_left=23; //舵机向右转90度 timer=0; while(timer<=4000);//延时400MS让舵机转到其位置 StartModule_Conut();//启动检测,计算距离 S4=S; push_val_left=14; //舵机归中 timer=0; while(timer<=4000);//延时400MS让舵机转到其位置 if((S2<20)||(S4<20))//只要左右各有距离小于,20CM小车后退 { backrun(); //后退 timer=0; while(timer<=4000); } if(S2>S4) { rightrun(); //车的左边比车的右边距离小 右转 timer=0; while(timer<=4000); } else { leftrun(); //车的左边比车的右边距离大 左转 timer=0; while(timer<=4000); } } else if(S>30) //距离大于,30CM往前走 run(); }}以上便是几个小车避障的关键函数,若要真正实现功能,需包含头文件、宏定义、全局变量定义等形成完整可编译程序。下面的代码包含实时测距结果数码管显示功能。小车避障完整程序代码:#include<AT89x51.H>#include<intrins.h>#defineSevro_moto_pwmP2_7 //接舵机信号端输入PWM信号调节速度#defineECHOP2_4 //超声波接口定义#defineTRIGP2_5 //超声波接口定义#defineLeft_moto_go{P1_0=1,P1_1=0,P1_2=1,P1_3=0;}//左边两个电机向前走#defineLeft_moto_back{P1_0=0,P1_1=1,P1_2=0,P1_3=1;} //左边两个电机向后转#defineLeft_moto_Stop{P1_0=0,P1_1=0,P1_2=0,P1_3=0;}//左边两个电机停转#defineRight_moto_go{P1_4=1,P1_5=0,P1_6=1,P1_7=0;} //右边两个电机向前走#defineRight_moto_back{P1_4=0,P1_5=1,P1_6=0,P1_7=1;} //右边两个电机向前走#defineRight_moto_Stop{P1_4=0,P1_5=0,P1_6=0,P1_7=0;} //右边两个电机停转unsignedcharconstdiscode[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xBF,0xff/*-*/};unsignedcharconstpositon[3]={0xfe,0xfd,0xfb};unsignedchardisbuff[4] ={0,0,0,0,};unsignedcharposit=0;unsignedcharpwm_val_left=0;//变量定义unsignedcharpush_val_left=14;//舵机归中,产生约,1.5MS信号unsignedlongS=0;unsignedlongS1=0;unsignedlongS2=0;unsignedlongS3=0;unsignedlongS4=0;unsignedinttime=0; //时间变量unsignedinttimer=0; //延时基准变量unsignedchartimer1=0; //扫描时间变量 /************************************************************************/voiddelay(unsignedintk) //延时函数{ unsignedintx,y; for(x=0;x<k;x++) for(y=0;y<2000;y++);}/************************************************************************/voidDisplay(void) //扫描数码管{ if(posit==0) {P0=(discode[disbuff[posit]])&0x7f;}//产生点 else {P0=discode[disbuff[posit]];} if(posit==0) {P2_1=0;P2_2=1;P2_3=1;} if(posit==1) {P2_1=1;P2_2=0;P2_3=1;} if(posit==2) {P2_1=1;P2_2=1;P2_3=0;} if(++posit>=3) posit=0; }/************************************************************************/voidStartModule_Conut(void) { //启动测距信号 TRIG=1; _nop_();_nop_();_nop_(); _nop_();_nop_();_nop_(); _nop_();_nop_();_nop_(); _nop_();_nop_();_nop_(); _nop_();_nop_();_nop_(); _nop_();_nop_();_nop_(); _nop_();_nop_();_nop_(); TRIG=0; //计算距离 while(!ECHO); //当RX为零时等待 TR0=1; //开启计数 while(ECHO); //当RX为1计数并等待 TR0=0; //关闭计数 time=TH0*256+TL0; //读取脉宽长度 TH0=0; TL0=0; S=(time*1.7)/100;//算出来是CM disbuff[0]=S%1000/100;//更新显示 disbuff[1]=S%1000%100/10; disbuff[2]=S%1000%10%10;}/************************************************************************///前速前进voidrun(void){ Left_moto_go;//左电机往前走

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论