基于51单片机压力检测系统设计毕业设计


     学号: xx 大 学 毕业设计(论文) (xxxx届) 题 目 基于51单片机的压力检测系统设计 学 生 学 院 专业班级 校内指导教师 专业技术职务 校外指导老师 专业技术职务 二〇xxx年X月 基于51单片机的压力检测系统设计 摘 要:本设计借助压力传感器将压力信号转换成电信号,经过信号放大,使用高精度A/D转换器件,将模拟信号转换成数字信号,再经单片机运算处理转换成LCD液晶可以识别的信息,最后显示输出。初始化后可以重设阈值,系统能够实现手动存储八个以内的数据,并可以查询历史记录,对存储的数据进行统计分析,并且在实时压力检测的过程中,预警电路一直监视系统的运行。 本设计根据压力传感器零点补偿与非线性补偿原理,设计出了测量压力传感器的硬件电路。采用单片机设计实现,具有精度高、功能强等特点。但是由于自身的稳定性其测量结果仍存在误差。本课题设计的压力检测系统具有压力测量、超重报警、压力存储及历史数据查阅和压力值数据的统计分析。该系统的压力检测范围为0-10Kg,测量精度可以达到10g,具有高精度,低成本,易携带的特点。采用LCD12864液晶显示测量结果,比传统压力检测系统的精确度更高和直观性更好。另外,该系统电路简单,成本低,使用寿命长,应用范围广等优点。 关键词:压力传感器;A/D转换器;LCD12864 Design of pressure detection system based on MCU 51 Abstract:Using pressure sensor converts the pressure signal into electrical signal, after amplification, using high precision A/D conversion device that converts analog signals into digital signals in this design, then through single chip microcomputer processing into the information that LCD can identify, at last displaying and outputting information. After initialization the system can reset the threshold, achieve storing within eight data manually, and can query the history records, the statistic analysis the stored data and in the process of real-time pressure detection, early warning circuit has been monitoring the operation of the system. This paper according to the principle of zero compensation and nonlinear compensation for pressure sensor, designing measuring pressure sensor hardware. Single-chip implementation has the characteristics of high precision, strong function. Because of its stability errors still exist in the measurement. The topic functions for pressure detection system are overweight alarm, storage, statistical analysis of historical data access and pressure value. The measurement range of the system is from 0 to 10 kg, measurement accuracy can reach to 10 g. It has the advantage of high precision, low cost, easy to carry. Measurement results display with LCD 12864 , Contrast to the traditional pressure test system, it has higher accuracy and intuitive. In addition, the system circuit is simple, low cost, long service life and wide scope of application. Key words:Pressure sensor; A/D converter; LCD12864 目 录 摘 要 I Abstract II 目 录 III 1 引言 1 1.1 研究背景及意义 1 1.2 压力检测系统的研究现状 1 1.3 课题任务 2 2 系统分析与总体方案设计 3 2.1 压力检测系统的整体设计 3 2.2 压力检测系统的设计方案 3 2.2.1 实时压力测量显示方案 4 2.2.2 实时压力监控预警方案 4 3 系统硬件电路设计 5 3.1 单片机系统 5 3.1.1 单片机选型 5 3.1.2 单片机晶振电路和复位电路 7 3.2 数据采集模块 8 3.2.1 压力传感器 9 3.2.2 信号放大电路 10 3.2.3 A/D模数转换 11 3.3 人机交互模块 15 3.3.1 液晶显示单元 15 3.3.2 矩阵键盘单元 17 3.4 声光报警模块 18 3.5 电源供电模块 18 4 软件程序设计 20 4.1 软件开发环境 20 4.2 I/O端口分配 21 4.3 软件主程序构架 22 4.4 主要功能子程序的设计 23 4.4.1 A/D子程序设计 24 4.4.2 中断子程序设计 25 4.4.3 查询历史数据子程序设计 25 4.4.4 数据统计分析子程序设计 26 4.4.5 阈值重设子程序设计 27 4.4.6 人机交互子程序设计 28 5 系统调试 33 5.1 数据采集调试 33 5.2 数据统计分析调试 33 5.3 声光报警调试 34 5.4 软件调试 34 5.5 实物展示 34 6 结束语 39 参 考 文 献 40 致 谢 41 附 录 A 42 附 录 B 44 1 引言 1.1 研究背景及意义 近年来,微型计算机越来越普遍地应用于人们的日常工作、生活中。计算机的使用在工业过程控制生产中是一个重要环节。人们越来越关注由单片机构成的嵌入式系统。可以毫不夸张的说,高端先进仪器是其构造中含有微型计算机系统,微型计算机控制系统的产生促使现代控制系统时代的到来。 在这信息高速发展的时代,传感器检测系统的发展有两个及其重要的方向,分别为智能化与集成化。而传感器检测系统智能化和集成化的程度主要取决于系统内部微处理器的性能[1]。当前国内外开发和研究的热点是具有数据处理能力,能够进行自动检测、自动校准、自动误差补偿、自动抽样、以及标度变换功能的智能压力传感器检测系统。传感器技术是现代测量和自动化技术的重要技术之一。 压力测量在工业安全生产的实时监测中具有重要的意义。为了确保工业制造过程中的高效与安全,必须精确地控制生产过程中的一些诸如压力、流量、温度等主要参数。其中良好的控制压力,可以保障生产过程中的安全,因此准确地测量压力显得尤为重要。压力是生产过程中四大重要参数之一,实时检测压力可以判断生产过程中机器是否安全可靠的运行[2]。如:确保密闭容器内的压力在安全指标范围以内,确保易燃易爆介质的压力不超标。 压力的检测在其他工业生产环节中对于控制生产的正常运行也非常重要。在一些工业装置上都时常可以见到有压力表,实时的监测压力大小,如若失常则报警,很好的保证了生产的安全运作。通过测取压力的大小也可以知晓液面的高度。 总而言之,为了保证生产的正常运行,必须按照工艺要求保持稳定的压力,所以准确测量压力在实际过程是非常重要的。 1.2 压力检测系统的研究现状 压力检测系统靠的就是压力传感器去采集压力信号。传感器从探索宇宙到海洋的开发,从生产过程的控制到现代科技文明中都有使用,使用面几乎涵盖了任何一项现代科技产物。世界上很多国家十分重视发展传感器技术,传感器技术可以应用在工业、农业、国防、科技等各个领域,有着极其广阔的前景。例如,在日本传感器技术被列为六大核心技术之一,其他五项核心技术为通信、激光、半导体、超导和计算机。并且日本还将传感器列为六大技术之首;美国将上世纪90年代看作是传感器时代,将传感器技术列为90年代22项关键技术之一。我国在传感器的研究上也已经有二十多年的历史并取得了很大的成就。21世纪提出了科学技术就是第一生产力的口号,各项科学技术在这一浪潮下取得了突飞猛进的发展和进步,传感器技术也越来越受到各方面的重视,虽然在某些领域我国已赶上或者接近世界先进水平。但是从总体来看,我国在传感器技术的研究和生产还落后于国外传感器技术,如今正处于方兴未艾的阶段。由于智能传感器系统的研究起步较晚,各方面理论缺乏和实践不够,离实际应用需求还有很大差距,尤其是用于压力测量的压力传感器。如何生产高性能、小体积、低成本的智能压力传感器系统还需进一步开发和研究。因此,研究开发高性能的智能压力传感器系统有利于促进信息技术及自动化技术的发展,对提高设备性能及自动化水平具有重要意义。 压力的实时检测和控制能够保证生产设备的安全运行。压力传感器是工业仪器、仪表控制中最为常用的一种传感器,广泛地应用在各种工业生产环境中,涉及众多行业。通过压力传感器将被测物体的压力信号转化为电信号,再经过放大器进行信号放大,送至24位A/D转换器,然后将模拟信号转换成单片机可以识别的数字信号,再经单片机转换成LCD显示器可以识别的信息,最后显示输出。 1.3 课题任务 该设计能够实现压力检测系统的智能检测,如实时压力测量、手动存储压力值、压力预警、数据统计分析等。该课题以STC89C51RC单片机为控制核心,配合电阻应变式压力传感器、A/D模数转换芯片HX711、12864液晶显示等外围器件,对压力检测系统进行控制与数据采集。LCD液晶设备显示压力值的测量结果及数据统计分析结果等,配合蜂鸣器和LED二极管进行声光报警。压力传感器采集被测物体的压力信号,传输给单片机进行分析处理。另外系统配有键盘,可以实现手动存储、预警值设定、系统复位,数据统计分析的有关功能。 2 系统分析与总体方案设计 2.1 压力检测系统的整体设计 压力检测系统装置主要由五个模块组成: 1、数据采集模块。该模块的作用是将检测到的模拟信号转换成为数字信号,经电平保护后输出到数据处理部分。 2、信号处理模块。用单片机作为信息处理单元,实现对数据的采样及数据分析运 算,并发出控制指令。 3、人机交互模块。由4*3矩阵键盘及液晶显示单元组成。通过4*3矩阵键盘对单片机下达指令实现对系统的控制;显示采用12864液晶模块,可以提供丰富、直观、友好的信息界面。 4、声光报警模块。当报警程序启动时,蜂鸣器发出声音、发光二极管点亮。 5、电源供电模块。系统通过USB电源供电,单片机程序也可通过USB线串行下载。借助按键开关操作可控制电源的通断,实现系统的良性运作。通电后电源指示灯点亮。 压力检测系统框图如图2.1所示: 图2.1 压力检测系统框图 2.2 压力检测系统的设计方案 实时压力测量和实时压力监控预警是压力检测系统装置的最重要两个部分,它是实现其他功能的基本条件,这两部分性能的好坏将关系到整个系统的性能,所以设计一个成本低、可靠性高、测量精度高、安装调试方便的压力检测系统是该设计的关键。 2.2.1 实时压力测量显示方案 本装置中系统压力的检测,采用量程为10kg的高精度电阻应变式压力传感器,将压力信号转换为模拟信号,再传送给A/D模数转换芯片HX711。输出数字信号给单片机进行处理分析。压力传感器在每次单片机复位后自动校准归零。再放上物体进行压力测量,显示器可以实时显示当前所测物体的质量,并且用户可以根据需要将压力值进行手动存储,然后通过按键查询所存储的历史数据。 2.2.2 实时压力监控预警方案 为了实时监控压力大小,预先在程序中设定阈值为9.999kg,系统开启后默认的阈值即为9.999kg。用户可以根据需要通过按键操作,在0.000~9.999kg区间内修改阈值大小。然后按确认键即可完成阈值重设的操作。放置被测物体在压力托盘上,当压力超过所设定的压力值时,系统报警,LED灯点亮,蜂鸣器发出声音。被测物体的压力,经过传感器变为模拟信号,再经模数转换芯片HX711转换为数字信号。输出给单片机,然后运算处理,判断检测到的压力和阈值,如若该压力大于阈值,则系统将显示出此时压力值,并发出报警提示;小于则在液晶上正常显示当前压力值。 3 系统硬件电路设计 3.1 单片机系统 单片机是集成在一块芯片上的完整计算机系统。单片机很多功能集成在一块小芯片上,它具有一个完整计算机所需要的大部分组件:外部总线系统、内存和CPU同时集成实时时钟通讯接口、定时器和实时时钟等外围设备。单片机也称作单片微电脑或单片微型计算机,它是把中央处理器(CPU)、随机存取存储器(RAM)、只读存储器(ROM)、输入/输出端口(I/O)等主要计算机功能部件集成在一块集成电路芯片上的微型计算机。 3.1.1 单片机选型 世界上各大芯片制造公司都推出了自己的单片机,从8位到16位再到32位,数不胜数,应有尽有,有很多与主流C51系列兼容的,也有不兼容的,但它们各具特色,相辅相成,为单片机的应用提供广阔的天地。 自从上世纪80年代初Intel公司推出MCS-51系列单片机以后,全球诸多著名的半导体厂商相继生产与51系列兼容的单片机,使得单片机型号不断增加,功能不断增强,品种不断丰富[3]。本系统采用STC89C51RC作为核心单片机系统,STC89C51RC是一种高性能、低功耗8位微控制器。引脚图如下图3.1所示。 图3.1 单片机引脚图 单片机各引脚介绍: l I/O口引脚P0(第32脚~39脚):双向8位三态I/O口。当接外部存储器时,总线复用,不仅可以作为数据总线,也可作为地址总线的低8位。 l I/O口引脚P1(第1脚~8脚):8位准双向I/O口。由于此端口没有高阻态,所以无法输入进行锁存,所以并不是真正意义上的双向I/O。 l I/O口引脚P2(第21脚~28脚):8位准双向I/O口。当使用外部存储器时,总线复用,不仅可以作为数据总线,也可作为地址总线的高8位。 l I/O口引脚P3(第10脚~17脚):8位准双向I/O口。P3口不仅可以作为一般的数据总线使用,这8个引脚还有各自的特殊功能,属于复用双功能口。作为第二功能使用时,各引脚的定义如表3.1所示,值得强调的是,P3口每一条引脚均可独立定义为第一功能的输入输出或第二功能。 表3.1 P3口第二功能表 引脚 特殊功能 P3.0 RXD(串行输入端) P3.1 TXD(并行输入端) P3.2 INT0(外部中断0) P3.3 INT1(外部中断1) P3.4 T0(定时器/计数器0输入端) P3.5 T1(定时器/计数器1输入端) P3.6 WR(外部数据存储器写选通信号输出端) P3.7 RD(外部数据存储器读选通信号输出端) l 电源引脚Vcc(第40脚):接+5V电压。 l 电源引脚Vss(第20脚):接地。 l 外部晶振引脚XTAL1与XTAL2(第19脚,18脚):接外部晶振时,将振荡信号输入给单片机内部的时钟发生器。 l EA(第31脚):当EA为低电平时,不管内部是否有程序存储器(8031型号单片机没有内部存储器),单片机只访问外部程序存储器。当EA为高电平时,先访问内部程序存储器,当寻址地址超过容量时,自动访问外部程序存储器。 l PSEN(第29脚):当从外部程序存储器读取指令时,每个机器周期内PSEN两次有效,时外部程序存储器的读选通信号。 l ALE(第30脚):当不访问外部存储器时,ALE引脚周期性的输入正脉冲信号,可以作为对外输出的时钟,频率为振荡器频率的1/6。当访问外部存储器时,ALE用于地址低位字节的锁存。 l RST(第9脚):当RST上出项两个机器周期以上的高电平时,单片机将复位。 单片机STC89C51RC内部ROM空间大小为4K,地址范围从0000H到0FFFH。RAM空间大小为128字节,地址范围从00H到FFH。地址80H到FFH为特殊功能寄存器区,用于计数器/定时器,串行通信,累加器以及一些特殊的控制寄存器。 3.1.2 单片机晶振电路和复位电路 (1)晶振电路 晶振是晶体振荡器的简称在电气上它可以等效成一个电容和一个电阻并联再串联一个电容的二端网络。晶振用一种能把电能和机械能相互转化的晶体在共振的状态下工作,给单片机提供工作所需要的时钟信号[4]。理论上来说,振荡频率越高表示单片机运行速度越快,但同时对存储器的速度和印刷电路板的要求也就越高。如同木桶原理。同时单片机性能的好坏,不仅与CPU运算速度有关,而且与存储器的速度、外设速度等都有很大关系。因此一般选用6~12MHZ。并联谐振电路对电容的值没有严格要求,但会影响振荡器的稳定、振荡器频率高低、起振快速性等。陶瓷封装电容可以进一步提高温度稳定性STC89C51RC内部有一个高增益反相放大器用于构成振荡器。 晶振有一个重要的参数,那就是负载电容值选择与负载电容值相等的并联电容就可以得到晶振标称的谐振频率。一般的晶振振荡电路都是在一个反相放大器的两端接入晶振,再有两个电容分别接到晶振的两端,每个电容的另一端再接到地。这两个电容串联的容量值就应该等于负载电容。 一般的晶振的负载电容为15pF或12.5pF, 如果再考虑元件引脚的等效输入电容,则两个22pF的电容构成晶振的振荡电路就是比较好的选择。 晶振与单片机的脚XTAL0和脚XTAL1构成的振荡电路中会产生偕波。这个波对电路的影响不大,但会降低电路的时钟振荡器的稳定性,为了电路的稳定性起见。 ATMEL公司只是建议在晶振的两引脚处接入两个10pf-50pf的瓷片电容接地来削减偕波对电路的稳定性的影响,所以晶振所配的电容在10pf-50pf之间都可以的。本系统采用了12 MHZ的晶振。 图3.2 单片机时钟原理图 (2)复位电路 单片机的复位电路有两种,上电自动复位方式以及手动复位方式。本系统已具备电源开关键,可以使用上电自动复位方式。复位是单片机的初始化操作。其主要功能使单片机从0000H单元开始执行程序。51单片机是高电平复 位,给单片机加5V电源(上电)启动时的情况:这时电容充电相当于短路(电容特性:通交流,隔直流,上电瞬间相当于交流),可以认为RST上的电压就是VCC,这是单片机就是复位状态。随着时间推移电容两端电压升高,即造成RST上的电压降低,当低至阈值电压时,即完成复位过程。外部复位电路是为提供两个机器周期以上的高电平而设计的。RST脚上只要保持10ms以上高电平,系统就会有效复位。电容C1可取10~33μF,R取10kΩ,充电时间常数为10×10-6×10×103=100ms。其电路如图3.3所示: 图3.3 单片机复位原理图 电容的作用就是缓冲使RST端保持高电平一段时间,以达到有效复位,电容越大,保持的时间就越久。单片机的复位需要至少持续两个机器周期以上的高电平的时间,所以在刚开始上电的时候图3.3中的电容C1 充电,所以在单片机的复位引脚RST上会出现大于2个机器周期的高电平,使单片机复位。 3.2 数据采集模块 使用型号为CZL-A、量程为10kg的电阻应变式压力传感器,对被测物体进行压力采集并将其转换成电压信号,输出电压信号通常很小,此时需要利用HX711转换模块中的可编程放大器进行放大。放大后的模拟电压信号经24位A/D转换芯片HX711电路转换成数字量,通过2线串行方式与单片机通信,即可完成数据的采集工作。数字采集模块原理图如图3.4所示。 图3.4数据采集模块图 3.2.1 压力传感器 (1)压力传感器的选择 在本设计中,我们需要使用压力传感器来对物品重量进行测量。压力传感器在压力检测系统中是一个重要的元件,因此,在选择压力传感器时需要考虑其量程和参数,还要考虑它的性价比和兼容性等等。由压力传感器将所测压力信号转换成容易测量的电信号输出,经过A/D转换及单片机处理后传送给液晶显示压力值,或供报警使用。压力传感器的种类有很多,比如应变式传感器,电容式压力传感器、压电传感器,谐振式压力传感器直接位移式传感器或是利用磁弹性、压阻等物理效应的传感器。 压电传感器是利用某些电介质受力后产生的压电效应制成的传感器[5]。但压电传感器只能用于动态测量。由于外力作用在压电元件上产生的电荷只有在无泄漏的情况下才能保存,即需要测量回路具有无限大的输入阻抗,这实际上是不可能的,因此压电式传感器不能用于静态测量。压电传感器主要应用在加速度、压力和力等的测量中。 电阻应变式传感器具有悠久的历史。电阻应变式传感器具有金属的应变效应,即如果有外力存在,那么金属会发生微弱的形变,从而改变其电阻值。它具有结构简单,精度高,易于实现小型化等特点,因此是目前应用最广泛的传感器之一。对于大应变有较大的非线性的输出信号较弱,但可以通过一些措施来补偿。 电阻应变片把机械应变信号转换为△R/R后,因为压力传感器在工作时应变片的形变量很小,导致电阻变化很微弱,测量得到的结果未必准确,并且由于结果数值很小,导致我们处理起来将会十分困难。因此,我们可以把测量结果经过某些电路将电阻变化或形变量转化为电信号,以此来提高测量效率和精确度[6]。此处通常选用测量电桥作为转换电路。 此处的测量电桥选用直流电桥,因为直流电桥抗干扰能力强,但是输出信号小,所以需要对转换的电信号通过高效的放大电路进行放大。R1、R2、R3和R4组成惠更斯电桥,将两对电阻应变片的阻值变化转变成输出电压,其工作原理如图3.5所示。 图3.5 测量电桥原理图 (2) 电阻应变式传感器测量原理 电阻应变式压力传感器主要由弹性元件、电阻应变片等组成。传感器内部线路采用惠更斯电桥,当弹性体承受载荷产生变形时,转换元件电阻应变片也会受到拉伸或变形,它的阻值将发生变化,从而使电桥失去平衡,产生相应的差动信号,供后续电路测量和处理。电 阻应变式传感器测量原理图如图3.6所示。 图3.6 电阻应变式传感器测量结构图 当外界施加一个垂直正压力P作用于金属横梁上时,横梁产生形变,电阻应变片R1、R3受压弯拉伸,阻值增加;R2、R4受压缩,阻值减小。电桥失去平衡,产生不平衡电压,不平衡电压与作用在传感器上的载菏P成正比,从而将非电量转化成电量输出[7]。 (3) 电阻应变片的基本结构 电阻应变式压力传感器是将所测物体压力的变化转换成电阻值的变化来进行测量的。应变片即是该型传感器的核心,它是由金属导体或半导体制成的电阻体,是一种将被测件上的应变的变化转换成为一种电信号的敏感器件。通常是将应变片通过特殊的方式使其紧密的粘合在应变基体上,当基体受力发生应力变化时,电阻应变片也跟着产生形变,应变片的阻值也改变,从而使加在电阻上的电压发生变化[7]。 电阻应变片主要由四部分组成。基本结构如图3.7所示,电阻丝是应变片敏感元件;基片、覆盖片起定位和保护电阻丝的作用,并使电阻丝和被测试件之间绝缘,引出线用以连接测量导线。 图 3.7电阻应变片的基本结构 3.2.2 信号放大电路 压力传感器的输出电压范围为0~20mV,而A/D转换的输入电压需要为0~2V,因此放大环节要有100倍左右的增益。对放大环节的要求是增益可调的(70~150倍),根据本设计的实际情况增益设为100倍即可。 由压力传感器的测量原理可知,电阻应变片组成的传感器是把机械应变转换成电阻的相对变化率ΔR/R,而应变电阻的变化一般都很微小,例如传感器的应变片电阻值200Ω,灵敏系数 K为3,弹性体在额定载荷作用下产生的应变为1000ε,则应变电阻相对变化率为: ΔR/R = K×ε= 3×1000×10-6 =0.003 (3-1) 由式3-1可以看出电阻变化ΔR只有0.6Ω,其电阻变化率只有0.3%。这么小的电阻变化既难以直接准确地测量,又不便直接处理。所以必须采用转换电路,把应变片的ΔR/R变化转换成电压或电流变化,但是这个电压或电流信号很小,需要增加增益放大电路来把这个电压或电流信号转换成可以被A/D转换芯片接收的信号。我们采用结合HX711芯片的放大电路,图3.8如下所示: 图3.8 HX711芯片放大电路 3.2.3 A/D模数转换 模拟量输入通道的任务是将模拟量转换成数字量。能够完成这一任务的器件称之为模数转换器,简称A/D转换器。本次设计中A/D转换器的任务是将放大器输出的模拟信号转换位数字量进行输出。 (1)A/D转换模块器件选择 目前许多类型的单片机内部已带有A/D转换电路,但此类单片机会比无A/D转换功能的单片机在价格上高出一些,为了节约成本,我们采用一个51单片机加上一个A/D转换器,实现模数转换的功能,A/D转换部分是整个设计的关键,这一部分处理不好,会使得整个设计毫无意义。目前,世界上有多种类型的A/D转换芯片,有传统的并行、串行、逐次逼近型、积分型ADC,也有近年来新发展起来的∑-Δ型和流水线型ADC,多种类型的ADC各有其优缺点并能满足不同的应用要求。 这里A/D转换芯片可选ADC0832、ADC0809、HX711等;A/D转换芯片种类很多,最常见的属于串行和并行接口模式,接口模式是选择器件的一项重要指标。在同样的转换分辨率和转换速度的下,不同的接口方式会对电路结构及采用周期产生影响。本次设计并没有选择常见的并行接口A/D转换器ADC0809或者串行接口A/D转换器ADC0832。根据系统的精度要求以及综合的分析比较,本设计采用了24位A/D转换器HX711,芯片封装如下图3.9所示。与同类型其它芯片相比,该芯片集成了包括稳压电源、片内时钟振荡器等其它同类型芯片所需要的外围电路,具有集成度高、响应速度快、抗干扰能力强等优点。降低了系统的整机成本,提高了整机的性能和可靠性。 图3.9 HX711封装图 (2)A/D转换芯片HX711的简介 HX711芯片采用了海芯科技集成电路专利技术,是一款专为高精度压力测量而设计的24 位A/D 转换器芯片。该芯片与单片机的接口电路设计和程序编写非常简单,所有控制信号由管脚驱动,无需对芯片内部的寄存器编程。输入选择开关可任意选取通道A 或通道B,与其内部的低噪声可编程放大器相连。通道A 的可编程增益为128 或64,对应的满额度差分输入信号电压值分别为±20mV或±40mV。通道B 则为固定的32 增益,用于系统参数检测。芯片内提供的稳压电源可以直接向外部传感器和芯片内的A/D 转换器提供电源,系统板上无需另外的模拟电源[8]。芯片内的时钟振荡器不需要任何外接器件。上电自动复位功能简化了开机的初始化过程。有关引脚说明如下表3.2所示: 表3.2 HX711引脚说明 管脚号 名称 性能 描述 1 VSUP 电源 稳压电路供电电源:2.6V~5.5V 2 BASE 模拟输出 稳压电路控制输出(不用稳压电路时为无连接) 3 AVDD 电源 模拟电源:2.6V~5.5V 4 VFB 模拟输入 稳压电路控制输入(不用稳压电路时为应接地) 5 AGND 地 模拟地 6 VBG 模拟输出 参考电源输出 7 INA- 模拟输入 通道A负输入端 8 INA+ 模拟输入 通道A正输入端 9 INB- 模拟输入 通道B负输入端 10 INB+ 模拟输入 通道B正输入端 11 PD_SCK 数字输入 断电控制(高电平有效)和串口时钟输入 12 DOUT 数字输出 串口数据输出 13 XO 数字输入输出 晶振输入(不用晶振时无连接) 14 XI 数字输入 外部时钟或晶振输入,0:使用片内振荡器 15 RATE 数字输入 输出数据速率控制,0:10HZ;1:80HZ 16 DVDD 电源 数字电源:2.6V~5.5V 正常情况下HX711与单片机的接口应为2条数据线,分别是PD_SCK、DOUT。它的结构示意图如图3.10所示。 图3.10 HX711内部方框图 芯片的串口通讯线由PD_SCK 和DOUT 两端口构成,用来输出数据,选择输入通道和增益。当数据输出管脚DOUT 为高电平时,表明A/D 转换器还未准备好输出数据,此时串口时钟输入信号PD_SCK 应为低电平。当DOUT 从高电平变低电平后,PD_SCK 应输入25 至27 个不等的时钟脉冲(图二)。其中第一个时钟脉冲的上升沿将读出输出24 位数据的最高位(MSB),直至第24 个时钟脉冲完成,24 位输出数据从最高位至最低位逐位输出完成。第25至27 个时钟脉冲用来选择下一次A/D 转换的输入通道和增益,参见下表3.3 表3.3 输入通道和增益选择 PD_SCK脉冲数 输入通道 增益 25 A 128 26 B 32 27 A 64 PD_SCK 的输入时钟脉冲数不应少于25 或多于27,否则会造成串口通讯错误。当A/D 转换器的输入通道或增益改变时,A/D 转换器需要4 个数据输出周期才能稳定。DOUT 在4 个数据输出周期后才会从高电平变低电平,输出有效数据。 (4) HX711的数据输出,输入通道和增益选择时序图如下图3.11所示。 T3:PD_SCK正脉冲电平时间 T4:PD_SCK正脉冲电平时间 T1:DOUT下降沿到PD_SCK脉冲上升沿 T2:PD_SCK脉冲上升沿到DOUT数据有效 图3.11 数据输出,输入通道和增益选择时序图 当芯片上电时,芯片内的上电自动复位电路会使芯片自动复位。管脚PD_SCK 用来控制HX711 的断电。当PD_SCK 为低电平时,芯片处于正常工作状态。断电控制图如下图3.12所示。 图3.12 断电控制 芯片从复位或断电状态进入正常工作状态后,A/D 转换器需要4 个数据输出周期才能稳定。DOUT 在4 个数据输出周期后才会从高电平变低电平,输出有效数据。 3.3 人机交互模块 矩阵键盘和液晶显示电路是压力检测系统与用户交互的接口,用户通过显示来观察压力大小及经过数据统计分析处理后的系统状态参数,再根据观察到的值,通过键盘对单片机进行控制。本节设计了较为合理的键盘和显示电路完成这些功能。 3.3.1 液晶显示单元 LCD12864用来显示实时压力值,液晶屏电路如图3.13所示。LCD_CS、LCD_RES、LCD_RS、LCD_SDA、LCD_SCK为液晶模块与单片机接口的控制线。CS_ZK、SCK_ZK、SO_ZK和SI_ZK为字库和单片机接口的控制线。 图3.13 12864液晶 该LCD液晶为晶联讯公司的生产的128*64汉字屏JLX12864G-086-PC显示模块。该显示模块既可以当成普通的图像型液晶显示模块使用,又含有JLX-GB2312 字库IC,可以从字库IC 中读取内置的字库的点阵数据写入到LCD 驱动IC 中,以达到显示汉字的目的。 JLX12864G-086可以显示128列*64行点阵单色图片,或显示8个/行*4行16*16点阵的汉字,或显示16个/行*8行8*8点阵的英文、数字、符号。采用点阵型液晶显示器(LCD),可显示128*64点阵或8个4行汉字,点尺寸为 0.48*0.48(WXH)mm,内置ST7920接口型液晶显示控制器,内带GB2312码简体中文字库(16*16点阵),可与MCU单片机直接连接,具有8位并行及串行的连接方式,广泛应用于各类仪器仪表及电子设备。晶联讯电子所生产JLX12864G-086型液晶模块由于使用方便、显示清晰,广泛应用于各种人机交流面板。其接口引脚功能介绍如表3.4所示。 主要技术参数与显示特性: l 电源:VDD 3.3V~+5V(内置升压电路,无需负压); l 显示内容:128列×64行; l LCD类型:STN; l 多种功能:光标显示、画面移位、睡眠模式等。 表3.4 LCD12864的引脚说明 管脚号 管脚符号 名称 管脚功能描述 1 ROM-IN 字库IC接口 串行数据输出 2 ROM-OUT 字库IC接口 串行数据输入 3 ROM-SCK 字库IC接口 串行时钟输入 4 ROM-CS 字库IC接口 片选输入 5 LEDA 背光电源 背光电源正极,同VDD电压(5V或3.3V) 6 VSS 接地 0V 7 VDD 电路电源 5V或3.3V可选 8 SCK I/O 串行时钟 9 SDA I/O 串行数据 10 RS 寄存器选择信号 H:数据寄存器0:指令寄存器 11 RST 复位 低电平复位,复位后,回到高电平,液晶工作 12 CS 片选 低电平片选 点阵LCD的显示原理 在数字电路中,所有的数据都是以0和1保存的,对LCD控制器进行不同的数据操作,可以得到不同的结果。对于显示英文操作,由于英文字母种类很少,只需要8位(一字节)即可。而对于中文,常用却有6000以上,于是我们的DOS前辈想了一个办法,就是将ASCII表的高128个很少用到的数值以两个为一组来表示汉字,即汉字的内码。而剩下的低128位则留给英文字符使用,即英文的内码。那么,得到了汉字的内码后,还仅是一组数字,若要在屏幕上显示,就涉及到文字的字模,字模虽然也是一组数字,但它的意义却与数字的意义有了根本的变化,它是用数字的各位信息来记载英文或汉字的形状,如英文的'A'在字模的记载方式如图3.14所示: 图3.14 “A”字模图 而中文的“你”在字模中的记载却如图3.15所示: 图3.15 “你”字模图 3.3.2 矩阵键盘单元 下图3.16所示的4*3矩阵键盘包含有上、下、左、右四个方向选择键,加、减键和六个功能键。“存储”键用来手动存储有用的压力值;“清空”键用来清空存储的历史数据,则相应的数据统计得到的值均为0;“调零”键用来将压力传感器调零,让当前压力值显示为0.000kg;“修改阈值”键用来修改系统预设的阈值9.999kg,可以任意在0~9.999kg之内设计阈值;“返回”键可以使当前操作返回到上一级;“确认”键用来将所中的功能确定,传送给系统,执行相应程序。矩阵键盘行扫描信号为ROW1~ROW3,列扫描信号为COL1~COL4。行信号为输入信号,低电平有效;列信号为输出信号。当没有键按下时,即使行扫描输入低电平信号,列信号仍为高电平;当行扫描为低电平并且有键按下时,则对应的列输出低电平。该低电平信号可以定位至按下键的位置。 图3.16 4*3矩阵键盘电路 3.4 声光报警模块 报警电路选用8550 PNP型三极管,基极为低电平时导通,当测量重量超过量程时,beep和alert给出低电平信号,驱动蜂鸣器鸣响,报警灯亮。如图3.17所示: 图3.17 声光报警电路图 3.5 电源供电模块 系统通过USB电源供电,电源电压为5V。单片机程序也可通过USB线串行下载。借助按键开关操作可控制电源的通断,实现系统的良性运作。通电后电源指示灯点亮,系统开始工作;断电后电源指示灯熄灭,系统停止运行。电源供电开关模块如下图3.18所示。 图3.18 电源供电模块电路 4 软件程序设计 根据设计要求,本次软件设计是由主程序和一个个子程序模块组成,这样方便编写和运行整理。软件的主要部分由主程序、A/D转换数据子程序、LCD显示子程序、历史查询子程序、数据统计分析子程序、中断和延时子程序等组成。系统工作时,单片机对各路电压、电流采样及数据的统计与分析,并实时显示。同时,在测试过程中,监控压力值大小,达到预警作用。 4.1 软件开发环境 本系统使用的单片机开发环境是Keil μVision4。Keil μVision4是德国Keil Software公司出品的51系列C语言软件开发系统,使用传统C语言的语法来开发,C语言在可维护性、结构性以及可读性有着明显的优势,可以大大的提高工作效率和项目开发周期,Keil C51为8051单片机的软件开发提供了C语言环境,同时还有着汇编代码高效和快速的特点。C51编译器可以更加贴近CPU本身。C51已被完全集成到uVision4的集成开发环境中,这个集成开发环境包含:实时操作系统,编译器以及调试器等等。uVision4 IDE可为它们提供单一而灵活的开发环境。 Keil μVision4 IDE开发界面图如图4.1所示。 图4.1 Keil μVision4 开发界面 Keil C51软件提供丰富的库函数。C51工具包可以完成编辑、编译、连接、调试等整个流程。程序员可用IDE或其它编辑器编辑C文件。 编写单片机程序有三种常见的方式,C语言编程、汇编语言编程及混合编程。就前两种编程方式相比,C语言更加通俗易懂,容易上手,C语言属于高级语言,并且有着编译器的强大支持与自动优化,使得编程者在软件设计的时候不用花费太多时间去研究单片机底层硬件资源。当然,对于汇编语言在某些方面仍然有着不小的优势,最为突出的一点就是效率优化的可操作性。由于C语言在编译器的支持下编译链接生成汇编文件,所以在性能优化方面完全受制于编译器,从C语言层面上几乎无法做任何优化。而直接使用汇编语言编写程序,在汇编级别上,具体执行哪条汇编指令,具体使用哪个寄存器完全是透明的,所以在性能要求特别高的场合下,如果有丰富的汇编经验,一般都是使用汇编语言编写 单片机程序。 为了克服C语言编程及汇编语言编程各自的缺点,混合编程方式完美的结合了两者的优点,做到了优势互补。通常单片机很合编程技术是,程序的框架或主体部分用C语言编写,对于那些使用频率高、要求执行效率高、延时精确的部分用汇编语言编写[9],这样既保证了整个程序的可读性,又保证了单片机应用系统的性能。 由于本系统对于性能的要求一般,所以采用C语言方式编写单片机程序。通过对编译选项的设置,Keil软件可以在编译链接后自动生成HEX16进制文件,方便单片机程序的直接烧写。 4.2 I/O端口分配 STC89C51RC共有40只引脚,P0~P3四个引脚组各有8只引脚。对于本系统而言,引脚数量还是够用的[10]。引脚功能分配如下: l P20~P27和P16、P17接于LCD中液晶与单片机的控制端口和字库与单片机的控制端口。 l P34~P37和P13是用于4*3矩阵键盘按键。包括功能选择按键,参数设置按键和工作启停等功能控制。 l P14,P15 用于接A/D转换芯片HX711数据采集端口,是串行工作方式,所以节省了很多的IO口的使用。 还有一些单独的接口,比如振荡电路接口,声光报警电路接口和单片机自带的烧录程序串口通讯接口TXD、RXD等。 程序中所有端口定义及功能如下: sbit A/DDO = P1^5; //串行数据输出端口 sbit A/DSK = P1^4; //断电控制(高电平有效)和串口时钟输入端口 sbit lcd_sclk=P2^3; //LCD的sclk接口 sbit lcd_sid=P2^4; //LCD的sid接口 sbit lcd_rs=P2^5; //LCD的rs接口 sbit lcd_reset=P2^ //LCD的reset接口 sbit lcd_cs1=P2^ ; //LCD的cs1接口 sbit Rom_IN=P1^7; //字库IC的SI接口 sbit Rom_OUT=P1^6; //字库IC的SO接口 sbit Rom_SCK=P2^0; //字库IC的SCK接口 sbit Rom_CS=P2^1; /字库IC的CS接口 sbit LedA = P2^2; //LCD液晶背光电源接口 sbit beep = P1^0; //报警电路蜂鸣器接口 sbit alert = P1^1; //LED发光二极管接口 sbit ROW1=P3^3; //矩阵键盘第一行接口 sbit ROW2=P3^2; //矩阵键盘第二行接口 sbit ROW3=P1^3; //矩阵键盘第三行接口 sbit COL1=P3^4; //矩阵键盘第一列接口 sbit COL2=P3^5; //矩阵键盘第二列接口 sbit COL3=P3^6; //矩阵键盘第三列接口 sbit COL4=P3^7; //矩阵键盘第四列接口 4.3 软件主程序构架 本系统的设计主要由五大模块构成,软件程序主要是实现对这些功能模块的控制,以及最终对数据进行分析计算得出性能测量结果。程序执行时,首先对整个系统进行初始化,这部分包括参数初始化、IO初始化和器件初始化三个操作。参数初始化时对一些全局系统参数进行初始化,保证程序执行的可靠性;IO初始化是将所有IO的电平和功能设置为关闭状态,防止发生误操作;器件初始化是对外围的A/D芯片、模拟开关、LCD进行初始化,保证器件能够正常运行。如果在此过程中发生错误,即调用报警电路进行报警。程序流程图如图4.2所示。 图4.2 系统主程序构架框图 初始化完毕后,延时等待所有模块准备好,向液晶显示器发送数据,显示初始的人机界面。此时,整个系统可以开始进行数据采集工作,但参数均处于默认状态,如果需要调整,则可以实时通过键盘控制,系统根据读取的键盘键值执行相应的操作,分别是执行修改阈值参数、读取A/D采样值、压力测量、手动存储、超重预警、发出报警信号、查阅历史,数据统计分析等。 等待这部分操作完成后,系统屏幕根据需要实时刷新显示一些数据和状态,显示新的参数或采样信息。 4.4 主要功能子程序的设计 先进行系统的初始化,初始化模块主要对单片机的堆栈指针,中断寄存器,全局变量定义,赋初值和定时器的初始化。定时器主要作为A/D转换时间的设定。然后进行模数转换,判断是否超过设定阈值,转换压力字符通过液晶显示。参数设定完毕,系统启动数据采集和控制程序,实现压力的实时检测。 4.4.1 A/D子程序设计 通过压力传感器输出后的数据经过信号放大器的处理后,由A/D转换芯片转换为数字信号。其中模拟信号的放大倍数由放大电路控制。在软件方面,单片机通过发送时序命令的方式对A/D芯片进行控制,由于选型的A/D芯片不需要启动命令,即可自动转换。所以在每次采集之前,程序通过延时等待转换完成,然后发送低电平片选信号,将数据读取功能使能,在数据读取的整个过程中保持不变。然后再发送一个时钟读取采样值,并将数据保存到存储器的设定空间,再将存储空间的指针移位。此时,将片选信号置高,等待读取下一组数据,完成其他程序功能。A/D采集部分流程图如图4.3所示: 图4.3 A/D转换流程图 4.4.2 中断子程序设计 系统的称重间隔为0.5S,每0.5S置标志位,累加器计数满400次则延时时间为0.5S,置称重标志位。中断子程序流程图如下图4.4所示。 图4.4 中断流程图 4.4.3 查询历史数据子程序设计 预先手动存储八个以内的压力值(超过阈值亦可),当存储第九个数据时,存储的历史数据会自动将第一位存储的数据挤掉,后面存储的数据均依次向前移一位。按上下键进行选择,光标停在查询历史数据功能菜单之前,按确认键确定。调用该子程序,判断是否为0,若不是显示“无历史”;若是则读取显示存储的压力值,并按顺序依次为NO.1~8显示输出。查询历史数据流程图如下图4.5所示。 图4.5 查询历史数据流程图 4.4.4 数据统计分析子程序设计 预先手动存储八个以内的压力值(超过阈值亦可),当存储第九个数据时,存储的历史数据会自动将第一位存储的数据挤掉,后面存储的数据均依次向前移一位。按上下键选择“数据统计分析”,则系统会将这些压力值进行数据分析处理(求均值、最值、排序求中位数、判断有无众数),然后依次显示输出均值大小、最大值、最小值、中位数、若有众数,则显示出现几次,并且显示该众数;在四种情况下,比如abcdefgh型、aabbccdd型、aaaaaaaa型、aaaabbbb型则显示无众数。如下图4.6所示。 图4.6 数据统计分析流程图 4.4.5 阈值重设子程序设计 系统开启后,系统会默认显示程序中预先设定的阈值9.999kg,按阈值重设键,键盘程序读取键码,调用该子程序,界面跳到修改阈值的界面,有个光标在第一个9的下面,可以通过按左右选择键,将光标左右移动,该光标停在任意数下面,就可以通过加减键对该数字进行修改,从而完成阈值的修改,最后按确认键即可跳转到主菜单。如下图4.7所示。 图4.7 阈值重设功能流程图 4.4.6 人机交互子程序设计 人机交互单元包括键盘处理和12864显示模块两部分。人机交互是设计人性化、便捷操作的必要操作,除了硬件上的设计基础,还必须要软件的灵活控制,由于显示时序均以时序建模的方式实现了控制驱动,大大简化了软件设计,软件仅需要按要求给出拟显示的图像和位置即可。 (1)液晶显示控制程序设计 液晶显示控制程序框图如图4.8所示,液晶的总线接口是P2.0~P2.7,P2.7定义为CS片选口,每次对液晶的操作必须先拉高CS信号,P2.5定义为液晶复位接口。开始先对液晶显示初始化,功能主要是对液晶的背光时间,背光等级,字符显示格式,汉字显示格式,和界面的初始化等。初始化完毕,下一步对各项参数显示。 图4.8 液晶显示初始化控制流程图 (2)键盘驱动程序设计 键盘处理程序为单片机控制口读取按键状态,消抖后得到按键状态,根据按键状态得到用户输入的键值进行相应的参数设定,也可以通过按键重设系统阈值。键盘驱动程序框图如图4.9所示。 图4.9 按键驱动流程图 矩阵键盘的处理方法比较简单,单片机上电后引脚默认电平为高点平。当按键被按下的时候变低电平,单片机读取到低电平状态后经过一段时间的延时消抖再去读取电平状态,确保有按键按下,因为有的时候会误读。然后去处理后续程序代码。键盘控制程序代码如下: #include "keyboard.h" //按键扫描函数 : //功能;只扫描一个按键,按键为号小优先 //返回键值: // 1(save) 2(clearHistory) 3(to_zero) 4(limit) // 5(plus) 6(up) 7(sub) 8(return) // 9(left) 10(down) 11(right) 12(enter) unsigned char Getkeyboard(void) { unsigned char number = 0; unsigned char i; //行输入低电平 ROW1=ROW2=ROW3=0; //如果列输出不全为高,则说明有键按下 if ((COL1!=1)||(COL2!=1)||(COL3!=1)||(COL4!=1)) { //输入011 ROW1=0; ROW2=ROW3=1; for (i=0;i<30;i++); if (COL1==0) return 1; else if (COL2==0) return 2; else if (COL3==0) return 3; else if (COL4==0) return 4; //输入101 ROW2=0; ROW1=ROW3=1; for (i=0;i<30;i++); if (COL1==0) return 5; else if (COL2==0) return 6; else if (COL3==0) return 7; else if (COL4==0) return 8; //输入110 ROW3=0; ROW1=ROW2=1; for (i=0;i<30;i++); if (COL1==0) return 9; else if (COL2==0) return 10; else if (COL3==0) return 11; else if (COL4==0) return 12; //没有检测到列低电平 return 99; } return 99; } 5 系统调试 5.1 数据采集调试 压力传感器的数据采集是压力检测系统的关键部分。压力的采集使用电阻应变式压力传感器,将传感器接到相应的端口,观察采集的压力是否正常。由应变片的形变,使得电阻值也随之改变,输出变化后的电压值,经过放大,输送给单片机。从而显示当前的压力大小。分别用已知质量的砝码,物体放置在压力托盘上,观察液晶显示,判断误差是否在可控范围内。如表5.1所示。 表5.1 数据采集结果记录表 序号 被测物体质量(kg) 测量结果(kg) 绝对误差(kg) 引用误差(%) 1 0.1 0.092 -0.008 -0.08 2 0.2 0.191 -0.009 -0.09 3 0.5 0.490 -0.010 -0.10 4 1.0 0.990 -0.010 -0.10 5 1.5 1.489 -0.011 -0.11 6 2.0 1.988 -0.012 -0.12 7 3.0 2.988 -0.012 -0.12 8 4.0 3.987 -0.013 -0.13 9 5.0 4.986 -0.014 -0.14 10 6.0 5.985 -0.015 -0.15 11 7.0 6.984 -0.016 -0.16 12 8.0 7.984 -0.016 -0.16 “测量结果”是用单片机在A/D芯片输出端读取到的转换结果。由结果我们可以看到,使用24位A/D芯片HX711后,本系统的数据采集精度较高,与实际数据偏差值较小。由测量数据与真值,在被测物体质量在较小时,测量结果误差较小,被测物体质量越大,测量误差越大。被测物体质量在0.1~2.0kg时,精度达到9.6g;被测物体质量在2.0~6.0kg时,精度达到12.75g;被测物体在6.0~10kg时,精度达到15.7g。求得该系统精度大概为12g左右,基本满足设计要求。 5.2 数据统计分析调试 连续放置物体于托盘上,按手动存储即可将当前被测物体的实时压力值,保存到系统。存储次数不要超过八次,按键选择数据统计分析功能。程序即调用相应的子程序,开始运行处理数据。计算均值,最值,中位数,众数。首先要将存储后的数据按从小到大排序。均值的计算即将所存储的数据相加求平均值。最值即选中排序后的数组直接读取,输出显示最大(小)值。中位数即选择排序后的中间的数输出,若为奇数个,则从小到大排序后的中间的数即为中位数;若为偶数个,排序后中间的两个数求平均值即为所求中位数。众数求法依次将一个数据与后面的数据进行比较,找出相同的数据,出现次数最多的数据显示输出,显示出现次数,和原数据大小。若有两个数据出现次数相同(出现次数大于1次),则将两个数据全部显示输出。经调试各按键均能准确进行系统功能选择,各功能也可以实现。 5.3 声光报警调试 程序中已经设定阈值为9.999kg,进入系统主界面后,显示当前阈值为9.999kg,按阈值重设键,界面切换到阈值重设状态,再按左右键选择想要修改的数字,接着按加减键将阈值设为用户想要的值,比如设“2.000kg“,然后放置物体当达到2.000kg时,声光报警模块启动,蜂鸣器发声,LED点亮,则报警调试成功。 5.4 软件调试 在软件调试中,需要先分模块调试软件中的各个子程序,确保每个模块都能正常工作的情况下,再去调试整个软件系统。如果直接调试整个系统,一旦其中某个模块出现问题将会很难发现问题的源头,这将会影响整个系统的调试效率。 1. ADC数据采集程序模块 本系统中,采用ADC模块HX711来获取压力传感器的电压及电流信息。数据采集的精准度将直接影响整个系统的工作精度。进入中断,等待ADC转换结束。定义压力时使用long型,在调试过程中,发现压力只能调到4.23kg左右,再调大就显示乱码,在检查错误发现,是long型的范围不够,数据溢出,将压力修改为UNSIGNED LONG型。 2. 显示模块程序 12864为该系统的液晶,还液晶在KEIL 0XFD编程时有个漏洞,有些汉字不能显示。为了解决问题,上网搜索,找到方法。①下个晓奇工作室出的补丁。②用十六进制编辑软件如HexEdit打开c51.exe,搜索80FBFD,改为80FBFF即可。采用第一种方法,很好解决了问题。将显示模块函数从整个程序中单独取出,进行软件独立调试。在程序中设定LCD显示不同的字符数据,运行程序,观察LCD是否按程序的设定来显示字符,若不是,则重新检查程序编写是否正确,调整程序然后继续检测,直至LCD显示结果符合预定值。 3. 按键交互单元 将按键模块独立出来,给每个按键设定不同的功能,使用LCD显示其按键值,运行程序,按下按键并观察LCD的显示结果是否正常,是否与程序设定的按键值一致,若不一致则调试程序直至按键结果符合预定值。 5.5 实物展示 本系统硬件最终实物图如下图5.1所示。 图5.1 整体系统实物 以下是系统主要模块的详细特写图。如下图5.2所示。 (a)数据采集模块 (b)单片机系统 (c)矩阵键盘模块 图5.2 系统主要模块特写图 系统开机后,会进入主菜单界面,如下图5.3所示。 图5.3 主菜单界面 阈值9.999kg为系统程序预设的值。用户可以根据需要按“修改阈值”键,进入阈值重设界面,如下图5.4(a)所示。通过左右按键分别将光标从个位移到小数的后三位,按加减键可对光标指向的数字实现更改,将阈值重设为1.000kg,如下图5.4(b)所示。 (a)阈值重设之前 (b)阈值重设之后 图5.4 阈值重设界面 按确认键后,系统界面跳转到主菜单,此时阈值已显示为1.000kg,放置一个重量超过1kg的物体在托盘上,系统声光报警,并显示当前压力。如下图5.5所示。 图5.5 声光报警显示 移除物体分别测7组数据,按手动存储键进行存储。按键时速度不宜过快,每0.5秒刷新一次,光标此时指在查询历史数据功能上,按确认键即可进入查询历史界面。按上下选择键即可上下翻页,查询历史。如下图5.6所示。 图5.6 查询历史数据界面显示 从液晶显示界面可以看出0.089kg出现3次,0.179kg出现4次。按“返回”键,到主菜单,再按上下选择键,光标指向数据统计分析功能,按“确认”键进入该界面。从上往下依次显示均值、最大值、最小值、中位数,按上下键翻页,可查看有无众数,并显示出现几次,为何值。如下图5.7所示。 图5.7 数据统计分析界面显示 若所存储数据无众数,则显示“无众数”,如下图5.8所示。 图5.8 显示“无众数”界面 若未存储数据,查询历史数据则显示如下图5.9,数据统计分析则显示如下图5.10及上图5.8所示。 图5.9 无历史数据界面 图5.10 无数据统计分析界面 6 结束语 本次设计,我的收获很多,我做的是基于51单片机压力检测系统的设计,用到的主要芯片是STC89C51RC和HX711,实现的功能是将电阻应变式压力传感器通过称重采集到的模拟信号转换成51单片机可以识别的数字信号,再经单片机运算处理输出到LCD液晶显示信息。矩阵键盘可实现对系统的实时控制,对单片机下达指令,实现压力检测、声光报警、手动存储、历史数据查询和数据统计分析等功能。为了更加精确地对物体进行称重测量,用到了一个以前从未接触过的新的A/D芯片HX711。24位高精度A/D转换器HX711是一种专为压力测量而设计制造的高精度芯片,从网上搜索的资料对我帮助很大,遇到不懂的问题自己解决不了,就和大家一起讨论。除学习芯片功能外,主要了解了对芯片串行输出的控制,这里的软件设计是一个难点,以前电视实习期间,学了Protel99SE绘图软件,鉴于该软件有些模块不易找到。我们这次用的是用Altium designer绘图软件,由于该软件是Protel的升级版,所以入手很快。通过看书和同学老师的帮忙,使得我画好了原理图。本系统程序设计上,有点难度,主要是12864液晶显示上,以前基本用的都是1602,但为了更直观的显示测量结果,选用可以显示汉字的12864液晶。在编程方面就有点难处理,另外由于本系统的实现的功能较复杂,且多。需要进行排序,求和,还有众数的处理,在修改程序的时候花了不少时间。最后,终于显示可以想要的结果。 此次毕业设计使我更加了解C51程序的强大功能,以前学习单片机过程中的漏洞也得到了很好的修补,Keil的使用加深了我对这种软件的理解程度。由于HX711在PROTEUS软件没有仿真元件,因此没能实现Keil与Proteus软件的联调仿真。但是我仍然自学了该仿真软件,熟悉了仿真的流程。本次毕设暴露了我在平时学习中的不足,以及对知识缺乏融会贯通的能力,毕业设计过程中,不断发现问题,不断修改,不断领悟,不断获取。实践出真知,自己亲自动手去做,才知道知识的匮乏! 参 考 文 献 [1] 沙占友主编.集成化智能传感器原理与应用.北京: 电子工业出版社, 2004,36-56. [2] 赵德安.单片机原理与应用[M].北京:机械工业出版社,2009. [3] 清源计算机工作室.Protel 99SE 原理图与PCB及仿真.北京:机械工业出版社,2001. [4] 李广第.单片机基础.北京:北京航空航天大学出版社,1995,33-64. [5] 徐恕宏.传感器原理及其设计基础.北京:机械工业出版社,1988,30-45. [6] 彭军.传感器与检测技术[M].西安:西安电子科技大学出版社,2003. [7] 周航慈.单片机应用程序设计技术.北京: 北京航空航天大学出版社,1991,18-27. [8]任向民.卢惠林.汇编语言程序设计使用教程[M].北京:清华大学出版社,2009. [9] Stephen G Kochan著.Programming in ANSI C.Hagden Books Indianapolis:Indiana,USA,1994. [10] E.Vargas-Rodrigueza.H.N.Rutte.Sensors and Actuators B.Sensors and Actuators B 137 (2009) 致 谢 本次设计是在导师xxx老师的悉心指导下完成的。回想大二学习高频电子技术,xx老师的兢兢业业,认真负责一直感染着我。在毕业设计开始阶段,xx老师对我的学习,设计实施选择创造了许多有利条件,在方案设计中也给了我很多的建议和灵感。当我畏难时,xx老师一直鼓励着我,才能令我将毕设功能完整的实现。xx老师他严谨细致的工作作风、宽以待人的高尚品质和谆谆教诲使我终身难忘。也感谢四年来对我传业解惑,育我成材的各位老师,感谢你们的辛劳与无私。在此,向这些为学生成长付出大量心血的导师表示衷心的感谢! 还要感谢在设计过程中帮助过我的所有同学和朋友们。在学习中我们互相帮助,互相鼓励,使我能够顺利的完成我的学业。是你们的帮助使我发现设计上的误区,使我能及时的发现问题把设计顺利的进行下去;是你们的监督使我在设计过程中按时完成既定任务。本次设计尤其要感谢班上的蔡涛同学,在我软件设计上给了我很大的帮助,帮我解决了很多问题。没有你们的帮助我不可能这样顺利地结稿。感谢陪伴我四年的同学,让我四年的大学生活充满精彩,在此,请接受我真诚的谢意。   最后,我还要特别感谢我的家人,正是他们的支持和教育让我有机会坐在大学的课堂里,完成本科四年的学习。感谢母校xx大学给了我走入社会的资本和心理准备,让我终生受益。 附 录 A 附:电路总原理图 附 录 B 附:系统主程序 #include"main.h" //定义标识 volatile bit FlagTest = 0; //定时测试标志,每0.5秒置位,测完清0 volatile bit FlagKeyPress = 0; //有键按下标志,处理完毕清0 volatile bit FlagSetPrice = 0; //价格设置状态标志,设置好为1。 //显示用变量 int Counter = 0; uchar idata str1[6] = "000000"; unsigned long idata limit = 9999; //阈值设置 unsigned char idata local[4] = {68,84,92,100}; unsigned char idata local_index = 0; //称重用变量 unsigned long idata FullScale; //满量程A/D值/1000 //历史记录 unsigned long idata history[8] = {0}; int idata hisCount = 0; void main(void) { Rom_CS=1; initial_lcd(); EA = 0; beep = 1; alert = 1; Timer0_Init(); //初始化完成,开中断 EA = 1; //背光 LedA = 1; clear_screen(); //clear all dots display_GB2312_string(1,1," 压力检测系统 "); display_GB2312_string(3,1," loA/Ding... "); To_Zero(); delay(120); funcList(); } //整型转字符串的函数,转换范围0--65536 void int2str(int x, char* str) { int i=1; int tmp=10; while(x/tmp!=0) { i++; tmp*=10; } tmp=x; str[i]='\0'; while(i>1) { str[--i]='0'+(tmp%10); tmp/=10; } str[0]=tmp+'0'; } //重新找回零点,每次测量前调用 void To_Zero() { FullScale=ReA/DCount()/1000; } //显示重量,单位kg,两位整数,三位小数 void displayPress(unsigned long weight,unsigned char lineNum) { unsigned int i,j; display_GB2312_string(lineNum,60," "); //weight单位是g i = weight/1000; //得到整数部分 j = weight - i*1000;//得到小数部分 memset(str1,0,6); int2str(i,str1); if (i>=10) { display_GB2312_string(lineNum,60,str1); } else { display_GB2312_string(lineNum,68,str1); } display_GB2312_string(lineNum,76,"."); memset(str1,0,6); int2str(j,str1); if (j<10) { display_GB2312_string(lineNum,84,"00"); display_GB2312_string(lineNum,100,str1); } else if (j<100) { display_GB2312_string(lineNum,84,"0"); display_GB2312_string(lineNum,92,str1); } else { display_GB2312_string(lineNum,84,str1); } } //定时器0初始化 void Timer0_Init() { ET0 = 1; //允许定时器0中断 TMOD = 1; //定时器工作方式选择 TL0 = 0x06; TH0 = 0xf8; //定时器赋予初值 TR0 = 1; //启动定时器 } //定时器0中断 void Timer0_ISR (void) interrupt 1 using 0 { TL0 = 0x06; TH0 = 0xf8; //定时器赋予初值 //每0.5秒钟刷新重量 Counter ++; if (Counter >= 400) { FlagTest = 1; Counter = 0; } } void funcList() { unsigned long press = 0; unsigned char keyValue = 0; unsigned char flag = 0; interface(); while(1) { if (FlagTest==1) { //To_Zero(); press = getPress(); if (press > limit) { beep = 0; alert = 0; //display_GB2312_string(1,60,"******"); } else { beep = 1; alert = 1; //display_GB2312_string(1,60," "); } displayPress(press,1); } if (beep == 1) { keyValue = Getkeyboard(); if (FlagKeyPress == 0) { FlagKeyPress = 1; switch(keyValue) { case 1: save(press); break; case 2: clear(); break; case 3: To_Zero(); break; case 4: setLimit(); clear_screen(); interface(); break; case 6: display_GB2312_string(5,1," "); display_GB2312_string(5,1," >查询历史数据 "); display_GB2312_string(7,1," 数据统计分析 "); flag = 0; break; case 10:display_GB2312_string(7,1," "); display_GB2312_string(5,1," 查询历史数据 "); display_GB2312_string(7,1," >数据统计分析 "); flag = 1; break; case 12:if(flag == 0) checkHistory(); else analysis(); flag = 0; clear_screen(); interface(); break; default:break; } FlagKeyPress = 0; } delay(20); } } } void interface() { display_GB2312_string(1,1,"压力: kg"); display_GB2312_string(3,1,"阈值: kg"); displayPress(limit,3); display_GB2312_string(5,1," >查询历史数据 "); display_GB2312_string(7,1," 数据统计分析 "); } unsigned long getPress() { unsigned long weight = 0; unsigned long A/Dval = 0; //称重,得到重量值weight,单位为g A/Dval = ReA/DCount(); weight = FullScale - A/Dval / 1000; if (weight>0x8000) weight = 0; weight = 10000 * weight / FullScale; weight = weight * RATIO; return weight; } void checkHistory() { unsigned char keyValue = 99; clear_screen(); if(hisCount == 0) { display_GB2312_string(1,1," 当前无任何 "); display_GB2312_string(3,1," 历史数据 "); display_GB2312_string(5,1," "); display_GB2312_string(7,1," 按return键返回"); while(1) { keyValue = Getkeyboard(); if(keyValue == 8) break; delay(20); } } else { if (hisCount <= 4) { firstPage(); while(1) { keyValue = Getkeyboard(); if(keyValue == 8) break; delay(20); } } else if(hisCount > 4) { firstPage(); while(1) { keyValue = Getkeyboard(); if (keyValue == 8) break; else if(keyValue == 10) secondPage(); else if(keyValue == 6) firstPage(); } } } return; } void firstPage() { char i; clear_screen(); for(i = 1;i <= hisCount;i++) { display_GB2312_string(i%5*2-1,1,"NO : Kg"); memset(str1,0,6); int2str(i,str1); display_GB2312_string(i%5*2-1,17,str1); displayPress(history[i-1],i%5*2-1); if (i == 4) break; } return; } void secondPage() { char i; clear_screen(); for(i = 5;i <= hisCount;i++) { display_GB2312_string((i-4)%5*2-1,1,"NO : Kg"); memset(str1,0,6); int2str(i,str1); display_GB2312_string((i-4)%5*2-1,17,str1); displayPress(history[i-1],(i-4)%5*2-1); } return; } void analysis() { unsigned char keyValue = 0; unsigned long idata temp[9]; int idata num_num[4] ; int idata num_index[4]; int i,j,k,a,b; int idata zhongwei,junzhi,zhongshu; memset(temp,0,9); memset(num_index,0,4); zhongwei = 0; junzhi = 0; zhongshu = 0; for(i = 0;i < hisCount;i++) temp[i] = history[i]; for(i = 0;i < 4;i++) num_num[i] = 1; //排序--获得最大值,最小值 if(hisCount > 1) { for(i = 0;i < hisCount-1; i++) { for(j = 0;j < hisCount-1-i; j++) { if(temp[j] >= temp[j+1]) { temp[8] = temp[j]; temp[j] = temp[j+1]; temp[j+1] = temp[8]; } } } } //均值 for(i = 0;i < hisCount;i++) { //temp[8] += temp[i]/hisCount; junzhi += (int)temp[i]; } if(hisCount != 0) junzhi = junzhi/hisCount; //中位数 if(hisCount != 0) { if(hisCount%2==1) { zhongwei = (int)temp[hisCount/2]; } else { a=(int)temp[hisCount/2-1]; b=(int)temp[hisCount/2]; zhongwei = (a+b)/2; //temp[9] = b; } } //众数 if(hisCount > 1) { k = 0; for(i = 0;i < hisCount - 1;i++) { for(j = i;j < hisCount - 1;j++) { if(history[j] != history[j+1]) break; num_num[k]++; num_index[k] = i; } if(i != j) k++; i = j; } } if(k != 0) { i = 0; j = i; if(k > 1) { while(1) { if(num_num[i] <= num_num[i+1]) j = i + 1; if(i + 1 == k - 1) break; i++; } } } clear_screen(); display_GB2312_string(1,1,"均值: Kg"); displayPress(junzhi,1); display_GB2312_string(3,1,"最大值: Kg"); if(hisCount > 1) displayPress(temp[hisCount - 1],3); else displayPress(temp[0],3); display_GB2312_string(5,1,"最小值: Kg"); displayPress(temp[0],5); display_GB2312_string(7,1,"中位数: Kg"); displayPress(zhongwei,7); while(1) { keyValue = Getkeyboard(); if(keyValue == 8) break; else if(keyValue == 6) { clear_screen(); display_GB2312_string(1,1,"均值: Kg"); displayPress(junzhi,1); display_GB2312_string(3,1,"最大值: Kg"); if(hisCount > 1) displayPress(temp[hisCount - 1],3); else displayPress(temp[0],3); display_GB2312_string(5,1,"最小值: Kg"); displayPress(temp[0],5); display_GB2312_string(7,1,"中位数: Kg"); displayPress(zhongwei,7); } else if(keyValue == 10) { clear_screen(); if(k==0 || k==4 || ((k==1)&&(num_num[0]==hisCount)) || ((k==2)&&(hisCount == num_num[0]+num_num[1]))) display_GB2312_string(3,1," 无众数 "); else { display_GB2312_string(1,1," 众数 "); for(i = 0;i < k;i++) { if(num_num[i] == num_num[j]) { a = num_num[i]; zhongshu = (int)temp[num_index[i]]; memset(str1,0,6); int2str(a,str1); display_GB2312_string((i+1)*2+1,1," 次 kg"); display_GB2312_string((i+1)*2+1,1,str1); displayPress(zhongshu,(i+1)*2+1); } } } } } return; } void setLimit() { unsigned char idata keyValue = 99; unsigned char idata flag = 0; local_index = 0; clear_screen(); display_GB2312_string(1,1," 阈值设置 "); display_GB2312_string(3,1,"阈值: Kg"); displayPress(limit,3); display_GB2312_string(5,local[0],"^"); while(1) { keyValue = Getkeyboard(); if(flag == 0) { flag = 1; if(keyValue == 9) { if(local_index > 0) { local_index--; display_GB2312_string(5,1," "); display_GB2312_string(5,local[local_index],"^"); } } else if(keyValue == 11) { if(local_index < 3) { local_index++; display_GB2312_string(5,1," "); display_GB2312_string(5,local[local_index],"^"); } } else if(keyValue == 2) { local_index = 0; limit = 0; display_GB2312_string(3,1,"阈值: 0.000Kg"); display_GB2312_string(5,local[0],"^"); } else if(keyValue == 5 || keyValue == 7) compute(keyValue); else if(keyValue == 12) break; flag = 0; } delay(20); } delay(20); return; } void compute(unsigned char key) { unsigned long idata index_num[4] = {1000,100,10,1}; unsigned long temp; temp = limit%(index_num[local_index]*10); if(key == 5) { if(temp >= 9*index_num[local_index]) limit = limit - 9*index_num[local_index]; else limit = limit + index_num[local_index]; } else if(key == 7) { if(temp < index_num[local_index]) limit = limit + 9*index_num[local_index]; else limit = limit - index_num[local_index]; } temp = limit%(index_num[local_index]*10); temp = temp/index_num[local_index]; memset(str1,0,6); int2str(temp,str1); display_GB2312_string(3,local[local_index],str1); display_GB2312_string(5,1," "); display_GB2312_string(5,local[local_index],"^"); return; } void save(unsigned long press) { unsigned char i; if (hisCount == 8) { for (i = 0;i <8;i++ ) history[i] = history[i+1]; history[7] = press; } else { history[hisCount] = press; hisCount++; } } void clear() { hisCount = 0; memset(history,0,sizeof(history)); } 本文档由香当网(https://www.xiangdang.net)用户上传

    下载文档到电脑,查找使用更方便

    文档的实际排版效果,会与网站的显示效果略有不同!!

    需要 10 香币 [ 分享文档获得香币 ] 0 人已下载

    下载文档