基于PLC的PID恒温控制系统_第1页
基于PLC的PID恒温控制系统_第2页
基于PLC的PID恒温控制系统_第3页
基于PLC的PID恒温控制系统_第4页
基于PLC的PID恒温控制系统_第5页
已阅读5页,还剩27页未读 继续免费阅读

下载本文档

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

文档简介

1、四川师范大学成都学院电子工程系课程设计基于S7-200型PLC的PID恒温箱控制 学生姓名范永林学 号2008103054所 在 系电子工程系专业名称自动化班 级2008级1班指导教师程 诚 段纯爽成 绩 四川师范大学成都学院二一一年六月四川师范大学成都学院电子工程系课程设计报告摘要:本论文阐述了利用PLC模块通过数模转换模块和温度检测模块等,并运用梯形图编写程序,实现对液体加热及对温度的保持。本系统的适用性很强,稳定性、精确性良好,程序开发通俗易懂,可以适应农业和工业生产中恒温系统的需求。本文主要介绍了恒温系统的硬件及软件设计方案。关键字:PLC,数模转换,恒温系统Abstract: Thi

2、s paper discusses how to use the PLC module through the analog-to-digital conversion module and temperature detection module, and used the ladder-diagram programming, realize the liquid heating and temperature is maintained. This system applicability is very strong, stability, accuracy, good program

3、 development understandable, can adapt to the agricultural production constant temperature that required by the system. This article mainly introduced the constant temperature and the hardware and software of the system design. Key words: PLC、Analog-to-digital、The constant temperature目录 TOC o 1-3 h

4、z u HYPERLINK l _Toc295936531 前言 PAGEREF _Toc295936531 h 1 HYPERLINK l _Toc295936532 1PLC简介 PAGEREF _Toc295936532 h 2 HYPERLINK l _Toc295936533 2PID指令与模拟量控制 PAGEREF _Toc295936533 h 3 HYPERLINK l _Toc295936534 2.1 PID算法 PAGEREF _Toc295936534 h 3 HYPERLINK l _Toc295936535 2.2 PID控制回路选项 PAGEREF _Toc295

5、936535 h 3 HYPERLINK l _Toc295936536 2.3 回路输入量转化和标准化 PAGEREF _Toc295936536 h 4 HYPERLINK l _Toc295936537 2.4 PID回路输出转换成比例的整数 PAGEREF _Toc295936537 h 4 HYPERLINK l _Toc295936538 3控制方案设计 PAGEREF _Toc295936538 h 5 HYPERLINK l _Toc295936539 3.1 任务及器件选型 PAGEREF _Toc295936539 h 5 HYPERLINK l _Toc295936540

6、 3.1.1 任务要求 PAGEREF _Toc295936540 h 5 HYPERLINK l _Toc295936541 3.1.2 PLC选型 PAGEREF _Toc295936541 h 5 HYPERLINK l _Toc295936542 3.1.3 加热器件选型 PAGEREF _Toc295936542 h 5 HYPERLINK l _Toc295936543 3.1.4 温度传感器选择 PAGEREF _Toc295936543 h 5 HYPERLINK l _Toc295936544 3.1.5 继电器选型 PAGEREF _Toc295936544 h 6 HYP

7、ERLINK l _Toc295936545 3.2具体方案 PAGEREF _Toc295936545 h 6 HYPERLINK l _Toc295936546 3.2.1 方案简介 PAGEREF _Toc295936546 h 6 HYPERLINK l _Toc295936547 3.2.2地址分配及符号表 PAGEREF _Toc295936547 h 7 HYPERLINK l _Toc295936548 3.3 放大电路图 PAGEREF _Toc295936548 h 8 HYPERLINK l _Toc295936549 3.4 流程图 PAGEREF _Toc295936

