STM32基于固件库学习笔记(4)(通用定时器)TIM3定时1S中断

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/weixin_43993734/article/details/101309289

STM32F103ZE系列定时器资源

  1. 有 TIME1 和 TIME8 等高级定时器,也有 TIME2~TIME5 等通用定时器,还有 TIME6 和TIME7 等基本定时器。
    通用定时器:是一个通过可编程预分频器(PSC)驱动的 16 位自动装载计数器(CNT)构成;可以用来测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和 PWM)等功能。
  2. STM3 的通用 TIMx (TIM2、TIM3、TIM4 和 TIM5)定时器功能包括:
     1)16 位向上、向下、向上/向下自动装载计数器(TIMx_CNT)。
     2)16 位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数为 1~65535 之间的任意数值。
     3)4 个独立通道(TIMx_CH1~4),这些通道可以用来作为:
      A.输入捕获
      B.输出比较
      C.PWM 生成(边缘或中间对齐模式)
      D.单脉冲模式输出
     4)可使用外部信号(TIMx_ETR)控制定时器和定时器互连(可以用 1 个定时器控制另外一个定时器)的同步电路。
     5)如下事件发生时产生中断/DMA:
      A.更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
      B.触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
      C.输入捕获
      D.输出比较
      E.支持针对定位的增量(正交)编码器和霍尔传感器电路
      F.触发输入作为外部时钟或者按周期的电流管理
  3. 定时器的时钟来源有 4 个:
      1)内部时钟(CK_INT)
      2)外部时钟模式 1:外部输入脚(TIx)
      3)外部时钟模式 2:外部触发输入(ETR)
      4)内部触发输入(ITRx):使用 A 定时器作为 B 定时器的预分频器(A 为 B 提供时钟)

使用定时器的一般步骤

注:
 因为本次是使用TIM3,所以所有代码都是配置TIM3; 
 本次使用到的库函数有:"stm32f10x_rcc.h"和"stm32f10x_rcc.c"时钟库
            "stm32f10x_tim.h"和"stm32f10x_tim.c"定时器库
            "misc.h"和"miscc"中断库
1)TIM3时钟使能
   TIM3 是挂载在 APB1 之下

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能

2)复位TIM3
  很多时候都没写这一步,不过建议还是写上。

TIM_DeInit(TIM6);//复位

3)初始化定时器参数 数, 设置 自动重装值 , 分频系数 ,计数方式
  主要通过使用定时器库函数中,定时器初始化函数

voidTIM_TimeBaseInit(TIM_TypeDef*TIMx,TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
//第一个参数是定位到某个定时器上,第二个参数是初始化结构体指针
typedef struct
{
uint16_t TIM_Prescaler;//设置分频系数
uint16_t TIM_CounterMode;//用来设置计数方式
uint16_t TIM_Period;//设置自动重载计数周期值
uint16_t TIM_ClockDivision;//是用来设置时钟分频因子
uint8_t TIM_RepetitionCounter;//重装载定时的次数,高级定时器才有用的
} TIM_TimeBaseInitTypeDef;
定时器定时时间计算公式

      T =   T I M P e r i o d + 1 ) ( T I M P r e s c a l e r + 1 )            T(一次中断的时间)=\frac { (设置的初值TIM_Period+1)*(设置的分频系数TIM_Prescaler+1) }{时 钟 频 率}
        时钟频率根据TIM_ClockDivision的值来计算,在APB1时钟线上初始为72MHZ
4)设置 TIM3_DIER 允许更新中断

 void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState)//第一个参数是定位到某个定时器上、第三个就是失能还是使能ENABLE或NABLE
  /*第二个用来指明我们使能的定时器中断的类型,定时器中断的类型有很多种,
     包括更新中断 TIM_IT_Update,触发中断 TIM_IT_Trigger,以及输入捕获中断等。*/

5)居然使用中断,就得初始化线上中断,设置触发条件等。

  //系统初始化就为2组
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  //设置 NVIC 中断分组 2: 2 位抢占优先级, 2 位响应优先级
  
  //中断优先级 NVIC 设置
  NVIC_InitTypeDef NVIC_ITDef_TIM6;
  NVIC_ITDef_TIM6.NVIC_IRQChannel = TIM6_IRQn; //TIM6 中断
  NVIC_ITDef_TIM6.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级 0 级
  NVIC_ITDef_TIM6.NVIC_IRQChannelSubPriority = 3; //从优先级 3 级
  NVIC_ITDef_TIM6.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道被使能
  NVIC_Init(&NVIC_ITDef_TIM6); //初始化 NVIC 寄存器

