网站首页 >> 交通安全 >> 正文
简介: 1引言 汽车的安全性一直都是消费者所关注的,其实在发生交通事故时,对人们安全起最主要保障作用的却是我们最常见的安全装置——安全带。 经过40多年的发展,安全带逐渐走向成熟,现在欧美的安全带均由强度极大

1引言 汽车的安全性一直都是消费者所关注的,其实在发生交通事故时,对人们安全起最主要保障作用的却是我们最常见的安全装置——安全带。 经过40多年的发展,安全带逐渐走向成熟,现在欧美的安全带均由强度极大的合成纤维制成,带有自锁功能的卷收器,采用对驾、乘人员的肩部和腰部同时实现约束的三点式设计。系上安全带后,卷收器自动将其拉紧,当车辆万一出现紧急制动、正面碰撞或发生翻滚时,乘员会使安全带受到快速而猛烈的拉伸,此刻卷收器的自锁功能可在瞬间卡住安全带,使乘员紧贴座椅,避免摔出车外或碰撞受伤。 但是当高速前进的汽车突然停车时,要将车中人前冲的身体维持在座位上,必须有很大的力量,因此安全带一定要强力,必须满足一定的质量标准才能投入使用。根据有关机构统计,在所有可能致命的车祸中,如果正确使用性能良好的安全带,可以挽救约45%的生命。 所有这些都说明,随着汽车工业的飞速发展和汽车的普及,为了减少交通事故的发生,保护人身的安全,汽车安全带的实际应用确实非常必要,而保证安全带的良好性能则是更实质的部分。而我国目前还没有能检测安全带质量性能的装置和系统,目前天津大学从国外引进一台设备,正投入研究。 本系统就是针对这些而开发的,成功后能起到实际作用,对社会具有一定的推广意义。 2.系统设计 本系统设计内容既涉及到微机并行接口的开发知识,又有DEPHI软件编程。主要是软件的开发与应用研究。 安全带的性能有两项技术指标: (1) 在加速度达到最大时,位移必须在5cm之内。 (2) 刹车期间平均加速度变化率 20。 系统中的性能测试都是围绕这两项指标的。 2.1 硬件设计 根据预定要求,先将两路模拟信号或脉冲信号经过多路开关MUX选择,然后经过放大器将信号放大到0~10V,再送到A/D板;A/D板将这些模拟信号或脉冲信号转换成12位数字量,送到ISA总线,然后进行校正,转换成参数数值。其中为实现高速采集,使用了8255A作ADC的接口进行查询式采集。经测试,采集一个数据大约要50us左右。 采集板的布局如下所示: 图1. 采集板卡 2.1.1 主要芯片介绍 (1). AD574 AD574是具有三态输出锁存器的逐次逼近型A/D转换芯片,可以作12位转换,也可作8位转换。转换速度较快,为25us,内部含有与微型计算机连接的逻辑控制电路,使用起来非常方便。若转换成12位二进制数,可以一次读出,也可分成两次输出,即先读出高8位后读出低4位。本系统采用12位转换。 AD574外部设置5跟控制线(CE、 、R/ 、12/ 、 )和一根状态线(STS)。5个控制信号的功能定义如下: CE:片允许信号,高电平允许工作。简单应用中可固定接高电平。 :片选中,低电平有效。 R/ :双功能引脚,作为读数据或启动转换的控制信号。R/C=1, 用于读数据;R/C=0,用于启动转换。 12/ :数字量输出位数控制,12/ =1,1次输出12位数据;12/ =0,1次输出8位数据。 :双功能引脚,用于分辨率和字节选择。在转换启动时,若 =0,则AD574作12位转换器用;若 =1,作8位转换器用。在读数据时,若 =0,则读高字节;若 =1,则读低字节。 以上信号线中, 、CE、和R/ 三个信号组合起来实现启动转换和读数据。当 =0、CE=1和R/ =0时,启动A/D进行转换;当 =0、CE=1和R/ =1时,读取数据。这5个控制信号的电平状态与AD574所产生的操作对应关系如表1所示: CE R/ 12/ AD574A的功能操作 0 X X X X 不允许转换 X 1 X X X 未接同芯片 1 0 0 X 0 启动一次12位转换 1 0 0 X 1 启动一次8位转换 1 0 1 高电平(+5V) X 一次输出12位 1 0 1 低电平(数字地) 0 输出高位字节 1 0 1 低电平(数字地) 1 输出低位字节 表1:AD574的控制信号的作用 STS:状态线,表示转换器状态,在转换期间,STS为高;当转换结束时,STS变低。可用此信号来查询转换是否结束。 (2).8255A 可编程并行接口 8255A是一个具有两个8位(A口和B口)和两个4位(C口高/低4位)并行I/O端口接口芯片,能适应CPU与I/O接口之间的多种数据传送方式的要求。如无条件传送、应答(查询)传送和中断方式传送,与此相应,8255A设置了0方式、1方式以及2方式(双向传送)。 8255A可执行功能很强,内容丰富的两条命令(方式字和控制字)为用户如何根据外界条件(I/O设备需要哪些信号线以及它能提供哪些状态线)来使用8255A构成多种接口电路,组建微机应用系统提供了灵活方便的编程环境。8255A在执行命令过程中和执行命令完毕之后,它所产生的状态保留在状态字中,以供查询。 本系统用的是8255的0方式。0方式是一种基本输入/输出工作方式。通常不用联络信号,或不使用固定的联络信号,因此,所谓基本I/O方式是指查询方式传送,也包括无条件传送。在0方式下不设置专用联络信号线,需要联络时,可由用户任意指定C口中的哪根线完成某种联络功能,本系统是指定的PC7口作为联络信号的。由于无固定的专用联络信号,因此也就在端口与I/O设备之间无固定的时序关系,由用户根据数据传送的要求决定输入/输出的操作过程。 2.1.2硬件结构简单框图 CD4067是一个16路的多路转换开关。由于AD574是单通道模拟量输入,每次只能转换一路数据信号,因此要通过CD4067进行通道选择。这个系统用到了CD4067的两个通道。通道0接位移信号,通道1接加速度信号。 CPU发出选通道信号命令,驱动器传送到74LS138译码器,输出地址锁存器,打开通道开关,准备接受模拟信号。接口处信号经信号放大器放大到0~10v,输入到AD574模数转换器,将模拟信号转换成数字信号,通过ISA总线输入电脑。 放大器 IN0 > IN1 A B C D pc7 图2. 采集电路简图 采用8255A作ADC的接口,这种接口电路设计方便,尤其在与CPU连接时的信号线及其时序配合中不需作什么工作。加上是可编程,使用灵活。本系统中用的是8255A的PC7口作联络信号,接AD574的STS状态线,通过简单编程就可方便查询数据是否转换完毕,然后再将查询结果传送到CPU,以便做下一步的处理。 2.2 软件设计 系统启动时,先要进行设备自检,看两路通道是否都能正常采集。采集底值是在没加任何信号时采集的一个基准值,以后采集的数据都要减去这个基准值。采集完后,将数据存入文件。可以直接查看测试结果,该部分给出了所需要的主要参数值。也可以进行曲线绘制查看采集时段数据的详细分布情况,此部分能绘制三个量程的参数—时间图,曲线分六屏显示,默认采集4000次。用户也可自己输入采集次数。可用光标任选曲线段进行评估。之后,能连接打印机将图形打印出来。 软件部分的主要模块结构如下图所示: 图3.软件部分总体结构图 2.2.1 所用编程语言简介 本系统是在Delphi5.0环境下开发的。Delphi是由Inprise公司(前Borland公司)推出的可视化编程环境,它提供了一种方便、快捷的Windows应用程序开发工具。Delphi使用了Microsoft Windows图形用户界面的许多先进特性和设计思想,采用了可重复利用的完整的面向对象程序语言(Object-Oriented Language)。 Delphi使用“可视化”的编程方法。程序员不必自己建立对象,利用Delphi所提供的可视“控件”,只要在提供的程序框架中加入完成功能的代码,如选择命令、移动鼠标等,而不必考虑按精确次序执行的每个步骤。在这种机制下,不必编写一个大型的程序,而是建立一个由若干微小程序组成的应用程序,这些微小程序可由用户启动的事件来激发。这样就可以快速创建强大的应用程序而勿需涉及不必要的细节。 另外,在Delphi中能方便的嵌套使用汇编语言。本系统中与硬件接口的地方全部是用汇编编写的。这样既方便对底层硬件的访问,又能提高代码的执行效率。所以Delphi环境非常有利于软硬件的结合。 2.2.2 设备自检模块设计 设备自检原理就是从所选通道读出的电压值必须要与所加的电压值相当,所以核心就是从端口读出多组数据值并显示出来。各端口地址分别为:选通道----228H ;启动转换----221H ;读高8位数据----221H ;读低8位数据----220H 。 此单元定义了一个计时器(Timer)控件Timer1,Timer控件可以在应用中以重复的时间间隔产生一个事件,由于属于非可视化控件,在运行时不可见,常用来做一些后台处理。该控件只有一个事件OnTimer,将需要循环执行的程序段放在这个事件里,计时器的Interval属性指定了两个Timer事件之间的毫秒数。缺省值为1000(1秒),计时器将每秒(近似等间隔)激发一次Timer事件。本模块将核心部分(读通道电压值 )放在Timer1的OnTimer事件里,输出多组值到列表框Listbox1内。这是通过语句listbox1.Items.add(s)来实现的,这里调用了Tstrings类的相应方法来处理Items中的数据。 事件由Timer控件的enabled属性来启动,该属性为True时,定时器开始工作,为False时暂停。开始时令其为false,当选定通道后开始工作。由于只有两路通道,在单元中添加了两个单选按扭RadioButton,按扭组放在一个GroupBox控件里。另外还定义一个字节型变量tdhao,用来保存所选通道序号0或1,0通道是用来采集位移信号的,1通道采集加速度信号。由以下语句来给tdhao赋值: if radiobutton1.checked=true then tdhao:=0 else if radiobutton2.checked=true then tdhao:=1; OnTimer事件的程序流程图如下页图所示: Timer1.enabled=true 为0或1 否则 图4.设备自检流程图 Ontimer事件每次开始时都会检测是否tdhao为0或1,只有满足时,才会继续往下执行。当然最初会给tdhao赋个初值。后面汇编语句的选通道部分直接将tdhao变量值读入端口。汇编采集部分的核心程序如下: mov dx,228h //选通道 mov al,tdhao out dx,al mov dx,221h //启动转换 out dx,al mov bx,20h //延时,等待转换结束 @b:mov cx,0e000h @c:loop @c dec bx jnz @b mov dx,221h //读高8位 in al,dx mov x1,al mov dx,220h //读低4位 in al,dx mov x2,al 其中x1和x2是定义的全局整型变量,存储读取的高低位二进制值,以作进一步转换。 这里的数据要进行处理主要是由于AD574的12条输出数据线的高8位接到系统总线的D0----D7,而把低4位接到数据总线的高4位,低4位补0,以实现左对齐。所以读出数据后高8位应该乘以16,而低4位则要除以16,再相加即可。这一点由语句x2:=(x2 div 16)+x1*16;来实现。此外,还必须转换为电压值。AD574的精度为12位,最高量程为10V。所以应该由公式x2*10/4096来转换。但是由于汇编语句的需要,x1和x2都设置成为整型变量,为保证精度,可以先乘以一个放大几倍的数,得出结果后再相除和取余。这样得到的商就是结果的整数部分,而余数则是小数部分,在输出时再一起输出,见如下语句所示: x1:=(x2*10000)div(4095); x3:=x1 mod 1000; x1:=x1 div 1000; s1:=inttoStr(x1)+'.'+inttoStr(x3)+'V'; listbox1.Items.add(s1); 其中s1为字符型变量,这是listbox输出的格式需要。S1也将数据的整数和小数部分连接了起来,起到中介的作用。随着OnTimer事件的反复执行,数据会逐渐增多,listbox会自动加上滚动条,但是交换通道检查时,还是必须清空listbox1。基于对程序控制的方便,添加了“暂停”、“继续”、“清空”、“返回”四个按扭。按暂停按扭,执行Timer1.enabled:=false;定时器停止工作;按继续,使Timer1.enable=true,定时器重新开始工作;清空按扭可以清空listbox1内的内容,并将光标移到首行,由以下两条语句来实现:listbox1.clear; listbox1.tag:=0; clear是系统定义的方法。Tag为listbox的属性,指行标。点返回按扭退回到主界面。 清空和继续按扭在程序开始时是无效的,在formcreate事件中设置其enabled属性为false即可。只有在listbox1中有数据后,清空按扭才生效;同样,只有在按下暂停按扭后继续按扭才生效。这都是通过在相应事件中设置enabled属性为true 来实现的。 2.2.3 采集模块设计 在信号输入之前首先要采集底值。为保证一定的精度,每路通道的底值都是采两次之后取的平均值。然后可以输入信号,进行实时测试。之后的汇编采集部分方法与采集底值是相同的,但是必须根据一定的加速度灵敏度、位移传感器电阻值、位移传感器长度来对数据进行处理,得出所需要的实际参数值。这在后面会有详细说明。此单元的采集用的是查询式采集,这是为了满足高速采集的需要。下面根据采集部分的流程图分别作出说明:(图见下页) 8255A的初始化是由以下三条语句来完成的: mov dx,22fh //8255A命令口地址 mov al,10011011b //初始化命令 out dx,al //送到命令口 方式字10011011是指将8255三个并行端口中的A口和B口都指定为0方式,输入;C口的上半部和下半部也都为输入。选通道部分端口地址为228H,由于只有两路通道,将依次进行采集,没有使用循环。然后往221H 端口写入任意数据就能启动转换了。 先看核心采集程序的流程图: 否 否 是 图5.采集程序流程图 接下来开始检查是否转换完毕。系统将循环检测STS信号,直到其为0为止。这里以8255的PC7口作为状态信号,即将STS状态线连到8255A的PC7口,系统直接查询PC7口即可。见下面程序段: mov dx,22eh //查STS端口 @q1: in al,dx and al,80h //PC7作控制信号 jnz @q1 转换完毕后就能读取数据了,还是先读高8位,后读低4位。读出后高8位乘16,低8位除16。这部分的相关程序可以参考设备自检部分或附录源程序代码。采集底值时将这部分程序依次执行了四遍,每个通道采了两个值取的平均。测试部分则循环采集k次,k是由用户输入的,如果用户没有输入,将默认采4000组数据。程序中定义了两个公用数组gh[]和lh[]分别用来存放采集的加速度和位移值。 下面的程序段将采集的数值转换为加速度和位移值。 gh[j]:=10000*gh[j] div 4095; // 0.001g,14mv/g gh[j]:=gh[j] div jia; //jia为所输入的加速度灵敏度,单位v/g 先将采来的数据转换为电压值,再除以加速度灵敏度,转换为加速度的单位。由于gh[j]是以mg为单位存储的,所以10v电压以10000mv计算。另外这也满足了整型数据的除法精度 ,排除了除0的可能性。 //(位移转换) if (cj1<>1000) or (cj2<>1000) then //若无输入,则采用默认数据 begin R:=5000; //位移传感器电阻值5000欧姆 S:=100; //位移传感器长度100mm end ; N1:=R*2048 div 5000; //N1:位移传感器最大阻值对应二进制数 for j:=1 to i do begin SX:=S*LH[j] DIV N1; //sx:实测长度 LH[j]:=SX; //单位为毫米 end; 位移转换的算法思路见上面的注释。其中N1之所以这样求是因为用1mA的电流输入5K电阻,只能产生5V电压,只能达到A/D芯片满量程的一半,所以对应二进制数也只有4096的一半,即2048。若用户无输入,系统默认的参数值为:jia=2v/g,R=5000,S=100mm,在formcreate事件中赋值。这些值与电压的对应关系为:加速度 1v—0.5g 位移 1v--2cm 。判断用户是否输入,可在相应的editchange事件里设置变量值来检测。此部分见附录程序清单。 可以将所采数据作为文本存盘。见下面程序段: p:=formatdatetime('yyyy/mm/dd/hh/nn',now)+'.txt'; Assignfile(tex,p); REWRITE(TEx); for j:=1 to i do begin WRITE(tex,lh[j]:6); //以每个字6个字节的格式存盘 WRITE(tex,gh[j]:6); end; CLOSEFILE(TEx); 其中tex是一个文件类型的变量,通过调用Assignfile过程可以初始化这一文件变量,即建立文件变量(F)与外部文件之间的联系。P为自定义的外部文件名,中间调用了读取系统时间的函数,有利于识别测试时间。之后的Rewrite函数是以写方式打开文件的方法,通过调用这个函数可以创建并打开一个新文件。在下面的for循环中,调用Write过程向文件中写入数据,数据存放在数组lh[j]和gh[j]中,以每个字6个字节的格式存储。写完之后,调用CloseFile过程中断文件变量tex和p所指外部磁盘文件之间的联系。这个过程将释放文件变量,并关闭该外部文件。 另外,除了处理本次实验采集数据外,本系统还必须能对以往数据进行分析,所以将“读数据文件”也放在这个单元里,可以直接将数据从已有文件读入数组gh[]和lh[]中,进行下一步分析处理。 这里用到了公用对话框控件中的opendialog控件,此控件用于打开一个已经存在的文件,用户选择某一文件,其所在的驱动器、文件夹、文件名以及文件扩展名将被赋予opendialog 的filename属性。在程序运行中使用execute命令来显示打开对话框,当用户选择一个文件并单击打开时,返回true;如果用户选择cancel,则返回false。参考下面的程序注释: if Dialogopen.Execute then begin assignfile(tex,Dialogopen.filename); Reset(tex); //以读方式打开文件 for j:=1 to 3990 do begin //从数据文件读出的数据值赋给数组 read(tex,x1); read(tex,y1); lh[j]:=x1; gh[j]:=y1; end; CLOSEFILE(TEx); edit15.text:='已读文件'; for循环中调用Read过程读取数据,通过中间变量x1和y1赋给数组元素。值得注意的是,由于干扰信号的存在,用这样的数据绘成曲线会出现很多毛刺,所以必须先进行滤波处理。这里进行了两次滤波:第一次是让本次值的80%与上次值的20%相加作加权平均。从第3个值开始,如下所示: p1:=(gh[1]+gh[2]) div 2; for j:=3 to 3990 do begin gh[j]:=(gh[j]*80+p1*20) div 100; p1:=gh[j]; end; 第二次在此基础上每三个值求一次平均,再将这个平均值赋给这相邻的三个值。如下程序: for j:=1 to 3990 do begin //每三个数求一次平均值 p1:=j mod 3; if p1=1 then begin p1:=(gh[j]+gh[j+1]+gh[j+2]) div 3; gh[j]:=p1; gh[j+1]:=p1; gh[j+2]:=p1; end; end; 2.2.4 绘制曲线模块设计 在Delphi中绘图时,是将图形画在窗体、Image控件、画框(Paintbox)中的画布Canvas上。画布也有自己的属性,它本身也是一个对象(控件),但一般不能单独使用。本单元中使用的是窗体form7的Canvas,用的最多的是它的画笔(Pen)属性。 系统能实现0.45g、0.8g、2g三个量程的绘图,这是为了满足用户精度和量程大小的需要。此单元根据公有变量fennei的值来识别是哪个量程的绘图,其中整型变量fennei的值是在单元2中选择量程时定下的。对应0.45g、0.8g、2g三个量程,fennei的值分别取为4,2,1。这样取值是为了分量程绘图时比例转换的方便,在下面会有说明,这部分有四个主要事件。 (一) 画网格、填纵轴坐标 在网格上显示曲线更有利于观察,另外纵轴坐标会随量程而不同,需要专门填写。画曲线时所用的坐标是根据窗体左上角为(0,0)推得的。画网格时画笔的颜色设置为蓝色,语句canvas.pen.color:=clblue;可以实现。另外网格横线和竖线的间距均为50。画横线时左边坐标取50,右边取到750。moveto(50,j); lineto(750,j);就可以画一条从(50,j)到(750,j)的横线。j 为纵坐标值,初值为50,每画完一条线增加50,一直到j=540。这样能画完g-t曲线和s-t曲线的网格横线。两种曲线网格横线间隔40,所以要分两个循环来完成。 画竖线时,由于两种曲线的网格竖线是分开的,一条线必须分两次画。每条线先从(I,50)画到(I,250),再从(I,290)画到(I,540)。这里I是指变动的横坐标,初值为50,也是每次增加50,一直到I=750。可以用一个循环完成。 下面开始填写s-t曲线的纵坐标,由于各个量程的位移刻度值相同,所以直接推出相应的坐标填写刻度即可。见下面程序段: canvas.textout(30,275,'单位:cm');//s-t曲线的纵坐标刻度canvas.textout(30,290,'10'); canvas.textout(30,330,'8'); canvas.textout(30,380,'6'); canvas.textout(30,430,'4'); canvas.textout(30,480,'2'); canvas.textout(30,530,'0'); 但是要填写g-t曲线的纵坐标还要先根据分类号fennei来判断是哪个量程的绘图。如果是0.45g的,依次填上0, 0.25, 0.5, 0.75,1.0;如果是0.8g,依次填写0, 0.5, 1.0, 1.5, 2.0;如果是2g,依次填上0, 1.0, 2.0, 3.0, 4.0.当然还要填上单位值,在坐标(30,25)处填写。以上填值的方法与上述s-t曲线是相同的,只是坐标不同而已。 (二) 绘制曲线 由于所绘曲线需要多屏才能显示出来,所以绘制完一屏后还必须进行消影。这里是将画笔颜色改的与窗体颜色一致,然后再将曲线绘制一遍来实现的。所以要记录下来前一屏显示的起始坐标和终坐标(对应的是数组gh[]和lh[]相应的下标),这样就保证了画图前消影工作的进行。这里定义了f1,f2,f3,f4四个变量,f1和f2代表当屏横轴起始坐标和终坐标;f3和f4 则代表前一屏的坐标。每次求得当屏坐标在开始绘图前,都将f1和f2的值先分别赋给f3和f4,以备下屏消影。 还要介绍两个重要变量cont和vv1。由于系统可以反复显示曲线,六屏显示完后会从第一屏重新开始。所以设置cont来记录总的显示第几屏,用vv1来记录六屏不同曲线中的第几屏。Cont的初值为0,每执行一次Button3Click(显示曲线)事件就自动增1。然后 vv1:=(cont mod 6)-1; //vv1=0,1,2,3,4,-1 if vv1=-1 then vv1:=5; 两行代码给vv1赋值。对应1--6屏不同曲线,vv1取值为0—5。然后就能由公式f1:=vv1*700+1; f2:=f1+700-1;求出每屏绘图的起始坐标和终坐标f1和f2。这里的700是指每屏的满横坐标。初始屏为1—700,第二屏为701—1400,依次类推。 下面是绘图程序的流程图: 是 否 是 否 图6.绘制曲线程序流程图 消影和绘图的原理实际上是一样的,只是画笔设置的颜色不同而已。消影的时候画笔颜色与窗体颜色一致,绘曲线时画笔的颜色设置为红色。另外,消影时将上一屏曲线重新绘制了一遍,而绘制曲线是新的一屏。所以它们的循环起始点也不相同:消影是从f3到f4,绘曲线是从f1到f2。 g-t曲线的起始点为(50,250),横坐标依次增一,所以只需要求出每点的纵坐标,依次将每个点连接起来即可。纵坐标必须根据量程实现一定的比例要求。见下面的消影曲线代码: canvas.MoveTo(50,250); //g-t曲线原点 Canvas.Pen.color:=clInfoBk; for j:=f3 to f4 do //g-t消影曲线 begin h1:=gh[j] div 10; y1:=250-(h1*fennei div 2); canvas.lineTo(x1,y1); x1:=x1+1; end; 由于系统坐标是从上往下的,而所绘坐标是从下往上,符合人们的视觉习惯。所以必须由横轴所在位置的纵坐标值(250)减去实际坐标,才能满足系统绘图的需要。至于实际纵坐标的求法,由于g-t曲线的坐标高度为200(4个网格,每格50),而0.45g量程、0.8g量程、2g量程的最大刻度分别为1g, 2g 和4g,所以加速度----坐标值的对应关系分别为:1g—200、1g—100、1g—50。而数组中存储的是以mg为单位的,上述关系即为:1mg—0.2、1mg—0.1、1mg—0.05。所以应该由数组gh[j]的值在不同量程下分别乘以0.2、0.1、0.05。三个数的比值为4:2:1。在fennei分别取4,2,1的情况下,先让gh[j]除以10,再乘以fennei除以2,就可以满足上面的需要,也满足了比例上的需要。这就是fennei这样取值的原因所在。 l-t曲线的起始点是(50,540),坐标变换和g-t曲线相同,求实际纵坐标时,不需要分量程。由于存的时候是以mm存的,绘图坐标单位为cm,所以数组值必须先除以10。另外需要乘以25,这是为了将位移值转换为坐标值而折合的一个数。因为画位移曲线的坐标高度为250(对应网格5格,每格50),对应最大位移10cm,所以1cm对应25个坐标位。将所采值lh[j]乘以这个数就能转换为绘图坐标了。见消影部分程序段: for j:=f3 to f4 do begin n2:=lh[j]*25 div 10; //乘2.5 n2:=540-n2; // 列值 m2:=m2+1; //行值 canvas.lineTo(m2,n2); end; 在每屏曲线开始显示时,会出现两条光标线,移动光标可选择曲线段进行分析。初始时光标线在同一位置。下一屏开始时,首先要消掉旧线,才能画新线。这就需要记载下来光标的原来位置,再将画笔颜色设置成窗体颜色,在原处再画一条即可。然后再改变画笔颜色,画出新线。定义两个全局变量le1和le2记录两条光标线的横坐标值,这两个变量值会随着光标的移动而改变。所以消影时从(le1,50)到(le1,700),从(le2,50)到(le2,700)画两条线就可以了。两条新线的横坐标值分别为100和400,之后将此值赋给le1和le2。上面所讲的坐标都是系统给的窗体坐标。另外还需定义两个全局变量u1和u2记录光标在自己定义的曲线坐标中的坐标值,此坐标从0到4500,分六屏。这样记录主要是因为此坐标对应数组下标值,方便取出光标所在处的加速度和位移值。U1和u2在每屏显示时的初值由下面两式来计算:u1:=vv1*700+50; u2:=vv1*700+350; 还有一点要注意的就是:六屏曲线的横坐标值都是不同的,必须按屏显示。前面已经提到变量vv1可以判别是哪一屏,用case语句分别对每屏赋以不同的坐标值即可。每个网格间隔50,在初值的基础上依次增加50,相应的填值点横坐标也增加50。用一重循环就能实现。填充文本用canvas对象的textout方法实现即可。这个方法有三个参数值,前两个是坐标值,指示文本输入位置,第三个就是要输入的文本了。这部分的程序可以参考附录。 另外要说明的一点是,虽然本单元绘制的是参数—时间图,但横坐标所标刻度并不是指对应的时间值。而是与真正的时间值成比例的,也就是说,是一个模拟的时间坐标。事实上每采一次的时间值并不能由软件精确得出,而硬件又没有设置定时器,所以不能以实际时间来绘制曲线。根据实际要求,以后有条件后这一点是应该做到的。 (三) 光标移动的实现 在整个绘图平面上有两条光标,本系统是在FormMouseDown事件中实现光标的移动的,此事件的形式参数x和y能随时给出鼠标的当前位置坐标值。移动原理是先判断鼠标按下的位置与哪条光标离得进,就将该光标移到鼠标按下的位置。在此单元中能够给出两条光标所在位置的加速度值和位移值,然后能计算出两条光标间加速度的变化率并显示。 这部分实现的思路如下: 前面已经说明u1,le1分别记录光标1在自定义坐标和系统坐标下的横坐标值;u2,le2分别记录光标2在自定义坐标和系统坐标下的横坐标值。现在再定义u3,le3来记录鼠标在两种坐标下的坐标值。其中u3:=vv1*700+(x-50); le3:=x; 事件开始时,先求出u3和le3,再判断鼠标离哪条光标近,然后将鼠标所在位置的两种坐标值赋给离它较近光标的坐标变量(u1,le1或者u2,le2)。值得注意的是,在赋新值之前,先将要移动的光标位置(le1或le2)记录到变量cn里,以待移动后消隐掉旧线。 之后以u1和u2为数组下标,读出光标所在位置的加速度值gh[u1]和gh[u2]以及位移值lh[u1]和lh[u2],并显示在对应的文本框内。加速度变化率可用公式(gh[u1]-gh[u2])/(u1-u2)求得并输出。接下来是画新光标和消旧线。画新线时从(x,50)画到(x,550)。消旧线时将画笔颜色改变后,从(cn,50)画到(cn,700)。对应的变量含义同上,程序见附录。 (四) 打印曲线 在Delphi中提供了printdialog 、printersetupdialog两个控件允许我们进行打印机以及其他影响打印输出的选择,此外最重要的一点是要想实现打印功能必须在编译程序以前将printers加入到interface或者impl ementation的UESE语句当中,因为printer单元包括一些控制打印机的过程。 此单元只用到了一个TprintDialog组件printdialog1,通过语句printdialog1.execute即可执行,并出现Windows Print对话框进行相关设置。由于曲线画在窗体的画布canvas上,所以窗体的打印直接调用窗体的print事件即可。见系统实现部分的执行界面。 2.2.5 查看测试结果模块设计 这一部分求出了最大加速度值,以及此刻对应的位移值。这是指标之一。另外模拟求出了曲线中梯度最大的一段,即找到最大加速度后,往前查找,直到曲线不再递减为止,求这段的加速度变化率作为刹车时的平均加速度变化率,作为指标之二。此单元定义了两个布尔型变量flag1和flag2,初始值为false。当指标一为真时,令flag1为true;指标二为真时,令flag2为真,只有当两个变量均为真时,所测安全带才算符合标准。结果在一个面板panel内输出。整个程序在TForm4.FormShow事件内实现。 求最大值时,可记录下最大值对应的数组下标为k。由于数据是成组采集的,所以此下标对应的lh[k]数组值即为同一时刻的位移值,只存在微秒级的误差。见下面程序段: for i:=1 to 3990 do begin if max0时,标签向左移动,否则标签从头开始。所添加的计时器控件Timer1的属性interval设置为100ms。代码实现如下: if label2.left+label1.width>0 then label2.left:=label2.left-10 else label2.left:=form1.width; 图7. 欢迎进入界面 另外,为帮助选项设置了一个快捷键F1,这是通过设置相应菜单项的shortcut属性来实现的,运行情况见图2。 图8. 帮助文档 下面进入设备自检界面:由滑动变阻器可调节输入的通道电压。下面是测1V左右电压的情况: 图9. 设备自检界面 自检结束后,若设备正常,就可以开始测试了。测试界面如下: 图10. 测试主界面 进入该页后,可根据需要先输入参数值,或者选用默认值。接着进行测量并能将数据存盘,在绘图按纽Onclik事件里设置将“采集结束”的文本框清空,这样做是为了查看采集图形后返回继续采集时能明显显示。也能直接分析历史数据,点击“读数据文件”按纽后,运行界面如下: 图11. 打开文件情况 采集完后或打开数据文件后,可以进行三个量程的绘图或者直接查看结果。见下面的界面: 图12. 曲线绘制界面 其中两种曲线的横坐标用的是同样的刻度。随着两条光标的移动显示不同曲线段对应的参数值。打印机的设置与Windows的相似。曲线绘制后,也能打印出来,运行情况如下: 图7.打印界面 图8. 查看测试结果界面 4.调试与测试部分 调试过程占整个毕业设计的很大一部分,也是至关重要的一部分。在此过程中,我遇到了各种各样的问题。正是对这些百思不得其解的问题一个个的解决,我才真正的学到了一些平时最容易忽视却又是最重要的细节问题。也将整个系统的流程、运作理解得更加清楚,同时也增加了一些相关的硬件知识。下面列出调试过程中感受最深也是比较重要的几个例子。 第一,要能进行信号采集,首先要把设备自检部分做好。这一部分实际上也是一个采集过程。只是用的是延时采集,而且没有进行数据转换而已,因为检测通道时没有高速的必要。所以如果将这一部分调通了,采集部分也完成了一半。因其只在此基础上添加了8255A,进行的是查询式的采集,再将采集数据转化为所需参数即可。在刚开始调试时,没有安装采集板,采到的只是0V或10V电压。装上后,接的是5V电压,但是看不出其采集多组数据的效果。后来李老师给我接了个滑动变阻器,可以在5V内调节电压进行采集,采集值在小范围内出现波动,这就能充分验证采集部分的正确性了。 第二,测试模块。这一部分的调试工作虽然建立在上一部分的基础上,但是在没有装采集板的情况下运行会出现死机的情况,使调试工作根本无法继续下去。在起初由于没有跟导师商量,又对硬件知识比较生疏,始终一头雾水,急得要命。但是由于没有信号输入,采出的数据全部是一致的电压值,所绘曲线也是一条直线。为了更好的测试这一模块,我跟老师商量了一下怎么输入一定的信号来检测。后来老师就让我快速的拨动滑动变阻器并快速拨回,以产生一个模拟的刹车信号,但由于是手动操作,加上一些其他的误差,使得采集的数据效果很差,绘出的曲线毛刺也很多,而且峰值不符合实际情况,不是太大就是太小。这个问题只好先搁置起来。直到有一天老师拿来一个信号发生器,让我采集正弦波、三角波、矩形波信号。采集情况见下面三副图所示: 矩形波信号 三角波 正弦波 为防止信号发生器短路,在接入时,已经加了一个1V左右的基底电压,所以波形的下半部分被抵消了一些。但这并不妨碍检测采集程序的正确性。这些波形的光滑性并不是很好,这主要是由于通过滑动变阻器接入信号时产生的误差所致。这样的情况在波形的频率较小时更加明显。但是总的来说,这是模拟信号,只是用来检测程序的正确性的,能够采集信号就可以了。真正的信号采集会直接通过采集板输入电脑。 第三,本系统实现起来最复杂的部分就是绘制曲线。这部分的程序代码最多,调试起来也是最麻烦的部分。所幸的是,这一部分主要是软件知识,以前实践的较多一点,调试起来有些思路。但是其中涉及到了两个单元的接口,是用公用变量来实现的。所以程序可读性和通用性可能有些欠缺,但是相对来说实现起来要简单一点且比通用函数便于调试。绘图的时候坐标的选择也颇费了一番周折。另外由于要消影和取值,两种坐标的变换也是经常搞混,最后是分别设了全局变量来记前一屏曲线及当前曲线坐标来实现的。在做光标移动时,本来是想直接用鼠标拖动的,当时是将一条线放在一个image控件内面来做试验,当鼠标点击控件并移动时,让image的left属性等于鼠标位置属性值。这在理论上是可行的,但运行起来情况就大不相同了。光标总是很不稳定,拖动后漂移老半天,很不理想。由于时间的原因,相关书籍的介绍也没有说明这种情况,于是放弃了拖动。采用直接在鼠标处重新画光标并消去旧光标这样的方法来模拟光标拖动,这样还是比较成功的,对于光标处参数值的显示也比较方便。 第四,这部分测试可以说与系统实现没有很大的关系,只是为了测试采集一次所需时间,并在绘图时完成横轴坐标与时间刻度的转换。由于硬件上没有使用8253定时器,所以在软件上做个测试完成这项技术参数。刚开始我想用Delphi上面的timer定时控件来实现。即在一次定时事件里设置一个死循环采集,看能采集多少次,等定时事件结束时,再查看计数变量值,但是后来运行时才发现一次也通不过就死机了,因为无法完成timer事件。后来我就利用系统时间来测试:在一定的时间到达后开始采集,设定几秒后停止(即判断是否到达另一时间)。这样虽然可以执行,但是采集的几组数据相差太大,也就是说软件定时对于高速采集是不可行的,误差太大了,由其中的几组数据求平均可知采集一个数据大概需要50us左右。所以在没有硬件支持的条件下,还是不能精确的测出采集一次需要多少时间,所以绘制的曲线也是一个模拟出来的参数—时间图,横坐标只能和时间对应成比例,但是不是明确的时间刻度,这是本次设计一个很大的不足之处。 5. 结语 本设计课题来自科研项目,与生产紧密相关,实用性和针对性很强。成功实现后不仅能带来可观的经济效益,也会给社会和人们创造一定的安全保障。完成后能实现高速采集数据,并能绘制出完整的参数-时间曲线。但也还有很多应该改进的地方:比如说应该能实现鼠标拖动光标、若条件允许,还应该可以求得每采一次所需时间、另外在打印前能实现打印预览等。 毕业设计是对大学四年所学知识的总结和综合运用,是一次锻炼与提高专业动手能力的很好机会,可以为将来的工作做下初步准备。从毕业设计正式开始,到六月初设计完成,两个月左右的时间里,紧张而又充实,我真切地体验到了科研工作的苦与乐,也学到了不少东西。尤其是DELPHI,第一次运用它开发软件,许多东西都不熟悉,边学边用,摸索前进,虽然遇到不少困难,但能力提高也快,比以前只看书效果好多了。总之,这次毕业设计对于我是有一定的意义的,基本上达到了预定目的。 致谢: 在毕业设计过程中,导师李华贵教授精心指导,帮助解决各种困难,并提供了很多毕业设计所需的设备,比如信号发生器、打印机等。在此表示衷心的感谢。另外,非常感激机房的赵立辉老师和杨师煊老师给我提供了良好的上机环境,在电脑出问题时积极帮助并提供各种安装软件。还有很多同学都给予了我很大的帮助,这里也表示衷心的感谢! 参考文献 附 录 附录1. 程序源代码 unit wus1;//欢迎进入 interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Menus, StdCtrls, ExtCtrls, jpeg; type TForm1 = class(TForm) MainMenu1: TMainMenu; qwe1: TMenuItem; ddd1: TMenuItem; gj1: TMenuItem; j1: TMenuItem; Label1: TLabel; Label3: TLabel; Label5: TLabel; Image1: TImage; Image2: TImage; Image3: TImage; Image4: TImage; Timer1: TTimer; Label2: TLabel; procedure qwe1Click(Sender: TObject); procedure ddd1Click(Sender: TObject); procedure gj1Click(Sender: TObject); procedure j1Click(Sender: TObject); procedure Timer1Timer(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation uses wus2, wus3,wus5; {$R *.DFM} procedure TForm1.qwe1Click(Sender: TObject); begin Form2.showmodal; end; procedure TForm1.ddd1Click(Sender: TObject); begin Form3.showmodal; end; procedure TForm1.gj1Click(Sender: TObject); begin Form5.showmodal; end; procedure TForm1.j1Click(Sender: TObject); begin close; end; procedure TForm1.Timer1Timer(Sender: TObject); begin if label2.left+label1.width>0 then label2.left:=label2.left-10 else label2.left:=form1.width; end; end. ********************************************************* unit wus3; //设备自检测试 interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls; type TForm3 = class(TForm) GroupBox1: TGroupBox; RadioButton1: TRadioButton; RadioButton2: TRadioButton; Label1: TLabel; ListBox1: TListBox; Button1: TButton; Button2: TButton; Button3: TButton; Timer1: TTimer; Button4: TButton; procedure Button2Click(Sender: TObject); procedure Button3Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); procedure Button4Click(Sender: TObject); procedure Timer1Timer(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form3: TForm3; implementation uses wus1; var //定义全局变量 x1,x2,x3:integer; s1:string; {$R *.DFM} procedure TForm3.Button2Click(Sender: TObject); begin listbox1.Clear; listbox1.Tag:=0; button2.enabled:=false; end; procedure TForm3.Button3Click(Sender: TObject); begin form1.show; close; end; procedure TForm3.FormCreate(Sender: TObject); begin button2.enabled:=false; button4.enabled:=false; end; procedure TForm3.Button1Click(Sender: TObject); begin timer1.enabled:=false; button4.enabled:=true; end; procedure TForm3.Button4Click(Sender: TObject); begin timer1.Enabled:=true; end; procedure TForm3.Timer1Timer(Sender: TObject); var tdhao:byte; begin tdhao:=2; //先赋初值 if radiobutton1.checked=true then tdhao:=0 else if radiobutton2.checked=true then tdhao:=1; if (tdhao=1) or (tdhao=0) then begin asm push ax push bx push cx push dx mov dx,228h //选通道 mov al,tdhao out dx,al mov ax,0 @a:dec ax jnz @a mov dx,221h //启动转换 out dx,al mov bx,20h @b:mov cx,0e000h @c:loop @c dec bx jnz @b mov dx,221h in al,dx mov x1,al mov dx,220h in al,dx mov x2,al pop dx pop cx pop bx pop ax end; x2:=(x2 div 16)+x1*16; x1:=(x2*10000)div(4095); x3:=x1 mod 1000; x1:=x1 div 1000; s1:=inttoStr(x1)+'.'+inttoStr(x3)+'V'; listbox1.Items.add(s1); x1:=0; x2:=0; x3:=0; button2.enabled:=true; end; end; end. ******************************************************** unit wus2; // 性能测试模块 interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm2 = class(TForm) Edit1: TEdit; Edit2: TEdit; Edit3: TEdit; Label1: TLabel; Label2: TLabel; Label3: TLabel; Button1: TButton; Button3: TButton; Button4: TButton; Button5: TButton; Label5: TLabel; Label6: TLabel; Edit4: TEdit; Label8: TLabel; Label9: TLabel; Label10: TLabel; Edit5: TEdit; Button8: TButton; Button12: TButton; Button2: TButton; Button11: TButton; DialogOPEN: TOpenDialog; edit12: TEdit; edit15: TEdit; Button13: TButton; Edit6: TEdit; Edit7: TEdit; procedure Edit1Change(Sender: TObject); procedure Button5Click(Sender: TObject); procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Edit3Change(Sender: TObject); procedure Button3Click(Sender: TObject); procedure Edit2Change(Sender: TObject); procedure Edit5Change(Sender: TObject); procedure Button4Click(Sender: TObject); procedure Button8Click(Sender: TObject); procedure Button12Click(Sender: TObject); procedure Button11Click(Sender: TObject); procedure Button13Click(Sender: TObject); procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form2: TForm2; lh:array[1..10000] of integer; gh:array[1..10000] of integer; CJ1,CJ2,n1,sx,jia,i,k,s,R,ld,gd,a,b,c,d:integer;//cardinal; x5,x6,x1,x2,x3,x4,y1,y2,y3,y4:byte; p,w:string; tex:Textfile; fennei,p1,p2,p3:integer; implementation uses wus1, wus4, wus7; {$R *.DFM} procedure TForm2.Edit1Change(Sender: TObject); begin R:=StrToInt(Edit1.text); //输入的位移传感器电阻值 CJ2:=1000; end; procedure TForm2.Button5Click(Sender: TObject); begin close; end; procedure TForm2.Button1Click(Sender: TObject); begin //采集底值 begin asm push ax push dx mov dx,22fh //8255A控制口地址 mov al,10011011b //8255初始化 out dx,al mov dx,228h //选通道 mov al,0 //采位移1 out dx,al mov ax,3500h //延迟 @w1: dec ax jnz @w1 mov dx,221h out dx,al //start CONVERT ,写入的数据可取任意值 mov dx,22eh //查STS ,STS=0表示转换结束 @q1: in al,dx and al,80h //PC7作控制信号 jnz @q1 mov dx,221h //转换结束,读数据,先读高8位 in al,dx mov x1,al mov dx,220h //读低8位 in al,dx mov x2,al mov dx,221h //发一次启动信号只能转换1次,采集一个数据 out dx,al //start CONVERT mov dx,22eh //读STS @q2: in al,dx and al,80h jnz @q2 mov dx,221h in al,dx mov x3,al mov dx,220h in al,dx mov x4,al mov dx,228h mov al,1 // 采加速度 out dx,al mov ax,3500h @H1: dec ax jnz @H1 mov dx,221h out dx,al //start CONVERT mov dx,22eh //读STS @N1: in al,dx and al,80h //查STS=0? jnz @N1 mov dx,221h //采集数据 in al,dx mov Y1,al mov dx,220h in al,dx mov Y2,al mov dx,221h out dx,al //start CONVERT mov dx,22eh //读STS @N2: in al,dx and al,80h jnz @N2 mov dx,221h in al,dx mov Y3,al mov dx,220h in al,dx mov Y4,al pop dx pop ax end; //采集完毕 end; a:=(x2 div 16)+x1*16; //数据高低位复原处理 b:=(x4 div 16)+x3*16; ld:=(a+b)div 2; //取两次采集的平均值 c:=(y2 div 16)+y1*16; d:=(Y4 div 16)+Y3*16; gd:=(c+d)div 2; edit6.text:= IntToStr(ld); //输出位移底值 edit7.text:= IntToStr(gd); //输出加速度底值 X1:=0;x2:=0;x3:=0;x4:=0; y1:=0;y2:=0;y3:=0;y4:=0;a:=0;b:=0;c:=0;d:=0; end; procedure TForm2.Button2Click(Sender: TObject); var j:integer; begin edit12.Clear; if a<>888 then i:=4000 //默认采4秒 else i:=k; //由输入时间定 for j:=1 to i do //循环采集i次 begin asm push ax push dx mov dx,22fh //8255初始化 mov al,10011011b out dx,al mov dx,228h //选通道 mov al,0 //采位移1 out dx,al mov ax,3500h //延迟 @w1: dec ax jnz @w1 mov dx,221h out dx,al //start CONVERT mov dx,22eh //读STS @q1: in al,dx and al,80h jnz @q1 mov dx,221h //读高8位数据 in al,dx mov x1,al mov dx,220h //低8位 in al,dx mov x2,al mov dx,228h mov al,1 //采加速度,选通道 out dx,al mov ax,3500h //延时 @H1: dec ax jnz @H1 mov dx,221h out dx,al //start CONVERT mov dx,22eh //读STS @N1: in al,dx and al,80h jnz @N1 mov dx,221h //读高8位数据 in al,dx mov Y1,al mov dx,220h in al,dx mov Y2,al pop dx pop ax end; //asm结束 a:=(x2 div 16)+x1*16; c:=(y2 div 16)+y1*16; lh[j]:=a-ld; //减去底值 gh[j]:=c-gd; end; //for语句结束 begin //转换采集数据(加速度) for j:=1 to i do begin gh[j]:=10000*gh[j] div 4095; gh[j]:=gh[j] div jia; //jia为所输入的加速度灵敏度 end; end; begin //(位移转换) if (cj1<>1000) or (cj2<>1000) then //若无输入,则采用默认数据 begin R:=5000; //位移传感器电阻值5000欧姆 S:=100; //位移传感器长度300mm end ; N1:=R*2048 div 5000; //N1:位移传感器最大阻值对应二进制数 for j:=1 to i do begin SX:=S*LH[j] DIV N1; //sx:实测长度 LH[j]:=SX; //单位为毫米 end; end; //数据转换结束 edit12.text:='采集结束!'; d:=0;X1:=0;x2:=0;x3:=0;x4:=0; y1:=0;y2:=0;y3:=0;y4:=0;a:=0;b:=0;c:=0;d:=0; end; procedure TForm2.Edit3Change(Sender: TObject); begin k:=StrToInt(Edit3.text); i:=k; a:=888 end; procedure TForm2.Button3Click(Sender: TObject); var j:integer; begin //0.45g数据存盘 p:=formatdatetime('yyyy/mm/dd/hh/nn',now)+'.txt'; Assignfile(tex,p); REWRITE(TEx); for j:=1 to i do begin WRITE(tex,lh[j]:6); //以每个字6个字节的格式存盘 WRITE(tex,gh[j]:6); end; CLOSEFILE(TEx); edit4.text:='数据已存盘!'; end; procedure TForm2.Edit2Change(Sender: TObject); begin s:=StrToInt(Edit2.text); //输入的位移传感器长度 CJ1:=1000; end; procedure TForm2.Edit5Change(Sender: TObject); begin jia:=StrToInt(Edit5.text); //输入加速度灵敏度(mv/g) end; procedure TForm2.Button4Click(Sender: TObject); begin fennei:=4; Form7.showmodal; edit12.text:=''; end; procedure TForm2.Button8Click(Sender: TObject); begin fennei:=2; Form7.showmodal; edit12.text:=''; end; procedure TForm2.Button12Click(Sender: TObject); begin fennei:=1; Form7.showmodal; edit12.text:=''; end; procedure TForm2.Button11Click(Sender: TObject); var p1,j,x1,y1:integer; begin if Dialogopen.Execute then begin assignfile(tex,Dialogopen.filename); Reset(tex); for j:=1 to 3990 do begin //从数据文件读出的数据值赋给数组 read(tex,x1); read(tex,y1); lh[j]:=x1; gh[j]:=y1; end; CLOSEFILE(TEx); edit15.text:='已读文件'; begin //作滤波处理 p1:=(gh[1]+gh[2]) div 2; for j:=3 to 3990 do begin gh[j]:=(gh[j]*80+p1*20) div 100; p1:=gh[j]; end; end; begin for j:=1 to 3990 do begin //每三个数求一次平均值 p1:=j mod 3; if p1=1 then begin p1:=(gh[j]+gh[j+1]+gh[j+2]) div 3; gh[j]:=p1; gh[j+1]:=p1; gh[j+2]:=p1; end; end; end; end else edit15.text:='没有读文件' end; procedure TForm2.Button13Click(Sender: TObject); begin Form4.show; end; procedure TForm2.FormCreate(Sender: TObject); begin jia:=2; end; end. ***************************************************** unit wus7;//绘制曲线模块 interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls,printers; type TForm7 = class(TForm) Button1: TButton; Button2: TButton; Label1: TLabel; Label2: TLabel; Button3: TButton; Edit3: TEdit; Edit4: TEdit; Label5: TLabel; Label6: TLabel; Label7: TLabel; Label8: TLabel; Edit5: TEdit; Edit6: TEdit; Label9: TLabel; Edit7: TEdit; Button4: TButton; PrintDialog1: TPrintDialog; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button3Click(Sender: TObject); procedure FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure FormCreate(Sender: TObject); procedure Button4Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form7: TForm7; implementation uses wus1, wus2,wus4; var u1,u2,u3,vv1,cont,cont2,le1,le2,le3,a,m,m2,n2,m3 :longint; p:string; f1,f2,f3,f4:integer; {$R *.DFM} procedure TForm7.Button1Click(Sender: TObject); var //显示网格按扭 i,j:integer; begin j:=50 ; canvas.pen.color:=clblue; while j<=250 do begin //画g-t曲线网格横线50-750 with canvas do begin moveto(50,j); lineto(750,j); end; j:=j+50; end; j:=290; while j<=540 do begin //画s-t曲线网格横线 with canvas do begin moveto(50,j); lineto(750,j); end; j:=j+50; end; i:=50; //画竖线 while i<=750 do begin with canvas do begin moveto(i,50); lineto(i,250); moveto(i,290); lineto(i,540); end; i:=i+50; end; canvas.textout(25,275,'单位:cm'); //s-t曲线的纵坐标刻度 canvas.textout(30,290,'10'); canvas.textout(30,330,'8'); canvas.textout(30,380,'6'); canvas.textout(30,430,'4'); canvas.textout(30,480,'2'); canvas.textout(30,530,'0'); Canvas.Pen.color:=clred; Canvas.Pen.width:=1; case fennei of //由分类号判断是哪个量程的绘图再填g-t曲线的纵坐标 4 : begin canvas.textout(30,240,'0'); canvas.textout(30,190,'0.25'); canvas.textout(30,140,'0.5'); canvas.textout(30,90,'0.75'); canvas.textout(30,40,'1.0'); canvas.textout(30,25,'单位:g'); end ; 2: begin canvas.textout(30,240,'0'); canvas.textout(30,190,'0.5'); canvas.textout(30,140,'1.0'); canvas.textout(30,90,'1.5'); canvas.textout(30,40,'2.0'); canvas.textout(30,25,'单位:g'); end ; 1: begin canvas.textout(30,240,'0'); canvas.textout(30,190,'1.0'); canvas.textout(30,140,'2.0'); canvas.textout(30,90,'3.0'); canvas.textout(30,40,'4.0'); canvas.textout(30,25,'单位:g'); end ; end; //case语句结束 end; procedure TForm7.Button2Click(Sender: TObject); begin form7.close; end; procedure TForm7.Button3Click(Sender: TObject); var //显示曲线按扭 x1,y1,i,h1,j:integer; begin //**********************初始准备工作************************ begin cont:=cont+1; //cont变量用来记录显示曲线第几屏,已赋初值0 vv1:=(cont mod 6)-1; //vv1=0,1,2,3,4,-1 if vv1=-1 then vv1:=5; f1:=vv1*700+1; //f1和f2记载起始时间刻度,也是数组坐标 f2:=f1+700-1; Canvas.Pen.color:=clred; Canvas.Pen.width:=1; x1:=50; //画图的起始点 end; //******************消影****************************** if cont<>1 then //第一次不用消影 begin canvas.MoveTo(50,250); //g-t曲线原点 Canvas.Pen.color:=clInfoBk; for j:=f3 to f4 do //g-t消影曲线 begin h1:=gh[j] div 10; y1:=250-(h1*fennei div 2); canvas.lineTo(x1,y1); x1:=x1+1; end; canvas.MoveTo(50,540); //画l-t消影曲线 m2:=50; for j:=f3 to f4 do begin n2:=lh[j]*25 div 10; //乘2.5 n2:=540-n2; //行值 m2:=m2+1; // 列值 canvas.lineTo(m2,n2); end; end; //*******************开始画曲线*************************** begin Canvas.Pen.color:=clred; canvas.MoveTo(50,250);//画g-t曲线 f3:=f1; //f3和f4记载上一次的起始坐标,用于消影 f4:=f2; x1:=50; for j:=f1 to f2 do begin h1:=gh[j] div 10; y1:=250-(h1*fennei div 2); canvas.lineTo(x1,y1); x1:=x1+1; //列 end; end; begin canvas.MoveTo(50,540); //画l-t曲线,画笔移到坐标原点 m2:=50; for j:=f1 to f2 do begin n2:=lh[j]*25 div 10;//乘2.5 n2:=540-n2; //行值 m2:=m2+1; // 列值 canvas.lineTo(m2,n2); end; end; //****************** 画光标线***************************** begin Canvas.Pen.color:=clInfoBk; //消旧线 Canvas.moveTo(le1,50); canvas.lineTo(le1,700); Canvas.moveTo(le2,50); canvas.lineTo(le2,700); Canvas.Pen.color:=clgreen;//首先画两条线 Canvas.Pen.width:=1; Canvas.moveTo(100,50); canvas.lineTo(100,700); Canvas.moveTo(400,50); canvas.lineTo(400,700); u1:=vv1*700+50; //数组值 u2:=vv1*700+350; le1:=100; //每显示一屏,光标恢复到原处 le2:=400; end; //********************填横轴坐标************ canvas.textout(758,245,'t'); case vv1 of 0: begin m:=90; x1:=50; //写X轴刻度 for i:=1 to 14 do begin p:=inttostr(x1); canvas.textout(m,255,' '); canvas.textout(m,255,p); m:=m+50; x1:=x1+50; end; end ; 1: begin m:=90; x1:=750; //写X轴刻度 for i:=1 to 14 do begin p:=inttostr(x1); canvas.textout(m,255,p); m:=m+50; x1:=x1+50; end; end; 2: begin m:=90; x1:=1450; //写X轴刻度 for i:=1 to 14 do begin p:=inttostr(x1); canvas.textout(m,255,p); m:=m+50; x1:=x1+50; end; end; 3: begin m:=90; x1:=2150; //写X轴刻度 for i:=1 to 14 do begin p:=inttostr(x1); canvas.textout(m,255,p); m:=m+50; x1:=x1+50; end; end; 4: begin m:=90; x1:=2850; //写X轴刻度 for i:=1 to 14 do

汽车安全性设计

本文标签: 安全性   汽车   设计  

温馨提示:本文是作者 admin 的原创文章,转载请注明出处和附带本文链接!

交通学习网

交通学习网

www.alimo.cn

最近发表
文章归档
网站分类
标签列表
搜索
sitemap网站地图

Copyright @ 2019-2021 交通学习网 All Rights Reserved.

切换白天模式 切换夜间模式 白天返回顶部 夜间返回顶部