我们在应用单片机的时候,实现定时的方式大概有以下两种方式。
一是使用循环延时。使用循环延时的好处是实现比较方便,但是在循环的过程中一直消耗单片机的效率以致于整个程序的执行效率比较低,主程序运行一个周期的时间会加长。在延时比较短的场合,比如几个微秒可以使用这种方式。但是循环延时的个数不能过多。在延时比较长的场合,比如十几上百个毫秒,这种延时方式就不适合了。
另一种就是扫描延时。什么是扫描延时,就是在程序执行到要延时的地方,通过程序判断延时时间是否到设定值。如果没有则继续执行下面的程序,直到扫描到延时时间到设定值才执行指定的程序。这种延时方式与PLC的定时指令是一样的原理。这种延时方式不会降低单片机的执行效率,不会影响延时指令以后的其他程序执行,是一种比较合理的延时方式。 下面我们主要讲的就是如何实现这一种定时方式。
扫描延时,首先需要一个时基。这个时基我们可以通过单片机的定时中断功能来获取。参考图1。
图1是一个定时器的中断服务函数。下面来讲解一下各个指令的含意。
TH0 = TRH[0];
TL0 = TRL[0];
重新装载定时器的值。TRH[0]、TRL[0]数组内储存的是定时器延时1ms进入中断的值。
t_1ms++; 定时器中断一次,也就是1ms,1ms时基加1。
if(t_1ms > 32000)
t_1ms = 0;
这两句的作用主要是防止寄存器的值变成负数和溢出而加入的。
t_50ms = t_1ms / 50; 定时到50ms时,50ms时基加1。
程序中如何应用这个定时功能,参考图2的程序。
下面我们来讲解一下这段程序的功能。
int FLOW_T[3] = {0,0,0};
int FLOW_TVAL[3] = {0,0,0}, FLOW_Ttmp;
char FLOW_TT[3] ={0,0,0};
定义程序中应用到的参数。这里是定义了3个定时器。根据你需要的定时器个数来修改上面数组的大小。
if((input_image & 0x1) && FLOW_TT[0] == 0) 输入信号来的时候开始定时。
{
FLOW_T[0] = t_50ms; 存储50ms时基的当前值。
FLOW_TVAL[0] = 0; 复位定时器。
FLOW_TT[0] = 1; 定时器开始工作标志。
}
if(FLOW_TT[0] == 1) 定时器工作中。
{
FLOW_Ttmp = t_50ms - FLOW_T[0]; 当扫描到这里时,计算出50ms时基差值。
FLOW_T[0] = t_50ms; 存储50ms时基的当前值。
if(FLOW_Ttmp > 0)
FLOW_TVAL[0] += FLOW_Ttmp; 累加定时器定时时间。
if(FLOW_TVAL[0] > 20)
{
//这里为定时间到时的执行程序,这里定时为1S
}
}
这段程序在寄存器溢出的时候最多会有50ms的误差,如果要减少这个误差可以使用10ms或1ms时基。这个时候的误差相应的就会变成10ms或1ms。
有需要源程序的朋友可以私信我。