1.确定初值
1kHz方波信号的周期 T =1/ f =1/1000=1ms,高、低电平各为0.5ms(500μs),要产生1kHz方波信号,只需让定时器/计数器每隔0.5ms产生一次计数溢出中断,中断后改变输出端口的值,并重复进行该过程即可。定时器/计数器T0工作在方式1时为16位计数器,最大计数值为65536。T0从0计到65536需要耗时65.536ms(单片机时钟频率为12MHz时),要T0每隔0.5ms产生一次计数溢出,必须给T0设置定时初值。定时器/计数器工作在方式1时的定时初值的计算公式如下:
定时初值=2 16 -定时值=2 16 -tf osc /12=65536-500×10 -6 ×12×10 6 ÷12=65036
定时初值放在TH0和TL0两个8位寄存器中,TH0存放初值的高8位,TL0存放初值的低8位,65036是一个十进制数,存放时需要转换成十六进制数,65036转换成十六进制数为0xFE0C,TH0存放FE,TL0存放0C。由于65036数据较大,转换成十六制数运算较麻烦,可采用65036/256得到TH0值,“/”为相除取商,结果TH0=254,软件编译时自动将十进制数254转换成十六进制数FE,TL0值可采用(65536-500)%256计算得到,“%”为相除取余数,结果TL0=12,十进制数12转换成十六进制数为0C。
2.程序说明
图7-11是一种让定时器/计数器T0工作在方式1时产生1kHz方波信号的程序。在程序中,先声明一个定时器及相关中断设置函数T0Int_S,在该函数中,设置T0的工作方式(方式1),设置T0的计数初值(65036,TH0、TL0分别存放高、低8位),将信号输出端口P1.0赋初值1,再打开总中断和T0中断,然后让TCON的TR0位为1启动T0开始计数。在图7-11所示程序中还编写一个定时器中断函数(子程序)T0Int_Z,在该函数中先给T0赋定时初值,再让输出端口P1.0值变反。
main函数是程序的入口,main函数之外的函数只能被main函数调用。图7-11所示程序运行时进入main函数,在main函数中先执行中断设置函数T0Int_S,设置定时器工作方式和定时初值,将输出端口赋值1,并打开总中断和T0中断,并启动T0开始计数,然后执行while(1)语句原地踏步等待,0.5ms(此期间输出端口P1.0为高电平)后T0计数达到65536溢出,产生一个T0中断请求信号触发定时器中断函数T0Int_Z执行,T0Int_Z函数重新给T0定时器赋定时初值,再将输出端口P1.0值取反(T0Int_Z函数第一次执行后,P1.0变为低电平),中断函数T0Int_Z执行完后又返回到main函数的while(1)语句原地踏步等待,T0则从中断函数设置的定时初值基础上重新计数,直到计数到65536产生中断请求再次执行中断函数,如此反复进行,P1.0端口的高、低电平不断变化,一个周期内高、低电平持续时间都为0.5ms,即P1.0端口有1kHz的方波信号输出。
使用频率计(也可以用带频率测量功能的数字万用表)可以在P1.0端口测得输出方波信号的频率,用示波器能直观地查看到输出信号的波形。由于单片机的时钟频率可能会漂移,另外程序语句执行需要一定时间,所以输出端口的实际输出信号频率与理论频率可能不完全一致,适当修改定时初值大小可使输出信号频率尽量接近需要输出的频率,输出信号频率偏低时可适当调大定时初值,这样计数时间更短就能产生溢出,从而使输出频率升高。
图7-11 定时器/计数器T0工作在方式1时产生1kHz方波信号的程序
定时器/计数器工作在方式1时执行程序中的重装定时初值语句需要一定的时间,若让定时器/计数器工作在方式1来产生频率较高的信号,则得到的高频信号频率与理论频率差距很大。定时器/计数器工作在方式2时,一旦计数溢出,定时初值会自动重装,无须在程序中编写重新初值语句,故可以产生频率高且频率较准确的信号。
图7-12是一种让定时器/计数器T1工作在方式2时产生50kHz方波信号的程序。在程序的中断设置函数T1Int_S中,在TL1和TH1寄存器中分别设置了计数初值和重装初值,由于单片机会自动重装计数初值,故在定时器中断函数T1Int_Z中无须再编写重装初值的语句。定时器/计数器从246计到256需要10μs,然后执行定时器中断函数T1Int_Z使输出端口电平变反,即输出方波信号周期为20μs,频率为50kHz。
图7-12 定时器/计数器T1工作在方式2时产生50kHz方波信号的程序
定时器/计数器的最大计数值为65536,当单片机时钟频率为12MHz时,定时器/计数器从0计到65536产生溢出中断需要65.536ms,若采用每次计数溢出就转换一次信号电平的方法,只能产生周期最长约为131ms的方波信号,要产生周期更长的信号,可以让定时器/计数器溢出多次后再转换信号电平,这样就可以产生周期为(2×65.536× n )ms的方波信号, n 为计数溢出的次数。
图7-13是一种让定时器/计数器T0工作在方式1时产生周期为1s方波信号的程序。该程序与图7-11程序的区别主要在于定时器中断函数的内容不同,本程序将定时器的定时初值设为(66536-50000),这样计到65536溢出需要50ms,即每隔50ms会执行一次定时器中断函数T0Int_Z,用i值计算T0Int_Z的执行次数,当第11次执行时i值变为11,if大括号内的语句执行,将i值清0,同时将输出端口值变反。也就是说,定时器/计数器执行10次(每次需要50ms)时输出端口电平不变,第11次执行时输出端口电平变反,i值变为0,又开始保持电平不变进行10次计数,结果输出端口得到1s(1000ms)的方波信号。
图7-13 定时器/计数器T0工作在方式1时产生周期为1s方波信号的程序
如果在T0Int_Z函数的“Xout=~Xout;”语句之后增加一条“TR0=0”语句,T0Int_Z函数仅会执行一次,并且会让定时器/计数器T0计数停止,即单片机上电后,P1.0端口输出低电平,500ms后,P1.0端口输出变为高电平,此后该高电平一直保持。若需要获得较长的延时,可以增大程序中的i值(最大取值为65535),比如i=60000,可以得到50ms×60000=3000s的定时,如果要获得更长的延时,可以将“unsigned int i”改成“unsigned long int i”,这样i由16位整数型变量变成32位整数型变量,取值范围由0~65535变成0~4294967295。