定时器是嵌入式系统中的关键外设之一,它可以用于生成精确的延时、周期性中断、PWM波形生成等功能。在STM32F1系列单片机中,定时器不仅能为系统提供精确的时钟,还支持外部事件的捕获以及信号输出。
对于定时器的功能,我们可以通过一个生活中非常常见的例子来形象地描述:微波炉的定时器。
想象你正在使用微波炉加热食物。在微波炉里,定时器的作用就是帮助你控制食物加热的时间。当你设置了加热时间后,定时器会启动,并开始计时。定时器的工作原理就像是一个计时器:它从你设定的时间开始倒计时,直到时间到达你设定的值,然后它会触发一个事件(通常是响铃或自动停止加热)来通知你加热已完成。
STM32F1系列单片机提供了多种类型的定时器,包括基本定时器、通用定时器和高级定时器。
STM32F1系列芯片内部集成了8个16位定时器:2个基本定时器、4个通用定时器、2个高级定时器。其中TIM6和TIM7为基本定时器,TIM2到TIM5为通用定时器,TIM1和TIM8为高级定时器。基本定时器功能比较单一,只能提供简单的延时功能。通用定时器则在基本定时器的功能基础上,增加了如PWM输出、输入捕获等功能。高级定时器则是在通用定时器的功能基础上,增加了带死区控制和紧急刹车功能,其适用于电机控制等需要高精度时序的场合。
定时器种类 |
计数器计数方式 |
分频器 |
输入/输出通道数 |
有无互补输出 |
基本定时器 |
向上计数 |
16位分频器 |
无 |
无 |
通用定时器 |
向上、向下、向上/向下计数 |
16位分频器 |
4 |
无 |
高级定时器 |
向上、向下、向上/向下计数 |
16位分频器 |
4 |
有 |
STM32基本定时器TIM6和TIM7是互相独立的,不共享任何资源,各包含一个16位自动装载计数器,由各自的可编程预分频器驱动。它们可以作为通用定时器提供时间基准,特别地可以为数模转换器(DAC)提供时钟。实际上,它们在芯片内部直接连接到DAC并通过触发输出直接驱动DAC。
在STM32F103系列微控制器中,基本定时器仅支持一种计数模式,即向上计数模式。在此模式下,计数器从0开始累加计数直至达到自动重装载寄存器(ARR)设定的值,这一过程会触发一个计数器溢出事件。该溢出事件不仅可以触发中断或直接请求DMA传输,同时还会使计数器重新从0开始新一轮的计数。每当计数器发生溢出时,根据相关配置寄存器的设定,可以产生更新事件,进而触发更新中断或DMA请求。
定时器的硬件结构由多个重要模块组成,包括计数器、自动重载寄存器(ARR)、预分频器、计数器模式选择、输出比较寄存器等。这些模块共同工作,实现定时器的不同功能。
1.时钟源
定时器实现计数功能依赖于一个稳定的时钟源。在STM32F1的基本定时器中,其时钟源TIMx_CLK仅能来源于内部时钟CK_INT。此内部时钟由APB1预分频器提供。具体而言,如果APB1预分频系数等于1,则定时器时钟频率与APB1总线的频率相同;否则,定时器时钟频率将是APB1总线频率的两倍。系统默认情况下APB1的时钟频率是72MHz。
2.预分频器
预分频器可以以系数介于1至65536之间的任意数值对计数器时钟分频。它是通过一个16位寄存器(TIMx_PSC)的计数实现分频。因为TIMx_PSC控制寄存器具有缓冲,可以在运行过程中改变它的数值,新的预分频数值将在下一个更新事件时起作用。
3.计数器时钟
定时器时钟经过预分频器(PSC)处理后生成的信号,即计数时钟(CK_CNT),用于驱动计数器进行计数操作。具体计算方法为:CK_CNT等于定时器的输入时钟频率(TIMxCLK)除以(PSC值加1)。换言之,通过调整预分频器的设置,可以改变计数时钟的频率,从而精确控制计数器的计数速率。这一机制允许开发者根据实际需求灵活调整定时器的操作周期,确保其适应各种应用场景下的时间管理要求。公式表达如下:CK_CNT = TIMxCLK/(PSC + 1)。
4.计数器
计数器(CNT)是一个16位的计数器,专门设计用于向上计数,其最大计数值可达65535。当计数器的值达到自动重装载寄存器(ARR)设定的数值时,会触发一个更新事件,随后计数器将被清零并重新开始计数。这一过程由预分频器输出的计数时钟(CK_CNT)驱动。要启用计数器的计数功能,需通过设置定时器控制寄存器1(TIMx_CR1)中的计数器使能位(CEN)来激活计数器。
5.自动重载寄存器
自动重装载寄存器(ARR)是一个16位的寄存器,用于存储计数器能够计数的最大数值。该寄存器采用了预加载机制,这意味着在进行读写操作时,实际上是在访问一个预加载寄存器,而非直接操作ARR本身。根据TIMx_CR1寄存器中的自动重装载预加载使能位(ARPE)的状态,写入预加载寄存器的内容可以选择立即生效或延迟至下次更新事件发生时才传输到其影子寄存器中。当TIMx_CR1寄存器中的更新禁止位(UDIS)设置为‘0’时,每当计数器达到其溢出值即自动重装载寄存器设定的数值时,硬件会自动生成一个更新事件。
6.控制器
控制器单元主要负责定时器的复位、使能及计数等基础功能的管理。特别地,基本定时器还具备专门的功能,用于触发数字模拟转换器(DAC)的转换过程。通过这一机制,控制器单元不仅能够确保定时器操作的精确性和可靠性,同时也支持与其他外设的有效协同工作,如在需要定时触发DAC转换的应用场景中提供精准的时间控制。
实验:使用基本定时器实现200ms的定时,每200ms翻转一下LED灯的状态
1.配置步骤:
2.编写tim_drv.c文件
#include "tim_drv.h"
void TIM6_Init(uint16_t psc,uint16_t arr)
{
//使能TIM6时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,ENABLE);
//初始化TIM6
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_Prescaler=psc; //预分频系数
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseInitStruct.TIM_Period=arr; //自动重装载值
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1; //时钟分割
TIM_TimeBaseInit(TIM6, &TIM_TimeBaseInitStruct);
//配置TIM中断
TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE);
//NVIC配置
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel=TIM6_IRQn; //中断通道号
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1; //抢占优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority=1; //子优先级
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStruct);
//定时器使能
TIM_Cmd(TIM6,ENABLE);
}
void TIM6_IRQHandler(void)
{
if(TIM_GetITStatus(TIM6,TIM_IT_Update)==SET)
{
uint8_t state = GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_8);
GPIO_WriteBit(GPIOA,GPIO_Pin_8,(BitAction)!state);
}
TIM_ClearITPendingBit(TIM6,TIM_IT_Update);
}
3.编写tim_drv.h文件
#ifndef __TIM_DRV_H__
#define __TIM_DRV_H__
#include "stm32f10x.h"
void TIM6_Init(uint16_t psc,uint16_t arr);
#endif
4.编写main.c文件
#include "led_drv.h"
#include "systick.h"
#include "tim_drv.h"
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断分组2
LED_Init();//初始化LED
TIM6_Init(7200-1,2000-1); //200ms定时
while (1)
{
}
}