第十三章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程序代码如下:#includeiostm8s207rb.h#defineLED1_FLASHPD_ODR_ODR0=!PD_ODR_ODR0voidCLK_Init(void);voidGPIO_Init(void);voidTIM1_Init(void);voidmain(void){CLK_Init();GPIO_Init();TIM1_Init();asm(rim);//主循环里没有程序需要执行while(1);}voidCLK_Init(void){CLK_CKDIVR=0x00;//16M内部RC直接输出}voidGPIO_Init(void){PD_DDR=0x01;//配置PD端口的方向寄存器PD0输出PD_CR1=0x01;//设置PD0为推挽输出PD_ODR=0xFF;}voidTIM1_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;//计数器使能,开始计数}#pragmavector=TIM1_OVR_UIF_vector//0x0D__interruptvoidTIM1_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,经过分频后的频率是15.625K,也就是0.064ms因此500ms/0.064=7813转为16进制是1E84,所以1S的定时是3D08,有了这些参数就可以开始我们例程二的软件代码编写了#includeiostm8s207rb.h#defineLED1_FLASHPD_ODR_ODR0=!PD_ODR_ODR0#defineLED2_FLASHPD_ODR_ODR1=!PD_ODR_ODR1#defineLED3_FLASHPD_ODR_ODR2=!PD_ODR_ODR2voidCLK_Init(void);voidGPIO_Init(void);voidTIM1_Init(void);voidTIM2_Init(void);voidTIM3_Init(void);voidmain(void){CLK_Init();GPIO_Init();TIM1_Init();TIM2_Init();TIM3_Init();asm(rim);//主循环里没有程序需要执行while(1);}voidCLK_Init(void){CLK_CKDIVR=0x00;//16M内部RC直接输出}voidGPIO_Init(void){PD_DDR=0x07;//配置PD端口的方向寄存器PD0输出PD_CR1=0x07;//设置PD0为推挽输出PD_ODR=0xFF;}voidTIM1_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;//计数器使能,开始计数}voidTIM2_Init(void){TIM2_PSCR=0x0A;//16M系统时钟经预分频f=16M/1024=15.625kTIM2_ARRH=0x1E;//15.625k*7813=500msTIM2_ARRL=0x84;TIM2_IER=0x01;//运行更新中断TIM2_CR1=0x01;//使能计数器}voidTIM3_Init(void){TIM3_PSCR=0x0A;//16M系统时钟经预分频f=16M/1024=15.625kTIM3_ARRH=0x3D;//15.625k*15626=1sTIM3_ARRL=0x08;TIM3_IER=0x01;//允许更新中断TIM3_CR1=0x01;//使能计数器}#pragmavector=TIM1_OVR_UIF_vector//0x0D__interruptvoidTIM1_OVR_UIF(void){LED1_FLASH;TIM1_SR1=0;//这步不能漏掉,否则会连续进入中断程序}#pragmavector=TIM2_OVR_UIF_vector//0x0F__interruptvoidTIM2_OVR_UIF(void){LED2_FLASH;TIM2_SR1=0;//这步不能漏掉,否则会连续进入中断程序}#pragmavector=TIM3_OVR_UIF_vector//0x11__interruptvoidTIM3_OVR_UIF(void){LED3_FLASH;TIM3_SR1=0;//这步不能漏掉,否则会连续进入中断程序}编译下载后就可以看到LED1、LED2、LED3在不停闪耀,而且是LED1闪耀两次LED2才闪耀一次,LED2闪耀两次LED3才闪耀一次。验证了我们的定时器正常工作了例程三、8位基本定时器TIM4TIM4简介该定时器由一个带可编程预分频器的8位可自定重载的向上计数器组成,它可以用来作为时基发生器,具有溢出中断功能。本例程也是利用到这个功能。TIM4的主要功能8位向上计数的自动重载计数器3位可编程的预分频器(可在运行中修改)中断产生TIM4的框图TIM4的时钟选择该定时器的时钟源是内部时钟f_master。该时钟源直接连接到CK_PSC时钟,CK_PSC时钟通过预分频器分频后给定时器提供CK_CNT时钟预分频器预分频器是基于由一个3位寄存器来控制的一个7位计数器。由于该控制寄存器是带缓冲的所以它可以再系统运行中被修改。可以分频计数器的时钟频率为1到128之间的2的任意次幂。简要说明:因为这个定时器的最大分频系数才只有128,就算分频128后还是相当高的频率,不善于我们观察LED的状态,所以我们通过设置CLK_CKDIVR的寄存器设置HIS输出为2M的f_master我们采用的是2M内部时钟,所以CK_PSC=2M,经过128分频后为CK_CNT为15.625k,也就是0.064ms,所以就算ARR最大时,定时的时间也才10几个ms,不便于我们观察。所有我们在中断服务程序中记录一定的次数才让LED改变状态一次相比之下这个定时器的功能和操作都比较简单,我们的例程就是实现之前的功能,在定时器