定时器中断及定时器产生PWM


《用CubeMX学习STM32》

注释 点击上面蓝字进入完整专栏,这个系列所有文章都会整合到这个专栏

4、STM32定时器中断以及定时器PWM

前言: STM32定时器概述
  我演示用的STM32F407ZGt6的核心板有多达14个定时器;  其中包含两个高级定时器(TIM1和TIM8); 十个通用定时器(TIM2~TIM5, TIM9~TIM14); 两个基础定时器(TIM6、TIM7)。

Tips: 在十个通用定时器里面包含两个看门狗定时器(two watchdog timers)

下面是datasheet里面官方给出的介绍

Couter resolution—> 计数器位数, 位数越高精度越高;
Counter type —> 计数类型 即向上计数还是向下计数
Prescaler factor —> 分频因子, 对时钟的分频, 比如单片机的时钟为84MHz, 预分频系数为4的话, 那定时器的计数器所能用的的就是21MHz了


  本文以用的比较多的通用定时器介绍, 用TIM3;

(1)主要涉及到的寄存器为
  •    计数器寄存器 (TIMx_CNT)
  •    预分频器寄存器 (TIMx_PSC)
  •    自动重载寄存器 (TIMx_ARR)

    太细致的寄存器相关的就不扯了, 看了也是忘, 多用自然会了然于心
(2)关于计数模式

以向上计数为例:

计数器从0计数到自动加载值(TIMx_ARR),然后重新从0开始计数并且产生一个计数器溢出事件。 我们可以在这个溢出事件进入中断, 只要使能中断, 那么溢出事件这个点就会进入中断, 我们只要在中断服务函数中写自己要做的功能, 这就是定时器中断了

溢出时间计算

Tout = ((ARR + 1)*(PSC + 1)) / Tclk
Tout: 溢出时间(us);  Tclk: 定时器的输入时钟频率(MHz);  ARR和PSC的值都在1~65535这个范围


如图中所示, PSC(预分频系数)决定计数周期, ARR(自动重装载值) 确定那个时刻发生溢出

下面开始Cube配置+IAR编程


4.1 操作简介

   (1) 定时器中断, 在中断中做点灯操作。使用向上计数模式;  每 200ms LED0翻转一次

   (2) 定时器产生PWM


4.2 定时器中断

在主函数的while(1) 里面我们什么都不做, 只在中断里面让LED闪烁。

Step1 : Cube配置

  • (1) 新建工程
     在新建的工程里面这一次先配置时钟树, 因为我们需要先配置好时钟频率然后计算定时器参数。

    • tips: 配置时钟树之前别忘了先把RCC和SYS勾选好
    • 接着配置时钟树
  • (2) TIM3配参数置

    • 1、 计算200ms的溢出时间所需要配置的ARR和PSC的值的大小
        通过查阅datatsheet可以知道, TIM3的时钟挂接在APB1总线上, 所以就使用APB1总线时钟频率(84MHz)进行分频

      而我们用CubeMx配置的时钟树里面APB1是84MHz, 根据前面的公式:
      Tout = ((ARR + 1)*(PSC + 1)) / Tclk
      已知 Tclk 为 84MHz , 我们需要 Tout 为 200ms 即 200000us , 不妨先让PSC为 839, 带入上述公式可得 ARR = 19999. 这样算出来之后ARR和PSC都在0~65535的范围, 则可以使用这组参数

      *注 :*这个过程最好自己算一下; 还有就是ARR和PSC都是16位的寄存器, 数值一定要在0~65535这个范围
下面是TIM3的具体配置

因为我们用到TIM3的中断, 所以不要忘记勾选中断使能; 可以在TIM3的NVIC Setting里面使勾选也可以在System Core里面勾选

关于 Priority Group(中断优先级分组)

在这次的学习中随便设置, 前面的博客也说了, 这个分组主要用于多个定时器中断的时候, 为了各个定时器中断不互相干扰, 而给每个定时器中断排个号, 大家按顺序来;
按图中的配置解释一下, 2位用于抢占优先级和2位用于子优先级就是抢占优先级可以为0~3, 子优先级也可以为0~3;
在二进制中, 00就是0, 11就是3, 所以两位数可以表示0~3;

