STM8S 的定时器 TIM4 由一个带可编程预分频器的 8 位可自动重载的向上计数器组成。
TIM4 的时钟源为系统主时钟 f MASTER ,因为 f MASTER 来源于 HSE、HSI、LSI,所以也相当于 TIM4 的时钟源可以为 HSE、HSI、LSI。
f MASTER 直接连接到 CK_PSC 时钟,然后经过预分频器分频,3 位可编程预分频器可以提供 1、2、4、8、16、32、64、128 的分频,生成 CK_CNT 时钟,以驱动向上计数器进行计数。计数时钟的频率为:
向上计数时,计数器从 0 开始计数,当计数值(TIM4_CNTR 寄存器的值)增加到用户预先设置在自动重装载寄存器 TIM4_ARR 寄存器中的值时,计数器重新从 0 开始计数并产生一个计数器溢出事件。此时,如果定时器 TIM4_CR1 寄存器中的 UDIS 位为 0,则会产生一个定时器更新事件 UEV。UEV 不一定必须定时器溢出时才会产生,如果 TIM4 计数器没有溢出,我们可以通过在程序中置位 TIM4_EGR 寄存器的UG 位来产生一个更新事件 UEV。使用软件置位 TIM4_CR1 寄存器中的 UDIS 位,可以禁止 UEV 事件的产生,可以避免在更新预装载寄存器时更新影子寄存器。
影子寄存器
某个寄存器在物理上对应 2 个寄存器,一个物理寄存器呈现在程序员面前,可以由程序员来读写它的值,我们称其为预装载寄存器(preload register);另一个寄存器则对程序员屏蔽,程序员无法直接对其操作,但实际中是它在起真正的作用,我们称其为影子寄存器(shadow register)。
在计数器计数的过程中,需要时刻将计数值与预设值进行比较,以判断是否有溢出,实际与计数值比较的不是 TIM4_ARR 寄存器,而是其影子寄存器。设计预装载寄存器与影子寄存器的优点是可以保证多个通道时可以准确的同步,因为这种架构下所有通道可以在更新事件发生时在同一时间更新影子寄存器为所对应的预装载寄存器,而如果只有预
装载寄存器,则只能通过程序一条一条的顺序更新,无法做到准确同步。
更新事件发生后 STM8S 的 CPU 完成以下的动作:
■ TIM4_ARR 的值被重新更新到其影子寄存器;
■ 预分频寄存器 TIM4_PSCR 的值被重新更新到预分频寄存器缓冲器;
■ 硬件更新状态寄存器 TIM4_SR1 中的 UIF 位(更新中断标志位);
如果想使用 TIM4 的溢出中断,还需要使能 TIM4 的溢出中断功能,具体为置位 TIM4_IER 寄存器的UIE 位。
控制寄存器 1 TIM4_CR1
此寄存器用于完成对定时器 4 的简单控制。BIT[6:4]为保留位。
-
BIT7 为自动预装载使能位,该位置位时,TIM4_ARR 通过缓冲预装载;该位清零时,自动预装载功能被关闭,TIM4_ARR 不通过缓冲预装载。即
- APRE=1 时,设置到 TIM4_ARR 寄存器的值被放入缓冲器中,需要下一次 UEV 产生时,TIM4_ARR 的值才会被写入到影子寄存器;
- APRE=0 时,TIM4_ARR 寄存器的值立即被写入影子寄存器。
例如,在 APRE=1 时,我们设置 TIM4_ARR 为 0x36,则计数器需要先计数到 0xFF,发生一次溢出之后,0x36 才会被写入到影子寄存器,下次计数器计数到 0x36 时就会产生溢出;在 APRE=0 时,我们设置 TIM4_ARR 为 0x36,则此值马上被写入影子寄存器,计数器计数至 0x36就会产生溢出。
-
BIT3,单脉冲模式设置位。OPM=0,计数器在更新事件发生时不停止;OPM=1,计数器在下一次更新事件发生时停止。
-
BIT2,更新中断请求设置位。URS=0 时,所有更新事件都会发生中断请求;URS=1 时,只有计数器溢出时,才会发生中断请求。通过置位 EG 位发生的更新事件不会发出中断请求。
-
BIT1,禁止更新位。UDIS=0 时,使能更新事件;UDIS=1 时,禁止更新事件产生。
-
BIT0,计数器使能位。CEN=0,禁止计数器;CEN=1,使能计数器。
中断使能寄存器 TIM4_IER
- BIT7、BIT[5:1]保留。
- BIT6,触发中断使能位。TIE=0,禁止触发中断;TIE=1,使能触发中断。
- BIT0,更新中断使能位。UIE=0,禁止更新中断;UIE=1,使能更新中断,发生更新事件时会发出中断请求。
状态寄存器 1 TIM4_SR1
- BIT[7:1]保留。
- BIT0,更新中断标志位。UIF=0,无更新中断;UIE=1,更新中断发生。如果 UDIS=0,则发生在计数器溢出时;如果 UDIS=0 和 URS=0,则发生在软件设置 UG 位产生软件重新初始化计数器时。
事件产生寄存器 TIM4_EGR
- BIT[7:1]保留。
- BIT[0],UG 更新事件产生位。UG=0,无更新事件产生;当 UDIS=0 时,通过软件置位 UG 可产生更新事件;如果同时 URS=0,则还会产生中断请求;当 UDIS=1 时,置位UG 会初始化计数器和分频计数器,但不会产生更新事件。
计数器 TIM4_CNTR
预分频寄存器 TIM4_PSCR
- BIT[7:3],保留位。
- BIT[2:0],分频器的值。计数器时钟的频率为 f CK_CNT =f CK_PSC /2 (PSC[2:0]) ,为了使新的分频值有效,需要产生一次更新事件。
自动重装寄存器 TIM4_ARR
使用寄存器实现 TIM4 定时
TIM4 是一个 8 位通用定时器,TIM4 工作时,其计数器从 0 开始向上计数,计数到 TIM4_ARR 寄存器中设置的值时,计数器重新从 0 开始计数,同时产生一个计数器溢出事件。
我们设计一个实例,利用 TIM4 定时器中断,使开发板的 3 个 LED 每隔大约 1 秒钟翻转一次明灭状态。
void main( void )
{
InitLED();
InitTIM4();
asm("rim");
TIM4_CR1|=0x01;
while(1)
{
}
}
void InitTIM4(void)
{
TIM4_PSCR=0x07;//分频值,2M/2^7=15.625K
TIM4_IER=0x01;//更新中断使能
TIM4_CNTR=255;//计数器初值,255*(1/15.625K)=0.01632S
TIM4_ARR=255;//自动重装的值
}
#pragma vector=TIM4_OVR_UIF_vector //定义中断服务函数入口地址
__interrupt void TIM4_OVR_UIF__IRQHandler(void)
{
i++;
TIM4_SR=0x00; //清除中断标志
if(i==61)
{ //翻转 LED 接口的输出状态
PC_ODR_ODR3^=1;
PE_ODR_ODR0^=1;
PD_ODR_ODR3^=1;
i=0;
}
}
TIM4_PSCR 寄存器设置 TIM4 计数器的分频值,设置为 0x07 之后,TIM4 的计数器计数时钟频率为2M/2^7=15.625KHz。
TIM4_CNTR 用来设置 TIM4 的计数器初值,TIM4_ARR 用来设置 TIM4 的自动重装
值,将它们设置为 255,则 TIM4 每隔 255×(1/15.625K)=0.01632 秒产生一次溢出中断。
要实现 LED每隔大约 1 秒翻转一次,则只要 TIM4 没中断 61 次翻转 LED 接口的输出状态即可。