相信学过51单片机的小伙伴们使用过定时刷新数码管吧,那也一定想过,我们在STM32中也想要实现定时刷新数码管,这该怎么实现呢?下面小编就带大家走进STM32的定时器模块吧!
一、什么是定时器
定时器是一种计时的工具,它具有延时、频率测量、PWM输出、电机控制及编码接口等功能。
STM32F103微控制器内部集成了多个可编程定时器,可以分为基本定时器(TIM6和TIM7)、通用定时器(TIM2~TIM5)和高级定时器(TIM1、TIM8)3种类型。从功能上看,基本定时器的功能是通用定时器的子集,而通用定时器的功能又是高级定时器的一个子集。
二、基本定时器
1、相关概念
在STM32F103中,基本定时器TIM6、TIM7各自都包含一个16位自动装载计数器,能够通过各自的可编程预分频器驱动,这两个定时器相互独立,不共享任何资源。
2、主要功能
- (1)16位自动重载累加计数器
- (2)16位可编程(可实时修改)预分频器
- (3)触发DAC同步电路
- (4)能够咱更新事件(计数器溢出)时产生DMA/中断请求
3、相关寄存器
■ TIM6 和TIM7 控制寄存器 1(TIMx_CR1)
■ TIM6 和TIM7 控制寄存器 2(TIMx_CR2)
■ TIM6 和TIM7 DMA/中断使能寄存器(TIMx_DIER)
■ TIM6 和TIM7 状态寄存器(TIMx_SR)
■ TIM6 和TIM7 事件产生寄存器(TIMx_EGR)
■ TIM6 和TIM7 计数器(TIMx_CNT)
■ TIM6 和TIM7 预分频器(TIMx_PSC)
■ TIM6 和TIM7 自动重装载寄存器(TIMx_ARR)
三、函数解析
1、清除中断标志位TIM_ClearFlag函数
![在这里插入图片描述](https://img-blog.csdnimg.cn/284d14db212c43e487ed389152a587a6.png)
2、定时器使能失能设置TIM_Cmd函数
![在这里插入图片描述](https://img-blog.csdnimg.cn/24050a92c6a64a4ebed2b3ac0f8ccf68.png)
3、定时器初始化TIM_TimeBaseInit函数
![在这里插入图片描述](https://img-blog.csdnimg.cn/e2ccc52b3580407490a1eaa63353b8da.png)
定时器时基单元配置信息结构体TIM_TimeBaseInitTypeDef
typedef struct
{
uint16_t TIM_Prescaler;
uint16_t TIM_CounterMode;
uint16_t TIM_Period;
uint16_t TIM_ClockDivision;
uint8_t TIM_RepetitionCounter; //仅高级定时器TIM1和TIM8有效
} TIM_TimeBaseInitTypeDef;
- TIM_Period:
设置在下一个更新事件装入活动的自动重装载寄存器周期的值。它的取值必须在 0x0000 和0xFFFF 之间。
- TIM_Prescaler:
设置用来作为 TIMx 时钟频率除数的预分频值。它的取值必须在 0x0000 和 0xFFFF 之间。
- TIM_ClockDivision:
配置时钟分割,具体值见下表:
- TIM_CounterMode :
选择时钟模式,具体选项见下表:
四、示例
小明突发奇想,打算利用STM32F103ZET6开发板做出一个实时时钟出来,其中利用定时器计时并且利用定时器来刷新数码管。
1、基本定时器6(TIM6)配置函数
/*
* @brif intialization of time(定时器初始化)
* @para none
* @reval none
*/
void time6_init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//打开Time6的APB1时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,ENABLE);
/* 定时器的初始化以及设置 */
//设置自动装载周期的值 寄存器的值为周期的值-1
TIM_TimeBaseStructure.TIM_Period = 360-1;
//设置预分频系数 预分频寄存器的值为分频系数-1
TIM_TimeBaseStructure.TIM_Prescaler = 200-1;
//设置时钟分割 TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
//时钟设置为向上计数模式
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM6,&TIM_TimeBaseStructure);
//清楚TIMx的中断待处理位 即TIMx的中断源
TIM_ClearFlag(TIM6,TIM_FLAG_Update);
/* 设置参数并打开中断*/
TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE);
//设置使能或者失能外设
TIM_Cmd(TIM6,ENABLE);
/* 设置NVIC参数 即优先级、打开中断 */
NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn;//指定终端通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//配置抢占式中断优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//配置响应式中断优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//设置成使能中断
NVIC_Init(&NVIC_InitStructure);
}
2、基本定时器7(TIM7配置函数)
/*
* @brif intialization of time(定时器初始化)
* @para none
* @reval none
*/
void time7_init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//打开Time6的APB1时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7,ENABLE);
/* 定时器的初始化以及设置 */
//设置自动装载周期的值 寄存器的值为周期的值-1
TIM_TimeBaseStructure.TIM_Period = 36000-1;
//设置预分频系数 预分频寄存器的值为分频系数-1
TIM_TimeBaseStructure.TIM_Prescaler = 2000-1;
//设置时钟分割 TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
//时钟设置为向上计数模式
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM7,&TIM_TimeBaseStructure);
//清楚TIMx的中断待处理位 即TIMx的中断源
TIM_ClearFlag(TIM7,TIM_FLAG_Update);
/* 设置参数并打开中断*/
TIM_ITConfig(TIM7,TIM_IT_Update,ENABLE);
//设置使能或者失能外设
TIM_Cmd(TIM7,ENABLE);
/* 设置NVIC参数 即优先级、打开中断 */
NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn;//指定终端通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//配置抢占式中断优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//配置响应式中断优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//设置成使能中断
NVIC_Init(&NVIC_InitStructure);
}
3、基本定时器6中断处理函数
void TIM6_IRQHandler(void)
{
TIM_ClearFlag(TIM6,TIM_IT_Update);//清楚中断标志位
refresh_segs();//刷新数码管
}
4、基本定时器7中断处理函数
void TIM7_IRQHandler(void)
{
TIM_ClearFlag(TIM7,TIM_IT_Update);
if(++second==60){//时钟的秒加1并且判断是否需要分钟加1
second=0;
if(++minute==60){//时钟的分加1并且判断是否需要时钟加1
minute=0;
if(++hour==24) hour=0;//时钟的时加1并且判断24小时是否过完
}
}
}
5、主函数
int main(void)
{
time6_init();
time7_init();
seg_GPIO_Init();
while(1){
segbuff[0] = hour/10;
segbuff[1] = hour%10+12;
segbuff[2] = minute/10;
segbuff[3] = minute%10+12;
segbuff[4] = second/10;
segbuff[5] = second%10;
}
}
五、附
1、基本定时器配置6、基本定时器7的配置
基本定时器6与基本定时器7在同一个函数中进行配置
/*
* @brif intialization of time(定时器初始化)
* @para none
* @reval none
*/
void time6_init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//打开Time6的APB1时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,ENABLE);
//打开Time7的APB1时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7,ENABLE);
/* 定时器的初始化以及设置 */
//设置自动装载周期的值 寄存器的值为周期的值-1
TIM_TimeBaseStructure.TIM_Period = 360-1;
//设置预分频系数 预分频寄存器的值为分频系数-1
TIM_TimeBaseStructure.TIM_Prescaler = 200-1;
//设置时钟分割 TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
//时钟设置为向上计数模式
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM6,&TIM_TimeBaseStructure);
//清楚TIMx的中断待处理位 即TIMx的中断源
TIM_ClearFlag(TIM6,TIM_FLAG_Update);
/* 设置参数并打开中断*/
TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE);
//设置使能或者失能外设
TIM_Cmd(TIM6,ENABLE);
/* 定时器的初始化以及设置 */
//设置自动装载周期的值 寄存器的值为周期的值-1
TIM_TimeBaseStructure.TIM_Period = 36000-1;
//设置预分频系数 预分频寄存器的值为分频系数-1
TIM_TimeBaseStructure.TIM_Prescaler = 2000-1;
//设置时钟分割 TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
//时钟设置为向上计数模式
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM7,&TIM_TimeBaseStructure);
//清楚TIMx的中断待处理位 即TIMx的中断源
TIM_ClearFlag(TIM7,TIM_FLAG_Update);
/* 设置参数并打开中断*/
TIM_ITConfig(TIM7,TIM_IT_Update,ENABLE);
//设置使能或者失能外设
TIM_Cmd(TIM7,ENABLE);
/* 设置NVIC参数 即优先级、打开中断 */
NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn;//指定终端通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//配置抢占式中断优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//配置响应式中断优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//设置成使能中断
NVIC_Init(&NVIC_InitStructure);
/* 设置NVIC参数 即优先级、打开中断 */
NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn;//指定终端通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//配置抢占式中断优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//配置响应式中断优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//设置成使能中断
NVIC_Init(&NVIC_InitStructure);
}
2、基本定时器的定时时长计算
- 定时时长T=(自动装载周期的值+1)(预分频系数+1)/72MHz;
例如,上面用于数码管刷新基本定时器6定时的时长T=360200/72000000=1/1000s;用于实时时钟时间刷新的基本定时器7的定时时长T=36000*2000/72000000=1s。
3、其他相关函数
假如大家想看相关模块的内容请点击链接前往:STM32-刷新数码管