毕 业 设 计
题 目: 基于51单片机的油量流量仪 学 院: 电气与信息工程学院 专 业: 电气工程与其自动化 姓 名: 学 号: 指导老师:
完成时间: 年 月 日
摘 要
工业生产中过程控制是流量测量与仪表应用的一大领域,流量与温度、压力和物位一起统称为过程控制中的四大参数,人们通过这些参数对生产过程进行监视。对流体流量进行正确测量和调节是保证生产过程安全经济运行、提高产品质量、降低物质消耗、提高经济效益、实现科学管理的基础。流量的检测和控制在化工、能源电力、冶金、石油等领域应用广泛。
本设计作为一个加油系统的智能电子设备,以ATS52单片机为核心器件,主要研究基于51单片机的智能控制和传感器的数据采集与相应的控制系统的构建,电路元件少,制作方便。单片机通过水流量传感器采集出相应的水流量并在液晶屏幕上显示相应的数字,可以读出使用的水流量,并查看出相应的价格,是一个数字化的智能水流量计。
关键词:ATS52单片机;水流量传感器;LCD1602
Abstract
Process control in industrial production is a large area of flow measurement and instrumentation, flow rate and temperature, pressure and level the four together are referred to as process control parameters, people with these parameters to monitor the production process. Correct measurement of fluid flow and regulation is to ensure the safety and economic running of production process, improve product quality, reduce material consumption and improve economic efficiency, the Foundation of scientific management. Traffic detection and control in the areas of chemicals, energy, electric power, metallurgy, petroleum widely used.
As a intelligent electronic device,this desing uses single chip microcomputer ATS52 as core component,making a primary research on that single chip microcomputer,which is a digital intelligent water meter,can gather relveant water flow and display corresponding figure on LCD screen and thus we can read water flow and check out relevant price based on water flow sensor and its advantages of intelligent controls of single chip microcomputer,data acquisition of sensor and the construction of control system.And it possesses few circuit components and convenient making.
Key Words:ATS52;water flow sensor;LCD1602
I / 59
目 录 摘要 AbstractI 绪论0 1 系统方案0
1.1 方案论证与选择0
1.1.1 作品电源模块的论证与选择0 1.1.2 流量检测模块论证与选择0 1.1.3 主控制芯片模块的论证与选择0 1.1. 4 显示器模块的论证与选择1 1.1.5 按键控制模块的论证与选择1 1.1.6 报警指示部分论证与选择2 1.2 系统设计2
1.2.1 结构方框图2 1.2.2 理论分析与计算2
2 系统硬件电路设计0
2.1 硬件电路的总体设计0
2.1.1 单片机最小系统0 2.1.2 液晶显示电路1
2.1.3 水流量传感器模块电路1 2.1.4 按键控制模块2 2.1.5 报警指示模块2 2.2 片子的简介3
2.2.1 ATS51单片机与引脚介绍3 2.2.2 LCD1602液晶显示器7
2.2.3 单片机与LCD1602液晶显示器的连接11
3 单片机软件程序设计0
3.1 主程序流程图0 3.2 水流量检测程序1 3.3 LCD液晶显示程序2
3.4 按键的控制程序4
4 电路调试和方法0
4.1 检测方法0 4.2 硬件系统调试0
4.2.1 初步硬件调试问题0 4.2.2 问题分析0 4.2.3 解决方案0 4.3 软件系统调试1
附录A:电路原理图0 附录B:PCB图0 附录C:作品图0 附录D:元件清单0 附录E:程序单0
结论0 0
致0 附录0
I / 59
参考文献
绪 论
当今由于中国经济的腾飞,落后的科技已经不能适应时代的发展,只有不断进步的科技才能推动社会的发展,流量计的测量在热电生产、石油化工、食品卫生等工业领域具有广泛的应用。随着传感器技术,微电子技术、单片机技术的发展,为液体流量的精确测量提供了新的手段。工业生产中过程控制是流量测量与仪表应用的一大领域,流量与温度、压力和物位一起统称为过程控制中的四大参数,人们通过这些参数对生产过程进行监视与控制。对流体流量进行正确测量和调节是保证生产过程安全经济运行、提高产品质量、降低物质消耗、提高经济效益、实现科学管理的基础。流量的检测和控制在化工、能源电力、冶金、石油等领域应用广泛。
我国近代流量测量技术发展比较晚,早起所需的流量仪表均从国外进口。中国流量仪表制造业从上世纪30年代中期以仪表修配开始,到前后在、等沿海地区形成了现代流量仪表的民族工业。改革开放以来又经历了技术引进,与国际先进技术企业合资、合作,仪表性能和水平有了很大提高。近年国际主流企业纷纷在中国建立生产基地,既增强了研发能力也增添了竞争因素,现在我国流量计产品已很全面,基本覆盖所有行业,满足各行业产生需要,技术革新较快,但在产品生产工艺上仍然有很大提高的空间。 为了适应各种用途,各种类型的流量计相继问世,投入使用的类型有上百种。根据其测量方法和结构原理大致分为差压式流量计、浮子流量计、容积式流量计、电磁流量计、涡街流量计、科里奥利质量流量计、超声流量计、插入式流量计等。20世纪随着各领域对流量测量需求的牵引,使得流量计得到快速发展尤其是微电子技术的迅速发展,为流量计的制造技术提供各种新型的元器件,进一步推动了流量计从机械式向智能化、模块化发展。新技术、新器件、新材料和新工艺与新软件的开发应用,使得流量计的测量准确度越来越高,流量的测量围越来越广。同时流量计对测量介质的要求在降低,适用围也越来越宽,智能化程度与可靠性得到了很大的提高。
智能化的家居生活让人们感到身心的放松,本设计是以ATS52为主控芯片,用来监控各加油站的加油系统,智能仪表除了可对加油量进行记录和电子显示外,还可对进行自动完成油价的计算。本设计还有一个重大的作用就是它适用于一般所有液体的检测,这款流量计的使用非常的广泛。可见研究一种低功耗、计量准确方便的流量计十分重要,尤其对节约油资源以与一些对水量有要求的工业的发展起到很大的支持。
0 / 59
1 系统方案
本系统主要有负责整个给作品供电的电源模块,负责检测油量的油量检测模块,负责整个对电路进行控制的主控制芯片模块,负责对数据进行显示的显示模块,用于切换和调节的按键模块,用于超过安全值而提出报警的报警部分,下面分别讨论和论证以下各个模块的选择以与选择该方案的原因。
1.1 方案论证与选择
1.1.1 作品电源模块的论证与选择
方案一:铅酸电池供电,优点电流大,输出稳定,缺点重量太沉,体积过大。 方案二:USB电源供电,电压电流恒定,但只能连接电脑或充电器。 方案三:太阳能电池板,绿色能源无污染,但受环境,电路构成复杂。 方案四:利用12V的开关电源,功率高,稳定性好,但是成本较高。 方案五:直接利用电池盒,四节五号蓄干电池,对于实验作品较为实用。 经比较,选择方案五,因为蓄电池体积较小,重量较轻,价格便宜,方便调试,又相对较安全。
1.1.2 流量检测模块论证与选择
方案一:LWGY-15涡轮流量计,优点是该传感器具有结构简单、轻巧、精度高。缺点是价格昂贵,对外界电场、磁场的抗干扰能力差。
方案二:YF-21霍尔式水流量传感器,精度高,重量轻,方波计数输出,可以直接被单片机用于计数,价格便宜,程序设计较为容易、抗干扰能力强,不易损坏。
方案三:自制光电对射式流量计,优点是价格便宜,程序设计方便。缺点是精度低,容易受到外界干扰、而且需要手工制作,加大作品制作的难度。
经比较,选择方案二,因为该传感器电路简单,与其他两个方案相比较,综合了其他两个方案的优点。而且作为实验用的设计,不需要太精密的传感器。
1.1.3 主控制芯片模块的论证与选择
方案一:采用宏晶公司的ATS52单片机作为控制系统。该单片机属于八位的MCS-51系列单片机,51单片机是目前低端智能电子产品的主流控制芯片,在八位的单片机中发展最快,资料最全,应用性强,价格便宜。种类多样。
方案二:采用FPGA/CPLD系统,该系统时钟精度高,每个I/O口都可以作为
0 / 59
双向输入输出,I/O口配置灵活。但是程序设计比较复杂,芯片价格昂贵,不适合推广。
方案三:采用飞利浦公司的嵌入式ARM7芯片—LPC2131,该芯片是32位的高级单片机,功能多样,时间快,精度高。资料比较齐全。但是价格昂贵,程序设计比较复杂。
方案四:采用国三星公司的嵌入式ARM9芯片—S3C2440,该芯片应用领域广,可以自带操作系统,智能化水平高,编程难度大,价格昂贵。适用于高端智能电子产品。
经比较,我选择采用方案一,因为我的作品是属于低端的智能电子产品,不需要那么多的功能和接口,虽然其他方案的控制芯片性能好,但是性价比不如方案一高。再加上51单片机经过几十年的发展,技术成熟,使用的频率很高,方便批量生产。
1.1. 4 显示器模块的论证与选择
方案一:诺基亚5110显示屏,是一款基于图形显示的LCD屏,黑白色显示,无任何字库,采用串行总线接口与微控制器相连,引脚少,体积小,价格便宜。程序设计较为复杂。
方案二:2.4寸TFT彩屏模块,可以显示彩色图片和文字,价格比较贵,视角较小,程序设计比较难。引脚比较多。
方案三:8×8点阵,LED点阵需要扫描和列驱动芯片,程序设计比较难,电路设计不方便,需要增加硬件成本。但是价格便宜,灵活性较强。
方案四:LCD1602,LCD液晶显示屏,带背光,自带字库,采用并口通信,功能多样,电路和程序设计简单,价格相对便宜,是低端电子产品的主流显示器之一。
经比较,采用方案四,因为显示的数据不会很多,通过切换就可以现实所有的数据,而且价格相对便宜,控制起来方便。综合以上四种方案,我选择方案四。
1.1.5 按键控制模块的论证与选择
方案一:矩阵键盘,矩阵键盘可以做成4×4、2×2等多种类型,节省I/O口资源。适用于多个按键组成的键盘。
方案二:键盘,每个I/O口控制一个按键,浪费I/O口,易于检测和维修,适用于很少的按键组成的键盘。
经比较,我采用了方案一,因为我的作品实现模式比较多,还要对油量与油价的设置,需要很紧凑的使用I/O口。
1 / 59
1.1.6 报警指示部分论证与选择
方案一:采用喇叭。喇叭的声音比较难听,而且不好控制,但是价格比较便宜。但是需要相关的驱动电路。
方案二:采用蜂鸣器。蜂鸣器的声音比较好听,而且易于控制,价格也便宜,仅需要开关三极管作为驱动电路即可。
方案三:采用LED灯,控制简单,价格极其便宜,无噪声污染。可以直接连接单片机,不需要其他电路。
经比较,我决定方案二和方案三相结合采用。因为本产品是实验设计,为了达到较好的实验效果,要在听觉和视觉上突显,以引起同学和老师们的注意。综合比较之下,我选择方案二和方案三结合起来。
1.2 系统设计
经过上述方案的论证,我决定用MCS-51系列的ATS52单片机作为主控制芯片,用YF-21霍尔式水流量传感器作为油流量的检测,采用LCD1602进行显示油价、油量和总价。采用矩阵按键作为切换和开关,用蜂鸣器和LED灯作为报警和指示。并针对以上器件编写相应的控制程序。
1.2.1 结构方框图
整个电路有矩阵按键,主控制器ATS52单片机,YF-21霍尔式水流量传感器,LCD1602液晶显示器,报警指示系统组成。系统方框图如图1.1所示:
水流量传感器 ATS52单片机 LCD1602显示器 矩阵按键系统 图1.1 系统方框图
报警显示系统
1.2.2 理论分析与计算
本系统要实现,必须先进行一些理论性的分析。主要分析水流量传感器的使用方法和数据转换。而且要确保精度,所以算法一定要精确。
水流量传感器主要由熟料阀体、水流转子组件和霍尔传感器组成。它是装在进水口,由于检测进水量。当水通过水流子组件时,磁性转子转动并且转速随着流量变化而变化,随着磁铁和霍尔开关的距离改变,通过霍尔开关的磁通量也发
2 / 59
生变化,当电流垂直于外磁场通过导体时,磁通量最大,在导体的垂直于磁场和电流方向的两个端面之间会出现电势差,这一现象就是霍尔效应。霍尔开关通过霍尔效应产生差动脉冲信号并输出。霍尔传感器输出相应脉冲信号,反馈给单片机,由单片机判断流量的大小,进行显示和。传感器部结构如图1.2所示。其输出波形如图1.3所示:
图1.2 传感器部结构图
图1.3 输出波形图
传感器技术参数如表1.1所示:
表1.1 传感器参数
适用围 1、最低额定工作电压 基 本 参 数 2、最大工作电流 3、工作电压围 4、负载能力 5、适用温度围 6、使用湿度围 7、允许耐压 8、保存温度 9、保存湿度 适用于热水器,咖啡机,家用数字水表等流量监测设备 DC4.5V-20V 15mA(DC5V) DC5~24V ≤10mA(DC 5V) ≤75℃ 35%~90%RH(无结霜状态) 水压1.75Mpa以下 -30~+86℃ 20%~92%RH 3 / 59
水流量传感器外观如图1.4所示:
图1.4 水流量传感器外观
引出线方式如图1.5所示: 1 红 IN 接正极 2 黄 OUT 信号输出线 3 黑 GND 接负极
图1.5 传感器引出线方式
在这里我选用的是径2mm的水流量传感器。流完一升水输出2400个脉冲。根据这些信息,我们决定采用计数器计波形的方式来采集水流量(计数器检测出脉冲的个数,因为一升水输出2400个脉冲,检测出输出脉冲数后,经过换算后得出流过水流量传感器水有多少升)。
4 / 59
2 系统硬件电路设计
2.1 硬件电路的总体设计
整体电路原理图如图2.1所示,分为显示相关数据的LCD1602显示模块,用于采集流过的水流量检测模块,负责人机交换的按键模块,超出围时的报警模块,为整个电路提供工作电压的主电源模块,对产品进行控制的51单片机最小系统模块。现在由我对每个模块分别进行简单的介绍。
图2.1 整体电路原理图
2.1.1 单片机最小系统
单片机最小系统有晶振电路和复位电路组成,负责提供给单片机工作的必要时钟和复位。其中,EA端接电源,表示采用单片机部的ROM。单片机晶振采用11.0592MHz,用两个30pf的瓷片电容作为起振电容。复位方式采用按键复位,根据电容电压不能突变的特点,用RC串联决定RST脚高电平的时间,高电平持续两个周期以上就可以可靠复位。电路图如图2.2所示:
0 / 59
图2.2 单片机最小系统
2.1.2 液晶显示电路
液晶显示电路主要由以LCD1602为主的配套电路,采用并口通信的方式和单片机通信,3脚接可调电阻调节背光,RS端接单片机P25脚,R/W接单片机P26脚,E接单片机P27脚,DB1到DB7接单片机的P0口,进行数据通信,15脚作为背光调节功能,RP1精密可调电阻作为LCD1602的对比度调整电阻。单片机和LCD液晶显示器的连接图如图2.3所示:
图2.3 单片机和LCD的连接示意图
2.1.3 水流量传感器模块电路
水流量传感器有三条线,分别是电源、信号线、接地,信号线用一个瓷片电
1 / 59
容104耦合,然后接入单片机的I/O口32脚。电路图如图2.4所示:
图2.4 水流量传感器连接电路图
2.1.4 按键控制模块
按键控制模块主要由4×4矩阵按键构成,其中有油量、油单价、总金额三个切换界面的按键和确定键,还有进行调节的数字键0~9,另外多余的两个按键没有用到,为了设计需要还必须得有,我把它们分别设置在了第一行的两边了。按键和单片机的接入如图2.5所示:
图2.5 按键连接电路图
2.1.5 报警指示模块
报警指示模块用于显示流量传感器和进水流量阀的运行情况,报警指示模块采用蜂鸣器和一个LED灯。当流量计流过所设置的流量时进水电磁阀和流量传感器都停止运行,蜂鸣器响起,LED指示灯就会亮起。报警显示的电路如图2.6所示:
2 / 59
图2.6 报警指示模块电路
2.2 片子的简介
2.2.1 ATS51单片机与引脚介绍
①主要性能
1)与MCS-51单片机产品兼容8K字节在系统可编程Flash存储器; 2)1000次擦写周期; 3)全静态操作0Hz~33Hz; 4)三级加密程序存储器; 5)32个可编程I/O口线;
6)三个16位定时器/计数器八个中断源; 7)全双工UART串行通道; 8)低功耗空闲和掉电模式; 9)掉电后中断可唤醒; 10)看门狗定时器; 11)双数据指针; 12)掉电标识符。 ②功能特性描述
ATS52是一种低功耗、高性能CMOS8位微控制器,具有8K在系统可编程 Flash 存储器。使用 Atmel 公司高密度非易失性存储器技术制造,与工业80C51 产品指令和引脚完全兼容。片上Flash允许程序存储器在系统可编程,亦适于常
3 / 59
规编程器。在单芯片上,拥有灵巧的8位CPU和在系统可编程Flash,使得ATS52 为众多嵌入式控制应用系统提供高灵活、超有效的解决方案。
ATS52具有以下标准功能:8k字节Flash,256字节RAM,32位I/O口线,看门狗定时器,2 个数据指针,三个 16 位定时器/计数器,一个6向量2级中断结构,全双工串行口,片晶振与时钟电路。另外,ATS52 可降至0Hz静态逻辑操作,支持2种软件可选择节电模式。空闲模式下,CPU停止工作,允许RAM、定时器/计数器、串口、中断继续工作掉电保护方式下,RAM容被保存,振荡器被冻结,单片机一切工作停止,直到下一个中断或硬件复位为止。
③引脚结构与功能
图2.7 PDIP封装
图2.8 PLCC封装
4 / 59
图2.9 TOFP封装
这里我选用的是图2.7 PDIP封装形式。 VCC:电源 GND:地
P0口:P0口是一个8位漏极开路的双向I/O口。作为输出口,每位能驱动8个TTL逻辑电平。对P0端口写“1”时,引脚用作高阻抗输入。当访问外部程序和数据存储器时,P0口也被作为低8位地址/数据复用。在这种模式下,P0具有部上拉电阻。在flash编程时,P0 口也用来接收指令字节;在程序校验时,输出指令字节。程序校验时,需要外部上拉电阻。
P1口:P1口是一个具有部上拉电阻的8位双向I/O口,p1输出缓冲器能驱动4个TTL逻辑电平。对P1端口写“1”时,部上拉电阻把端口拉高,此时可以作为输入口使用。作为输入使用时,被外部拉低的引脚由于部电阻的原因,将输出电流(IIL)。此外,P1.0和P1.2分别作定时器/计数器2的外部计数输入(P1.0/T2)和时器/计数器2的触发输入(P1.1/T2EX),具体如下表2.1所示。
表2.1 P1口第二功能
引脚号 P1.0 P1.1 P1.5 P1.6 P1.7 第二功能 T2(定时器/计数器T2的外部计数输入),时钟输出 T2EX(定时器/计数器 T2 的捕捉/重载触发信号和方向控制) MOSI(在系统编程用) MISO(在系统编程用) SCK(在系统编程用) 5 / 59
P2口:P2口是一个具有部上拉电阻的8位双向I/O口,P2输出缓冲器能驱动
4个TTL逻辑电平。对P2端口写“1”时,部上拉电阻把端口拉高,此时可以作为输入口使用。作为输入使用时,被外部拉低的引脚由于部电阻的原因,将输出电流(IIL)。在访问外部程序存储器或用16位地址读取外部数据存储器(例如执行MOVX DPTR)时,P2口送出高八位地址。在这种应用中,P2口使用很强的部上拉发送“1”。在使用8位地址(如MOVX RI)访问外部数据存储器时,P2口输出P2锁存器的容。在flash编程和校验时,P2口也接收高8位地址字节和一些控制信号。
P3口:P3口是一个具有部上拉电阻的8位双向I/O口,p2输出缓冲器能驱动4个TTL逻辑电平。对P3端口写“1”时,部上拉电阻把端口拉高,此时可以作为输入口使用。作为输入使用时,被外部拉低的引脚由于部电阻的原因,将输出电流(IIL)。
P3口亦作为ATS52特殊功能(第二功能)使用,如下表2.2所示。
表2.2 P3口第二功能
引脚号 P3.0 P3.1 P3.2 P3.3 P3.4 P3.5 P3.6 P3.7
第二功能 RXD(串行输入) TXD(串行输出) INT0(外部中断0) INT1(外部中断1) T0(定时器0外部输入) T1(定时器1外部输入) WR(外部数据存储器写选通) RD(外部数据存储器写选通) RST:复位输入。晶振工作时,RST脚持续2个机器周期高电平将使单片机复位。看门狗计时完成后,RST脚输出96个晶振周期的高电平。特殊寄存器AUXR(地址8EH)上的DISRTO位可以使此功能无效。DISRTO默认状态下,复位高电平有效。
ALE/PROG:地址锁存控制信号(ALE)是访问外部程序存储器时,锁存低8 位地址的输出脉冲。在flash编程时,此引脚(PROG)也用作编程输入脉冲。在一般情况下,ALE以晶振六分之一的固定频率输出脉冲,可用来作为外部定时器或时钟使用。然而,特别强调,在每次访问外部数据存储器时,ALE脉冲将会跳过。如果需要,通过将地址为8EH的SFR的第0位置“1”,ALE操作将无效。这一位置“1”,ALE仅在执行MOVX或MOVC指令时有效。否则,ALE将被微弱拉高。这个ALE使能标志位(地址为8EH的SFR的第0位)的设置对微控制器处于外部执行模式下无效。
6 / 59
PSEN:外部程序存储器选通信号(PSEN)是外部程序存储器选通信号。 当ATS52从外部程序存储器执行外部代码时,PSEN在每个机器周期被激活两次,而在问外部数据存储器时,PSEN将不被激活。
EA/VPP:访问外部程序存储器控制信号。为使能从0000H到FFFFH的外部程序存储器读取指令,EA必须接GND。为了执行部程序指令,EA应该接VCC。在flash编程期间,EA也接收12伏VPP电压。
XTAL1:振荡器反相放大器和部时钟发生电路的输入端。 XTAL2:振荡器反相放大器的输出端。
石英晶振起振后要能在XTAL2线上输出一个3V左右的正弦波,以便是MCS-51片的OSC电路按石英晶振一样频率自激振动。通常,focs的输出时钟频率为0.5MHz-16MHz,典型值为12MHz或11.059MHz。电容可以帮助起振,典型值为30pf,它们可以达到微调focs的目的。
MCS-51所需的时钟也可以由外部振荡器提供。外部时钟源应是方波发生器,频率应根据所用MCS-51中的具体机型确定。
2.2.2 LCD1602液晶显示器
LCD(英文全称为Liquid Crystal Display)是液晶显示器的简称。LCD具有低辐射、体积小、能耗低的优点,而且结构简单,价格便宜。
LCD1602液晶显示原理
液晶显示的原理是利用液晶的物理特性,通过电压对其显示区域进行控制,优点就有显示,这样即可以显示出图形。一般1602字符型液晶显示器实物如图2.10
图2.10 LCD1602液晶显示器实物图
①主要技术参数
表2.3 1602的技术参数
显示容量 工作电压 工作电流 背光源颜色 背光源电流 ②引脚说明
16×2个字符 4.8~5.2V 2.0Ma(5.0V) 黄绿 ﹤150mA 模块最佳工作电压 字符尺寸 工作温度 存储温度 表2.4 1602的引脚说明
5.0V 4.95×7.95mm 0~+50℃ -20~+70℃ 7 / 59
脚号 1 2 符号 Vss Vdd 引脚说明 电源地(GND) 电源电压(+5V) LCD驱动电压(可调)寄存器选择输入端,输入MPU选择3 VO 模块部寄存器类型信号:RS=0,当MPU进行写模块操作,指向指令寄存器 4 5 6 7 8 9 10 11 12 13 14 15 16 RS R/W E DB0 DB1 DB2 DB3 DB4 DB5 DB6 DB7 A K 当MPU进行读模块操作,指向地址计数器;RS=1,无论MPU读操作还是写操作,均指向数据寄存器 R/W=0读操作;R/W=1写操作 使能信号输入端,输入MPU读/写模块操作使能信号 数据输入/输出口,MPU与模块之间的数据传送通道 数据输入/输出口,MPU与模块之间的数据传送通道 数据输入/输出口,MPU与模块之间的数据传送通道 数据输入/输出口,MPU与模块之间的数据传送通道 数据输入/输出口,MPU与模块之间的数据传送通道 数据输入/输出口,MPU与模块之间的数据传送通道 数据输入/输出口,MPU与模块之间的数据传送通道 数据输入/输出口,MPU与模块之间的数据传送通道 背光的正端+5V 背光的负端 0V 注意:四位方式通讯时,不能用DB0~DB3。 ③控制器接口说明 1)基本操作时序
读状态:输入:RS=L, RW=H, E=H;输出:D0~D7=状态
写指令:输入:RS=L, RW=L, D0~D7=指令码, E=高脉冲;输出:无 读数据:输入:RS=H, RW=H, E=H;输出:D0~D7=数据
写数据:输入:RS=H, RW=L, D0~D7=数据, E=高脉冲;输出:无 2)RAM地址映射图
控制器部带有80×8位(80字节)的RAM缓冲区,对应关系如图2.11所示:
8 / 59
图2.11 地址映射图
④初始化过程(复位过程) 延时15ms
写指令38H(不检测忙信号) 延时5ms
写指令38H(不检测忙信号) 延时5ms
写指令38H(不检测忙信号)
(以后每次写指令、读/写数据操作之前均需检测忙信号) 写指令38H:显示模式设置 写指令08H:显示关闭 写指令01H:显示清屏 写指令06H:显示光标移动设置 写指令0CH:显示开与光标设置 ⑤控制器接口时序说明 1)读操作时序
9 / 59
图2.12 读操作时序
2)写操作时序
图2.13 写操作时序
3)时序参数
10 / 59
表2.5 液晶1602时序图标号说明
时序参数 E信号周期 E脉冲宽度 E上升沿/下降沿时间 地址建立时间 地址保持时间 数据建立时间(读操作) 符号 tc tpw Tr,tf Tsp1 Thd1 Td 极限值 最小值 典型值 最大值 400 150 - 30 10 - 20 40 10 - - - - - - - - - - - 25 - - 100 - - - 单位 ns ns ns ns ns ns ns ns 测试条件 引脚E ns 引脚E、RS、R/W 数据保持时间(读操作) Thd2 数据建立时间(写操作) Tsp2 数据保持时间(写操作) Thd2 引脚DB0~D 2.2.3 单片机与LCD1602液晶显示器的连接
其连接图如图2.14所示:
图2.14 1602的连接图
其中1602的D0~D7分别通过排阻与单片机的P00~P07口相连。
11 / 59
3 单片机软件程序设计
系统软件设计是设计的核心,也是设计的重点和难点部分。控制系统软件设计的好坏直接影响到该控制系统的控制功能,因此,要想做好本设计,一个好的系统软件是关键。
单片机程序设计在整个系统中是十分重要的,为了设计方便和便于修改,本作品用C语言进行程序的设计和控制,因为C语言编写简单,置入容易,方便修改。而且本作品在时间上不需要太精确,程序占的存小,单片机的存也足够大,所以不采用汇编语言。
为了方便书写和检查,本作品采用了多个C文件分开写,在MAIN.c中进行调用的方式编写程序。下面将程序分模块进行描述,本作品的程序主要分为三部分:主程序、各种中断子程序。主程序完成系统的地址分配、系统初始化。实现系统的数字化显示。各子程序完成相应的各功能。
主程序 液晶 显 示 按 键 输 入 数 据 采 集
图3.1 程序结构图
3.1 主程序流程图
主程序部分,主要完成存储器分配、系统初始化等,并通过调用各子程序段,实现软件的总体设计功能。其流程图如图3.2所示:
其对应的程序主要如下: void main() {
init_1602(); Dis_SetSum();
EX0=0;//关闭外部中断0
0 / 59
IT0=1;//边沿触发中断 EA=1;//开启总中断 while(1) {
keyscan(); display(); Control(); } }
开 始 初始化程序 流量检测程序 LCD液晶显示程序
图3.2 主程序流程图
3.2 水流量检测程序
水流量传感器是采用霍尔传感器制作的,只要收集传感器传回的方波个数,就可以换算成水量。常用的设计方法是,采用单片机的定时器和计数器对方波信号进行计数,并且定时器每50ms中断一次,每中断两次,就采集一次脉冲的个数,把脉冲的个数经过处理以后转换成水量,经过数据处理以后送给LCD进行显示。其程序流程图如图3.3所示:
其中油费的主要计算程序如下:
write_(0x80+0x40+10);//显示加入油量的金额 if(Total_Sum/10000>0)
write_date(LCD1602_Table[Total_Sum/10000]); else
1 / 59
write_date(' '); if(Total_Sum/1000>0)
write_date(LCD1602_Table[Total_Sum%10000/1000]); else
write_date(' '); if(Total_Sum/100>0)
write_date(LCD1602_Table[Total_Sum%1000/100]); else
write_date(' ');
write_date(LCD1602_Table[Total_Sum%100/10]); write_date('.');
write_date(LCD1602_Table[Total_Sum%10]); }
开 始 设置为定时器0,计数器1 开启定时计数器,开始计数定时 否 100ms?是 获取计数值,将脉冲转换为油量 计算油费,并将其送至LCD 结 束
图3.3 油流量检测程序流程
3.3 LCD液晶显示程序
LCD液晶显示程序专门用于控制LCD1602液晶屏的程序,对时序要求比较严格,
2 / 59
我在编写前特意查阅了时序逻辑图。LCD液晶显示程序大致分为写命令、写数据和初始化三部分。其流程图如图3.4所示:
其对应的程序如下: sbit EN=P2^7; sbit RS=P2^5; sbit RW=P2^6;
unsigned char LCD1602_Table[]=\"01234567:-\";//01234567abcdef unsigned char code DIS1_TAB[]={\" :---.- Pr:---.-\显示金额和单价 unsigned char code DIS2_TAB[]={\"---.--L :----.-\显示加入的油量和总金额
unsigned char code DIS3_TAB[]={\" Please set the\unsigned char code DIS4_TAB[]={\"unit price:---.-\
/ * * * * * * * * * * * * * * *液 晶 显 示 写 数 据* * * * * * * * * * * * * ** */
void write_date(uchar date)//写数据 {
EN=0;//使能为0 RS=1;//写数据设置 P0=date;//输入数据 EN=0;//使能为0 delayms(5);//延时5ms EN=1;//使能为1 }
/ * * * * * * * * * * * * * * *液 晶 显 示 写 指 令* * * * * * * * * * * * * ** */
void write_(uchar date) {
EN=0;//使能为0 RS=0;//写命令设置 P0=date;//输入命令 EN=0;//使能为0 delayms(5);//延时5ms EN=1;//使能为1 }
3 / 59
void init_1602() {
unsigned char i; RW=0;//并行数据的读写 write_(0x38); write_(0x0c); write_(0x06); write_(0x01); write_(0x80);
开 始 是 LCD忙? 否 写命令 写数据 RS=0,写入命令 RS=1,写入数据 LCD初始化,设置工作方式 各子程序调用写数据和写命令函数 结 束
图3.4 LCD显示流程图
3.4 按键的控制程序
对于按键的控制程序我设计为如下: sbit KEY_ROW1=P1^3;
4 / 59
sbit KEY_ROW2=P1^2; sbit KEY_ROW3=P1^1; sbit KEY_ROW4=P1^0; sbit KEY_LIN1=P1^4; sbit KEY_LIN2=P1^5; sbit KEY_LIN3=P1^6; sbit KEY_LIN4=P1^7; unsigned char key_num=0; unsigned char key_flag=0;
extern void delayms(unsigned int xms); #defineDEF_KEY1 KEY_ROW1=0; KEY_ROW2=1; KEY_ROW3=1; KEY_ROW4=1 #defineDEF_KEY2 KEY_ROW1=1; KEY_ROW2=0; KEY_ROW3=1; KEY_ROW4=1 #defineDEF_KEY3 KEY_ROW1=1; KEY_ROW2=1; KEY_ROW3=0; KEY_ROW4=1 #defineDEF_KEY4 KEY_ROW1=1; KEY_ROW2=1; KEY_ROW3=1; KEY_ROW4=0
5 / 59
4 电路调试和方法
4.1 检测方法
本作品主要是调试和检测油流量传感器采集来的数据是否正确,是否有报警,各个按键能否正常行驶功能,LCD能否正常工作并正常显示。
首先检测LCD能不能工作和显示正常的容。开机以后,观察LCD的显示是不是自己想要的样子,并且同时通过按键切换显示界面和修改油的单价,确定按键能不能正常工作。
然后检测传感器能否送回数据,以与送回的数据是否有错。如果正常,作品上电,在LCD显示正常等的情况下,把一定量的油慢慢注入传感器,尽量保证没有溢出。注入完毕后,观察LCD显示器上的数据是否显示差不多正确的数据。同时查看蜂鸣器和LED指示灯是否有效的报警提示。
4.2 硬件系统调试
4.2.1 初步硬件调试问题
当完成PCB板焊接后,把程序写入单片机,接上电源,显示屏上有亮度,但亮度不够也没有显示。当显示正常的时候,把油通入流量传感器的时候,显示屏上关于水流量的数字并没有变化。单价和流量的控制按键调节时不会变动。LED灯也不会亮。
4.2.2 问题分析
①可能是LCD1602与单片机连接的引脚可能有错误。
②显示屏亮度不够可能是因为程序冲突或者是连接电阻过大导致电流太小。 ③屏幕上关于油流量的流量示数不变,可能是因为流量计的入水口和出水口装反了或是流量传感器的三个引脚与单片机的连接有误。
④使用按键并没有发现单价与流量的切换可能是因为出现了虚焊,焊接不牢固的原因。
⑤LED灯不亮可能是正负极接反了或是坏了。
4.2.3 解决方案
①显示屏LCD1602不亮,经检查是ATS52第20引脚忘记接地,把第20引脚接地后问题得以解决了,出现了所希望的功能列表。
0 / 59
②显示屏LCD1602亮度不够,通过调节变阻器使得显示屏有足够的亮度看清楚上面的显示。
③屏幕上关于流量的示数不变,我检查了一下,发现是我不注意把传感器进出口搞错了。
④我把切换按键与周围的器件重新在焊接了一遍,又把电池重新换了新的,结果就出现了变动。
⑤LED灯不亮是因为我把它的正负极接反了。重新接好后会亮了。
4.3 软件系统调试
单片计程序烧入以后,调试的时候, LCD液晶显示器显示的油价和理论计算出的油价格差距过大。经过我的分析,我对油价格的计算程序部分做了修改正油。
write_(0x80+0x40+10);//显示加入油量的金额 if(Total_Sum/10000>0)
write_date(LCD1602_Table[Total_Sum/10000]); else
write_date(' '); if(Total_Sum/1000>0)
write_date(LCD1602_Table[Total_Sum%10000/1000]); else
write_date(' '); if(Total_Sum/100>0)
write_date(LCD1602_Table[Total_Sum%1000/100]); else
write_date(' ');
write_date(LCD1602_Table[Total_Sum%100/10]); write_date('.');
write_date(LCD1602_Table[Total_Sum%10]); }
1 / 59
结 论
通过软硬件联调和综合测试,本作品完全实现了预期的功能。经过这次毕业设计的制作,我得到了很好的锻炼,一方面是对整个系统设计的方法有了很清楚的认识,能够统筹兼顾的考虑各类问题并且对模块化设计思路有更进一步的认识。另一方面是提高了我的单片机程序设计的技巧,硬件电路的设计方法,电路疑难故障处理方法,以与面对难题不退却,用于攻关的精神。
在设计过程中我遇到了很多问题,例如:各硬件芯片的选择,流量计控制部分设计,软件的编程等。不过最终这些问题在老师和同学的细心帮助下,我一点一点的解决了。同时也增加了我收集资料的能力,能几个思路放在一起择优取之。在设计的过程中学到了许多解决问题的思想,特别是某些细节难点的解决思想。当我做设计是需要考虑各方面的情况和方案的可行性程度,包括对总体和各个模块的方案进行理论上的论证,对各个具体的模块进行分块功能测试,设计使用的元件能不能很方便的买到与整个作品的成本等等因素都需要考虑,最终选择我可以接受的较优的方案。
在一些细节问题上有很多要特别的注意,比如要在现有的硬件条件下,有的功能不能用硬件来完成,这时可以考虑利用程序来完成。这次设计过程给我较深的问题是用软件来实现的仿真,我感觉有点不好整。除了这些,给我很大感触的一个程序调试,这个事既花时间又尤为重要,特别是流量传感器调试的时候和LCD1602的显示调试,这个过程我是在几个同学的共同帮助下才完成的。
实际的应用加深了我对大学所学的软、硬件知识的理解。单片机的选用与学习增强了我实际分析解决问题的能力。这次设计让我初次体验了产品设计开发的过程,学习了开发应用的主要方法,也让我意识到理论知识与实际应用之间的距离。当然,在本设计中没有涉与到芯片部的元件设计,另外我的软件设计也存在着一些不足和缺陷之处,在此恳请各位老师对我的作品进行批评指正,我将尽力改善我的作品功能。
0 / 59
参考文献
[1] 毅刚.单片机原理与应用[M].:高等教育,2004.
[2] 郭天祥.新概念51单片机C语言教程[M].:电子工业,2009. [3] 童诗白、华成英.模拟电子技术基础[M].:高等教育,2006. [4] 阎石.数字电子技术基础[M].:高等教育,2006. [5] 为.单片机典型系统设计实例精讲[M].:电子工业,2006. [6] 梁国伟、蔡武昌.流量测量技术与仪表[M].:机械工业,2002. [7] 王玉巧、蔡晓艳.基于单片机的流量控制[J].科技信息,2010.
[8] 徐晓光、徐康.基于单片机的涡轮流量检测仪设计[J].工业控制计算机,2008. [9] 昌权.基于ATC52单片机的智能流量积算仪设计[J].轻工业,2010. [10] 颖.基于单片机的流量检测表设计[J].科技,2007.
[11] 于文辉.基于单片机的智能流量控制系统[J].微计算机信息杂志,2009. [12] 周常柱、胡松.单片机在流量测量中的应用[J].微计算机信息杂志 ,2005.
0 / 59
致
经过两个月的努力,整个毕业设计按照毕业任务书的相关容,在参阅了大量资料后,做的紧而有条理。我觉得自己学习到了很多东西,提高了我发现问题,分析问题,解决问题的能力。非常感贺伟老师对我的悉心指导和帮助,还有陪伴在身边一起做毕业设计的同学们,我们都做不同的毕业设计,但是很多地方我们还是互帮互助,让我感受到大家庭的温暖,最后感大学几年里所有给我们上过课的老师们,是他们为我们的专业知识打下坚实的基础。
0 / 59
附 录
附录A:电路原理图
0 / 59
附录B:PCB图
0 / 59
附录C:作品图
0 / 59
附录D:元件清单
单元器件名称 单片机 液晶显示器 进水电磁阀 水流量传感器 继电器 电池盒 拔头开关 电阻 电阻 电容 电容 晶振 排阻 可变电阻 LED 续流二极管 三极管 蜂鸣器 按键
型号 ATS52 LCD1602 220V 50HZ FY-21 HK4100FDC5V 1K 10K 10uF 30P 11.0592MHz 103 103 8550 数量 1 1 1 1 1 1 1 4 1 1 2 1 1 1 1 1 2 1 17 0 / 59
附录E:程序单
#include #define uchar unsigned char//宏定义 #define uint unsigned int sbit Relay=P2^3;//继电器控制接口 sbit Beep=P2^4;//报警指示接口 uchar Dat_buf[8]=0; //按键输入数据的缓冲数组 uchar Mode_flag=0;//模式标志位0金额模式1体积模式2设置单价模式 uint Set_Sum=0;//设定加油金额(单位:角) uint Set_Liter=0;//设定加油的油量(单位:ml) uint In_Liter=0;//当前已经加入多少升的油量 uint Price=0;//单价(单位:/L) uint Total_Sum=0;//加入油量的总金额(单位:元) uint num1=0; bit start_flag=0;//开始加油标志位 /*************************************************** 函数名称:延时子函数 函数功能:按键消抖 ***************************************************/ void delayms(uint xms) { uint i,j; for(i=xms;i>0;i--) for(j=110;j>0;j--); } #include \"1602.C\" #include \"KEY.C\" //显示设置的金额 void Dis_SetSum() { Set_Sum=Dat_buf[3]*1000+Dat_buf[2]*100+Dat_buf[1]*10+Dat_buf[0];//计算设定的金额 0 / 59 write_(0x80);//显示设定的金额 write_date(0x5c);//'¥' write_date(':'); if(Set_Sum/1000>0) write_date(LCD1602_Table[Set_Sum/1000]); else write_date(' '); if(Set_Sum/100>0) write_date(LCD1602_Table[Set_Sum%1000/100]); else write_date(' '); write_date(LCD1602_Table[Set_Sum%100/10]); write_date('.'); write_date(LCD1602_Table[Set_Sum%10]); } //显示设置的油量 void Dis_SetLiter() { Set_Liter=Dat_buf[3]*1000+Dat_buf[2]*100+Dat_buf[1]*10+Dat_buf[0];//计算设定的油量 write_(0x80); //显示设定的油量 write_date('L'); //'L' write_date(':'); if(Set_Liter/1000>0) write_date(LCD1602_Table[Set_Liter/1000]); else write_date(' '); if(Set_Liter/100>0) write_date(LCD1602_Table[Set_Liter%1000/100]); else write_date(' '); write_date(LCD1602_Table[Set_Liter%100/10]); write_date('.'); write_date(LCD1602_Table[Set_Liter%10]); 1 / 59 } //显示设置单价 void Dis_SetPrice() { Price=Dat_buf[3]*1000+Dat_buf[2]*100+Dat_buf[1]*10+Dat_buf[0];//计算设定的单价 write_(0x80+11+0x40); //显示设定的单价 if(Price/1000>0) write_date(LCD1602_Table[Price/1000]); else write_date(' '); if(Price/100>0) write_date(LCD1602_Table[Price%1000/100]); else write_date(' '); write_date(LCD1602_Table[Price%100/10]); write_date('.'); write_date(LCD1602_Table[Price%10]); write_date(' '); } //按键扫描 void keyscan() { uchar i; key(); switch(key_num) { case 1://清零按键 In_Liter=0; Total_Sum=0; num1=0; break; case 2://开始加油按键按键 start_flag=1; 2 / 59 num1=0; EX0=1; //打开外部中断0 break; case 5: if(!start_flag) { if(Mode_flag==2) { write_(0x80); for(i=0;i<16;i++) write_date(DIS1_TAB[i]); write_(0x80+0x40); for(i=0;i<16;i++) write_date(DIS2_TAB[i]); write_(0x80+0x40+8); write_date(0x5c);//'¥' } Mode_flag=0;//0金额模式 Dat_buf[3]=Set_Sum%10000/1000; Dat_buf[2]=Set_Sum%1000/100; Dat_buf[1]=Set_Sum%100/10; Dat_buf[0]=Set_Sum%10; Dis_SetSum(); } break; case 9: if(!start_flag) { if(Mode_flag==2) { write_(0x80); for(i=0;i<16;i++) write_date(DIS1_TAB[i]); write_(0x80+0x40); 3 / 59 for(i=0;i<16;i++) write_date(DIS2_TAB[i]); write_(0x80+0x40+8); write_date(0x5c); //'¥' } Mode_flag=1;//1体积模式 Dat_buf[3]=Set_Liter%10000/1000; Dat_buf[2]=Set_Liter%1000/100; Dat_buf[1]=Set_Liter%100/10; Dat_buf[0]=Set_Liter%10; Dis_SetLiter(); } break; case 13: if(!start_flag) { Mode_flag=2;//2设置单价模式 write_(0x80); for(i=0;i<16;i++) write_date(DIS3_TAB[i]); write_(0x80+0x40); for(i=0;i<16;i++) write_date(DIS4_TAB[i]); Dat_buf[3]=Price%10000/1000; Dat_buf[2]=Price%1000/100; Dat_buf[1]=Price%100/10; Dat_buf[0]=Price%10; Dis_SetPrice(); } break; default: break; } switch(Mode_flag) { 4 / 59 case 0://金额模式 switch(key_num) { case 3://数字‘0’ for(i=7;i>0;i--) {Dat_buf[i]=Dat_buf[i-1];} Dat_buf[0]=0; Dis_SetSum(); break; case 6://数字‘1’ for(i=7;i>0;i--) {Dat_buf[i]=Dat_buf[i-1];} Dat_buf[0]=1; Dis_SetSum(); break; case 7://数字‘2’ for(i=7;i>0;i--) {Dat_buf[i]=Dat_buf[i-1];} Dat_buf[0]=2; Dis_SetSum(); break; case 8://数字‘3’ for(i=7;i>0;i--) {Dat_buf[i]=Dat_buf[i-1];} Dat_buf[0]=3; Dis_SetSum(); break; case 10://数字‘4’ for(i=7;i>0;i--) {Dat_buf[i]=Dat_buf[i-1];} Dat_buf[0]=4; Dis_SetSum(); break; case 11://数字‘5’ 5 / 59 for(i=7;i>0;i--) {Dat_buf[i]=Dat_buf[i-1];} Dat_buf[0]=5; Dis_SetSum(); break; case 12://数字‘6’ for(i=7;i>0;i--) {Dat_buf[i]=Dat_buf[i-1];} Dat_buf[0]=6; Dis_SetSum(); break; case 14://数字‘7’ for(i=7;i>0;i--) {Dat_buf[i]=Dat_buf[i-1];} Dat_buf[0]=7; Dis_SetSum(); break; case 15://数字‘8’ for(i=7;i>0;i--) {Dat_buf[i]=Dat_buf[i-1];} Dat_buf[0]=8; Dis_SetSum(); break; case 16://数字‘9’ for(i=7;i>0;i--) {Dat_buf[i]=Dat_buf[i-1];} Dat_buf[0]=9; Dis_SetSum(); break; } break; case 1:// 油量模式 switch(key_num) { 6 / 59 case 3://数字‘0’ for(i=7;i>0;i--) {Dat_buf[i]=Dat_buf[i-1];} Dat_buf[0]=0; Dis_SetLiter(); break; case 6://数字‘1’ for(i=7;i>0;i--) {Dat_buf[i]=Dat_buf[i-1];} Dat_buf[0]=1; Dis_SetLiter(); break; case 7://数字‘2’ for(i=7;i>0;i--) {Dat_buf[i]=Dat_buf[i-1];} Dat_buf[0]=2; Dis_SetLiter(); break; case 8://数字‘3’ for(i=7;i>0;i--) {Dat_buf[i]=Dat_buf[i-1];} Dat_buf[0]=3; Dis_SetLiter(); break; case 10://数字‘4’ for(i=7;i>0;i--) {Dat_buf[i]=Dat_buf[i-1];} Dat_buf[0]=4; Dis_SetLiter(); break; case 11://数字‘5’ for(i=7;i>0;i--) {Dat_buf[i]=Dat_buf[i-1];} Dat_buf[0]=5; 7 / 59 Dis_SetLiter(); break; case 12://数字‘6’ for(i=7;i>0;i--) {Dat_buf[i]=Dat_buf[i-1];} Dat_buf[0]=6; Dis_SetLiter(); break; case 14://数字‘7’ for(i=7;i>0;i--) {Dat_buf[i]=Dat_buf[i-1];} Dat_buf[0]=7; Dis_SetLiter(); break; case 15://数字‘8’ for(i=7;i>0;i--) {Dat_buf[i]=Dat_buf[i-1];} Dat_buf[0]=8; Dis_SetLiter(); break; case 16://数字‘9’ for(i=7;i>0;i--) {Dat_buf[i]=Dat_buf[i-1];} Dat_buf[0]=9; Dis_SetLiter(); break; } break; case 2://单价设置模式 switch(key_num) { case 3://数字‘0’ for(i=7;i>0;i--) {Dat_buf[i]=Dat_buf[i-1];} 8 / 59 Dat_buf[0]=0; Dis_SetPrice(); break; case 6://数字‘1’ for(i=7;i>0;i--) {Dat_buf[i]=Dat_buf[i-1];} Dat_buf[0]=1; Dis_SetPrice(); break; case 7://数字‘2’ for(i=7;i>0;i--) {Dat_buf[i]=Dat_buf[i-1];} Dat_buf[0]=2; Dis_SetPrice(); break; case 8://数字‘3’ for(i=7;i>0;i--) {Dat_buf[i]=Dat_buf[i-1];} Dat_buf[0]=3; Dis_SetPrice(); break; case 10://数字‘4’ for(i=7;i>0;i--) {Dat_buf[i]=Dat_buf[i-1];} Dat_buf[0]=4; Dis_SetPrice(); break; case 11://数字‘5’ for(i=7;i>0;i--) {Dat_buf[i]=Dat_buf[i-1];} Dat_buf[0]=5; Dis_SetPrice(); break; case 12://数字‘6’ 9 / 59 for(i=7;i>0;i--) {Dat_buf[i]=Dat_buf[i-1];} Dat_buf[0]=6; Dis_SetPrice(); break; case 14://数字‘7’ for(i=7;i>0;i--) {Dat_buf[i]=Dat_buf[i-1];} Dat_buf[0]=7; Dis_SetPrice(); break; case 15://数字‘8’ for(i=7;i>0;i--) {Dat_buf[i]=Dat_buf[i-1];} Dat_buf[0]=8; Dis_SetPrice(); break; case 16://数字‘9’ for(i=7;i>0;i--) {Dat_buf[i]=Dat_buf[i-1];} Dat_buf[0]=9; Dis_SetPrice(); break; } break; default: break; } key_num=0; } //控制子程序 void Control() { unsigned long dat=0; if(start_flag)//如果开始加油标志位置位 10 / 59 { if(num1>10) { num1=0; In_Liter++; } dat=(In_Liter*Price)/100; Total_Sum=(uint)(dat); if(Mode_flag==0)//在设定金额模式下 { if(Set_Sum>Total_Sum) Relay=0; else { EX0=0;//关闭外部中断0 display(); display(); start_flag=0; Beep=0; delayms(200); Beep=1; delayms(200); Beep=0; delayms(200); Beep=1; delayms(200); Beep=0; delayms(200); Beep=1; delayms(200); } } else if(Mode_flag==1) { 11 / 59 if(Set_Liter>In_Liter/10) Relay=0; else { EX0=0;//关闭外部中断0 display(); display(); start_flag=0; Beep=0; delayms(200); Beep=1; delayms(200); Beep=0; delayms(200); Beep=1; delayms(200); Beep=0; delayms(200); Beep=1; delayms(200); } } } else { Relay=1; } } //主程序 void main() { init_1602(); Dis_SetSum(); EX0=0;//关闭外部中断0 / 59 12 IT0=1;//边沿触发中断 EA=1;//开启总中断 while(1) { keyscan(); display(); Control(); } } void E_X0() interrupt 0 { num1++; } sbit KEY_ROW1=P1^3; sbit KEY_ROW2=P1^2; sbit KEY_ROW3=P1^1; sbit KEY_ROW4=P1^0; sbit KEY_LIN1=P1^4; sbit KEY_LIN2=P1^5; sbit KEY_LIN3=P1^6; sbit KEY_LIN4=P1^7; unsigned char key_num=0; unsigned char key_flag=0; extern void delayms(unsigned int xms); #define DEF_KEY1 KEY_ROW1=0;KEY_ROW2=1;KEY_ROW3=1;KEY_ROW4=1 #define DEF_KEY2 KEY_ROW1=1;KEY_ROW2=0;KEY_ROW3=1;KEY_ROW4=1 #define DEF_KEY3 KEY_ROW1=1;KEY_ROW2=1;KEY_ROW3=0;KEY_ROW4=1 #define DEF_KEY4 KEY_ROW1=1;KEY_ROW2=1;KEY_ROW3=1;KEY_ROW4=0 void key() { if(key_num==0) { DEF_KEY1; if((!KEY_LIN1)||(!KEY_LIN2)||(!KEY_LIN3)||(!KEY_LIN4)) 13 / 59 { delayms(8); if(((!KEY_LIN1)||(!KEY_LIN2)||(!KEY_LIN3)||(!KEY_LIN4))&&(key_flag==0)) { key_flag=1; if(!KEY_LIN1) key_num=1; else if(!KEY_LIN2) key_num=2; else if(!KEY_LIN3) key_num=3; else if(!KEY_LIN4) key_num=4; } } else if(key_flag==1) key_flag=0; DEF_KEY2; if((!KEY_LIN1)||(!KEY_LIN2)||(!KEY_LIN3)||(!KEY_LIN4)) { delayms(8); if(((!KEY_LIN1)||(!KEY_LIN2)||(!KEY_LIN3)||(!KEY_LIN4))&&(key_flag==0)) { key_flag=2; if(!KEY_LIN1) key_num=5; else if(!KEY_LIN2) key_num=6; else if(!KEY_LIN3) key_num=7; else if(!KEY_LIN4) key_num=8; 14 / 59 } } else if(key_flag==2) key_flag=0; DEF_KEY3; if((!KEY_LIN1)||(!KEY_LIN2)||(!KEY_LIN3)||(!KEY_LIN4)) { delayms(8); if(((!KEY_LIN1)||(!KEY_LIN2)||(!KEY_LIN3)||(!KEY_LIN4))&&(key_flag==0)) { key_flag=3; if(!KEY_LIN1) key_num=9; else if(!KEY_LIN2) key_num=10; else if(!KEY_LIN3) key_num=11; else if(!KEY_LIN4) key_num=12; } } else if(key_flag==3) key_flag=0; DEF_KEY4; if((!KEY_LIN1)||(!KEY_LIN2)||(!KEY_LIN3)||(!KEY_LIN4)) { delayms(8); if(((!KEY_LIN1)||(!KEY_LIN2)||(!KEY_LIN3)||(!KEY_LIN4))&&(key_flag==0)) { key_flag=4; if(!KEY_LIN1) key_num=13; 15 / 59 else if(!KEY_LIN2) key_num=14; else if(!KEY_LIN3) key_num=15; else if(!KEY_LIN4) key_num=16; } } else if(key_flag==4) key_flag=0; } } sbit EN=P2^7; sbit RS=P2^5; sbit RW=P2^6; unsigned char LCD1602_Table[]=\"01234567:-\";//01234567abcdef unsigned char code DIS1_TAB[]={\" :---.- Pr:---.-\显示金额和单价 unsigned char code DIS2_TAB[]={\"---.--L :----.-\显示加入的油量和总金额 unsigned char code DIS3_TAB[]={\" Please set the\unsigned char code DIS4_TAB[]={\"unit price:---.-\ / * * * * * * * * * * * * * * *液 晶 显 示 写 数 据* * * * * * * * * * * * * ** */ void write_date(uchar date)//写数据 { EN=0;//使能为0 RS=1;//写数据设置 P0=date;//输入数据 EN=0;//使能为0 delayms(5);//延时5ms EN=1;//使能为1 } / * * * * * * * * * * * * * * *液 晶 显 示 写 指 令* * * * * * * * * * * * * ** */ 16 / 59 void write_(uchar date) { EN=0;//使能为0 RS=0;//写命令设置 P0=date;//输入命令 EN=0;//使能为0 delayms(5);//延时5ms EN=1;//使能为1 } void init_1602() { unsigned char i; RW=0;//并行数据的读写 write_(0x38); write_(0x0c); write_(0x06); write_(0x01); write_(0x80); for(i=0;i<16;i++) write_date(DIS1_TAB[i]); write_(0x80+0x40); for(i=0;i<16;i++) write_date(DIS2_TAB[i]); write_(0x80+0x40+8); write_date(0x5c); //'¥' } void display() { if(Mode_flag<2) //未在单价设置状态下 { write_(0x80+11);//显示单价 if(Price/1000>0) write_date(LCD1602_Table[Price/1000]); else 17 / 59 write_date(' '); if(Price/100>0) write_date(LCD1602_Table[Price%1000/100]); else write_date(' '); write_date(LCD1602_Table[Price%100/10]); write_date('.'); write_date(LCD1602_Table[Price%10]); write_(0x80+0x40);//显示加入的油量 if(In_Liter/10000>0) write_date(LCD1602_Table[Price/10000]); else write_date(' '); if(In_Liter/1000>0) write_date(LCD1602_Table[In_Liter%10000/1000]); else write_date(' '); write_date(LCD1602_Table[In_Liter%1000/100]); write_date('.'); write_date(LCD1602_Table[In_Liter%100/10]); write_date(LCD1602_Table[In_Liter%10]); write_(0x80+0x40+10);//显示加入油量的金额 if(Total_Sum/10000>0) write_date(LCD1602_Table[Total_Sum/10000]); else write_date(' '); if(Total_Sum/1000>0) write_date(LCD1602_Table[Total_Sum%10000/1000]); else write_date(' '); if(Total_Sum/100>0) write_date(LCD1602_Table[Total_Sum%1000/100]); else write_date(' '); 18 / 59 write_date(LCD1602_Table[Total_Sum%100/10]); write_date('.'); write_date(LCD1602_Table[Total_Sum%10]); } } write_(0x80+0x40); //显示加入的油量 if(In_Liter/10000>0) write_date(LCD1602_Table[Price/10000]); else write_date(' '); if(In_Liter/1000>0) write_date(LCD1602_Table[In_Liter%10000/1000]); else write_date(' '); write_date(LCD1602_Table[In_Liter%1000/100]); write_date('.'); write_date(LCD1602_Table[In_Liter%100/10]); write_date(LCD1602_Table[In_Liter%10]); write_(0x80+0x40+10); if(Total_Sum/10000>0) write_date(LCD1602_Table[Total_Sum/10000]); else write_date(' '); if(Total_Sum/1000>0) write_date(LCD1602_Table[Total_Sum%10000/1000]); else write_date(' '); if(Total_Sum/100>0) write_date(LCD1602_Table[Total_Sum%1000/100]); else write_date(' '); write_date(LCD1602_Table[Total_Sum%100/10]); write_date('.'); write_date(LCD1602_Table[Total_Sum%10]); 19 / 59 //显示加入油量的金额 } } 20 / 59
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- 517ttc.cn 版权所有 赣ICP备2024042791号-8
违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务