news 2026/4/22 23:12:49

STM32定时中断学习笔记

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32定时中断学习笔记

TIM定时中断

    • TIM简介
      • 时基单元
    • 定时器类型
      • 基本定时器
        • 主模式触发DAC
      • 通用计时器
        • 输入
        • 定时器级联
      • 高级计时器
    • 定时中断基本结构
      • 预分频器时序
      • 计数器时序
      • 计数器预装时序
        • 无预装时序
        • 有预装时序
    • RCC时钟树
  • 代码—定时器定时中断
  • 代码—定时器外部中断

TIM简介


  • TIM(Timer计时器)
  • 定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断
  • 16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时
  • 不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能
  • 根据复杂度和应用场景分为了高级定时器、通用定时器、基本定时器三种类型

时基单元


计数器:用于执行计数定时的一个寄存器,每接收一次时钟信号,计数器加一
预分频器:对计数器的时钟进行分频,使计数更加灵活,原理是预分频器可以对时钟脉冲进行整合,将多个脉冲整合为一个脉冲输出给计数器
自动重装寄存器:用于设置申请中断值

  • 定时器中断时间最大值=1/(72Mhz/65535/65535)=59.65s

定时器类型


  • STM32F103C8T6定时器资源:TIM1,TIM2,TIM3,TIM4

基本定时器



预分频器:对输入的频率提前进行分频操作,输出频率 = 输入频率 / 分频系数,预分频器值 = 分频系数 - 1,最大预分频器值为65535 + 1 = 65536
计数器:对预分频后的计数时钟进行计数,每出现一个上升沿,计数器值加一,最大计数值65535
自动重装载寄存器:存储设定的计数目标值,当计数器计数到目标值时,产生中断信号,并且清零计数器,计数器自动开启下一次计时

主模式触发DAC

为了每隔一段时间触发DAC,可以通过主模式将事件更新映射到TRGO后触发DAC

通用计时器


  • 支持向下计数模式,即为从重装值开始,向下自减,到0之后申请中断并返回重装值循环

  • 支持中央对齐模式模式,即为从重装值开始,先向上自增到重装值并申请中断,然后向下自减到0后,再申请中断,依次循环

  • 编码器接口可读取正交编码器波形,可通过TRGO映射

输入
  • 可选的外部时钟(TIMx_ETR)
  • ITRx(其他定时器)
  • TIMx_CH1引脚边沿
  • CH1引脚(T12FP1),CH2引脚(T12FP2)
定时器级联

可通或TIMx的事件更新映射到TRGO,内部触发连接输出到其他定时器,实现定时器级联

  • ITR与定时器的连接关系

高级计时器


  • 重复次数计数器:可配置周期进行事件更新与事件中断
  • DTG(Dead Time Generate)死区生成电路,用于防止直通
  • 输出互补,可输出一对互补的PWM波形
  • 刹车输入:产生故障可自动切断输出

定时中断基本结构



中断输出控制中断输出的允许位

预分频器时序


计数器寄存器中的FC:ARR自动重装值标志位
预分频缓冲器(影子寄存器):当进行分频值改变操作时,会等到当前计数周期完成后才产生改变

计数器时序


CNT_EN:计数器使能,高电平启动
更新中断标志位(UIF):置 1 申请中断,需要在中断程序中手动清零

计数器预装时序


  • 通过设置ARPE位进行配置
无预装时序


计数到最新设定的指定值(自动加载寄存器值)后直接更新开始下一轮计数

有预装时序


受影子寄存器作用,重装值在更改后不会立即生效,而是在计数器计数到旧重装值后的下一个周期才生效。

RCC时钟树

  • 四个振荡源:内部8Mhz高速RC振荡器,外部4-16Mhz高数石英晶体振荡器,外部32.768Khz低速晶振(供RTC时钟使用),内部40Khz低速RC振荡器(看门狗时钟)
  • ST配置: 先启动内部8Mhz内部时钟,接着外部时钟通过锁相环(PLLMUL)进行倍频到指定频率,最后设定该频率为系统频率
  • 时钟安全系统(CSS) :监测外部时钟状态,如果失效,切换为内部时钟

代码—定时器定时中断

  • 函数