注 : 优先级大小 0 > 1 > 2 > 3

中断事件 Preemption Priority Sub Priority
E1 2 0
E2 2 1
E3 1 0

  这个表格表示:
    1、 当 E1 和 E2 中断发生时, 若 E3 发生中断, 则可以打断 E1 和 E2 的中断, 因为 E3 的抢占优先级是三者最高的;
    2、 对于抢占优先级相同的E1和E2事件, 若E1 中断正在执行, E2 中断的到来不可以打断 E1 , 等 E1 执行完再去执行 E2 的中断; 反之亦然, 只要抢占优先级一样, 那么谁先发生就先执行谁, 不用比较Sub Priority
    3、 E1 和 E2, 若同时到来, 这个时候才考虑Sub Priority, 先执行E1再执行E2

  • (3) 其他引脚的配置
      我们要在中断里面翻转LED, 所以配置一下LED灯即可

  • (4) 工程配置(与前面的类似)

  • (5) Generate Code


Step2 : IAR或Keil编程

  • (1) 先看一下tim.c 里面的初始化写了些什么

  • (2) 写入用户代码

    • 在主函数里面开启定时器中断
    /* USER CODE BEGIN 2 */
    HAL_TIM_Base_Start_IT(&htim3);/* USER CODE END 2 */
    

    注 : 要使用定时器中断一定要自己在主函数里面用代码打开, cubeMX配置的只是初始化参数, 是否打开取决于用户

    • 写中断服务函数
    在 stm32f4xx_it.h 里面找到 void TIM3_IRQHandler(void); 然后Go To Definition查看定义
    /**
    * @brief This function handles TIM3 global interrupt.
    */
    void TIM3_IRQHandler(void)
    {/* USER CODE BEGIN TIM3_IRQn 0 *//* USER CODE END TIM3_IRQn 0 */HAL_TIM_IRQHandler(&htim3);/* USER CODE BEGIN TIM3_IRQn 1 *//* USER CODE END TIM3_IRQn 1 */
    }
    
    再查看 HAL_TIM_IRQHandler() 的定义


  可以看到, 对于更新中断事件, 最终是执行的 HAL_TIM_PeriodElapsedCallback() 这个回调函数, 所以我们只需重构这个回调函数, 在里面写入自己的代码

  • (3) 重构中断回调函数
      我们把对回调函数的重构写在tim.c 里面, 便于查看也便于以后修改什么的
/* USER CODE BEGIN 1 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{// 如果是定时器3的中断if (htim == (&htim3)){// 翻转LED0的引脚; 下面两句是等价的, main.h 有对应宏定义HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin);//HAL_GPIO_TogglePin(GPIOF, GPIO_PIN_10);}
}/* USER CODE END 1 */
  • (4) 编译下载
    实际效果如动图所示

   验证LED灯是每200ms翻转一次, 需要用示波器查看LED0对应引脚的波形数据

可以看到正频宽是200ms, 负频宽也是200ms, 所以跟我们预期的计算结果是一样的, 完美。


4.3 定时器产生PWM

操作简介 : 通过STM32定时器产生的PWM, 让LED灯做出呼吸灯的效果;
参考正点原子开发指南, 用CubeMX完成其标准库的程序配置
PWM(Pulse Width Modulation): 即脉冲宽度调制


  这个是以向上计数比较的, 当定时器计数器向上计数到CCRx之前, IO口一直输出0, 从到达CCRx开始输出1, 到ARR时溢出,重新计数。
  IO口输出高低电平就用0和1表示。
  显然, 如果改变CCRx值的大小, 就可以变化IO输出的PWM波形的占空比; 改变ARR(自动重装载值), 就可以改变PWM波形的频率。

在前面配置TIM3的时候我们没有用到那几个Channel, 现在产生PWM就需要用到了。 关掉IAR工程, 回到CubeMX开始配置

Step1 : Cube配置

  • (1) LED灯的引脚对应的是TIM14的通道1, 所以要配置TIM14来实现效果

注释 :

