当前位置: 首页 > news >正文

stm32定时器

定时器介绍

软件定时
缺点:不精确、占用 CPU 资源

还记得以前在开发C51的时候,经常使用stc助手生成的定时代码,形如:

void Delay500ms() //@11.0592MHz
{unsigned char i, j, k;_nop_();i = 4;j = 129;k = 119;do{do{while (--k);} while (--j);} while (--i);
}
定时器工作原理:
使用精准的时基,通过硬件的方式,实现定时功能。定时器核心就是计数器。

定时器分类

基本定时器(TIM6,TIM7)没有输入输出通道,常用作时基,即定时功能

通用定时器(TIM2~TIM5)具有多路独立通道,可用于输入捕获/输出比较,也可用作时基

高级定时器(TIM1,TIM8)除具备通用定时器所有功能外,还具备带死区控制的互补信号输出刹车输入等功能(可用于电机控制、数字电源设计等)

STM32F103C8T6 定时器资源:
所以32 STM32F103C8T6 的定时器资源是:一个高级定时器TIM1和三个通用定时器TIM2,3,4!
通用定时器介绍:

可见,和51/52相比,stm32的定时器复杂得多

定时器计数模式

定时器时钟源

下图是手册P56,主要关注红圈部分

根据上图的原理,可以推出下面的公式,十分重要!!!

Tout = 设定时间 (单位秒s)

Tclk = 通过预分频后输出的TIMxCLK(上图右侧红线)

PSC = 预分频系数 (+1是因为计算机是从0开始的)

ARR = 自动重装载值(+1是因为计算机是从0开始的)

例如:要定时500ms,则可以在配置定时器时使用: PSC = 7199,ARR = 4999,TClk = 72M(72 000 000)(有多种组合)

((7199+1)/72000000)/(4999+1)=0.5s

使用定时器中断实现LED灯的状态反转 

需求:使用定时器中断方法,每 500ms 翻转一次 LED1 灯状态。
1. RCC 配置
2. LED1 灯配置
3. 时钟数配置
4. TIM2 配置
打开CubeMX,先进行惯例配置

配置时钟(上图)最右侧一列的“APB1 Timer clocks”和“APB2 Timer clocks”就是刚刚提到的计算公式中的Tclk,单位是MHz,此处就是Tclk = 72MHz,具体详情查看上图的时钟原理图

配置PB8(LED1)为GPIO_out模式且初始值为HIGH

Timer 配置

1. 在左侧选择Timers选项,此处选择通用定时器Timer2(Timer1是高级定时器,故不选用)

第一个参数就是预分频器,第三个参数就是ARR:

 回顾刚刚的计算公式:

要定时500ms,则可以在配置定时器时使用: PSC = 7199,ARR = 4999,TClk = 72M(72 000 000)(可选其他多种组合)

同时打开第五个参数的自动重载!(因为希望LED连续不断的翻转状态,而不是翻转一次就结束)

进行如下设置:(目前可以只关心 Clock Source),在设置为Internal Clock后,下方会自动弹出NVIC界面,选择打开中断。

打开Keil

此时自动弹出Keil工程,记得先编译一下,养成良好编程习惯!

通过 stm32f1xx_it.c --> TIM2_IRQHandler() --> HAL_TIM_IRQHandler() --> 然后就和之前不大一样了,之前进行到这里就会出现一个 weak 类型的可重写中断处理函数,但此时是一个巨长无比的函数:

void HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim)
{/* Capture compare 1 event */if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC1) != RESET){if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC1) != RESET){{__HAL_TIM_CLEAR_IT(htim, TIM_IT_CC1);htim->Channel = HAL_TIM_ACTIVE_CHANNEL_1;/* Input capture event */if ((htim->Instance->CCMR1 & TIM_CCMR1_CC1S) != 0x00U){
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)htim->IC_CaptureCallback(htim);
#elseHAL_TIM_IC_CaptureCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}/* Output compare event */else{
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)htim->OC_DelayElapsedCallback(htim);htim->PWM_PulseFinishedCallback(htim);
#elseHAL_TIM_OC_DelayElapsedCallback(htim);HAL_TIM_PWM_PulseFinishedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;}}}/* Capture compare 2 event */if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC2) != RESET){if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC2) != RESET){__HAL_TIM_CLEAR_IT(htim, TIM_IT_CC2);htim->Channel = HAL_TIM_ACTIVE_CHANNEL_2;/* Input capture event */if ((htim->Instance->CCMR1 & TIM_CCMR1_CC2S) != 0x00U){
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)htim->IC_CaptureCallback(htim);
#elseHAL_TIM_IC_CaptureCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}/* Output compare event */else{
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)htim->OC_DelayElapsedCallback(htim);htim->PWM_PulseFinishedCallback(htim);
#elseHAL_TIM_OC_DelayElapsedCallback(htim);HAL_TIM_PWM_PulseFinishedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;}}/* Capture compare 3 event */if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC3) != RESET){if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC3) != RESET){__HAL_TIM_CLEAR_IT(htim, TIM_IT_CC3);htim->Channel = HAL_TIM_ACTIVE_CHANNEL_3;/* Input capture event */if ((htim->Instance->CCMR2 & TIM_CCMR2_CC3S) != 0x00U){
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)htim->IC_CaptureCallback(htim);
#elseHAL_TIM_IC_CaptureCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}/* Output compare event */else{
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)htim->OC_DelayElapsedCallback(htim);htim->PWM_PulseFinishedCallback(htim);
#elseHAL_TIM_OC_DelayElapsedCallback(htim);HAL_TIM_PWM_PulseFinishedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;}}/* Capture compare 4 event */if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC4) != RESET){if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC4) != RESET){__HAL_TIM_CLEAR_IT(htim, TIM_IT_CC4);htim->Channel = HAL_TIM_ACTIVE_CHANNEL_4;/* Input capture event */if ((htim->Instance->CCMR2 & TIM_CCMR2_CC4S) != 0x00U){
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)htim->IC_CaptureCallback(htim);
#elseHAL_TIM_IC_CaptureCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}/* Output compare event */else{
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)htim->OC_DelayElapsedCallback(htim);htim->PWM_PulseFinishedCallback(htim);
#elseHAL_TIM_OC_DelayElapsedCallback(htim);HAL_TIM_PWM_PulseFinishedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;}}/* TIM Update event */if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_UPDATE) != RESET){if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_UPDATE) != RESET){__HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)htim->PeriodElapsedCallback(htim);
#elseHAL_TIM_PeriodElapsedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}}/* TIM Break input event */if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_BREAK) != RESET){if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_BREAK) != RESET){__HAL_TIM_CLEAR_IT(htim, TIM_IT_BREAK);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)htim->BreakCallback(htim);
#elseHAL_TIMEx_BreakCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}}/* TIM Trigger detection event */if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_TRIGGER) != RESET){if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_TRIGGER) != RESET){__HAL_TIM_CLEAR_IT(htim, TIM_IT_TRIGGER);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)htim->TriggerCallback(htim);
#elseHAL_TIM_TriggerCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}}/* TIM commutation event */if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_COM) != RESET){if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_COM) != RESET){__HAL_TIM_CLEAR_IT(htim, TIM_FLAG_COM);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)htim->CommutationCallback(htim);
#elseHAL_TIMEx_CommutCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}}
}

