这个电路图是复位电路吗?还是什么功能?tx,rx接单片机蜂鸣器电路图,sd电压23伏特左右。

 下载
 收藏
该文档贡献者很忙,什么也没留下。
 下载此文档
正在努力加载中...
单片机式语音播报伏特表
下载积分:750
内容提示:
文档格式:DOC|
浏览次数:1|
上传日期: 23:44:59|
文档星级:
该用户还上传了这些文档
下载文档:单片机式语音播报伏特表.DOC
官方公共微信当今世界面临着能源短缺与环境污染两大问题,以太阳能电池为核心元件的太阳能光伏..
扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
毕业设计(论文)-基于单片机的太阳能电池数据采集系统设计(含电路图和流程图)
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='/DocinViewer-4.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口您所在位置: &
&nbsp&&nbsp&nbsp&&nbsp
基于单片机的数字式光照强度检测系统的设计-说明书.doc46页
本文档一共被下载:
次 ,您可免费全文在线阅读后下载本文档
文档加载中...广告还剩秒
需要金币:100 &&
你可能关注的文档:
··········
··········
本科学生毕业设计
基于单片机的数字式光照强度检测系统的设计
机电工程学院
专业班级:机械设计制造及其自动化08-3班
指导教师:陈曦
职 称:教授
哈 尔 滨 工 程 大 学
二○一二年六月
The Graduation Design for Bachelor's Degree
The Digital Light Intensity Detector System Base on MCU
Candidate:Xu Dongsheng
Specialty:Machinery Design and Manufacturing and Its Automation
Class:08-3
Supervisor:Lecturer Chen Xi
Heilongjiang Institute of Technology
2012-06?Harbin
摘要……………………………………………………………………………Ⅰ
Abstract……………………………………………………………………Ⅱ
课题的意义、目的和要求 11.1.1 课题的意义 11.1.2 课题的目的 11.1.3 课题的要求 2
1.2 数字式光照强度检测仪的发展前景及趋势 3
本课题主要研究的内容 4
1.3.1 单片机………………………………………………………4
1.3.2 单片机发展历史及应用…………………………………………6
第2章 系统概述 9
2.1 系统方案的选择与论证 9
2.2 光敏电阻简介 10
2.3 本章小结 13
系统的硬件部分 14
3.1单片机最小系统和通信模块的设计 143.1.1单片机最小系统的设计 143.1.2下载通信模块的设计 16
3.2光敏电阻网络的设计 17
3.3输出选择电路的设计 18
3.4 A/D模数转换电路的设计 20
3.5数码管显示电路的设计 20
本章小结 22
第4章系统软件部分 23
4.1 软件流程图 244.2 Keil软件简介..26
4.3 程序清单 26
4.4 Protues软件绘图及仿真 28
4.5 软件的调适与仿真 294.5.1系统软件调试 294.5.2 仿真结果 30
4.6本章小结 32
参考文献 34
正在加载中,请稍后...是导致交通事故的主要原因, 占交通事故数量的80%以上。 哪里有交通警察在场, 哪里的交通事故就极少发生。如果给每辆汽车安装上“电子警察&,有效地监督 驾驶人员的驾驶行为,必能预防或减交通事故的发生;在发生交通事故后,“电 子警察”也能给我们提供数据和资料,提高事故处理的效率和准确性[2.3]。 汽车行驶记录仪对预防驾驶员疲劳驾驶、约束驾驶员违章、分析鉴定事故、 提高交警的执法水平和运输管理水平、 保障车辆运行安全等具有重要的实际作用 及意义。统计资料表明,汽车黑匣子的使用,使交通事故率降低37%~52%,大 大减少了人员伤亡和财产损失,产生了显著的社会效益和经济效益[4]。 1.2 记录仪的国内外发展现状 1934年, 德国发明了世界上第一台纸盘式行驶记录仪, 至今已有75年的历史。 它可以将曲线画在圆形的记录纸上。 由于技术的发展, 纸盘式记录仪现在应用少。 20世纪70年代后期,欧洲率先推出了机模拟式驾驶记录仪。 进入九十年代,科学技术飞速发展,计算机日益普及,美国和德国又开发了 数字式汽车事故记录仪。20世纪90年代,美国、欧共体相继推出性能优良的电子 式记录仪,并得到美国国家运输安全委员会的支持,敦促在其轿车和卡车上安装 这种仪器。主管交通安全的国家安全委员会(NTSB)也一直在致力于推广汽车黑 匣子的工作。NTSB正式要求各汽车生产厂家安装汽车黑匣子,通用、福特等汽 车公司随即纷纷行动。据报道,仅通用一家公司就为600万辆出厂车安装了黑匣 子[5.6]。 2003年日本汽车研究所开发小组研制出一种能记录在交通事故发生时驾驶 数据的汽车“黑匣子&。“黑匣子”安装在司机座位下面,能够记录速度、方向 盘角度、 刹车板及油门踩放的情况。 当急刹车或急转弯使汽车达到一定的速度时, 便判断为“事故”,事故发生前55秒和后5秒问的各种数据自动记录到磁盘中。 另有一个如后视镜一样的照相机,自动收录事故发生前10秒和后5秒间从驾驶座 上能看到的场面。在一年半的试验期间,在实际发生的38起交通事故中,黑匣子 都正确地显示了何时踩刹车等情况[7]。这种“黑匣子&数据存储在磁盘中,车辆 行驶中可能颠簸,磁盘抗震能力较差。随着半导体技术和集成电路的发展,容量 大体积小的存储芯片层出不穷,而且相对磁盘来说,存储芯片具有抗震性能,更 适合车辆的行驶环境,在车辆行驶记录装置上得到了广泛应用。视频功能对存储 空间要求较高,实现复杂,成本较高。 记录仪最早是在1984年国内某大学研发了汽车行车记录仪, 由于技术不太成 熟,没有投入实际生产。1994年,记录仪在我国市场上蓬勃发展,出现了近百家 记录仪生产企业[8]。 2002年我国公安部根据2001年底公安部、交通部、国家安全生产监督管理局 下发的《关于加强公路客运交通安全管理的通告》和2002年公安部、·国家安全 生产监督管理局制定的《2002年预防道路交通事故工作方案》的要求,着手制定 《汽车行驶记录仪》的国家标准。《汽车行驶记录仪》GB/T 1标准 于日发布,日实施[9]。 广州市二汽公司率先试用NC.7000系列数字式行车记录仪。2004年5月北京 巴士旅游分公司的150辆旅游车上都已经安装了记录仪[10]。 目前市面上的汽车行驶状态记录仪主要有以下类型: ★ 记录式记录仪 记录式记录仪的主要特点是模拟航空记录仪的工作方式, 记录车辆的实时状 态数据并保存,为交通肇事的评判提供佐证。但是,记录数据一般只作为交通事 故的事后技术参考,不能作为评判的直接依据。 该记录仪以一个合适的间隔采集、存储车辆状态数据,包括车速、发动机转 速、节气门位置、车灯、制动等指标。采样时间间隔一般有 0.3、0.5、1、5min 等几种。同时可以记录车辆停车前 20-120s 间隔的密集数据,为事故疑点分析提 供帮助,密度一般为 0.1s 左右。 为了扩展使用范围,有些型号的产品还附加有超速和超时驾驶报警功能。功 能上实现了“实现预警”,延伸了传统记录仪“事后决断”的特点。 ★ 管理式记录仪 管理式记录仪在使用应用上与记录式有所不同,它是记录式记录仪的升级, 是为满足车辆营运管理要求而设计的,主要的应用是基于加强车队营运管理。管 理式记录仪主要由车载记录系统和管理系统组成, 车载记录部分完成相当于记录 式记录仪的工作,将记录数据传递给管理系统进行高级处理。因此可以实现多个 记录仪的统一管理,为车队调度提供便利。数据的传递一般有计算机串口、存储 卡、专用读取设备等几种方式。 管理式记录仪一般是以记录式为基础与 GPS 和 GIS 技术结合。因此所获取 的信息更加丰富,除了基本的车速、里程、节气门位置、制动等信号外,还有车 辆实时的地理位置、海拔高度等地理信息,使车辆在平面上,甚至空间上的管理 成为可能。因此,该类型记录仪应该属于交通管理设备,也正是由于这种原因, 它正在成为行车记录仪的主流产品[11]。 记录仪的使用场合主要有以下几个方面: ★ 交通执法管理 记录仪可以记录汽车停车前 20-120s 的密集状态数据(事故疑点数据) 。这 些数据在事故调查中具有重要作用。 管理系统可以利用疑点数据仿真再现事故的 发生过程,帮助交通管理部门准确、科学地执法。此外,管理人员还可以通过查 看记录数据来判别驾驶员是否违章驾驶,为严格执法提供科学依据。 ★ 公共交通管理 在公共交通管理中,记录仪可以为管理部门提供行车信息服务,管理部门可 以及时地掌握公交车的行驶状态和地理位置。因而,行车记录仪既起到了公共交 通行业服务监督的作用,又方便了车队的管理和调度。 ★ 长途运输管理 在长途运输过程中, 交通事故的发生大多由于驾驶员的疲劳驾驶和路途生疏 引起的。 记录仪通过对驾驶员进行超时和超速驾驶报警, 来提醒驾驶员注意安全。 另一方面, 管理中心向记录仪及时发送 GSM 信息, 使驾驶员及时了解路况信息, 也可以及时避免事故。 ★ 特殊运输管理 特殊运输包括重要人物、物资的运输以及危险品运输。管理部门为了实时掌 握相关的运输状况,就要不断地监测记录仪的记录数据,不断了解运输车辆的状 态和位置。因此,记录仪可以有效地保证特殊运输的安全与可靠性[11]。 1.3 系统设计思路分析 分析系统需要实现的功能可知, 需要设计的功能模块应包括数据采集、 控制、 键盘输入、液晶显示、日历时钟、数据存储等,对于这些功能,选用 51 单片机 来实现是合适的,采集、控制、键盘以及“屏显”都属于 51 单片机的典型应用 范畴。 1.3.1 获取行驶状态信息 毫无疑问,对于汽车行驶状态记录仪系统来说,获取行驶状态信息是所有工 作的前提。系统的首要任务是采集汽车的行驶状态信息,包括速度、里程、超速 度及时间、停车次数及时间等,这里最重要的是速度,其它信息可由计算机分析 得出。 信息采集的方法和汽车上的速度表实现的方法类似, 汽车行驶过程中轮子每 转一周会通过内部的霍尔传感器送给系统一对差分信号, 系统通过信号采集模块 获得一个对应的脉冲信号, 通过对脉冲的基计数及已知的轮子的直径信息计算出 汽车的运行的速度。 然后根据速度和计时信息可以算出车子的里程, 速度超出设定的门限值便认 为是超速度行驶,记下此时通过日历模块显示的超速度发生时间;从速度大于零 到速度等于零是一次停车,记下此时通过日历模块显示的时间。经过这些处理就 可以得到较为全面的行驶状态信息了[12]。 1.3.2 系统模块分析 在获取行驶状态信息后,系统需要对信息进行实时的处理、显示、存储,存 储后的信息可以用来进行分析。 信号采集模块: 将汽车内部霍尔传感器传过来的一对差分信号经过适当的变 换变成一个脉冲信号提供给单片机系统,这其中需要用光耦模块进行隔离,来避 免强脉冲信号对电路板的干扰。 信息存储模块:单片机系统将采集到的信息经过适当的运算处理后存储到 IC 卡芯片中,IC 卡中的信息可以长时间地保存,可以用读卡设备读出其中的信 息然后进行分析。由于 IC 卡芯片存取的速度有限,引入数据扩展芯片作为缓存。 键盘输入和液晶显示是常用的单片机输入输出模块, 为用户提供友好方便的 人际操作界面,用户可以输入特定的信息,也可以看到实时的速度、里程及时间 等信息,可以做出实时判断[12]。 2 系统方案设计2.1 系统设计要求 系统的设计要求如下: ★ 能实时监测并记录汽车行驶的各种状态信息,包括速度、里程、超速度 及时间、停车次数及时间等重要数据; ★ 能记录驾驶员信息、汽车信息、发车时间、到站时间、发车站和终点站 等信息; ★ 具有汽车超速报警的功能。 2.2 系统总体方案设计 2.2.1 仪器的功能要求及技术性能指标 根据国家标准GB T1《汽车行驶记录仪》[1]的要求,汽车行驶记 录仪应该满足如下几个方面的要求。 (1)电气性能要求:由于汽车的供电系统通常为蓄电池,随着汽车行驶状 态的不同,汽车放电机的输出电压会有较大的波动;另外随着蓄电池使用年限和 工作状态等的不同,其输出电压往往有一定波动,从而影响到整个汽车的供电电 压。因此,国家标准GB_T1要求记录仪能够在一定的电压波动范围内 正常工作[13]。电源电压的波动范围如表2-1所示。表2-1 电气性能试验参数 标称电 源电压 12 24 36 电源电压 波动范围 9~16 18~32 27~48 极性反接 试验电压 14(0.1) 28(0.2) 42(0.2) 单位:伏特 过电 压值 24 36 54(2)数据安全性:记录仪应防止数据被更改或删除,应从记录仪硬件和数 据分析软件系统两个方面来实现: ★ 硬件上, 应在记录仪主机上或其它适当的地方采取可靠安全措施(如铅封) 防止数据储存器等重要器件被更换; ★ 记录仅主机内车辆行驶速度、里程、驾驶时间等原始数据不能通过外部 设备进行任何改写或删除操作; ★ 分析软件对车辆识别号、车牌号码、车牌分类、车辆特征系数、驾驶员 代码、驾驶证号码等重要参数,一般情况下只能读,不能更改或删除。在记录仪 初始化调试、校准、维修或其他特殊情况下需对上述重要参数进行设置操作时, 需经操作授权[13]。 (3)气候环境适应性:记录仪在承受各项气候环境试验后,应无任何电气 故障,机壳、插接器等不应有严重变形:其记录功能、显示功能、打印功能等应 保持正常;试验前存储的数据不应丢失或改变。 (4)机械环境适应性:记录仪在承受各项机械环境试验后,应无永久性结 构变形;零部件应无损坏:应无电气故障,紧固部件应无松脱现象,插头、通信 接口等接插件不应有脱落或接触不良现象;其记录功能、显示功能、打印功能等 应保持正常;试验前存储的数据不应丢失。 2.2.2主板的功能与设计[13] 主板:包括有中央处理器、数据采集、数据存储器、实时时钟芯片、数据通 信接口、插接件及电源单元等; 主板主要处理汽车行驶数据的采集、记录和长期存储,同时主板为整个记录 仪提供实时时钟、电源检测和对外通信(串口)等功能,是整个系统的核心。 主板以AT89C51作为中央处理器。 整个记录仪采用并行总线的工作方式进行 连接。汽车的状态信号经过调整后,通过74LS373挂在数据总线上;利用单片机 的INT0中断对调整后的速度脉冲进行计数,从而获得汽车行驶的速度和里程等 信息。 记录仪使用FM1808芯片作为扩展数据存储器,使用Atmel公司的4M基于SPI 总线访问的Data Flash AT45DB041作为海量存储器。单片机采集到的汽车行驶数 据首先存放在FM1808中,当满足一定条件的时候,将FM1808中的数据保存到 Flash存储器中,进行长期的存储。 “看门狗”作为复位电路可以防止单片机发生死机;系统掉电部分提醒单片 机对重要的行驶数据作保存和处理;实时时钟采用;整个主机部分设计体现了高 性价比和安全、可靠的设计思想。 2.2.3面板的功能与设计 面板主要提供人际交互功能。包括指示灯(一个电源指示灯、两个状态指示 灯),蜂鸣器,LCD(分辨率为128*64)和键盘(拥有16个按键)。 3 系统硬件设计本章将以汽车行驶状态记录仪为例, 根据系统的功能和设计要求介绍系统的 总体构成框图各部分硬件电路的设计方案,并对主要芯片原理与应用加以介绍。 系统控制核心芯片选用AT89C51单片机;实时液晶显示部分采用DM12864芯片; 按键显示部分采用ZLG7289芯片;实时时钟部分采用DS1302日历芯片;片外扩 展的数据缓存采用FM1808铁质存储器; IC卡芯片AT45DB041用来存储完整数 据;用“看门狗”芯片MAX706监视单片机的运行情况;串口采用MAX232芯片。 汽车行驶状态记录仪的总体结构图如图1所示。以下将介绍单片机及各个部 分的接口电路。图3-1 汽车行驶状态记录仪总体结构图3.1单片机的选择 单片机是微控制器的典型代表,从20世纪70年代末出现到今天,虽然已经过 去了30年历史,但是这种8位的电子器件目前在嵌入式设备中仍然有着极其广泛 的应用。单片机芯片内部集成ROM/EPROM、RAM、总线、总线逻辑、定时/计 数器、看门狗、I/O、串行口、脉冲调制输出、A/D、D/A等各种必要功能和外设。 因此,单片机只需要和适当的软件及相关的外设相结合,便可形成一个可实现相 应功能的单片机控制系统。 在汽车行驶状态记录仪中我们采用AT89C51单片机作为中央处理器。该CPU 有4K字节Flash闪存,128字节内部RAM,32个I/O口线,2个16位定时/计数器, 一个5向量两级中断结构,一个全双工串行通信口,片内振荡器及时钟电路。同 时, AT89C51可降至0Hz的静态逻辑操作, 并支持两种软件可选的节电工作模式。 空闲方式停止CPU工作,但允许RAM、定时/计数器、串行通信口及中断系统继 续工作,掉电方式保存RAM的数据,但振荡器停止工作并禁止其它所有部件工 作指导下一个硬件复位[14]。 3.2单片机及外围接口电路设计 3.2.1MAX706、AT45DB041和AT89C51接口电路 在本记录仪中, 采用MAXIM公司的MAX706芯片作为电源监控和复位器件。 MAX706能够提供上电、掉电复位功能,独立的“看门狗”保护功能,电压检测 和手动复位功能[15]。 采用4M字节的数据闪存AT45DB041作为数据存储器,用来实现车辆行驶数 据的长期存储。AT45DB041是ATMEL公司推出的一款基于Flash计数的大容量数 据存储器,采用2.7V—3.6V供电;通过SPI总线进行数据的访问,其主要接口允 许直接5VCMOS或TTL电平信号,并且与之兼容;4M存储空间被划分成2048页, 每一页含有264个字节数据,支持页擦写和段擦写,还有两个264字节的SRAM数 据缓存[16]。接口电路图如图3-2所示:图3-2 MAX706、AT45DB041和AT89C51接口电路 3.2.2车辆数据采集接口电路 数据采集包括信号的调理设计和车辆状态信号的采集。对于+12V车辆系统, 其开关量的信号电平是+12V,开关量信号的频率很低,不高于4Hz。开关在闭合 和断开的过程中,往往存在一定的尖峰脉冲干扰;同时由于汽车的工作环境比较 恶劣,开关信号的频率信号中也会含有较多的高频干扰成分。采用光电耦合隔离 措施和增加必要的滤波电路能很好的解决这些问题[13]。 速度信号是一个方波,通过外部中断INT0与单片机相连,进行计数。再根 据车辆特征系数、车辆特征转数和时间就可计算车辆行驶里程和车辆行驶速度。 接口电路如图3-3所示:图3-3 车辆数据采集接口电路3.2.3串口接口电路 RS-232接口是目前最常用的一种串行通讯接口。本记录仪中使用DB9连接 器,使用的引线为接受数据(RXD) 、发出数据(TXD)和信号地线(SG) ,对 应的引脚为2、3和5。 在RS-232中任何一条信号线的电压均为负逻辑关系。即:逻辑“1”的电平 在-5V—-15V;逻辑“0”的电平在+5V—+15V。噪声容限为2V,即要求接收器 能识别低至+3V的信号作为逻辑“0” ,高到-3V的信号作为逻辑“1” 。高于+15V 或低于-15V的电压认为无意义,介于+3V和-3V间的电压也无意义。 单片机的串口是TTL电平,需要将TTL电平转换成RS232电平,本系统中使 用MAX232实现电平的转换。串口接口电路如图3-4所示: 图3-4 串口接口电路3.2.4液晶显示接口电路 DM12864是一种采用低功耗CMOS技术实现的点阵图形LCD模块, 每页能显 示32个汉字(4行8列) 。既可实现串行数据传送,也可实现并行数据传送。本次 设计中采用该芯片的并行数据传送功能。液晶显示接口电路如图3-5所示:图3-5 液晶显示接口电路3.2.5DS1302日历芯片接口电路 DS1302是DALLAS公司推出的涓流充电时钟芯片,内含有一个实时时钟/日 历和31字节静态RAM,并能提供秒、分、时、日、月、年的信息。DS1302与单 片机之间能简单地采用同步串行的方式进行通信,仅需用到三个口线:RET复位、 I/O数据线和SCLK串行时钟。日历芯片接口电路如图3-6所示: 图3-6 DS1302日历芯片接口电路3.2.6键盘接口电路图3-7 键盘接口电路ZLG7289能够管理多达64只按键,并能自动消除抖动,本次设计中只使用了 其中16只按键。ZLG7289与单片机的接口采用3线制SPI串行总线,由CS、CLK 和DIO这3条信号线组成。CS和CLK是输入信号,由单片机提供。DIO信号是双 向的,必须接到单片机上具有双向功能的I/O上。本次设计中,CLK接P1.6口, DIO接P1.7口,同时芯片上的中断INT接单片机的INT1。键盘接口电路如图3-7所 示。 3.2.7声光报警电路 在单片机控制系统中,一般的工作状态可以通过指示灯或数码显示来指示, 以供操作员参考。但对于某些紧急状态或反常状态,为了使操作人员不致忽视, 以便及时采取措施,往往还需要有某种更能引人注意、提起警觉的报警信号。本 系统的报警电路采用的是鸣音报警方式。 电路图中的 3 个发光二极管的功能分别是:超速报警灯(J1) ,车辆正常工 作指示灯(J2)和电源指示灯(J3) 。车辆车速正常时,J1 灯熄灭,J2 灯点亮; 当 J2 灯点亮时表示车辆此时超速,同时扬声器发出报警声。当车辆电源正常工 作时,J3 灯一直亮着。声光报警电路如图 3-8 所示:图3-8 声光报警电路 3.2.8数据存储器扩展电路 FM1808是一种32*8的高集成度的RAM,采用单一+5V供电,双列直插式28 引脚封装。本次设计中FM1808作片外数据存储器,起缓冲器作用。车辆行驶数 据先存放在FM1808中,最终存放到IC卡芯片中。数据存储器扩展电路如图3-9所 示:图3-9 FM1808数据存储器扩展电路 4 系统软件设计4.1 软件设计语言的选择 在单片机应用系统开发过程中,程序设计有两种方法:一种是基于汇编语言 的程序设计方法,另一种是基于 C 语言的程序设计方法。汇编语言的机器代码 生成效率高但可读性不强,而 C 语言在大多数情况下,其机器代码生成效率和 汇编语言相当,而可读性和可移植性却远远超过汇编语言。此外,由于 C 语言 有很好的层次结构,使其编写的程序更容易阅读和维护。且 C 编写的程序比汇 编更符合人们的思考习惯, 开发者能更专心的考虑程序设计而不是考虑些细节问 题,这样就减少了开发和调试的时间[17]。所以,C 语言已成为在单片机应用系统 开发中程序设计的主流语言。 C 语言程序设计具有如下特点[18]: ① C 语言简洁,使用方便灵活。C 语言是现有程序设计语言中规模最小的 语言之一,ANSIC 标准 C 语言只有 32 个关键字,9 种流程控制语句。 ② 可移植性好。采用 C 语言编写的程序,不依赖机器硬件,可以不加修改 地移植到别的机器上。 ③ 表达能力强。C 语言具有丰富的数据结构类型,用户可根据需要,采用 多种数据类型来实现各种复杂的数据结构运算;C 语言还有多种运算符,用户可 灵活使用各种运算符实现复杂运算。 ④ 表达方式灵活。利用 C 语言提供的多种运算符,可以组成各种表达式, 还可以采用多种方法来获得表达式的值, 从而使用户在程序设计中具有更大的灵 活性。 ⑤ 可进行结构化程序设计。C 语言以函数作为程序设计的基本单位,C 语 言程序中的函数相当于一般语言中的子程序。 ⑥ 可以直接操作计算机硬件。C 语言具有直接访问机器物理地址的能力, Keil 的 C51 编译器和 Franklin 的 C51 编译器都可以直接对单片机的内部特殊功 能寄存器和 I/O 端口进行操作,可以直接访问片内或片尾存储器,还可以进行各 种位操作。 ⑦ 生成的目标代码质量高。 4.2 编程软件的选择 目前针对不同厂家的不同单片机, 所采用的开发环境也不同, PIC 单片机 如 采用的 MPLAB IDE 开发环境, HOLTEK 单片机采用的 HT-IDE3000 开发环境等。 Keil uVision2 集成开发环境是 Keil Software, Inc/ Keil Elektronik GmbH 开发的基 于 80C51 内核的微处理器软件开发平台,内嵌多种符合当前工业标准的开发工 具,可以完成从工程建立和管理、编译、链接、目标代码的生成、软件仿真及硬 件仿真等完整的开发流程。尤其是 C 编译工具在产生代码的准确性和效率方面 达到了较高的水平, 而且可以附加灵活地控制选项, 在开发大型项目时非常理想, 是目前应用最广泛的单片机开发环境之一[19]。 4.3 软件设计 4.3.1 软件设计应遵循的原则 单片机应用软件系统设计包括功能模块划分、程序流程确立、模块接口设计 以及程序代码编写。我们依据系统的功能要求,将整体软件系统分割成若干个独 立的程序模块。这些程序模块可以是几条语句的集合、功能函数或程序文件。随 后, 根据各个程序模块的实现功能写出流程, 一般需要写出具体的实现功能描述。 软件的设计原则应遵循以下几个方面: ★ 设计对于分析模型应是可跟踪的:软件的模块可能被映射到多个需求上; ★ 设计结构应该尽可能的模拟实际问题; ★ 设计应该表现出一致性; ★ 不要把设计当成编写代码; ★ 在创建设计时就应该能够评估质量; ★ 评审设计以减少语言性的错误。 4.3.2 软件结构设计 合理的软件结构是设计出一个性能优良的单片机应用系统软件的基础, 必须 充分重视。根据系统的定义,可把整个工作分解为若干相对独立的操作,再考虑 各操作之间的相互联系及时间关系而设计出一个合理的软件结构。 对于简单的单片机应用系统,可采用顺序结构设计方法,其系统软件由主程 序和若干个中断服务程序构成。 明确主程序和中断服务程序完成的操作及指定各 中断的优先级。 对于复杂的实时控制系统,可采用实时多任务操作系统。此操作系统应具备 任务调度、实时控制、实时时钟、输入输出和中断控制、系统调用、多个任务并 行运行等功能,以提高系统的实时性和并行性。 在程序设计方法上,模块程序设计是单片机应用中最常用的程序设计方法。 这种模块化程序便于设计和调试,有容易完成并可提供多个程序共享等优点,但 各模块之间的连接有一定的难度。根据需要也可采用自上而下的程序设计方法, 此方法是先从主程序开始设计,然后再编制各从属的程序和子程序。这种方法比 较符合人们的日常思维,缺点是上一级的程序错误会对整个程序产生影响。软件 结构设计和程序设计方法确定后,根据系统功能定义,可先画出程序粗框图,再 对粗框图进行扩充和具体化,即对存储器、寄存器、标志位等工作单元作具体的 分配和说明,再绘制出详细的程序流程图。 程序流程图设计出以后, 便可着手编写程序, 再经编译、 调试, 正常运行后, 固化到 EPROM 中去,完成了整个应用系统的设计[20]。 4.4 系统软件设计 4.4.1 主程序功能及其设计的实现 系统的功能决定了系统程序设计,由于系统的功能需求直接明了,所以软件 流程也相应清晰,易于设计。设计的主程序流程图如图 4-4 所示。汽车启动后, 系统先进行初始化, 包括对程序执行过程中用到的相关变量初始化和各模块初始 化。 初始化完成后,液晶主屏显示提示信息:车号、工号及起始站,用户可以通 过键盘输入相关信息。 程序中设置车辆状态变量 car_state, 通过测试变量 car_state 的值来判断车辆的运行状态。 car_state 等于 0, 若 表示车辆启动并处于停止状态; 若 car_state 等于 0X55,表示车辆处于行驶状态;若 car_state 等于 0XFF,表示 车辆行驶一段时间后停车。 当车辆第一次处于行驶状态时, 主程序通过调用日历芯片子程序和液晶显示 子程序,在液晶主屏上显示实时时间和汽车所行驶的里程信息,每分钟记录 1 次数据并存入 IC 卡中。在行驶过程中通过调用超速报警子程序,判断汽车有无 超速,超速要给出报警等指示,并将超速的实时时间和超速度存入 IC 卡中。速 度信号可看作是脉冲信号,单片机利用定时器 0 中断定时,利用外部中断 0 记录 脉冲个数,从而得到速度等信息。程序中不断将速度值和预先设定的门限值作比 较,如果超过则启动超速报警。 通过测试 car_state 是否等于 OXFF,判断是否停车:若未停车,则继续实时 显示时间、里程等信息。在确认停车后,通过调用按键中断子程序,确认是否按 下到站键,若到站键未按下,表明车辆只是普通的途中停车,记录停车时间后, 停车次数加 1,并将这些信息存入 IC 卡后,继续判断车辆是否行驶,形成循环。 反之,表示车辆到站,记录到站时间,停车次数加 1 后存入 IC 卡中。到站键按 下的同时,判断车辆是否到终点站,若车辆到终点站,则驾驶员按下终点站键 (0X0B) ,液晶通过清屏后,显示“终点站” ,信息存储后,主程序结束。 液晶显示界面如下图所示: 车 工 号 号 X X X X起始站图 4-1 汽车启动后主屏显示提示信息及相关输入界面20 XX 里XX 时 程年 XX XXX 分 X月XX日Km图 4-2 汽车行驶、停车及到站实时显示界面终点站图 4-3 汽车到达终点站显示界面 汽车启动初 始 化主屏显示 提示信息输入相关信息 并存入 IC 卡N车辆行驶?Y实时显示日历 里程等信息每分钟记录 1 次数据 并存入 IC 卡超速?Y启动声光报警NN 停车? Y记录停车时间 停车次数加 1N 到站键按下? Y 记录到站时间,停车次 数加 1,并存入 IC 卡终点站? Y 按键并存储信息N图 4-4 主程序流程图 主屏显示终点站 4.4.2 DM12864 液晶显示软件设计 DM12864 有两种数据传送方式:串行数据传送和并行数据传送。本次设计 采用并行数据传送方式。8 位并行数据传送时序下图如所示:图 4-5 单片机写数据到 DM12864 时序图图 4-6 单片机从 DM12864 读出数据时序图RS 为并行的指令/数据选择信号,RS=0 表示并行指令选择信号,RS=1 表示 并行数据选择信号;E 为 DM12864 的使能信号,由时序图可知,使能信号为高 电平有效;R/W 为并行的读写选择信号,逻辑“1”表示读,逻辑“0”表示写。 DM12864 初始化指令包括功能设定指令、显示状态开/关指令、清除显示指 令和进入点设定指令。 1.功能设定指令: D7 0 D6 0 D5 1 D4 1 D3 X D2 RE D1 X D0 X 其中 RE=1 为扩充指令集动作,RE=0 为基本指令集动作,初始化中 RE=0。 2.显示状态开/关指令: D7 0 D6 0 D5 0 D4 0 D3 1 D2 D D1 C D0 B其中 D=1:整体显示 ON,C=1:游标 ON,B=1:游标位置 ON。 3.清除显示指令: D7 0 D6 0 D5 0 D4 0 D3 0 D2 0 D1 0 D0 14.进入点设定指令: D7 0 D6 0 D5 0 D4 0 D3 0 D2 1 D1 I/D D0 S其中 I/D=1 表示游标右移,S=1 表示画面不移动。 液晶显示时,需设定 DDRAM 位址。指令代码如下: D7 1 D6 AC6 D5 AC5 D4 AC4 D3 AC3 D2 AC2 D1 AC1 D0 AC0DM12864 每页能显示 32(4 行 8 列)个汉字,显示位址的范围从 80H~9FH, 具体显示位置如表所示;表 4-1 汉字显示位置关系80H 90H 88H 98H81H 91H 89H 99H82H 92H 8AH 9AH83H 93H 8BH 9BH84H 94H 8CH 9CH85H 95H 8DH 9DH86H 96H 8EH 9EH87H 97H 8FH 9FH液晶显示执行指令为 void display2(uchar dat,uchar add),其中,形参 dat 表 示要显示的 8 位数据, 形参 add 表示地址, 通过与 80H 相 “或” 以确保 DDRAM , 位址的最高位为 1,得到的结果赋值给 c,c 即是数据在液晶上显示的具体位置。 DDRAM 提供 32 个汉字的空间,当写入文本显示 RAM 时,可以显示中文 字型:将两字节编码写入 DDRAMK,范围为 A1A0H~F7FFH(国标码) 。具体 的中文字型编码可参见 ST7920 GB 中文字型码表。 4.4.3 按键扫描软件设计 按键扫描采用 ZLG7289 芯片。 该芯片与单片机之间采用 SPI 串行总线接口, 操作方便,占用 I/O 资源少。同时还能够扫描管理多达 64 只按键,自动消除抖 动[21]。本次设计只需用到其中的 16 只按键。 ZLG7289与微控制器的接口采用3线制SPI串行总线,由CS、CLK和DIO这3 根信号线组成。CS和CLK是输入信号,由微控制器提供。DIO信号是双向的,必 须接到微控制器上具有双向功能的I/O上。SPI信号线的具体意义参见表4-2,图 4-7是读按键值的时序图,只有当INT引脚出现下跳沿时才允许去读取按键值,否 则将得不到有意义的数据。表 4-2 ZLG7289 的 SPI 串行接口信号信号名称 CS引脚序号 6描述 SPI 总线片选输入信号, 低电平有效CLK7SPI 总线时钟输入信号, 上升沿有效DIO8SPI 总线数据信号,双向图 4-7 读键盘指令时序图(命令字在前,键值在后)ZLG7289在扫描键盘时,已经采取了消抖动措施,因此在程序中不必另外编 写消抖动的代码。 某个按键按下时,ZLG7289的INT引脚会出现低电平,向主控制器发出中断 请求。主控制器既可以采用中断方式处理,也可以采用查询INT引脚电平状态的 方法处理。但是要避免通过SPI总线用软件命令的方式去查询是否有键按下,这 将导致SPI总线频繁处于活动状态,不利于抗干扰。应当在INT引脚出现低电平 时及时地读取键值。读取键值后,INT引脚并不会自动恢复为高电平,一定要等 到按键抬起为止。如果没有及时读取按键值,则按键抬起后INT引脚也将恢复到 高电平,而在INT引脚处于高电平期间,试图去读取键值将可能得不到有意义的 数据。 按键扫描软件流程图如图4-8所示:开始ZLG7289 初始化读取按键向 ZLG7289 发出数据Y接收 ZLG7289 返回键值KEY=FFH?N单片机读到该键按下结束图4-8 按键扫描软件设计流程图利用中断方式处理按键时, 通常将微控制器外部中断的触发方式设置成负边 沿触发,而不要设置成低电平触发。按下某个键时,ZLG7289B会在INT引脚产 生低电平信号,这低电平信号直到松开按键时才会撤除。如果程序中采用低电平 触发中断,则进入中断完成读取键值操作后,还必须要等待INT信号恢复为高电 平,即等待操作者放键,在等待期间,CPU几乎不能再干其它事情,造成浪费。 如果不等待,读完键值后就直接从中断返回主程序,那么由于INT信号还是低电 平,这将再次触发中断,从而导致程序错误。如果设置成负边沿触发方式,则进 入中断读完键值后不必等待即可退出,返回主程序后也不会再次触发中断。 读键盘数据指令当有键按下时,ZLG7289B的INT引脚会变成低电平。这时利用该指令可以 读出当前的键值。 第1字节为命令字, 第2字节是ZLG7289B向单片机返回的键值。 正常情况下,键值的范围是0~63(0X00~OX3F),无按键的状态用255(0XFF) 表示。本次论文设计了16个按键,故在软件设计时,可将第2字节的高4位均置0, 低4位表示键值的范围0~15(0X00~0X0F)。具体键值0X00~0X09为数字键, 分别表示从0~9的10个数字,键值0X0A为到站键,键值0X0B为终点站到站键。 4.4.4 IC 卡存储软件设计 IC 卡采用 AT45DB041,该芯片包含主内存和两块缓冲区,并提供专门的读 写指令对它们操作。AT45DB041 的存储单元被分成三个等级:段、块和页。芯 片允许对页进行写入操作,可以整块或整页进行擦除操作。本次设计主要是对单 页进行写(数据存储)操作。 AT45DB041 通过 SPI 总线进行访问,在访问的过程中,首先应该将片选端 CS 置低,然后通过时钟信号 SCK 控制数据的输出或输入。芯片的各操作指令都 是由单片机发出,一个有效的命令是在 CS 有效,并且要紧随有效的 8 位控制字 和合适的缓存或者主存中的地址,所有的串行操作都是高位在前[22]。 车辆实时数据存入 IC 卡程序设计主要包括写字节、读字节、读状态寄存器、 将数据写入从某个地址(0~263)开始的 buffer(缓存)中及将缓存中的数据写 入主内存中 5 个部分。下面将分别介绍每个部分的实现情况: 1.通过 SPI 写入一个字节的数据 程序为 void At45WriteByte(uchar Bytename) ,形参 Bytename 表示要写入的 1bit 数据。 执行过程:Bytename 和 80H 相与,判断其最高位的状态,若为 1,则 SI 引 脚置 1,若为 0,则 SI 引脚置 0;判断完最高位状态后,将 Bytename 向左移 1 位,用同样的方法,目的是判断要写入字节的次高位状态。如此循环 8 次单片机 即可通过 SPI 向 AT45DB041 写入 1 个字节的数据。程序执行过程中需要模拟时 钟信号。 2.通过 SPI 读出一个字节的数据 程序为 uchar At45ReadByte(void)。 执行过程: 初始化变量 rByte, 通过对 SCKFlash 赋值来模拟时钟信号, rByte 和 SO 引脚的信号相或后,其值仍赋值给 rByte,后将 rByte 向左移一位。如此循 环 8 次单片机即可通过 SPI 读出 AT45DB041 一个字节的数据,最后返回读到的 1 个字节的数据。 3.读状态寄存器 程序为 uchar AT45DB041B_StatusRegisterRead(void)。状态寄存器决定了器 件的忙/闲状态、页大小、主存和缓存页比对结果、页保护状态和芯片密度。可 以在任意时间读取状态寄存器,即使在芯片编程和擦除器件时也可以读。要读状 态寄存器,CS 引脚必须首先有效,之后送入 8 位控制字 D7H,紧随控制字之后, 1 字节的状态寄存器值即可在轮询时钟作用下,从 SO 引脚读出,最后一位读出 之后,SCK 引脚再变化,就会再次从 SO 引脚输出状态寄存器的值。状态寄存器 的值是持续更新的,所以能不断读出新的数据。 状态寄存器格式如:Bit7 RDY/BUSY Bit6 COMP Bit5 0 Bit4 1 Bit3 1 Bit2 1 Bit1 X Bit0 X状态寄存器的第 7 位指示芯片的忙闲状态,如果它的值是 1,那么芯片就是 空闲的,可对其进行任何操作;如果是 0,就表示忙,不能对其进行写入或擦出 等操作。缓存内容写入主存、页擦除、主存缓存对比等操作都会导致芯片进入忙 状态。 状态寄存器的第 6 位指示最近一次主存缓存比对的结果,如果该位值为 0, 则表示主存和缓存的数据是匹配的,数据传输没有出现错误;为 1 则表明主存和 缓存至少有 1 字节的数据不一样,数据传输存在错误。 Bit5-Bit2 为器件标志号,可以用读取该数据来判断 AT45DB041 的好坏。最 后两位为无关位。 4. 将数据写入从某个地址(0~263)开始的 buffer(缓存)中 在轮换时钟作用下,数据可以从 SI 引脚送到缓存 1 或缓存 2,程序为 void AT45DB041_BufferWrite (uchar buffer,uint BFA,uchar *pHeader,uint len)。形 参 BFA 表示 buffer 中的起始地址(0~263) ,pHeader 表示待存数据的头指针, len 是待存数据的长度。程序的主要功能是将数据写入缓存区中。AT45DB041 芯 片有两种不同的写缓存方式:写 264 字节的页和写 256 字节的页。 (1)写 264 字节的页:命令字由控制字 84H(选择缓存 1)/87H(选择缓存 2) +15bit 任意码+9bit 缓存地址码组成,其中的 9bit 地址码用于指定缓存中要写入 的首字节。 (2)写 256 字节的页:命令字由控制字 84H(选择缓存 1)/87H(选择缓存 2) +16bit 任意码+8bit 缓存地址码组成,其中的 8bit 地址码用于指定缓存中要写入 的首字节。 执行过程:首先选通 AT45DB041,然后通过 AT45DB041 的 SI 引脚写入命 令字(40bit) ,紧跟着继续通过 AT45DB041 的 SI 引脚写入数据,当写入完需要 的数据后,CS 置高,结束操作。如果写到缓存区的最后一个地址,下一个写入 的数据将会写到缓存区的第一个地址。 本次程序设计中选择写 264 字节的页缓存 方式。 5. 将缓存中的数据写入主内存中 程序为 void AT45DB041_BufferToPageProgram (uchar buffer,uint PA,uint BFA,uchar *pHeader,uint len),其中形参 PA 表示要写入的页地址(0~2047) 。 程序的主要功能是芯片自动完成对指定页的擦除, 同时自动将写到缓存区中的数 据写入主内存的该页。AT45DB041 芯片同样具有两种不同的写主内存方式:写 264 字节的页和写 256 字节的页。 (1)写 264 字节的页:命令字由 83H(选择缓存 1)/86H(选择缓存 2)+4bit 任意码+11bit 页地址码+9bit 任意码组成,其中的 11bit 页地址码用于指定主内存 中要写入的首字节。 (2)写 256 字节的页:命令字由 83H(选择缓存 1)/86H(选择缓存 2)+5bit 任意码+11bit 页地址码+8bit 任意码组成,其中的 11bit 页地址码用于指定主内存 中要写入的首字节。 执行过程:首先选通 AT45DB041,然后通过 AT45DB041 的 SI 引脚写入命 令字(32bit) ,CS 置高,结束操作。如果在写的过程中 CS 引脚由低变高,芯片 仍将继续完成该操作。如果芯片内部正在进行擦除或写入操作,状态寄存器将会 指示忙状态。图 4-9 AT45DB041 写操作流程图4.4.5 MAX232 串行通信软件设计 本次串口设计采用 MAX232 芯片,MAX232 芯片是一款常用的串口芯片, 其软件设计较为简单。 TMOD、 TCON 及 SCON 为串行通信软件设计中需要用到 的寄存器,下面先对 3 个寄存器做简要的介绍: 1.定时器/计数器的工作方式寄存器 TMOD D7 GATE D6 C/T D5 M1 D4 M0 D3 GATE D2 C/T D1 M1 D0 M0定时器 T1定时器 T0C/T: 计数工作方式/定时器工作方式选择位。 C/T=0, 设置为定时工作方式; C/T=1, 设置为计数工作方式;GATE:门控位,用于决定是软件还是硬件启动/停止计数 器。GATE=0,INT0/INT1 被封锁,只要用软件对 TR0(或 TR)置“1”就启动 了定时器;GATE=1,定时器/计数器的计数受外部引脚输入电平控制。在 TR0 (或 TR1)置“1”时,若 INT0/INT1 引脚为高电平,启动定时器计数,若为低 电平则停止计数。M1,M0:工作方式控制位,可构成以下四种工作方式: M0 0 0 1 1M1 0 1 0 1工作方式 0 1 2 3说明 13 位计数器 16 位计数器 8 位可自动装载计数器 T0 分成两个独立 8 位计 数器,此方式 T1 关闭2. 定时器/计数器控制寄存器 TCON TCON 的高四位用于控制定时器的启动、 停止以及标明定时器的溢出和中断 情况,低四位用于两个外部中断源控制。定义如下: 8FH TF1 8EH TR1 8DH TF0 8CH TR0 8BH IE1 8AH IT1 89H IE0 88H IT0TF1、TF0:定时器 1、0 溢出标志,T1(T0)溢出时由硬件置 1 并申请中断, CPU 响应中断后,由硬件清 0 也可由软件清零;TR1、TR0:定时器 1、0 运行 控制位,可由软件置 1 或清 0 来启动或停止 T1(T0) ;IT1、IT0:外部中断 1、 0 触发方式选择位。 3.串行口控制寄存器 SCON 9FH SM0 9EH SM1 9DH SM2 9CH REN 9BH TB8 9AH RB8 99H TI 98H RISM0、SM1:串行口方式选择位,用于控制串行口的工作方式;SM2:允许方式 2 和方式 3 进行多机通信控制位,SM2=0 表示单机对单机通信,SM2=1 表示多 机通信;REN:允许串行接收控制位,由软件清 0 时,禁止串行口接收,由软件 置位时,允许串行接收;TB8、RB8:发送数据第 9 位、接收数据第 9 位;TI、 RI:发送中断标志、接收中断标志。 本记录仪为了获得较高的通讯效率,串行通信程序均采用 9600bps 的波特 率。每帧 10 位,其中 1 个起始位,8 个数据位,1 个停止位。在 9600bps 时,每 一位的传送时间 T=1/7ms。 51 系列单片机内部有全双工串行口,提供了 4 种工作方式。在本次设计中, 串行口采用工作方式 1,采用定时器/计数器 T1 作为波特率发生器,定时器 T1 工作在方式 2,这时 16 位计数器被拆分成两个部分:TL1 作计数器,TH1 用来 保存计数初值。 一旦计数溢出, 将置位中断标志, 并把 TH1 中的初值再装入 TL1, 从而进入新一轮的计数,如此循环,重复不止。这种工作方式可以避免在程序中 因重新装入初值而对定时精度的影响, 非常适用于作为波特率发生器等需要产生 相当精度的定时时间的应用场合[23]。 波特率的计算公式为:n= 制位; * 。其中:SMOD 为波特率加倍控为晶振频率;X 为定时器 1 的 TH1 装入初值。对本记录仪而言,设置 =11.0592MHz,通过上述公式,可以计算得到计数器的SMOD=0,晶振频率装入初值为 X=253=0xFD。开 始初始化串口调用串口接收 中断处理函数等待向发送端 申请数据重发N数据接收完成?Y调用求校 验和函数N数据正确?Y调用发送程序结束图 4-10 串口通信软件设计流程图 4.4.6 DS1302 实时时钟软件设计 DS1302 为汽车行驶状态记录仪系统提供实时时钟数据。采用 SPI 三线接口 与单片机进行同步通信。SCLK—串行时钟输入,I/O—三线接口的双向数据线, RST—输入信号,在读、写数据期间必须为高。 DS1302 的控制字与读写时序如下所示: 1.控制字 D7 1 D6 RAM/CK D5 A4 D4 A3 D3 A2 D2 A1 D1 A0 D0 RD/WRD7:必须是逻辑 1,如果它为 0,则不能把数据写入到 DS1302 中;D6:如 果为 0,则表示存取日历时钟数据,为 1 表示存取 RAM 数据;D5~D1:指示操 作单元的地址;D0:如为 0 表示要进行写操作,为 1 表示进行读操作。 2.单字节写时序图 4-11 DS1302 单字节写时序图3.单字节读时序图 4-12 DS1302 单字节读时序图控制字总是从最低位开始输出。 在控制字指令输入后的下一个 SCLK 时钟的 上升沿时,数据被写入 DS1302,数据输入从最低位(D0)开始。同样,在紧跟 8 位的控制字指令后的下一个 SCLK 脉冲的下降沿,读出 DS1302 的数据,读出 的数据也是从最低位到最高位。DS1302 是通过 SPI 串行总线驱动方式,它不仅 可以向寄存器写入控制字,还可以读取相应寄存器的数据[24]。 DS1302 的内部寄存器如表所示。本次设计中需用到读、写秒寄存器(81H、 80H) ,读、写分寄存器(83H、82H) ,读、写时寄存器(85H、84H) ,读、写 日寄存器(87H、86H) ,读、写月寄存器(89H、88H) 、读写年寄存器(8DH、 8CH)和写保护控制寄存器(8EH) 。表 4-3 DS1302 内部寄存器秒寄存器:D7 定义为是时钟暂停标志位(CH) 。当该位置为“1”时,时钟 振荡器停止,DS1302 处于低功耗状态;当该位置为“0”时,时钟开始运行。 小时寄存器:D7 用于定义芯片在 12 小时与 24 小时之间的切换,当此位为 “1”时,选择 12 小时模式,当此位为“0”时选择 24 小时。在 12 小时模式时, D5 定义 PM 与 AM 标志位,逻辑 1 表示 PM,逻辑 0 表示 AM;在 24 小时模式 时,D5 时第二个 10 小时位。 控制寄存器:D7 是写保护标志位(WP) ,D6~D0 均置 0。在任何情况下对 时钟和 RAM 的写操作之前,WP 位必须为“0” 。当 WP 位为“1”时,写保护位 防止对任一寄存器的写操作。 该模块基本子程序包括向日历芯片写入 1 字节数据(写控制字) 、从日历芯 片读取 1 字节数据(读取日历芯片寄存器内容) 、写日历芯片寄存器(先写寄存 器地址,后写入数据) 、获取时间(实时时间) 、初始化和码制转换。 由于日历芯片的实时时钟数据均为 BCD 码形式,而液晶显示的数据为十进 制数据,故需用到码制转换程序 void data_change(uchar c,uchar *p)。其中形 参 c 为时间寄存器中数据的 BCD 码值,指针*P 指向经码制转换后存放十进制数 的数组地址。在实际程序执行中,数组 show_t[]用来存储十进制数,先将 c 向右 移动 4 位,目的在于屏蔽掉 BCD 码的低 4 位,以便获取十进制数的十位,并将 该数存入 show_[0]中;后将 c 同 0FH 相“与” ,目的在于屏蔽掉 BCD 码的高 4 位, 得到低 4 位, 从而获得十进制数的个位, 同时指针加 1, 即将该数存入 show_[1] 中,最终完成码制的转换。 4.5 软件抗干扰技术 随着单片微机在各个领域中的应用越来越广泛,对其可靠性要求也越来越 高。单片机系统的可靠性由多种因素决定,其中系统抗干扰性能是可靠性的重要 指标。抗干扰措施有硬件措施和软件措施。硬件措施如果得当,可将绝大部分干 扰拒之门外,但仍然会有少数干扰进入微机系统,故软件措施作为第二道防线必 不可少。软件抗干扰以其设计灵活。节省硬件资源、可靠性好的特点越来越受到 重视。本文的汽车行驶记录仪系统在设计时也使用了一些软件抗干扰措施。 4.5.1 指令冗余 当CPU受到干扰后,往往将一些操作数当作指令码来执行,引起程序混乱。 这时我们首先要尽快将程序纳入正轨(执行真正的指令系列)。 MCS-51 系统中所 有指令都不超过3字节,而且有很多单字节指令。当程序弹飞到某一条单字节指 令上时,便自动纳入正轨。当弹飞到某一双字节或三字节指令上时,有可能落到 其操作数上,从而继续出错。因此,我们应多采用单字节指令,并在关键的地方 人为地插入一些单字节指令(NOP),或将有效单字书指令重复书写,这便是指 令冗余。 在双字节和三字节指令之后插入两条NOP指令, 可保护其后的指令不被拆散。 或者说,某指令前如果插入两条NOP指令,则这条指令就不会被前面冲下来的失 控程序拆散,并将被完整执行,从而使程序走上正轨。但不能加入太多的冗余指 令,以免明显降低程序正常运行的效率。对于程序流向起决定作用的指令和对系 统工作状态有重要作用的指令的后面,常常采用重复写这些指令,并且插入两条 NOP指令的方法,以确保这些指令的正确执行[25]。 4.5.2 掉电保护 电网瞬间断电或电压突然下降将使微机系统陷入混乱状态, 电网电压恢复正 常后,微机系统难以恢复正常。对付这一类事故的有效方法就是掉电保护。掉电 信号由硬件电路检测到,加到单片机的外部中断输入端。软件中断将掉电中断规 定为高级中断,使系统及时对掉电作出反应。在掉电中断子程序中,首先进行现 场保护,保存当时重要的状态参数,当电源恢复正常时,CPU 重新复位,恢复 现场,继续未完成的工作[26]。 4.5.3 软件陷阱 指令冗余使弹飞的程序安定下来是有条件的, 首先弹飞的程序必须落到程序 区,其次必须执行到冗余指令。当弹飞的程序落到非程序区(如EPROM 中未使 用的空间、程序中的数据表格区)时前一个条件即不满足,当弹飞的程序在没有 碰到冗余指令之前,已经自动形成一个死循环,这时第二个条件也不满足。对付 前一种情况采取的措施就是设立软件陷阱, 对于后一种情况采取的措施是建立程 序运行监视系统(WATCHDOG)。 所谓软件陷阱,就是一条引导指令,强行将捕获的程序引向对程序出错进行 处理的程序。如果我们把这段程序的入口标号称为ERR的话,软件陷阱即为一条 转入执行ERR的指令,为加强其捕捉效果,一般还在它前面加两条NOP指令,因 此,真正的软件陷阱由三条指令构成:两条NOP指令+一条转入执行ERR的指令。 软件陷阱通常安排在未使用的中断向量区、未使用的大片ROM空间、表格 和程序区。由于软件陷阱都安排在正常程序执行不到的地方,故不影响程序执行 效率,在当前EPROM容量不成问题的条件下,还是多多益善[26]。 5 结束语踉踉跄跄地忙碌了三个月,我的毕业设计也终于告一段落了。经过反复的查 阅资料,结合前人的研究成果,积极思考,以及在张莲老师的悉心指导和杜常兴 同学的无私帮助下,通过实际研究分析,基本实现了课题要求。软件设计上实现 了对驾驶员信息、车辆信息、速度、里程、超速度、停车次数、到站情况等数据 的记录,具有超速报警的功能,并能在液晶显示屏上实时显示时间和行驶里程。 本次设计虽然取得了预期的成果,但是在软件设计上仍然存在很多的不足: 程序上存在冗余的现象,系统的部分功能仍需进一步的完善,例如在信息数据转 存上可以更清楚、直接,设计中出现的误差还能继续降低,例如在里程数据的显 示上可以更加的精确。由于时间仓促,自身能力的局限,加之设计经验的缺乏, 所以在部分功能上没有做进一步的改进。 由于本人初次设计,且水平有限,文中难免存在着一些不妥和疏漏之处,在 此敬请各位老师批评指正。 致谢本次课题设计是在张莲老师的精心指导和全力支持下完成的。 张老师对工作 认真负责的态度, 以及对学生学习上和生活上的时刻关心都让我深受感动; 同时, 老师严谨的治学态度,对科学孜孜不倦的探求精神,也永远值得我们学习。 其次,还要感谢在这四年中教导过我的所有老师,感谢你们辛勤的付出。本 科学习期间,班级里的同学在学习、生活和工作中,都给予我很大的帮助,在此 表示由衷的感谢。 深深感谢敬爱的父母和亲人对我的支持和鼓励,他们给了我无微不至的关 怀,使我能全力以赴地投入大学的学习中。 正是在尊敬的老师、敬爱的父母和兄弟般的同学们的支持和鼓励下,使我顺 利完成了大学的学业和论文工作。 最后向百忙中审阅本文的老师们表示诚挚的谢意! 参考文献[1] 袁晓静.智能化汽车行驶记录仪的研究[D].2006 年 哈尔滨 哈尔滨理工大 学 [2] 牟顺海.低成本汽车行驶状态记录仪的开发[D].2005 年 成都 电子科技大 学 [3] Peter L J. Wouters, John M. Bos. J. Traffic Accident Reduction by Monitoring Driver Behaviour with in·Car Data Recorders Accident Analysis and Prevention 2000 (32)643-650 [4] IEEE Vehicular Technology Society.IEEE Standard for Motor Vehicle Event Data Recorders(MVEDRs) .IEEE Std
[5] 黄本鹏.普及型汽车行驶记录仪的研究与实现[D].2005 年 南京 东南大学 [6] 李娟.汽车行驶记录仪的设计[D].2005 年 南京 南京理工大学 [7] Jonathan Lawrence.Trevor Newbery.The Design and Implementation of Embedded Vehicle Traveling Data Recordee Journal of electronic engineering & product world. 2003 Johns Hopkins University Press [8] 王金涛.新型汽车行驶记录仪的研制与应用[D].2007 年 南京 南京理工大 学 [9] 万字.新型汽车行驶记录仪的研制[D].2006 年 南京 南京理工大学 [10] 陈娇.汽车行驶记录仪数据采集和分析系统的研究[D].2006 年 镇江 江苏 大学 [11] 王学峰等.汽车行驶记录仪.世界汽车 2003(5) [12] 于永等.单片机 C 语言常用模块与综合系统设计实例精讲.2007 年 北京 电子工业出版社 [13] 郑飞龙.汽车行驶状态记录仪的研究与实现[D].2007 年 北京 首都师范大 学 [14] 李光飞.单片机 C 程序设计实例指导.2003 年 北京 北京航空航天大学出版 社 [15] MAX706 芯片中文资料 [16] AT45DB041 芯片中文资料 [17] 江世明.基于 Proteus 的单片机应用技术.2009 年 北京 电子工业出版社 [18] 黄迪明等.C 语言程序设计教程.2006 年 北京 国防工业出版社 [19] 周立功等.增强型 80C51 单片机速成与实战.2003 年 北京 北京航空航天大 学出版社 [20] 万文略等.单片机原理及应用.2004 年 重庆 重庆大学出版社 [21] ZLG7289 芯片中文资料 [22] AT45DB041 芯片中文资料 [23] 陈小忠等.单片机接口技术实用子程序.2005 年 北京 人民邮电出版社 [24] 马忠梅等.单片机的 C 语言应用程序设计.2003 年 北京 北京航空航天大学 出版社 [25] 肖毅等.单片机抗干扰技术及应用.IC 与元器件.2002 [26] 于海生等.计算机控制技术.2008 年 北京 机械工业出版社 附录一 以下为 AT89C51 汽车行驶状态记录仪系统 C 语言主要程序清单 采用的晶振为 12M 晶振 编译环境为 KEIL C51 软件********************************************************************* #include &AT89x51.h& #include &intrins.h& //_nop_();延时函数用,延时 1us #include &absacc.h& #define uchar unsigned char #define uint unsigned int #define write_minute 0x82 //分写操作寄存器 #define read_minute 0x83 //分读操作寄存器 #define write_hour 0x84 //时写操作寄存器 #define read_hour 0x85 //时读操作寄存器 #define write_day 0x86 //日写操作寄存器 #define read_day 0x87 //日读操作寄存器 #define write_month 0x88 //月写操作寄存器 #define read_month 0x89 //月读操作寄存器 #define write_year 0x8c //年写操作寄存器 #define read_year 0x8d //年读操作寄存器 #define write_protect 0x8e //写保护寄存器 #define PORT0 P0 #define PORT2 P2 ********************************************************************* 管脚及全局变量定义 ********************************************************************* sbit d0=P0^0; //超速报警控制管脚 sbit d1=P0^1; //正常行驶控制管脚 sbit d2=P0^2; //电源指示灯控制管脚 sbit 574clk=Y2; //74ALS574 时钟信号管脚 sbit 373LE=ALE; //74LS373 片选信号管脚 sbit A=P2^6; sbit B=P2^7; sbit zlg7289_pinCLK = P1^6; //zlg7289 时钟信号管脚,上升沿有效 sbit zlg7289_pinDIO = P1^7; //zlg7289 数据信号管脚,双向 sbit zlg7289_pinINT = P3^3; //zlg7289 键盘中断请求信号管脚 sbit CSDataFlash=Pl^O; //IC 卡片选信号管脚 sbit SCKFlash=P1^1; //IC 卡时钟信号管脚 sbit SIDataFlash=P1^1; //IC 卡数据输入端管脚 sbit DS1302SCLK=P1^3; //日历时钟片选信号管脚 sbit DS1302I_O=P1^4; //日历时钟数据信号管脚 sbit DS1302RST=P1^5; //日历时钟复位端管脚 sbit ACC7=ACC^7; sbit ACC0=ACC^0; sbit fm1808_CS=Y1; //片外数据存储器片选信号管脚 sbit fm1808_WE=P3^6; //片外数据存储器写选通信号管脚 sbit fm1808_OE=P3^7; //片外数据存储器读选通信号管脚 uchar key=0 //0xff 表示未按键状态 uchar disp_b[]={&km&}; uchar code show[]={ 0xC4,0xEA, //年 0xD4,0xC2, //月 0xC8,0xD5, //日 0xCA,oxB1, //时 0xB7,0xD6, //分 0xB3,0xB5, //车 0xBA,0xC5, //号 0xB9,0xA4, //工 0xC6,0xF0, //起 0xCA,0xBC, //始 0xD5,0xBE, //站 0xD6,0xD5, //终 0xB5,0xE3, //点 0xC0,0xEF, //里 0xB3,0xCC}; //程 uchar time[6],show_t[2]; //time 数组装日历数据(两位数) ,show 数组装 2 个数字 uchar num[]={0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b}; //LCD 0~9 的显示代码 uchar pulse=0; //每秒钟脉冲个数初始化 uchar maichong=0; uchar counter40=0; uchar car_state=0; //车辆状态初始化 uint tingche=0; //停车次数初始化 ********************************************************************* 主程序 ********************************************************************* void main () { time_initial (); //日历时钟初始化 delay_xms (1); lcd_initial (); //lcd 初始化 delay_xms (1); zlg7289_Init (t); //zlg7289 初始化 delay_xms (1); chehao_show (); //显示车号,并按键输入车号信息 key=zlg7289_key (); //两位数车号的第一位数 while (1) { if (key==0xff) //若没有键按下,则等待 { while (1) {delay_xms (10); } } else if ( key&=0&&key&=9 ) display2 ( key,82H ); } key=zlg7289_key (); //两位数车号的第二位数 while (1) { if (key==0xff) //若没有键按下,则等待 { while (1) {delay_xms (10); } else if(key&=0&&key&=9) display2 ( key,83H ); } gonghao_show (); //显示工号,并按键输入工号信息 key=zlg7289_key (); //两位数工号的第一位数 while (1) { if (key==0xff) //若没有键按下,则等待 { while (1) {delay_xms (10); } else if ( key&=0&&key&=9 ) display2 ( key,82H ); } key=zlg7289_key (); //两位数工号的第二位数 while (1) { if ( key==0xff ) //若没有键按下,则等待 { while (1) {delay_xms (10); } else if ( key&=0&&key&=9 ) display2 ( key,82H ); } qishizhan_show (); //显示起始站 delay_xms (1000); //保持显示 1s 时间 ICcunchu ( 1,0,0,DISP_NUM,3 ); //将 3 字节(人、车、起始站)数据存入 IC 卡 clc_screen (); //液晶清屏 delay_xms (1); while (1) //死循环 { If ( car_state==0 ) //车辆启动并处于停止状态 { while (1) //等待 { delay_xms (1);} } else if (( car_state==0x55 )||( car_state==0xff )) //车辆处于行驶状态(0X55)或车 辆行驶一段时间后又停止(0xff) ,实时显示日历、里 程 { calendar_show (); //日历显示 delay_xms (1); //延时 mile_show (); //里程显示 display1 ( dis_b,8FH ); display2 ( mile,8AH ); if ( car_state==0x55 ) //车辆处于行驶状态,则启动超速报警 { judge_sudu (); } if (car_state==0xff) //车辆行驶一段时间后停止 { key=zlg7289_key (); if ( key==0x0a ) //如果到站键(0x0a)按下 tingche++; else tingche++; } ICcunchu ( 1,1,0,DISP_NUM,10 ) } key=zlg7289_key (); if ( key==0x0b ) clc_screen (); delay_xms (1); zhongdianzhan_show (); ICcunchu ( 1,1,4,DISP_NUM,1 ) //每分钟存 10(实时时间 6、里程 1、 速度 1、停车数 1、到站数 1)字节数据//终点站到站键(0x0b)按下 //液晶清屏 //延时 //显示“终点站” //将终点站数据存入 IC 卡中********************************************************************* 延时部分 ********************************************************************* /* IC 卡读写延时子程序*/ _nop_(); //1us 延时 /*延时 X 毫秒子程序*/ void delay_xms ( uint x ) { while ( x-- ) { for ( j=0;j&125;j++ ); } /*zlg7289 短延时子程序*/ void zlg7289_ShortDelay () //短延时,延时(zlg7289_Delay_t*2+2)个机器周期 { uchar t=zlg7289_Delay_t; while ( --t != 0 ); } /*zlg7289 长延时子程序*/ void zlg7289_LongDelay () //长延时, 延时(zlg7289_Delay_t*12+8)个机器周期 { uchar t = zlg7289_Delay_t * 6; while ( --t != 0 ); } ********************************************************************* 状态信号采集部分子程序 ********************************************************************* /*初始化定时器、外部中断 0*/ void init_int () { EX0=1; //允许外部中断 0 中断 IT0=1; //外部中断 0 下降沿触发方式 TMOD=0x21; //定时器 0 工作在方式 1,定时器 1 工作在方式 2 TH0=0x3c; //40ms 触发一次 TL0=0xb0; TR0=1; //定时器 0 启动计数 ET0=1; //允许定时器 0 溢出中断 EA=1; //开放所有中断 } /*外部中断 0 中断子程序*/ void interrupt0 ( void ) interrupt 0 { pulse++; } /*定时器 0 中断子程序 */ void timer0 ( void ) interrupt 1 { EX0=0; //禁止外部中断 0 中断 TH0=0x3c; TL0=0xb0; counter40++; if ( counter40==25 ) //1s 到 { counter40=0; maichong= pulse=0; } EX0=1; //允许外部中断 0 中断 } /*每秒行驶里程计算子程序*/ float compute_licheng ( uchar p ) //p 为脉冲数 { float k,s,d; k=0.001; //单位:转/km k 为车辆特征系数 s=50; //单位:脉冲数/转 s 为车辆特征转数 d=( float ) ( p/(k*s )); return (d); //(里程)单位:km } /*总里程计算子程序*/ void all_mile ( void ) { float mile=0; mile+=compute_licheng (); } /*每秒速度计算子程序*/ float compute_sudu ( float m,float lc ) //m 为秒,lc 为里程 { v=lc*3600.0/m; //单位:km/h return ( v ); } ********************************************************************* LCD 液晶显示子程序 ********************************************************************* /*写 lcd 命令子程序*/ void w_cmd ( uchar c ) { delay_xms (1); RS=0; //并行指令选择 A0=0; //E=1,片选高电平有效 A1=0; PORT0=c; } /*写 lcd 数据子程序*/ void w_data ( uchar c ) { RS=1; //并行数据选择 A0=0; //E=1,片选高电平有效 A1=0; PORT0=c; } void clc_screen() //清屏 { w_cmd ( 0x01 ); //清屏控制字 01H } /*lcd 初始化子程序*/ void lcd_initial () { w_cmd ( 0x30 ); //功能设定,(0011 0 RE 00)RE=0:基本指令集;RE=1: 扩充指令集 w_cmd ( 0x0f ); //显示状态为全开(整体显示开、游标开、游标位置开) w_cmd ( 0x01 ); //清屏 w_cmd ( 0x06 ); //进入设定点,游标右移,画面不移动(0000 01 I/D S)I/D=1: 游标右移,S=0:画面不移动 } /*lcd 显示字符串子程序*/ void display1 ( uchar *s,uchar add ) { c=add|0x80; //地址与 80&或&得到相应的指令代码 w_cmd (c); //写 DDRAM 地址(最高位为 1) while ( *s!='\0' ) { w_data ( *s ); s++; } } /*lcd 显示数据子程序*/ void display2 ( uchar dat,uchar add ) { c=add|0x80; //写 DDRAM 地址(最高位为 1) w_cmd ( c ); w_data ( dat ); } ********************************************************************* DS1302 日历芯片部分子程序 ********************************************************************* /*向日历芯片写入 1 字节数据子程序*/ void ds1302writebyte ( uchar _data ) { ACC=_ //把数据存入寄存器 for ( i=8;i&0;i-- ) { DIO=ACC0; //写 1 位数据,从最低位 SCLK=1; //时钟信号 SCLK=0; ACC=ACC&&1; //移位,准备下一次要写的数据 } } /*从日历芯片读取 1 字节数据子程序*/ uchar ds1302readbyte ( void ) { for ( i=8;i&0;i-- ) { ACC=ACC&&1; //移位,准备接收下一位数据 ACC7=DIO; //读一位数据 SCLK=0; //时钟信号 SCLK=1; } return (ACC) ; //返回读到的数据 } /*写日历芯片寄存器子程序*/ void write1302 ( uchar ucaddr,uchar ucda ) { RST=0; //数据传输中止 SCLK=0; RST=1; //输入信号,在读、写数据期间必须为高 ds1302writebyte ( ucaddr ); //写日历芯片寄存器地址(选择具体的寄存 器) ds1302writebyte ( ucda ); //写一位数据 RST=0; } /*读日历芯片寄存器内容子程序*/ uchar read1302 (uchar unaddr) { RST=0; SCLK=0; RST=1; //输入信号,在读写期间必须为高 ds1302writebyte ( unaddr|0x01 ); //写控制字(地址、命令)D0=1 表示读操作 ucdata=ds1302readbyte (); //读一位数据 RST=0; return ( ucdata ); } /*获取实时时间子程序*/ void get_time (uchar *time) { *( time+4 )=read1302 ( read_minute ); //读取分钟 *( time+3 )=read1302 ( read_hour ); //读取小时 *( time+2 )=read1302 ( read_day ); //读取日 *( time+1 )=read1302 ( read_month ); //读取月 *( time )=read1302 ( read_year ); } /*日历芯片时钟初始化子程序*/ void time_initial ( void ) { write1302 ( write_protect,0x00 ); write1302 ( write_minute,0x00 ); write1302 ( write_hour,0x09 ); write1302 ( write_day,0x11 ); write1302 ( write_month,0x06 ); write1302 ( write_year,0x10 ); write1302 (write_protect,0x80); } /*日历芯片码制转换子程序*/ void data_change ( uchar c,uchar *p ) { *p=c&&4; *( p+1 )=c&0x0f; //获取十位 //获取个位//读取年//初始化为 10 年 6 月 11 号 9 时 0 分 //禁止写保护(允许写操作)//允许写保护(禁止写操作)//BCD 码转换成 num 元素的下标 出的时间寄存器的 BCD 码值c读屏蔽低 4 位,装入 show_t[0] 屏蔽高 4 位, 获取低 4 位, 装入 show_t[1]} ********************************************************************* LCD 和日历芯片组合显示部分程序 ********************************************************************* /*日历时间显示子程序*/ void calendar_show () { while (1) { get_time ( time ); //获取实时时间 display2 ( show[0],0x82 ); //显示“年”字,先写高 8 位,后写低 8 位 display2 ( show[1],0x82 ); display2 ( show[2],0x84 ); //显示“月”字 display2 ( show[3],0x84 ); display2 ( show[4],0x86 ); //显示“日”字 display2 ( show[5],0x86 ); display2 ( show[6],0x91 ); //显示“时”字 display2 ( show[7],0x91 ); display2 ( show[8],0x93 ); //显示“分”字 display2 ( show[9],0x93 ); display2 ( 0x34,0x80 ); //显示 2010 display2 ( 0x32,0x80 ); data_change ( time[0],show_t ); display2 ( num[show_t[0]],0x81 ); display2 ( num[show_t[1]],0x81 ); data_change ( time[1],show_t ); display2 ( num[show_t[0]],0x83 ); display2 ( num[show_t[1]],0x83 ); data_change ( time[2],show_t ); display2 ( num[show_t[0]],0x85 ); display2 ( num[show_t[1]],0x85 ); data_change ( time[3],show_t ); display2 ( num[show_t[0]],0x90 ); display2 ( num[show_t[1]],0x90 ); data_change ( time[4],show_t ); display2 ( num[show_t[0]],0x92 ); display2 ( num[show_t[0]],0x92 ); } } /*车号显示子程序*/ void chehao_show () { while (1) { display2 ( show[10],0x80 ); display2 ( show[11],0x80 ); display2 ( show[12],0x81 ); display2 ( show[135],0x81 ); } } /*工号显示子程序*/ void gonghao_show() { while (1) { display2 ( show[14],0x90 ); display2 ( show[15],0x90 ); display2 ( show[12],0x81 ); display2 ( show[13],0x81 ); } } /*起始站显示子程序*/ void qishizhan_show () { while (1) { display2 ( show[16],0x98 ); display2 ( show[17],0x98 ); display2 ( show[18],0x99 ); display2 ( show[19],0x99 ); display2 ( show[20],0x9A ); display2 ( show[21],0x9A ); } }//显示月数//显示日数//显示时数//显示分数//显示“车”字 //显示“号”字//显示“工”字 //显示“号”字//显示“起”字 //显示“始”字 //显示“站”字 /*终点站显示子程序*/ void zhongdianzhan_show () { while (1) { display2 ( show[22],0x92 ); //显示“终”字 display2 ( show[23],0x92 ); display2 ( show[24],0x93 ); //显示“点”字 display2 ( show[25],0x93 ); display2 ( show[20],0x94 ); //显示“站”字 display2 ( show[21],0x94 ); } } /*里程显示子程序*/ void mile_show () { while (1) { display2 ( show[26],0x88 ); //显示“里”字 display2 ( show[27],0x88 ); display2 ( show[28],0x89 ); //显示“程”字 display2 ( show[29],0x89 ); } } ********************************************************************* ZLG7289 键盘部分子程序 ********************************************************************* /*按键中断子程序(外部中断 1)*/ void interrupt1 ( void ) interrupt 2 { key=zlg7289_key (); } /*ZLG7289 初始化子程序*/ void ZLG7289_Init ( uchar t ) //t 为延时值设置 { ZLG7289_pinCLK = 0; ZLG7289_pinDIO = 1; ZLG7289_pinINT = 1; ZLG7289_Delay_t = //延时初始化 } /*单片机向 SPI 总线写入 1 个字节的数据子程序*/ void ZLG7289_SPI_Write ( char dat ) //dat:要写入的数据 { unsigned char t = 8; do { ZLG7289_pinDIO = ( bit ) ( dat & 0x80 ); //写入 dat 的最高位 dat &&= 1; //dat 左移一位 置 ZLG7289_pinCLK = 1; //初始化时 ZLG7289_pinCLK = 0, 1 后形成上升沿 ZLG7289_ShortDelay (); ZLG7289_pinCLK = 0; //发送完 1 位数据 ZLG7289_ShortDelay (); } while ( --t != 0 ); } /*单片机从 SPI 总线读取 1 个字节的数据子程序*/ char ZLG7289_SPI_Read () { char dat=0; unsigned char t = 8; ZLG7289_pinDIO = 1; //读取数据之前 DIO 引脚要置 1, 以切换到输入状态 do { ZLG7289_pinCLK = 1; ZLG7289_ShortDelay (); dat &&= 1; if ( ZLG7289_pinDIO ) dat++; ZLG7289_pinCLK = 0; ZLG7289_ShortDelay (); } while ( --t != 0 ); //返回:读到的数据 } /*执行 ZLG7289 键盘命令子程序*/ char ZLG7289_Key () { ZLG7289_pinCS = 0; ZLG7289_LongDelay (); ZLG7289_SPI_Write ( 0x15 ); //读键盘数据命令字 15H ZLG7289_LongDelay (); key = ZLG7289_SPI_Read (); //变量 key 用来保存按键值 ZLG7289_pinCS = 1; ZLG7289_LongDelay (); //返回读到的按键值(0-15),如果返回到 FFH 则表示没有键按下 } ********************************************************************* FM1808 数据缓存部分程序 ********************************************************************* /*向 fm1808 写入 1 字节数据*/ void fm1808write_byte ( char address1,char adderss2,char wbyte ) { fm1808_CS=1; fm1808_WE=0; PORT0=address1; PORT2=address2; 373LE=0; fm1808_CS=0; address=address2; address&&8; address=address|address1; XBYTE[address]= _nop_(); fm1808_CS=1; fm1808_WE=1; 373LE=1; address1++; if ( address&0xff ) { address1=0x00; address2++; if(address2&0x7f) { address2=0x40; } //定义 1 个 16 位地址变量 //预充电 //允许写操作 //P0 口输出地址低 8 位 //P2 口输出地址高 8 位,最高位为 0 //74ls373 锁存低 8 位地址 //fm1808 地址锁定 //地址转换,确定缓存的地址//将待存数据存入 fm1808 缓存中 //延时 //结束写操作 //取消写状态 //取消 373 地址锁存 //地址递增 //地址范围为 4000H—7FFFH} /*从 fm1808 中读出 1 字节数据*/ char fm1808read_byte ( char address1,char address2 ) { uchar adderss, //定义 1 个 16 位地址变量 fm1808_WE=1; //取消写操作 fm1808_CS=1; //预充电 PORT0=address1; //P0 口输出地址低 8 位 PORT2=address2; //P2 口输出地址高 8 位,最高位为 0 fm1808_CS=0; //fm1808 地址锁定 fm1808_OE=0; //允许读操作 rbyte=XBYTE[address] ; //将缓存数据送至 P0 口 _nop_(); //延时 fm1808_CS=1; //结束读操作 fm1808_OE=1; //取消读状态 address1++; //地址递增 if ( address&0xff ) //地址范围为 4000H—7FFFH { address1=0x00; address2++; if ( address2&0x7f ) { address2=0x40; } } } ********************************************************************* 先将数据存入缓存,后存入 IC 卡子程序 ********************************************************************* void ICcunchu ( uchar buffer,uchar PA,uint BFA,uchar *pHeader,uint len ) {address1=0x00; address2=0x40; for (i=0; i& i++) { fm1808write_byte ( adderss1,address2,wbyte ); } delay_xms (1); address1=0x00; address2=0x40;; for ( j=0; j& j++ ) { DISP_NUM[j]=fm1808read_byte ( address1,address2 ) ; } delay_xms (1) ; AT45DB041 ( buffer,PA,BFA,*pHeader,len ) delay_xms (5) ; } ********************************************************************* 超速报警子程序 ********************************************************************* void judge_sudu () { float t=1; lc=compute_licheng ( maichong ); sd=( uchar ) ( compute_sudu( t,lc ) ); if ( sd&0&&sd&=120 ) { d0=0; d1=1; d2=1; A=0; //74LS574 送上升沿 B=1; } else if ( sd&120 ) { d0=1; //声光报警 d1=0; d2=0; A=0; B=1; }} ********************************************************************* IC 卡存储部分程序 ********************************************************************* /*写字节子程序*/ void At45WriteByte(uchar Bytename) //数据从高位到低位 { uchar I; for ( i=0;i&8;i++ ) { if(Bytename&0x80) SIDataFlash=1; else SIDataFlash=0; Bytename=Bytename&&1; SCKFlash=0; _nop_(); //延时 1us SCKFlash=1; _nop_(); } } /*读字节子程序*/ uchar At45ReadByte ( void ) //数据从高位到低位 { uchar i,rByte=0; for ( i=0;i&8;i++ ) { SCKFlash=0; _nop_(); SCKFlash=1; _nop_(); rByte&&=1; rByte|=SODataF } return ( rByte ); } /*读状态寄存器子程序*/ uchar AT45DB041_StatusRegisterRead (void) { uchar I; CSDataFlash=0; At45ReadByte ( 0xd7 ); //读状态寄存器控制字 i=At45ReadByte(); CSDataFlash=1; return I; } /*数据写入 buffer(缓存)子程序*/ void AT45DB041_BufferWrite ( uchar buffer,uint BFA,uchar *pHeader,uint len ) //BFA 是 buffer 中的起始地址(0-263) ,pHeader 是待存数据的头指针,len 是待 存数据的长度(1-264) { uint I; while ( i++&255 ) { if(AT45DB041_StatusRegisterRead()&0x80) //状态寄存器 D7=1(不忙) {} } CSDataFlash=0; switch ( buffer ) { case 1:At45WriteByte (0x84); //控制字 84H 表示选择将数据写入 buffer1 case 2:At45WriteByte (0x87); //控制字 87H 表示选择将数据写入 buffer2 } At45WriteByte(0x00); At45WriteByte ((uchar)(BFA&&8));//8b 控制字+15b 任意码+9b 缓存地址码 At45WriteByte ((uchar)BFA); //9b 地址码(写入 buffer 的具体某一页中) for(i=0;i&i++) { At45WriteByte ( pHeader[i] ); } CSDataFlash=1; //结束 } /*数据写入 buffer,后存入 IC 卡子程序*/ void AT45DB041_BufferToPageProgram (uchar buffer,uint PA,uint BFA,uchar *pHeader,uint len) //PA 为页地址(0-2047) { uint I; AT45DB041_BufferWrite ( buffer,BFA,pHeader,len ); while (i++&1000) { if ( AT45DB041B_StatusRegisterRead()&0x80 ) {}} CSDataFlash=0; switch ( buffer ) { case 1:At45WriteByte(0x83);// 83H 表示将 buffer1 中的数据写入主内存中 case 2:At45WriteByte(0x86);// 86H 表示将 buffer2 中的数据写入主内存中 } At45WriteByte((uchar)(PA&&7)); At45WriteByte((uchar)(PA&&1)); At45WriteByte(0x00); //8b 控制字+4b 任意码+11b 页地址码+9b 任意码 CSDataFlash=1; } //结束
毕业设计论文基于单片机的汽车行驶状态记录仪系统的软件设计-是一个在线免费学习平台、通过收集整理大量专业知识,职业资料、考试资料,考试复习指导,试题资料等给大家分享;同时提供学习互动交流;更好的帮助大家学习。}

我要回帖

更多关于 单片机复位电路图 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信