今天我们来看看STC的定时器。
定时器同时也可以是计数器,其实是差不多的。
对于STC8G1K08A来说,有仨16位的定时器,但是如果是SOP8的话,那就只有两个定时器,是定时器0和定时器1。
定时器有四种工作模式,模式0为16位自动重装载(也是最常用的),模式1为16位不自动重装载,模式2为8位自动装载,模式3为16位不可屏蔽中断自动重装载。
定时器0的话是四种工作模式都可以使用,而定时器1不能用模式3。
而对于STC32G12K来说,定时器是有五个。
定时器0和1的工作模式和STC8的一模一样。
剩下的定时器234的工作模式固定为模式0也就是16位自动重装载。
了解了定时器资源和工作模式之后,我们简单看看手册里对于定时器物理结构的描述,因为手册里列出了7种(定时器0的0123工作模式和定时器1的012工作模式)有点多,所以我们这边就只看看定时器0的模式0意思意思。
下图是STC32G的定时器框图,STC8和下面的几乎一模一样,就是少了TM0PS。
我们从左往右一个个看,首先是SYSclk,也就是系统时钟,不管是STC8还是STC32都是24MHz,记得在烧录的时候,在烧录软件里选择24MHz。
然后经过TM0PS,它是定时器0的预分频器,一共有8个bit,也就是说最多可以是2^8 - 1 + 1= 256分频(减一是因为8个bit的范围是0~255,加一是预分频器的值加一之后才会拿去分频)
接下来是÷12或÷1,也就是可以选择要不要接着分频一下,不过只能是要么不再分要么就是固定12分频。
再往下就是一个分叉路口了,C/T等于0的时候,那就是我们刚刚推算过来的系统时钟来的脉冲作为计数来源;C/T等于1的时候定时器的计数来源就是外部引脚了,T0的外部脉冲引脚是P34。
过了分岔路口有个方框,这个不用管,可以当成是定时器的使能部位。
再往下就是存放计数的寄存器(TH0、TL0)和重装载寄存器(RL_TH0、RL_TL0)
当我们计数器的值溢出就会置位TF0从而引发中断,然后重装载寄存器的值就会写入计数的寄存器里进入新一轮的计数。
上面看不懂没关系,我们只要有下面这样一个公式就够了。如果是STC8的话没有TM0PS那部分。
接下来讲解一下库函数。
我们需要把三个文件包含进工程里。STC32G_Timer.c、STC32G_Timer_Isr.c、STC32G_NVIC.c
关于NVIC我们就用一个函数用于配置中断优先级以及打开中断。

如果是定时器1的话就把上面函数名里的0改成1即可。
然后除了这个函数之外,我们还需要手动把EA置1,关于这个EA,昨天的外部中断那篇有提到。
接着是定时器的配置函数,也是只有一个函数。
参数一指定定时器通道,参数二结构体变量的指针来配置参数。
结构体的成员从上到下依次是工作模式,一般使用TIM_16BitAutoReload16位自动重装载模式也就是模式0。
时钟源,可以选择的是下面三种。
可以参考前面的频率计算公式,一般我们就选择TIM_CLOCK_1T。
第三个是可编程时钟输出设置,可以选择ENABLE或者是DISABLE,也就是使能和失能,一般就是DISABLE。
第四个就是定时器的初值,记得最多是16个bit,也就是最大值为2^16 - 1= 65535,超过这个值就会溢出中断。
最后一个就是使能,给个ENABLE。
其实还有一个成员,在库函数手册里没有标出来,那就是预分频器的值。
下面的代码里我将定时器触发的周期设为了5ms。
#include "STC32G_GPIO.h"
#include "STC32G_NVIC.h"
#include "STC32G_Timer.h"
void NVIC_Init(void) {
NVIC_Timer0_Init(ENABLE, Priority_1);
}
void GPIO_Init(void) {
P2_MODE_OUT_PP(GPIO_Pin_7);
}
void Timer_Init(void) {
TIM_InitTypeDef initer;
initer.TIM_Mode = TIM_16BitAutoReload; // 模式0,16位自动重装载寄存器.
initer.TIM_ClkOut = DISABLE; // 失能可编程时钟输出
initer.TIM_ClkSource = TIM_CLOCK_1T; // 1T工作模式
initer.TIM_Value = 55536; // 计数寄存器和重装载寄存器的值设为55536
initer.TIM_PS = 11; // 预分频器的值设为11,实际上是12分频
initer.TIM_Run = ENABLE; // 定时器,启动!
Timer_Inilize(Timer0, &initer);
}
void main(void) {
WTST = 0; // 设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
EAXSFR(); // 扩展SFR(XFR)访问使能
CKCON = 0; // 提高访问XRAM速度
GPIO_Init();
Timer_Init();
NVIC_Init();
EA = 1;
while (1) {
}
return;
}
在STC32G_Timer_Isr.c的定时器0中断触发函数里我的代码逻辑是每溢出20次,就切换一下P27的电平,接个LED就可以看到效果了。
定时器里唯一的问题就是如何设置定时器溢出的周期。
这个我们可以参考手册里的公式。
公式里周期的单位是秒。
如果我们不需要定时器的周期比较大的话,可以把PS(预分频器)置0,这样计算起来就很方便了。
当PS为0的时候,公式就变成了计数寄存器的初始值 = 65536 - T*F,其中T是周期,F是时钟频率。
T周期是我们自己定的,F是24MHz,所以我们就可以很轻松地算出应该给计数寄存器赋的值是多少了。