8、549 h 8 HYPERLINK l _Toc295936550 3.5 程序梯形图 PAGEREF _Toc295936550 h 9 HYPERLINK l _Toc295936551 4系统功能 PAGEREF _Toc295936551 h 11 HYPERLINK l _Toc295936552 5设计总结 PAGEREF _Toc295936552 h 12 HYPERLINK l _Toc295936553 6参考文献 PAGEREF _Toc295936553 h 12 PAGE 29前言恒温系统装置是一个模拟生产使用恒温系统。他使用了PLC,数模转换功能模块,温度传感器,电

9、热棒等。实现系统的加热,以及恒温保持。使用PID算法可以精确的控制系统温度。该模拟系统可用于对室温的加热,以及保温。外面虽然可以买到类似的商品,但是却不如该系统灵活。随着经济的增长,有些农业生产对温度的要求相当严格,例如,农场的养殖场就对温度非常讲究。据研究表明禽类不仅对光照有严格要求,对温度更有严格要求,温度会下降到15度左右,禽类的产蛋率成明显下降趋势,而温度高于30度左右,禽类的产蛋率同样受到影响,此时我们就得严格控制室温在20-25摄氏度为最佳温度,才能提高养殖场的经济效益。该系统主要划分为PLC主模块,数模转换功能模块,温度监控模块,加热模块。主要功能有:PLC模块将数据信号传送到功

10、能模块使之转换成模拟信号使温度传感器工作,温度传感器检测当前系统温度,转化成模拟电压信号,然后通过EM235CN模块将温度信号转化成数据信号,从而达到控制温度的目的。1PLC简介PLC英文全称Programmable Logic Controller ,中文全称为可编程逻辑控制器,定义是:一种数字运算操作的电子系统,专为在工业环境应用而设计的。它采用一类可编程的存储器,用于其内部存储程序,执行逻辑运算,顺序控制,定时,计数与算术操作等面向用户的指令,并通过数字或模拟式输入/输出控制各种类型的机械或生产过程.PLC是可编程逻辑电路,也是一种和硬件结合很紧密的语言,在半导体方面有很重要的应用,可以

11、说有半导体的地方就有PLC。PLC是一种专门为在工业环境下应用而设计的数字运算操作的电子装置。它采用可以编制程序的存储器,用来在其内部存储执行逻辑运算、顺序运算、计时、计数和算术运算等操作的指令,并能通过数字式或模拟式的输入和输出,控制各种类型的机械或生产过程。PLC及其有关的外围设备都应该按易于与工业控制系统形成一个整体,易于扩展其功能的原则而设计。国际电工委员会(IEC)在其标准中将PLC定义为: 可程式逻辑控制器是一种数位运算操作的电子系统,专为在工业环境应用而设计的。它采用一类可编程的存储器,用于其内部存储程序,执行逻辑运算、顺序控制、定时、计数与算术操作等面向用户的指令,并通过数字或

12、模拟式输入/输出控制各种类型的机械或生产过程。可程式逻辑控制器及其有关外部设备,都按易于与工业控制系统联成一个整体,易于扩充其功能的原则设计。2PID指令与模拟量控制2.1 PID算法典型PID算法包括三项:比例项、积分项和微分项。即:输出=比例项+积分项+微分项计算机在周期性地采样并离散化后进行PID运算,算法如下:Mn=Kc*(SPn-PVn)+Kc*(Ts/Ti)*(SPn-PVn)+Mx+Kc*(Td/Ts)*(PVn-1-PVn)比例项:Kc*(SPn-PVn)积分项:Kc*(Ts/Ti)* (SPn-PVn)+Mx微分项:Mx+Kc*(Td/Ts)*(PVn-1-PVn)2.2 P