但是,我们现在只关注:如果定时时间到了之后,定时器会做什么的函数

因此,可以找到这样一个函数:HAL_TIM_PeriodElapsedCallback(htim);

对于这个函数进行跳转,终于出现了可以重写的中断处理函数:

 然后在main.c中重写这个函数:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM2){ //注意,htim是一个结构体指针,所以对于结构体中成员变量的访问要用“->”HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8);}
}

经查找,要在main函数中添加一句,启动定时器:(当然,也是在生成的初始化之后)

HAL_TIM_Base_Start_IT(&htim2);

相关文章:

  • scDEA一键汇总12种单细胞差异分析方法 DESeq2、edgeR、MAST、monocle、scDD、Wilcoxon
  • K8S Storage
  • PYTorch训练和推理 指定GPU
  • docker swarm 集群创建
  • Go语言学习04~05 函数和面向对象编程
  • c++算法学习笔记 (15) 质数
  • 新手如何入门电子电路
  • 我的VSCode配置和常见插件
  • 探秘开源隐语:架构深度剖析与隐私计算技术之旅
  • 解读 Xend Finance:向 RWA 叙事拓展,构建更具包容性的 DeFi 体系
  • c++类型转换(持续更新)
  • 七仔充电桩平台 二轮电动自行车 四轮汽车 云快充1.5 云快充1.6
  • #鸿蒙生态创新中心#揭幕仪式在深圳湾科技生态园举行
  • 点云从入门到精通技术详解100篇-点云采样理论知识详解
  • C# 右键快捷菜单(上下文菜单)的两种实现方式
  • .pyc 想到的一些问题
  • “Material Design”设计规范在 ComponentOne For WinForm 的全新尝试!
  • Angular6错误 Service: No provider for Renderer2
  • axios 和 cookie 的那些事
  • CentOS7简单部署NFS
  • Debian下无root权限使用Python访问Oracle
  • ES6系列(二)变量的解构赋值
  • iOS | NSProxy
  • JavaScript函数式编程(一)
  • KMP算法及优化
  • Linux下的乱码问题
  • MYSQL 的 IF 函数
  • rc-form之最单纯情况
  • Spark in action on Kubernetes - Playground搭建与架构浅析
  • Work@Alibaba 阿里巴巴的企业应用构建之路
  • 笨办法学C 练习34:动态数组
  • 力扣(LeetCode)357
  • 聊聊redis的数据结构的应用
  • 免费小说阅读小程序
  • 扑朔迷离的属性和特性【彻底弄清】
  • 微信小程序:实现悬浮返回和分享按钮
  • 我建了一个叫Hello World的项目
  • 新手搭建网站的主要流程
  • 阿里云ACE认证之理解CDN技术
  • 正则表达式-基础知识Review
  • ​一、什么是射频识别?二、射频识别系统组成及工作原理三、射频识别系统分类四、RFID与物联网​
  • #Linux(帮助手册)
  • %3cli%3e连接html页面,html+canvas实现屏幕截取
  • (14)目标检测_SSD训练代码基于pytorch搭建代码
  • (9)YOLO-Pose:使用对象关键点相似性损失增强多人姿态估计的增强版YOLO
  • (二十五)admin-boot项目之集成消息队列Rabbitmq
  • (附源码)spring boot校园健康监测管理系统 毕业设计 151047
  • (附源码)计算机毕业设计SSM基于java的云顶博客系统
  • (南京观海微电子)——I3C协议介绍
  • (转)c++ std::pair 与 std::make
  • (转)visual stdio 书签功能介绍
  • .chm格式文件如何阅读
  • .NET CORE 3.1 集成JWT鉴权和授权2
  • .Net Remoting常用部署结构
  • .NET 实现 NTFS 文件系统的硬链接 mklink /J(Junction)