• 基于STM32G431嵌入式学习笔记——七、定时器定时


    一、题目引入

    在这里插入图片描述上述为第13届蓝桥杯省赛节选内容,为了研究定时器的机理并独立书写计时函数,上述内容简化为以下要求:

    ①按下B4按键,LD1点亮5s后熄灭
    ②按下B3按键,LD2以0.1秒为间隔切换亮灭状态

    二、基础知识

    定时器相关知识可以参考“STM32G4系列微控制器参考手册”
    在这里插入图片描述

    三、CubeMX配置

    关于led、key、lcd的配置不再赘述,详细环境可见前三节内容:
    基于STM32G431嵌入式学习笔记——一、LED模块入门
    基于STM32G431嵌入式学习笔记——二、LCD模块入门
    基于STM32G431嵌入式学习笔记——三、KEY按键入门
    若先前已跟随教程配置过,可在配置完毕的环境下继续沿用:
    在这里插入图片描述

    打开CubeMX中的时钟树
    在这里插入图片描述其中右上角,是我们各个部件的时钟频率,均为80MHz
    在这里插入图片描述我们做一些简单的计算:
    f = 80 M H z = 80 ∗ 1 0 6 H z 表示运行 1 s 的次数即计数量 f=80MHz=80*10^6Hz表示运行1s的次数即计数量 f=80MHz=80106Hz表示运行1s的次数即计数量

    如果像题目所说的间隔5s,则需要运行多少次呢?
    5 ∗ f = 4 ∗ 1 0 8 次 5*f = 4*10^8次 5f=4108
    若以二进制计数,早已超过计数器的16位/32位,因此我们需要让时钟慢一点儿,计数次数少一点儿,即需要将系统时钟进行分频/降频
    f = 80 ∗ 1 0 6 H z f=80*10^6Hz f=80106Hz,则 T ≈ 1 0 − 6 s T≈10^{-6}s T106s 1 μ s 1μs 1μs
    我们可以将其改变成 T = 1 0 − 3 s T=10^{-3}s T=103s 1 m s 1ms 1ms
    这里我们假设使用timer2(自己任选)
    在这里插入图片描述在这里进行了第一次降频,从 80 ∗ 1 0 6 H z 80*10^6Hz 80106Hz降低为 80 ∗ 1 0 3 H z 80*10^3Hz 80103Hz(除以1000)
    在这里插入图片描述在这里进行了第二次降频,从 80 ∗ 1 0 6 H z 80*10^6Hz 80106Hz降低为 1 ∗ 1 0 3 H z 1*10^3Hz 1103Hz(除以80)
    即周期成功变为 1 m s 1ms 1ms,可以理解为计数器计数一次的时间为 1 m s 1ms 1ms
    1 s 1s 1s计数器计数次数为1000, 0.1 s 0.1s 0.1s计数器计数次数为100,以此类推。


    定时器实现功能的本质是中断,因此我们要配置中断优先级等内容:

    在这里插入图片描述配置完毕,生成代码。

    四、代码书写
    1.打开工程,编译。

    在这里插入图片描述

    2.函数书写

    (1)在主函数调用函数开启定时器中断
    在这里插入图片描述函数位于stm32g4xx_hal_tim.c的470行左右
    在这里插入图片描述(2)全局变量配置
    在这里插入图片描述(3)相关头文件是否齐全
    在这里插入图片描述(4)相关功能函数
    记得养成好的习惯,将函数写在主函数之下:
    在这里插入图片描述

    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    {
      if(htim->Instance==TIM2)//是timer2,且过了1ms
      {
        if(led1_flag==1)//led1要用定时器了
        {
          led1_count++;
        }
        if(led2_flag==1)//led2要用定时器了
        {
          led2_count++;
        }
      }
    }
    void led_proc(void)//led1的控制函数
    {
      if(led1_flag==1)
      {
        Control_LED(LED1,ON);
        if(led1_count>=5000)//计数5000,即亮了5s
        {
          led1_flag = 0;
          led1_count = 0;
          Control_LED(LED1,OFF);
        }
      }
    }
    void bulingbuling(void)//led2的闪烁函数
    {
      if(led2_flag==1)
      {
        if(led2_count>=100)//0.1s
        {
          led2_count = 0;
          HAL_GPIO_TogglePin(GPIOC,LED2);//翻转
          HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
    			HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
        }
      }
      else
      {
        Control_LED(LED2,OFF);
      }
    }
    void key_proc(void)
    {
      char value = Key_Scan();
      switch(value)
      {
        case 3:
          led1_flag = 1;
          break;
        case 4:
          led2_flag = (led2_flag+1)%2;
          break;
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    第一个函数名含有“Callback”,如果基础知识够扎实想必可以想到上一节我们遇到过串口中断的Callback,实际上该函数便是发生时钟中断后处理的函数(中断处理子程序)。
    位于5920行左右
    在这里插入图片描述
    (5)主函数补充
    在这里插入图片描述
    编译+下载,程序结束。

  • 相关阅读:
    回溯算法基础
    [0CTF 2016]piapiapia
    Maleimide-PEG-DMPE,科研试剂DMPE-PEG-Mal供应
    SQL12 高级操作符练习(2)
    ELK + kafka 日志方案
    8.3Jmeter使用json提取器提取数组值并循环(循环控制器)遍历使用
    CPU体系(2):ARM Store Buffer
    MIPI CSI接口调试方法:时序调试
    Linux常用命令
    汇川PLC学习Day1:跑马灯程序编写
  • 原文地址:https://blog.csdn.net/qq_53826699/article/details/128077869