13、ID控制回路选项常用的控制回路有PI、PID。(1)如果不需要积分回路(即在PID算法中无“I”),则应将积分时间Ti设为无穷大。由于积分项Mx的初始值,虽然没有积分运算,积分项的数值也可能不为零。(2)如果不需要微分运算,则应将微分时间Td设定为0.02.3 回路输入量转化和标准化在PLC进行PID控制之前,必须将其转换成标准化浮点表示法。(1)将回路输入量数值从16位整数转换成32位浮点数或实数。如下:ITD AIW0 , AC0 /将输入数值转化成双字DTR AC0 ,AC0 /将32位整数转换成实数(2)将实数转换成0.0-1.0之间的标准化数值。/R 32000.0,AC0 /是累加

14、器中数值标准化+R 0, AC0 /加偏移量0 MOVR AC0, VD100 /将标准化数值写入PID回路参数表中2.4 PID回路输出转换成比例的整数程序执行后,PID回路输出0.0-1.0之间的标准化实数值,必须被转换成16位成比例整数数值,才能驱动模拟输出。PID回路输出成比例实数数值=(PID回路输出标准化实数值-偏移量)*取值范围MOVR VD108,AC0 /将PID回路输出送入AC0*R 32000.0, AC0 /将实数四舍五入取整,变为32位整数DTI AC0,AC0 /32位整数转换成16位整数MOVW AC0,AQW0 /16位整数写入AQW03控制方案设计3.1 任务

15、及器件选型3.1.1 任务要求对恒温箱进行恒温控制,对温度进行PID调节,PID运算结果去控制接通电加热器或者制冷风扇,但由于电加热器或制冷风扇只能为OFF和ON,为开关量,不能接受模拟量调节,故采用“占空比”的调节方法。温度传感器检测到的温度值送入PLC后,若经过PID指令运算得到一个0-1的实数,把该实数按比例换算成一个0100的整数,把该整数作为一个范围为1-10S的时间。设计一个时间周期为10S的脉冲,脉冲宽度为,把该脉冲加给电加热器或制冷风扇,即可控制温度。3.1.2 PLC选型 选用实验室具备的SIEMENS S7-200 CN(CPU 226)型PLC及EM235CN模块。3.1

16、.3 加热器件选型电热棒的功率考虑到继电器的成本随负载功率的增大而增大应尽量选择小功率的电热棒3.1.4 温度传感器选择使用Pt100热敏电阻传感器。用高纯度铂做电阻导体,具有非常好的线性、高温稳定性和复现性。在现代工业生产过程中具有十分广泛的应用。测量范围:-200C+850C允许偏差0.15C3.1.5 继电器选型选择驱动电压为24V的继电器,负载考虑到使用电热棒功率较大,选择使用10A的负载避免继电器被烧坏。3.2具体方案3.2.1 方案简介在恒温箱内有一个加热元件和一个制冷风扇,电加热元件和风扇的工作状态只有OFF和ON,即不能自行调节,现要使恒温箱的温度恒定,且能在25100摄氏度范

17、围内可调节,如图所示:3.2.2地址分配及符号表(1)地址分配:Q1.0:控制接通加热器;Q1.1:控制接通制冷风扇;AIW0:接收温度传感器的温度检测值(2)符号表:符号地址符号地址设定值VD 204微分时间VD224回路增益VD212控制量输出VD208采样时间VD216检测值VD200积分时间VD2203.3 放大电路图3.4 流程图给点温度T1给点温度T1温度检测T2=T1?T2T1启动制冷风扇T2T1启动加热装置温度恒定在T1相等3.5 程序梯形图 4系统功能系统开始运行时,在编程软件上修改初始设定温度T1,T1应该比常温高,例如取T1=50度,电热棒开始加热,当室温别加热到50度时

18、,电热棒停止加热。若检测温度高于50度时,启动制冷风扇,使温度下降,保持在T1附近不变;具体过程是:温度传感器检测到的温度值送入PLC后,若经过PID指令运算得到一个0-1的实数,把该实数按比例换算成一个0100的整数,把该整数作为一个范围为1-10S的时间。设计一个时间周期为10S的脉冲,脉冲宽度为,把该脉冲加给电加热器或制冷风扇,即可控制温度。5设计总结完成本次课程设计过程中遇到很多实际问题,如放大电路的设计,温度传感器的信号采集电路设计,都遇到不小问题,但在老师的指导下,以及同学的配合下,这些问题都逐一解决,最终使恒温系统,达到一个让大家满意的效果。通过本次课程设计,让我在实践当中运用了