CH Polarity即通道输出极性。我们用TIM3向上计数模式, 按照前面PWM原理图解, CH Polarity的极性加上IO逻辑, 才是最终PWM的波形; 举个栗子, 如果CH Polarity为High(1), 那么当向上计数到CCRx之前本该是0(低电平), 但实际上还要加上Ch的输出极性, 所以那一段实际上是输出1(高电平)。 细细品一下脑子就通了
选用PWM模式1, Pulse(脉宽)这个不用设置, 因为我们在程序里面要不断改变占空比去调节LED的亮度
  • (2) 生成代码
先声明两个变量

/* USER CODE BEGIN 1 */
uint16_t CCRx_val = 0; // CCRx的值; 通过不断改变这个值, 并把这个值送入CCRx寄存器, 达到改变占空比的效果
uint8_t dir = 1;       // 计数方向控制/* USER CODE END 1 */
启动定时器的PWM

/* USER CODE BEGIN 2 */
HAL_TIM_PWM_Start(&htim14, TIM_CHANNEL_1);/* USER CODE END 2 */
while(1)循环内部

/* USER CODE BEGIN 3 */HAL_Delay(10);if(dir)CCRx_val++;elseCCRx_val--;if(CCRx_val > 300)dir=0;if(CCRx_val == 0)dir=1;// 追踪 HAL_TIM_OC_ConfigChannel   找到  TIM_OC1_SetConfig 再追踪进去// TIM14->CCR1 = 任意数值x  即可控制TIM14通道1的脉宽, 占空比为 (x)/(htim14.Init.Period + 1)TIM14->CCR1 = CCRx_val;      // 修改占空比  (调节脉宽我们需要调节 sConfigOC.Pulse )
所有用户代码就是这些, 这里用是寄存器操作去修改占空比, 不管使用什么库函数, 标准库或者HAL库亦或者LL库, 他们在程序里的地位都要低于寄存器。 所以当使用CubeMX配置使用HAL库不方便对某些IO操作的时候, 就可以用寄存器来操作
刚才在cube里面脉宽(Pulse)我们没有配置, 就是在这里通过寄存器操作的, 最终的本质都是寄存器操作; 感兴趣可以按照我的代码注释, 去 Go To Definition 一路追踪到 TIM_OC1_SetConfig() 这个函数, 这里面就是对相应的寄存器操作的。 在 stm32f4xx_hal_tim.c 这个文件里面
  • (3) 编译下载

    • 实际效果如下面动图所示, 看个三到四秒钟就可以看到变化了
      可能看起来不是非常的明显, 自己操作一下可以好好观察现象


人生岂止爱恨, 还有孤独和酒, 更有梦想与生活, 坚持住。 加油 !

Author : 李光辉
date : Sun Jan 5 22:18:02 CST 2020
blog ID: Kevin_8_Lee
blog site : https://blog.csdn.net/Kevin_8_Lee

