电子科技大学综合课程设计报告基于单片机门控位的脉冲宽度测量与显示think2011/5/4一、 可行性分析及其原理:该项目是要实现脉冲宽度的测量,再把测量值用数码管显示。
为了实现这一功能我们大致把整个系统分为以下几个模块:1. 振荡器模块:产生某一特定振荡频率的时钟,一般要求这一频率较高,本题要求精度为10us ,所以采用100kHZ 的振荡频率即可。
2. 计数器模块:对振荡脉冲进行计数,用待测脉冲信号作为使能输入(或开关),这样就可以记录下脉冲有效的时间,计数值乘以10us 即为待测脉冲宽度。
3. 译码显示模块:题目中要求用数码管显示6位测量值,分别完成译码和数码管的静态显示或是动态扫描输出即可。
框图如下:二、 本次设计构思了两个方案:方案一:运用CD4518(BCD 码全加器)的级联来实现计数,CD4511七段译码,555多谐振荡器提供100kHZ 频率,待测信号输入到计数器使能。
电路连接图如下:上述方案为数码管静态显示。
优点为方案简单无需编程,只需要组合逻辑与时序逻辑即可完成。
缺点为硬件电路的连线过于复杂上容易出错且很难排除故障,另一个问题在于使用的外接振荡源精度不是很高,势必带来不小的误差。
此方案理论上可行,由于实际操作带来的不方便,我们考虑了后面一种方案。
方案二:利用单片机门控位实现脉冲宽度测量。
基本思路为:利用单片机内部定时器的GATE信号,对于定时器T0来讲,如果GATE=1,则用软件把TR0置1,且INT0为高电平时可以启动定时器T0,所以我们就把被测脉冲信号从INT0端输入,使其上升沿触发启动T0计数,下降沿停止T0计数。
定时器数值乘以机器周期即为脉冲宽度。
电路连接图如下:可以看出,电路结构由以下部分构成:1.振荡模块:12MHZ晶体振荡器,由XTAL1和XTAL2接入单片机。
2.单片机控制模块:AT89S51单片机实现控制,主要任务是对其进行必要的编程设计。
3.输出显示模块:由数码管动态扫描显示,注意P0需要外接上拉电阻。
另外,还有一个异或门电路是用来实现选择测量正脉冲还是负脉冲。
和前一方案相比可以发现,这样的方案要比用组合时序逻辑连线简单,而且较容易查错。
单片机内部有定时器计数器,就可以使用相同的原理来对脉冲宽度进行测量,所以说使用单片机编程实现控制也是可行的,所以,下面就针对方案二的程序进行进一步的分析。
三、程序设计及分析:51单片机的计数功能我们已经很熟悉了,但是我们也知道不论是哪种方式的计数,其最大值也只能计65535,而本次设计要求要计的范围是0到99.99ms,这就意味着超出了计数器的量程,解决方案也有两个。
第一种,使用两个计数器配合实现计数位的扩展。
第二种,使用中断服务程序,也可以实现扩展。
这里我们选择使用中断服务程序的方法。
以下是该设计的中断服务程序:T0INT: PUSH ACCMOV TH0,#00HMOV TL0,#00HMOV A,COUNT+1ADD A,#01HMOV COUNT+1,AMOV A,COUNTADDC A,#00HMOV COUNT,APOP ACCRETI考虑到单次测量可能会带来较大的误差,我们采用次测量取平均的方法,方便起见,我们使用两个计数器共32位计数值,对连续脉冲测量256次,只显示其高24位,低8位舍掉不显示,这样就巧妙地实现了测量256次取平均的效果。
另外,因为外部电路省掉了译码的部分,所以必须在单片机内部完成译码功能,在译码之前首先还必须经过一次转码,即把2进制码转换成可以由数码管显示的码。
这里用循环移位的方法把所有测量位都连了起来。
然后再转换成BCD码存放。
最后还有显示的子函数就实现把BCD码转换成7段码,显示程序如下:DISPLAY: MOV R0,#70HMOV R3,#01HNEXT: MOV A,#00HMOV P1,AMOV A,@R0MOV DPTR,#LABLE1MOVC A,@A+DPTRMOV P0,AMOV A,R3MOV P1,ALCALL DELAYINC R0JB ACC.5,EXITRL AMOV R3,ASJMP NEXTEXIT: RETLABLE1: DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FHDB 6FH,77H,7CH,39H,5EH,79H,71H,00H,73H DELAY: MOV R7,#02HDEL1: MOV R6,#0FFHDEL2: DJNZ R6,DEL2DJNZ R7,DEL1RETEND2进制转换为BCD码程序如下:WDISBUF:CLR AMOV R3, AMOV R4, AMOV R5, AMOV R2, #24HB1: MOV R6, HEXMOV R7, HEX+1MOV R1, HEX+2HB2: MOV A,R1RLC AMOV R1,AMOV A,R7RLC AMOV R7,AMOV A,R6RLC AMOV R6,AMOV A,R5ADDC A,R5DA AMOV R5,AMOV A,R4ADDC A,R4DA AMOV R4,AMOV A,R3ADDC A,R3DA AMOV R3,AJNC OVERMOV A,#00HMOV P1,ARETOVER: DJNZ R2,HB2MOV R0,#DISBUF+5MOV A,#00HMOV @R0,AMOV A,R3SWAP AANL A,#0FHMOV @R0,ADEC R0MOV A,R3ANL A,#0FHMOV @R0,ADEC R0MOV A,R4SWAP AANL A,#0FHMOV @R0,ADEC R0MOV A,R4ANL A,#0FHMOV @R0,ADEC R0MOV A,R5SWAP AANL A,#0FHMOV @R0,ADEC R0MOV A,R5ANL A,#0FHMOV @R0,ARET四、关于程序及硬件电路的调试过程程序调试:作为没太多经验的程序员,程序编写完成后就编译一般会报出很多错误,通常为语法错误,这时就需要根据编程软件(我们用的是keil)的提示检查程序的错误。
我还记得我们是从几十个错误一点一点地改正过来,包括push和pop后面的A改成ACC。
还需要注意的是,有些错误很隐蔽,比如中文的输入法造成的错误,这样的中文字符或标点在编辑界面都是看不见的,要找出这样的错误就需要把那一行注释掉,这样就可以看到以前错误输入的中文字符和标点,再加以改正就可以了。
这属于语法错误的改正方法。
还有一类错误是:语法都正确,但是运行结果不正确,这样的错误就比较难改,建议大家单步执行来调试仿真,keil里可以单步执行,但是我特别想推荐的是protus软件,在连接好单片机及其外围电路后,可以把在keil上对单片机编的程序直接在protus上运行仿真,而且protus可以打开单片机的RAM单元和各个特殊功能寄存器,可以观察到每一步执行后各个地址里所存放的单元的具体变化,这样对查错带来了极大的方便。
我们在进行此类调试的时候,出现的问题比较难解决的主要是一个:不管输入多少HZ的信号显示的数码管一直显示29952。
这样的错误简直太严重了,问题的原因可能是显示部分程序不对,或者是单片机的控制程序本身就出了问题,经过一系列的试验,我们排除了第一种可能,单步执行前面的程序,观察每个寄存器的数值,好几天后才发现了这个奇怪的现象:每当定时器记满中断后,我们用于存放数据的40H就会被改变,但我们一开始也不知道是什么原因,后来才发现堆栈指针*SP指向的就是40H,修改SP后,程序就变得正常了,可以显示正确的测量值。
其他还存在的问题比如说显示的数值会闪烁,我们修改延时程序后也相应解决了。
硬件调试:我个人觉得我们对硬件的调试要比对软件的调试痛苦,虽然软件我们也花了一个多星期调试,但是硬件调试有个很要命的问题,就是硬件的东西都是真实的,有可能会买来就是坏的而你不知道顺势把它焊在板子上了,而且也有可能本来是好的,你稍不注意通电的时候短路了,烧坏几个器件就得重新再来,我们还算幸运,从开始到调试成功只遇到了一个异或门是坏的和不小心烧了一个三极管,其他电路基本都正确。
硬件电路一开始存在的问题:1.有些连接部分其实并没有导通,造成显示结果不正确。
2.有些引脚很难焊,可能连到一起了。
3.排除了第一第二种可能后,还有就是外围电路需要一个振荡源提供某一频率的输入信号,我们因为条件限制,没有这样的输入信号,就用单片机的ALE信号代替,结果怎么都出不了正确测量值,这也是我们这几天不管怎么努力也出不了结果的原因。
当我们把输入信号源找到,一切问题都迎刃而解了。
失败和成功原本就只有一步之遥,在还没成功的时候,你根本想不到它原来已经这么近了。
五、对结果的分析总结5%,其他地方均在3%以下,所以可以认为误差在允许范围内。
需要说明的是,当使用最大量程时,即测量1s 的脉宽的时候,需要等待的时间太长,因为我们选用的是重复测量256次取平均的方式,这样就就需要花大约四分钟的时间。
在这一点上,程序还可以优化。
画出了输入取对数对应的输出图:另外,造成这些误差的原因我想应该是多方面的,首先,我们选择单片机编程,而且是使用中断服务程序实现计数计时的扩展,这样会有个弊端,就是中断服务程序自身代码的执行会需要几个机器周期,这样造成的误差使用重复测量是无法消除的,有一个办法就是不用中断服务程序,只执行一个外部中断计数使另一个计数器加一。
但是这样的程序又不能实现我们需要的众多操作,所以对此进一步优化的方案还没有给出来。
其误差关于频率的曲线如下:02468101214160.050.10.150.20.25log2(x )y输入输出关系0.511.52 2.533.544.5x 104-0.04-0.020.020.040.06频率x相对误差y相对误差关于输入频率曲线。