19、PLC和PID调节,对PLC的编程方面,也有所提升;熟悉掌握了温度传感器的工作原理,并对一些电路的设计有所了解,相信在以后的学习中,这次的经验会带给我很多启迪,且为以后工作奠定一定实践基础。6参考文献1 吴建强,可编程序控制器原理及其应用M.哈尔滨:哈尔滨工业大学出版社,2004.2 陈宇.可编程控制器基础及编程技巧M.广州:华南理工大学出版社,2000. 1.3 魏志精.可编程控制器应用技术M.北京:电子工业出版社,2003.4 何衍庆,俞金寿.可编程控制器原理及应用技巧M.北京:化学工业出版社,2007.5 周渊深.可编程控制器应用技术M.北京:化学工业出版社,2002.6 黄净主编.电器

20、及PLC控制技术M.北京:北京工业出版社,2005.7 廖常初.可编程控制器应用技术(第6版)M.重庆:重庆大学出版社,2008.附录资料:不需要的可以自行删除C语言中如何获取时间?精度如何?1 使用time_t time( time_t * timer ) 精确到秒2 使用clock_t clock() 得到的是CPU时间精确到1/CLOCKS_PER_SEC秒3 计算时间差使用double difftime( time_t timer1, time_t timer0 )4 使用DWORD GetTickCount() 精确到毫秒5 如果使用MFC的CTime类,可以用CTime:GetCu

21、rrentTime() 精确到秒6 要获取高精度时间,可以使用BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency)获取系统的计数器的频率BOOL QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount)获取计数器的值然后用两次计数器的差除以Frequency就得到时间。7 Multimedia Timer FunctionsThe following functions are used with multimedia timers.timeBeginPeriod/tim