第四节:定时器中断及定时器产生PWM(用CubeMX学习STM32)相关推荐

  1. stm32学习笔记 TIM定时器中断1.定时器基本定时功能(含代码)

    TIM定时器分四个部分 目录 一.定时器基本定时功能 二.定时器输出比较功能 三.定时器输入捕获功能 四.定时器编码接口 一.定时器基本定时功能 RCC时钟树 SystmInit函数 外部晶振出问题会 ...

  2. 【STM32】HAL库 STM32CubeMX教程六----定时器中断

    前言: 今天我们来学习定时器,32的定时器有着非常丰富的功能, 输入捕获/输出比较,PWM,中断等等.是我们学习STM32最频繁使用到的外设之一,所以一定要掌握好,这节我们讲解定时器中断,本系列教程将 ...

  3. 串口中断和定时器中断_启士 | 蓝桥杯单片机教程12 中断与定时器 (上)

    这是 北航士谔书院 的第 949 篇推送 本文介绍中断(interrupt)的基本概念,并演示定时器中断.外部中断的使用方法.如果同学们对文章内容有疑问,或发现文中有任何不妥之处,请点击"阅 ...

  4. STM32F407ZGT6|定时器中断

    功能:LED每500ms闪烁一次 步骤: 1.结构体的定义 2.使能LED(GPIOC外设)/定时器/中断/定时器中断 3.初始化LED/定时器 4.配置中断分组NVIC 5.编写中断服务函数(重:溢 ...

  5. 51单片机学习笔记之中断(外部中断、定时器中断、中断嵌套)

    要学习51单片机中断的朋友,拥有这一篇博文就够了,深入浅出,里面包含了寄存器,外部中断.定时器中断.中断嵌套等的讲解,还有代码实战.快一万字,写得不容易,还请大家点赞支持一下,后续持续更新 (一)寄存 ...

  6. CubeMX系列教程——9 定时器中断

    复制上篇工程,并打开 选择定时器,查看参数,1ms定时. 允许定时器中断 设置定时器中断优先级 生成初始化代码,打开工程 在time.c文件中添加测试代码,当定时器1ms时间到时进入中断回调函数. 在 ...

  7. 51单片机(四)定时器中断(+数码管——24小时制钟表)

    定时器中断 一.中断 1.中断概念 2.中断嵌套 二.中断源(优先级顺序必记!) 三.中断允许寄存器IE和中断优先级寄存器IP 1.中断允许寄存器IE(Interrupt Enable ) 2.中断优 ...

  8. Holtek合泰单片机 《四》 从TM定时器中断到led灯1s闪烁

    跳过中断直接讲TM中断是不是有些超前了? 由于最近参加了一个项目,真是忙的不要不要的,没办法,只有抽了点放假的时间来更新下自己的博文,希望对正在学习HT单片机的同学有帮助. 重庆合泰初赛是5月15日, ...

  9. 瑞萨单片机之定时器中断实现数码管动态扫描(四)

    目录 一.实现原理 二.具体实现 三.例子 一.实现原理 数码管的驱动方式很简单,图中的A B C D E F G Dp (8个段 含点)分别代表的数码管的每个段(笔画),需要显示什么就把相应的段点亮 ...

  10. 51单片机学习笔记(郭天祥版)(3)——引脚讲解、数码管静态显示、中断系统(外部中断,定时器中断)...

    学习引脚的功能 9引脚 复位管脚,当给2个机器周期(24个时钟振荡周期)的高电平时会复位,单片机正常工作时会给0.5v的低电平 VPD备用电源的输入端,当主电源VCC发生故障降低到某一规定的低电平时, ...

最新文章

  1. 【Netty】入门Netty官方例子解析(二)Time Server
  2. SAP RETAIL 供应商寄售库存的UB STO
  3. controller-runtime 控制器实现
  4. SpringBoot笔记:SpringBoot2.3集成SpringSession+nginx+redis实现session共享
  5. 【Python】用 Highcharts 绘制饼图,也很强大
  6. mysql 查询条件
  7. Error -Cannot add direct child without default aggregation defined for control
  8. mysql dal_Entity Framework连接Mysql数据库并生成Model和DAL层
  9. OS中atomic的实现解析
  10. 机器学习 - 随机森林手动10 折交叉验证
  11. js html转为实体,字符串js编码转换成实体html编码的方法(防范XSS攻击)
  12. 第一:Java+MyBatis(快速入门)
  13. Cygwin下用Open SSH启动SSH服务
  14. 应用程序虚拟化工具(VMware ThinApp)5.2.1汉化绿色企业版
  15. 怎样用计算机计算矩阵,【活用工具】教你如何用卡西欧fx82es计算机计算复数 矩阵等...
  16. fudannlp初试
  17. 如何控制局域网网速_水星无线路由器怎么设置网速限制【设置方法】
  18. 如何把50多张jpg图片合成一张PDF图片?——下载了破解版PS也不怎么会用的傻瓜极简做法用Word一招解决
  19. 2023年全国最新工会考试精选真题及答案53
  20. python课程论文_python结课论文_python论文_工程伦理结课论文文库

热门文章

  1. Please make sure you have the correct access rights and the repository exists.
  2. java源码-AtomicInteger
  3. idea 未实现接口红线提示,重复代码波浪线提示,自动换行,控制台输出内容自动换行...
  4. 一小时精通SVN版本控制 之五 团队协作开发
  5. 《编译与反编译技术实战》——1.2 词法分析生成器LEX
  6. D-News|扎克伯格下月发布人工智能管家,美放宽无人机商用飞行标准
  7. shopnum1商城系统
  8. MongoDB学习笔记~官方驱动的原生Curd操作
  9. Oracle常用SQL总结
  10. day 07总结(数字类型内置方法/字符串类型内置方法)