TIM_DeInit(TIM_TypeDef*TIMx);//恢复缺省配置/*时基单元*/TIM_TimeBaseInit(TIM_TypeDef*TIMx,TIM_TimeBaseInitTypeDef*TIM_TimeBaseInitStruct);//时基单元初始化TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef*TIM_TimeBaseInitStruct);//结构体变量赋默认值/*运行控制*/TIM_Cmd(TIM_TypeDef*TIMx,FunctionalState NewState);//计数器使能/*中断输出控制*/TIM_ITConfig(TIM_TypeDef*TIMx,uint16_tTIM_IT,FunctionalState NewState);//使能中断输出信号(中断输出控制)/*时钟源选择*/TIM_InternalClockConfig(TIM_TypeDef*TIMx);//内部时钟选择TIM_ITRxExternalClockConfig(TIM_TypeDef*TIMx,uint16_tTIM_InputTriggerSource);//选择ITRx其他定时器时钟TIM_TIxExternalClockConfig(TIM_TypeDef*TIMx,uint16_tTIM_TIxExternalCLKSource,uint16_tTIM_ICPolarity,uint16_tICFilter);//选择TIx捕获通道时钟,TIM_TIxExternalCLKSource(选择TIx具体引脚),TIM_ICPolarity(选择级性),ICFilter(选择滤波器)TIM_ETRClockMode1Config(TIM_TypeDef*TIMx,uint16_tTIM_ExtTRGPrescaler,uint16_tTIM_ExtTRGPolarity,uint16_tExtTRGFilter);//选择ETR通过外部模式1输入的时钟,TIM_ExtTRGPrescaler(外部触发预分频器),极性,滤波器TIM_ETRClockMode2Config(TIM_TypeDef*TIMx,uint16_tTIM_ExtTRGPrescaler,uint16_tTIM_ExtTRGPolarity,uint16_tExtTRGFilter);//选择ETR通过外部模式2输入的时钟,同上TIM_ETRConfig(TIM_TypeDef*TIMx,uint16_tTIM_ExtTRGPrescaler,uint16_tTIM_ExtTRGPolarity,uint16_tExtTRGFilter);//配置ETR引脚的预分频器,极性,滤波器参数/*其他配置*/TIM_PrescalerConfig(TIM_TypeDef*TIMx,uint16_tPrescaler,uint16_tTIM_PSCReloadMode);//预分频值配置TIM_CounterModeConfig(TIM_TypeDef*TIMx,uint16_tTIM_CounterMode);//计数器计数模式配置TIM_ARRPreloadConfig(TIM_TypeDef*TIMx,FunctionalState NewState);//自动重装器预装功能配置TIM_SetCounter(TIM_TypeDef*TIMx,uint16_tCounter);//计数器写入计数值TIM_SetAutoreload(TIM_TypeDef*TIMx,uint16_tAutoreload);//自动重装器写值TIM_GetCounter(TIM_TypeDef*TIMx);//获取当前计数器的值TIM_GetPrescaler(TIM_TypeDef*TIMx);//获取当前预分频器值
  • TIMER.c
#include"stm32f10x.h"// Device headervoidTIMER_Init(void){/*开启时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);/*选择内部时钟*/TIM_InternalClockConfig(TIM2);/*配置时基单元*/TIM_TimeBaseInitTypeDef TIM_TimerBaseInitStructure;TIM_TimerBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//指定时钟分频TIM_TimerBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//设置计数模式为向上计数TIM_TimerBaseInitStructure.TIM_Period=10000-1;//ARR自动重装器值TIM_TimerBaseInitStructure.TIM_Prescaler=7200-1;//PSC预分频器值,定时频率 = 72M/(PSC + 1)/(ARR + 1)TIM_TimerBaseInitStructure.TIM_RepetitionCounter=0;//重复计数器值,用于高级计数器TIM_TimeBaseInit(TIM2,&TIM_TimerBaseInitStructure);/*使能中断*/TIM_ClearFlag(TIM2,TIM_FLAG_Update);//手动清除更新中断标志位,避免刚初始化完就进中断TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);/*NVIC配置*/NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;//NVIC通道选择NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//开启通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;//响应优先级NVIC_Init(&NVIC_InitStructure);/*启动定时器*/TIM_Cmd(TIM2,ENABLE);}/* void TIM2_IRQHandler(void){ if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET){ //获取中断标志位 TIM_ClearITPendingBit(TIM2, TIM_IT_Update); //清除中断标志位 } } */
  • main.c