22、eEndPeriod/timeGetDevCaps/timeGetSystemTime/*/用标准C实现获取当前系统时间的函数一.time()函数time(&rawtime)函数获取当前时间距1970年1月1日的秒数,以秒计数单位,存于rawtime 中。#include time.hvoid main ()time_t rawtime;struct tm * timeinfo;time ( &rawtime );timeinfo = localtime ( &rawtime );printf ( 007The current date/time is: %s, asctime (timein

23、fo) );exit(0);=#include - 必须的时间函数头文件time_t - 时间类型(time.h 定义是typedef long time_t; 追根溯源,time_t是long)struct tm - 时间结构,time.h 定义如下:int tm_sec;int tm_min;int tm_hour;int tm_mday;int tm_mon;int tm_year;int tm_wday;int tm_yday;int tm_isdst;time ( &rawtime ); - 获取时间,以秒计,从1970年1月一日起算,存于rawtimelocaltime ( &ra

24、wtime ); - 转为当地时间,tm 时间结构asctime ()- 转为标准ASCII时间格式:星期 月 日 时:分:秒 年二.clock()函数,用clock()函数,得到系统启动以后的毫秒级时间,然后除以CLOCKS_PER_SEC,就可以换成“秒”,标准c函数。clock_t clock ( void );#includeclock_t t = clock();long sec = t / CLOCKS_PER_SEC;他是记录时钟周期的,实现看来不会很精确,需要试验验证;三.gettime(&t); 据说tc2.0的time结构含有毫秒信息#include#includeint

25、main(void)struct time t;gettime(&t);printf(The current time is: -:d:d.dn,t.ti_hour, t.ti_min, t.ti_sec, t.ti_hund);return 0;time 是一个结构体, 其中成员函数 ti_hund 是毫秒。四.GetTickCount(),这个是windows里面常用来计算程序运行时间的函数;DWORD dwStart = GetTickCount();/这里运行你的程序代码DWORD dwEnd = GetTickCount();则(dwEnd-dwStart)就是你的程序运行时间, 以

26、毫秒为单位这个函数只精确到55ms,1个tick就是55ms。五.timeGetTime()t,imeGetTime()基本等于GetTickCount(),但是精度更高DWORD dwStart = timeGetTime();/这里运行你的程序代码DWORD dwEnd = timeGetTime();则(dwEnd-dwStart)就是你的程序运行时间, 以毫秒为单位虽然返回的值单位应该是ms,但传说精度只有10ms。=/*Unix#unix时间相关,也是标准库的/*1.timegm函数只是将struct tm结构转成time_t结构,不使用时区信息;time_t timegm(stru

27、ct tm *tm);2.mktime使用时区信息time_t mktime(struct tm *tm);timelocal 函数是GNU扩展的与posix函数mktime相当time_t timelocal (struct tm *tm);3.gmtime函数只是将time_t结构转成struct tm结构,不使用时区信息;struct tm * gmtime(const time_t *clock);4.localtime使用时区信息struct tm * localtime(const time_t *clock);1.time获取时间,stime设置时间time_t t;t = ti

28、me(&t);2.stime其参数应该是GMT时间,根据本地时区设置为本地时间;int stime(time_t *tp)3.UTC=true 表示采用夏时制;4.文件的修改时间等信息全部采用GMT时间存放,不同的系统在得到修改时间后通过localtime转换成本地时间;5.设置时区推荐使用setup来设置;6.设置时区也可以先更变/etc/sysconfig/clock中的设置再将ln -fs /usr/share/zoneinfo/xxxx/xxx /etc/localtime 才能重效time_t只能表示68年的范围,即mktime只能返回1970-2038这一段范围的time_t看看你

29、的系统是否有time_t64,它能表示更大的时间范围/*windows#Window里面的一些不一样的/*一.CTime () 类VC编程一般使用CTime类 获得当前日期和时间CTime t = GetCurrentTime();SYSTEMTIME 结构包含毫秒信息typedef struct _SYSTEMTIME WORD wYear;WORD wMonth;WORD wDayOfWeek;WORD wDay;WORD wHour;WORD wMinute;WORD wSecond;WORD wMilliseconds; SYSTEMTIME, *PSYSTEMTIME;SYSTEMT

30、IME t1;GetSystemTime(&t1)CTime curTime(t1);WORD ms = t1.wMilliseconds;SYSTEMTIME sysTm;:GetLocalTime(&sysTm);在time.h中的_strtime() /只能在windows中用char t11;_strtime(t);puts(t);/*获得当前日期和时间CTime tm=CTime:GetCurrentTime();CString str=tm.Format(%Y-%m-%d);在VC中,我们可以借助CTime时间类,获取系统当前日期,具体使用方法如下:CTime t = CTime:

31、GetCurrentTime(); /获取系统日期,存储在t里面int d=t.GetDay(); /获得当前日期int y=t.GetYear(); /获取当前年份int m=t.GetMonth(); /获取当前月份int h=t.GetHour(); /获取当前为几时int mm=t.GetMinute(); /获取当前分钟int s=t.GetSecond(); /获取当前秒int w=t.GetDayOfWeek(); /获取星期几,注意1为星期天,7为星期六二.CTimeSpan类如果想计算两段时间的差值,可以使用CTimeSpan类,具体使用方法如下:CTime t1( 1999

32、, 3, 19, 22, 15, 0 );CTime t = CTime:GetCurrentTime();CTimeSpan span=t-t1; /计算当前系统时间与时间t1的间隔int iDay=span.GetDays(); /获取这段时间间隔共有多少天int iHour=span.GetTotalHours(); /获取总共有多少小时int iMin=span.GetTotalMinutes();/获取总共有多少分钟int iSec=span.GetTotalSeconds();/获取总共有多少秒三._timeb()函数_timeb定义在SYSTIMEB.H,有四个fieldsdst

33、flagmillitmtimetimezonevoid _ftime( struct _timeb *timeptr );struct _timeb timebuffer;_ftime( &timebuffer );取当前时间:文档讲可以到ms,有人测试,好象只能到16ms!四.设置计时器定义TIMER ID#define TIMERID_JISUANFANGSHI 2在适当的地方设置时钟,需要开始其作用的地方;SetTimer(TIMERID_JISUANFANGSHI,200,NULL);在不需要定时器的时候的时候销毁掉时钟KillTimer(TIMERID_JISUANFANGSHI);

34、对应VC程序的消息映射void CJisuan:OnTimer(UINT nIDEvent)switch(nIDEvent)#如何设定当前系统时间windowsSYSTEMTIME m_myLocalTime,*lpSystemTime;m_myLocalTime.wYear=2003;m_myLocalTime.wM;m_myLocalTime.wDay=1;m_myLocalTime.wHour=0;m_myLocalTime.wMinute=0;m_myLocalTime.wSec;m_myLocalTime.wMillisec;lpSystemTime=&m_myLocalTime;i

35、f( SetLocalTime(lpSystemTime) ) /此处换成 SetSystemTime( )也不行MessageBox(OK !);elseMessageBox(Error !);SYSTEMTIME m_myLocalTime,*lpSystemTime;m_myLocalTime.wYear=2003;m_myLocalTime.wM;m_myLocalTime.wDay=1;lpSystemTime=&m_myLocalTime;if( SetDate(lpSystemTime) ) /此处换成 SetSystemTime( )也不行MessageBox(OK !);el

36、seMessageBox(Error !);本文来自CSDN博客,转载请标明出处:HYPERLINK /khuang2008/archive/2008/12/09/3483274.aspx/khuang2008/archive/2008/12/09/3483274.aspx一种制作微秒级精度定时器的方法当使用定时器时,在很多情况下只用到毫秒级的时间间隔,所以只需用到下面的两种常用方式就满足要求了。一是用SetTimer函数建立一个定时器后,在程序中通过处理由定时器发送到线程消息队列中的WM_TIMER消息,而得到定时的效果(退出程序时别忘了调用和SetTimer配对使用的KillTimer函数

37、)。二是利用GetTickCount函数可以返回自计算机启动后的时间,通过两次调用GetTickCount函数,然后控制它们的差值来取得定时效果,此方式跟第一种方式一样,精度也是毫秒级的。用这两种方式取得的定时效果虽然在许多场合已经满足实际的要求,但由于它们的精度只有毫秒级的,而且在要求定时时间间隔小时,实际定时误差大。下面介绍一种能取得高精度定时的方法。在一些计算机硬件系统中,包含有高精度运行计数器(high-resolution performance counter),利用它可以获得高精度定时间隔,其精度与CPU的时钟频率有关。采用这种方法的步骤如下:1、首先调用QueryPerform

38、anceFrequency函数取得高精度运行计数器的频率f。单位是每秒多少次(n/s),此数一般很大。2、在需要定时的代码的两端分别调用QueryPerformanceCounter以取得高精度运行计数器的数值n1,n2。两次数值的差值通过f换算成时间间隔,t=(n2-n1)/f。下面举一个例子来演示这种方法的使用及它的精确度。在VC 6.0 下用MFC建立一个对话框工程,取名为HightTimer.在对话框面板中控件的布局如下图:其中包含两个静态文本框,两个编辑框和两个按纽。上面和下面位置的编辑框的ID分别为IDC_E_TEST和IDC_E_ACTUAL,通过MFC ClassWizard添

39、加的成员变量也分别对应为DWORD m_dwTest和DWORD m_dwAct. “退出”按纽的ID为IDOK,“开始测试”按纽ID为IDC_B_TEST,用MFC ClassWizard添加此按纽的单击消息处理函数如下:void CHightTimerDlg:OnBTest()/ TODO: Add your control notification handler code hereUpdateData(TRUE); /取输入的测试时间值到与编辑框相关联的成员变量m_dwTest中LARGE_INTEGER frequence;if(!QueryPerformanceFrequency(

40、 &frequence) /取高精度运行计数器的频率,若硬件不支持则返回FALSEMessageBox(Your computer hardware doesnt support the high-resolution performance counter,Not Support, MB_ICONEXCLAMATION | MB_OK);LARGE_INTEGER test, ret;test.QuadPart = frequence.QuadPart * m_dwTest / 1000000; /通过频率换算微秒数到对应的数量(与CPU时钟有关),1秒=1000000微秒ret = MyS

41、leep( test ); /调用此函数开始延时,返回实际花销的数量m_dwAct = (DWORD)(1000000 * ret.QuadPart / frequence.QuadPart ); /换算到微秒数UpdateData(FALSE); /显示到对话框面板其中上面调用的MySleep函数如下:LARGE_INTEGER CHightTimerDlg:MySleep(LARGE_INTEGER Interval)/ 功能:执行实际的延时功能 / 参数:Interval 参数为需要执行的延时与时间有关的数量 / 返回值:返回此函数执行后实际所用的时间有关的数量 / LARGE_INTE

42、GER privious, current, Elapse;QueryPerformanceCounter( &privious );current = privious;while( current.QuadPart - privious.QuadPart Interval.QuadPart )QueryPerformanceCounter( t );Elapse.QuadPart = current.QuadPart - privious.QuadPart;return Elapse;注:别忘了在头文件中为此函数添加函数声明。至此,可以编译和执行此工程了,结果如上图所示。在本人所用的机上(

43、奔腾366, 64M内存)测试,当测试时间超过3微秒时,准确度已经非常高了,此时机器执行本身延时函数代码的时间对需要延时的时间影响很小了。上面的函数由于演示测试的需要,没有在函数级封装,下面给出的函数基本上可以以全局函数的形式照搬到别的程序中。BOOL MySleep(DWORD dwInterval)/ 功能:执行微秒级的延时功能 / 参数:Interval 参数为需要的延时数(单位:微秒) / 返回值:若计算机硬件不支持此功能,返回FALSE,若函数执行成功,返回TRUE / BOOL bNormal = TRUE;LARGE_INTEGER frequence, privious, cu

44、rrent, interval;if(!QueryPerformanceFrequency( &frequence):MessageBox(NULL, Your computer hardware doesnt support the high-resolution performance counter,Not Support, MB_ICONEXCLAMATION | MB_OK); /或其它的提示信息return FALSE;interval.QuadPart = frequence.QuadPart * dwInterval / 1000000;bNormal = bNormal &

45、QueryPerformanceCounter( &privious );current = privious;while( current.QuadPart - privious.QuadPart interval.QuadPart )bNormal = bNormal & QueryPerformanceCounter( t );return bNormal;需要指出的是,由于在此函数中的代码很多,机器在执行这些代码所花费的时间也很长,所以在需要几个微秒的延时时,会影响精度。实际上,读者在熟悉这种方法后,只要使用QueryPerformanceFrequency和QueryPerforma

46、nceCounter这两个函数就能按实际需要写出自己的延时代码了。使用CPU时间戳进行高精度计时对关注性能的程序开发人员而言,一个好的计时部件既是益友,也是良师。计时器既可以作为程序组件帮助程序员精确的控制程序进程,又是一件有力的调试武器,在有经验的程序员手里可以尽快的确定程序的性能瓶颈,或者对不同的算法作出有说服力的性能比较。在Windows平台下,常用的计时器有两种,一种是timeGetTime多媒体计时器,它可以提供毫秒级的计时。但这个精度对很多应用场合而言还是太粗糙了。另一种是QueryPerformanceCount计数器,随系统的不同可以提供微秒级的计数。对于实时图形处理、多媒体数

47、据流处理、或者实时系统构造的程序员,善用QueryPerformanceCount/QueryPerformanceFrequency是一项基本功。本文要介绍的,是另一种直接利用Pentium CPU内部时间戳进行计时的高精度计时手段。以下讨论主要得益于Windows图形编程一书,第15页17页,有兴趣的读者可以直接参考该书。关于RDTSC指令的详细讨论,可以参考Intel产品手册。本文仅仅作抛砖之用。在Intel Pentium以上级别的CPU中,有一个称为“时间戳(Time Stamp)”的部件,它以64位无符号整型数的格式,记录了自CPU上电以来所经过的时钟周期数。由于目前的CPU主频都

48、非常高,因此这个部件可以达到纳秒级的计时精度。这个精确性是上述两种方法所无法比拟的。在Pentium以上的CPU中,提供了一条机器指令RDTSC(Read Time Stamp Counter)来读取这个时间戳的数字,并将其保存在EDX:EAX寄存器对中。由于EDX:EAX寄存器对恰好是Win32平台下C+语言保存函数返回值的寄存器,所以我们可以把这条指令看成是一个普通的函数调用。像这样:inline unsigned _int64 GetCycleCount() _asm RDTSC 但是不行,因为RDTSC不被C+的内嵌汇编器直接支持,所以我们要用_emit伪指令直接嵌入该指令的机器码形式

49、0X0F、0X31,如下:inline unsigned _int64 GetCycleCount() _asm _emit 0 x0F _asm _emit 0 x31 以后在需要计数器的场合,可以像使用普通的Win32 API一样,调用两次GetCycleCount函数,比较两个返回值的差,像这样: unsigned long t; t = (unsigned long)GetCycleCount(); /Do Something time-intensive . t -= (unsigned long)GetCycleCount(); Windows图形编程第15页编写了一个类,把这个计

50、数器封装起来。有兴趣的读者可以去参考那个类的代码。作者为了更精确的定时,做了一点小小的改进,把执行RDTSC指令的时间,通过连续两次调用GetCycleCount函数计算出来并保存了起来,以后每次计时结束后,都从实际得到的计数中减掉这一小段时间,以得到更准确的计时数字。但我个人觉得这一点点改进意义不大。在我的机器上实测,这条指令大概花掉了几十到100多个周期,在Celeron 800MHz的机器上,这不过是十分之一微秒的时间。对大多数应用来说,这点时间完全可以忽略不计;而对那些确实要精确到纳秒数量级的应用来说,这个补偿也过于粗糙了。 这个方法的优点是: 1.高精度。可以直接达到纳秒级的计时精度

51、(在1GHz的CPU上每个时钟周期就是一纳秒),这是其他计时方法所难以企及的。 2.成本低。timeGetTime 函数需要链接多媒体库winmm.lib,QueryPerformance* 函数根据MSDN的说明,需要硬件的支持(虽然我还没有见过不支持的机器)和KERNEL库的支持,所以二者都只能在Windows平台下使用(关于DOS平台下的高精度计时问题,可以参考图形程序开发人员指南,里面有关于控制定时器8253的详细说明)。但RDTSC指令是一条CPU指令,凡是i386平台下Pentium以上的机器均支持,甚至没有平台的限制(我相信i386版本UNIX和Linux下这个方法同样适用,但没有条件试验),而且函数调用的开销是最小的。 3.具有和CPU主频直接对应的速率关系。一个计数相当于1/(CPU主频Hz数)秒,这样只要知道了CPU的主频,可以直接计算出时间。这和QueryPerformanceCount不同,后者需要通过QueryPerformanceFrequency获取当前计数器每秒的计数次数才能换算成时间。 这个方法的缺点是: 1.现

温馨提示

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

评论

0/150

提交评论