S T M教程S T M S定时器模块及其应用实例集团标准化工作小组 [Q8QX9QT-X8QQB8Q8-NQ8QJ8-M8QMN]第十三章 STM8S207 定时器模块及其应用实例这一节,我们将向大家介绍如何使用 STM8 的定时器中的基本定时功能,STM8 的定时器功能十分强大,有 TIM1 高级定时器,也有 TIM2、TIM3 等通用定时器,还有TIM4 基本定时器。
在 STM8S 参考手册里面,定时器的介绍占了 1/3 的篇幅,足见其重要性。
这一节,我们分别介绍 TIM1 到 TIM4 定时器中的基本定时功能。
例程一、16 位高级控制定时器(TIM1)简介:TIM1 由一个 16 位的自动装载计数器组成,它由一个可编程的预分频器驱动。
TIM1 有 4 个通道,分别是 1 到 4。
分别对应于四个不同的捕获/比较通道。
高级控制定时器适用于许多不同的用途:基本的定时测量输入信号的脉冲宽度(输入捕获)产生输出波形(输出比较,PWM 和单脉冲模式)对应与不同事件(捕获,比较,溢出,刹车,触发)的中断与 TIM5/TIM6 或者外部信号(外部时钟,复位信号,触发和使能信号)同步高级控制定时器广泛的适用于各种控制应用中,包括那些需要中间对齐模式PWM 的应用,该模式支持互补输出和死区时间控制。
高级控制定时器的时钟源可以是内部时钟,也可以是外部的信号,可以通过配置寄存器来进行选择。
这一节我们实现的功能是基本的定时,关于 PWM 的编程留下以后的章节中。
还有建议大家研究更为深入的功能TIM1 的时基单元包括,如下图所示:● 16 位向上/向下计数器● 16 位自动重载寄存器●重复计数器●预分频器16 位计数器,预分频器,自动重载寄存器和重复计数器寄存器都可以通过软件进行读写操作。
自动重载寄存器由预装载寄存器和影子寄存器组成。
可在在两种模式下写自动重载寄存器:●自动预装载已使能(TIM1_CR1 寄存器的 ARPE 位置位)。
在此模式下,写入自动重载寄存器的数据将被保存在预装载寄存器中,并在下一个更新事件(UEV)时传送到影子寄存器。
●自动预装载已禁止(TIM1_CR1 寄存器的 ARPE 位清除)。
在此模式下,写入自动重载寄存器的数据将立即写入影子寄存器。
更新事件的产生条件:●计数器向上或向下溢出。
●软件置位了 TIM1_EGR 寄存器的 UG 位。
●时钟/触发控制器产生了触发事件。
在预装载使能时(ARPE=1),如果发生了更新事件,预装载寄存器中的数值(TIM1_ARR)将写入影子寄存器中,并且 TIM1_PSCR 寄存器中的值将写入预分频器中。
置位 TIM1_CR1 寄存器的 UDIS 位将禁止更新事件(UEV)。
计数器由预分频器的输出 CK_CNT 驱动,而 CK_CNT 仅在 IM1_CR1 寄存器的计数器使能位(CEN)被置位时才有效。
简要说明:CK_PSC 的时钟来源于 f_master,我们使用 16M 内部时钟源 HIS然后可以通过 PSCR 这个寄存器设置 CK_CNT,PSCR 是 2 个 8 位寄存器组成的16 位寄存器,可以在 0~65535 之间任务分频,分频后的频率提供给 CK_CNT 我们的实验为了方便计算,CK_CNT 为1K 的频率,所以PSCR = 16M/1K = 16000,换成 16 进制为 0x3E80我们使用了默认的向上溢出,所以为了 500ms 溢出中断一次,需要设置 ARPE这个定时器,而且设置为自动预装功能,这样就可以一直提供 2Hz 的频率中断最后允许中断和计数器使能就可以实现我们的功能有了以上的基础就可以进入到 TIM1 的基本定时器编程了,为了验证效果,我们采用了 LED0 作为判断依据。
在 TIM1 的溢出中断服务程序中闪耀 LED0程序代码如下:#include ""#define LED1_FLASH PD_ODR_ODR0 = !PD_ODR_ODR0void CLK_Init(void);void GPIO_Init(void);void TIM1_Init(void);void main( void ){CLK_Init();GPIO_Init();TIM1_Init();asm("rim");// 主循环里没有程序需要执行while(1);}void CLK_Init(void){CLK_CKDIVR = 0x00; // 16M内部RC直接输出}void GPIO_Init(void){PD_DDR = 0x01; // 配置PD端口的方向寄存器PD0输出PD_CR1 = 0x01; // 设置PD0为推挽输出PD_ODR = 0xFF;}void TIM1_Init(void){TIM1_PSCRH = 0x3E; // 16M系统时钟经预分频f=fck/(PSCR+1)TIM1_PSCRL = 0x7F; // PSCR=0x3E7F, f=16M/(0x3E7F+1)=1000Hz//每个计数周期1msTIM1_ARRH = 0x01; // 自动重载寄存器ARR=0x01F4=500TIM1_ARRL = 0xF4; // 每记数500次产生一次中断,即500msTIM1_IER = 0x01; // 允许更新中断TIM1_CR1 = 0x01; // 计数器使能,开始计数}#pragma vector=TIM1_OVR_UIF_vector //0x0D__interrupt void TIM1_OVR_UIF(void){LED1_FLASH;TIM1_SR1 = 0; //清除中断标记,这步不能漏掉,否则会连续进入中断程序}编译下载后就可以看到LED1一闪一闪的,闪耀的频率我们设置是2Hz,大家也可以设置不一样的定时时间,我们只是简单介绍如何使用TIM1的基本定时功能例程2、16位通用定时器TIM2、TIM3TIM2/TIM3的功能包括:● 16位向上计数和自动装载计数器● 4位可编程(可以实时修改的)预分频器,计数器时钟频率的分频系数为1~32768之间的2的幂● 3个独立通道:输入捕获输出比较PWM生成(边缘对齐模式)单脉冲模式输出●如下事件发生时产生中断:更新:计数器向上溢出,计数器初始化(通过软件)输入捕获输出比较和TIM1介绍一样,下面介绍时基单元时基单元包含:16位向上计数器预分频器16位自动装载寄存器没有重复寄存器。
计数器使用内部时钟(fMASTER),它由CK_PSC提供,并经过预分频器分频产生计数器时钟CK_CNT。
预分频器预分频器的实现:预分频器基于4位寄存器控制的16位计数器,由于寄存器带有缓冲器因此可以随时修改预分频的数值。
计数器可以取值为1到32768之间的2的幂进行分频。
计数器时钟频率的计算公式:fCK_CNT = fCK_PSC/2(PSCR[3:0])]预分频器的值由预装载寄存器写入。
一旦写入预装载寄存器的LS字节时,带有当前使用值的影子寄存器就被写入了新的值。
新的预分频值在下一个周期时生效(在下一个更新事件之后)。
对TIMx_PSCR寄存器的读操作通过预装载寄存器实现,因此可以随时读取不受限制。
TIM2、TIM3与TIM1不同之处是预分频器并非在0~65535之间的认为分频系数,而是1到32768之间2的幂进行分频。
关于TIM2和TIM3的预分频寄存器如下:这次实验是TIM2、TIM3同时工作,因为预分频系数不能随意设置,所以为了计算方便,我们设置为1024分频,也就是PSC = 0x0A,经过分频后的频率是,也就是因此500ms/ = 7813 转为16进制是1E84,所以1S的定时是3D08,有了这些参数就可以开始我们例程二的软件代码编写了#include ""#define LED1_FLASH PD_ODR_ODR0 = !PD_ODR_ODR0#define LED2_FLASH PD_ODR_ODR1 = !PD_ODR_ODR1#define LED3_FLASH PD_ODR_ODR2 = !PD_ODR_ODR2void CLK_Init(void);void GPIO_Init(void);void TIM1_Init(void);void TIM2_Init(void);void TIM3_Init(void);void main( void ){CLK_Init();GPIO_Init();TIM1_Init();TIM2_Init();TIM3_Init();asm("rim");// 主循环里没有程序需要执行while(1);}void CLK_Init(void){CLK_CKDIVR = 0x00; // 16M内部RC直接输出}void GPIO_Init(void){PD_DDR = 0x07; // 配置PD端口的方向寄存器PD0输出PD_CR1 = 0x07; // 设置PD0为推挽输出PD_ODR = 0xFF;}void TIM1_Init(void){TIM1_PSCRH = 0x3E; // 16M系统时钟经预分频f=fck/(PSCR+1)TIM1_PSCRL = 0x7F; // PSCR=0x3E7FTIM1_ARRH = 0x00; // 自动重载寄存器ARR=0x00FA=250TIM1_ARRL = 0xFA; // 每记数250次产生一次中断,即250msTIM1_IER = 0x01; // 允许更新中断TIM1_CR1 = 0x01; // 计数器使能,开始计数}void TIM2_Init(void){TIM2_PSCR = 0x0A; //16M系统时钟经预分频f=16M/1024=TIM2_ARRH = 0x1E; // * 7813 = 500msTIM2_ARRL = 0x84;TIM2_IER = 0x01; //运行更新中断TIM2_CR1 = 0x01; //使能计数器}void TIM3_Init(void){TIM3_PSCR = 0x0A; //16M系统时钟经预分频f=16M/1024=TIM3_ARRH = 0x3D; // * 15626 = 1sTIM3_ARRL = 0x08;TIM3_IER = 0x01; //允许更新中断TIM3_CR1 = 0x01; //使能计数器}#pragma vector=TIM1_OVR_UIF_vector //0x0D__interrupt void TIM1_OVR_UIF(void){LED1_FLASH;TIM1_SR1 = 0; //这步不能漏掉,否则会连续进入中断程序}#pragma vector=TIM2_OVR_UIF_vector //0x0F__interrupt void TIM2_OVR_UIF(void){LED2_FLASH;TIM2_SR1 = 0; //这步不能漏掉,否则会连续进入中断程序}#pragma vector=TIM3_OVR_UIF_vector //0x11__interrupt void TIM3_OVR_UIF(void){LED3_FLASH;TIM3_SR1 = 0; //这步不能漏掉,否则会连续进入中断程序}编译下载后就可以看到LED1、LED2、LED3在不停闪耀,而且是LED1闪耀两次LED2才闪耀一次,LED2闪耀两次LED3才闪耀一次。