6)许允许TIM3工作能 ,也就是使能TIM3 。
  也就相当于开定时器。

void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState)//第一个参数是定位到某个定时器上、第二个就是失能还是使能ENABLE或NABLE

7 )编写中断服务函数。

  • 先看看获取中断标志位函数
//先判断这种中断是否使能,再判断标志位
 ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t)//直接判断标志位
 FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG)//主要有这几个中断标志位
 #define TIM_IT_Update/*TIM中断源*/  
 #define TIM_IT_CC1/*TIM捕获/比较1中断源*/
 #define TIM_IT_CC2/*TIM捕获/比较2中断源*/
 #define TIM_IT_CC3/*TIM捕获/比较3中断源*/
 #define TIM_IT_CC4/*TIM捕获/比较4中断源*/
 #define TIM_IT_Trigger/*TIM触发中断源*/ 
//判断定时器溢出中断方法:
 if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET){}
  • 清楚标志位函数
void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG)void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT)

注:使用的TIM_GetITStatus()函数判断标志位,就用TIM_ClearITPendingBit()函数清标志位。

  • 定时器中断函数格式
//定时器 3 中断服务程序
//TIM3_IRQHandler在“USART1_IRQHandler”固件库给好了的名字
void TIM3_IRQHandler(void) //TIM3 中断
{
  if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查 TIM3 更新中断发生与否
  {
    
    TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除 TIM3 更新中断标志 
  }
}

完整程序

/*
 主要实现LED间隔1s闪烁,其时间用定时器定时中断完成
*/
#include "stm32f10x.h"                  // Device header
//初始化LED灯 -> PB5推挽输出、高电平
void LED_Init_PB5(void)
{
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
  GPIO_InitTypeDef GPIO_ITDef_PB5;
  GPIO_ITDef_PB5.GPIO_Pin = GPIO_Pin_5;
  GPIO_ITDef_PB5.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出  
  GPIO_ITDef_PB5.GPIO_Speed = GPIO_Speed_2MHz;  
  GPIO_Init(GPIOB,&GPIO_ITDef_PB5);
  GPIO_SetBits(GPIOB,GPIO_Pin_5);// 置为高电平
}
void TIM6_Init(void)
{
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//挂载tim6时钟
  TIM_DeInit(TIM6);//复位  
  TIM_TimeBaseInitTypeDef TIM_TITDef_TIM6;
  TIM_TITDef_TIM6.TIM_Prescaler = 7199;//72MHz
  TIM_TITDef_TIM6.TIM_Period = 9999;// 1S
  TIM_TITDef_TIM6.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
  TIM_TITDef_TIM6.TIM_ClockDivision = TIM_CKD_DIV1;//自动重载计数周期值
  TIM_TimeBaseInit(TIM6,&TIM_TITDef_TIM6);
  
  TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE);//更新中断
  
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置 NVIC 中断分组 2:2 位抢占优先级,2 位响应优先级
 
  //中断优先级 NVIC 设置
  NVIC_InitTypeDef NVIC_ITDef_TIM6;
  NVIC_ITDef_TIM6.NVIC_IRQChannel = TIM6_IRQn; //TIM6 中断
  NVIC_ITDef_TIM6.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级 0 级
  NVIC_ITDef_TIM6.NVIC_IRQChannelSubPriority = 3; //从优先级 3 级
  NVIC_ITDef_TIM6.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道被使能
  NVIC_Init(&NVIC_ITDef_TIM6); //初始化 NVIC 寄存器

  TIM_Cmd(TIM6,ENABLE);//使能 TIM6
}
void TIM6_IRQHandler(void) //TIM6 中断
{
  if (TIM_GetITStatus(TIM6,TIM_IT_Update) != RESET) //检查 TIM6 更新中断发生与否
  {
    if(GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_5))//读取PB5当前状态
    {       
        GPIO_ResetBits(GPIOB,GPIO_Pin_5);// 置0
    }else {
       GPIO_SetBits(GPIOB,GPIO_Pin_5);// 置1
    }
    TIM_ClearITPendingBit(TIM6,TIM_IT_Update ); //清除 TIM6 更新中断标志
  }
}
int main(void)
{
  LED_Init_PB5();
  TIM6_Init();//1s
  while(1)
  {
   ;   
  }     
}

STM32F10x_StdPeriph_Lib_V3.5.0(官方固件库)
链接:STM32固件库使用手册的中文翻译版 提取码:4lkx

猜你喜欢

转载自blog.csdn.net/weixin_43993734/article/details/101309289