#include"stm32f10x.h"// Device header#include"TIMER.h"uint16_tNum;intmain(void){/*模块初始化*/TIMER_Init();while(1){}}voidTIM2_IRQHandler(void){if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET){//获取中断标志位Num++;TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//清除中断标志位}}

代码—定时器外部中断

  • TIMER.c
#include"stm32f10x.h"// Device headervoidTIMER_Init(void){/*开启时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//启动GPIOA时钟/*配置GPIO*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);/*选择外部时钟*/TIM_ETRClockMode2Config(TIM2,TIM_ExtTRGPSC_OFF,TIM_ExtTRGPolarity_NonInverted,0x00);//ETR外部时钟模式2配置/*配置时基单元*/TIM_TimeBaseInitTypeDef TIM_TimerBaseInitStructure;TIM_TimerBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//指定时钟分频TIM_TimerBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//设置计数模式为向上计数TIM_TimerBaseInitStructure.TIM_Period=10-1;//ARR自动重装器值TIM_TimerBaseInitStructure.TIM_Prescaler=1-1;//PSC预分频器值,定时频率 = 72M/(PSC + 1)/(ARR + 1)TIM_TimerBaseInitStructure.TIM_RepetitionCounter=0;//重复计数器值,用于高级计数器TIM_TimeBaseInit(TIM2,&TIM_TimerBaseInitStructure);/*使能中断*/TIM_ClearFlag(TIM2,TIM_FLAG_Update);//手动清除更新中断标志位,避免刚初始化完就进中断TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);/*NVIC配置*/NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;//NVIC通道选择NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//开启通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;//响应优先级NVIC_Init(&NVIC_InitStructure);/*启动定时器*/TIM_Cmd(TIM2,ENABLE);}uint16_tTimer_GetCounter(void){returnTIM_GetCounter(TIM2);}/* void TIM2_IRQHandler(void){ if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET){ //获取中断标志位 TIM_ClearITPendingBit(TIM2, TIM_IT_Update); //清除中断标志位 } } */
  • main.c
#include"stm32f10x.h"// Device header#include"TIMER.h"uint16_tNum;intmain(void){/*模块初始化*/TIMER_Init();while(1){}}voidTIM2_IRQHandler(void){if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET){//获取中断标志位Num++;TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//清除中断标志位}}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/22 23:12:09

二叉树 (1)

1.节点的结构typedef int BTDatatype; typedef struct BineryTreeNode {BTDatatype val;struct BineryTreeNode* left;struct BineryTreeNode* right; }BTnode;2.节点的创建BTnode* BuyNode(int x) {BTnode* newnode (BTnode*)malloc(sizeof(BTnode));if (newnode NULL){perr…

作者头像 李华
网站建设 2026/4/22 23:10:32

别再傻傻用加法器了!Verilog里数1的个数,这个分治写法能省多少资源?

Verilog高效数1算法:从加法器到分治法的资源优化实战 在FPGA和ASIC设计中,资源优化永远是工程师们绕不开的话题。当我们面对一个看似简单的任务——统计二进制数中1的个数时,新手往往会直接想到用加法器逐位累加。但真正经历过流片痛点的工程…

作者头像 李华
网站建设 2026/4/22 23:08:40

为什么东西而喷,这是个问题,大问题。

本文手搓多年前,我以不亚于现在的力量喷过。当时有人留言,说“你是不是感觉你很优越”,还有人留言说“你这么牛怎么不去上街啊”。我回复说“我不敢”。然后他说“你这个人渣”。我用了多年才醒悟到这一层:你喷的,最终…

作者头像 李华
网站建设 2026/4/22 23:07:45

跨维智能DexWorldModel斩获榜首,世界模型真正的考场在机器人执行里

允中 发自 凹非寺量子位 | 公众号 QbitAIVLA与世界模型:一次被行业自己推着走的范式迁移今年4月,具身智能领域发生了一件看起来不大、但意味深长的事。Generalist AI——也就是PaLM-E、RT-2背后那批人创办的明星公司——发布了GEN-1,并在三个…

作者头像 李华