描述

这一篇文章是关于stm32的led灯控制的最后一篇。这篇想要实现的功能就是led以固定周期进行状态的翻转。

  • 研发平台:淘宝上购买的野火店铺的一款单片机,名字叫骄阳开发板,核心芯片是
    stm32F407IGT6

最简单的实现办法(没有技术含量)

我们可以在main.c的代码中找到程序的主循环while函数,在函数中我们可以通过HAL_Delay的方式进行延时控制,在延时中间穿插灯的控制语句,就可以实现这个功能了。如下

HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_15);
HAL_Delay(500);

但是显然,作为机器人下位机的主控,未来需要控制的元器件有很多。我们不可能将所有的元器件的控制频率,都以delay的方式写在主循环中。这样,不仅程序运行受到了限制,而且也是一种不可能实现的方法。

因此我们需要用到:时钟与定时器

概念

  1. 什么是时钟?
    时钟可以理解为电子元器件的心跳。例如,stm32芯片会根据程序设定的时钟节拍来工作,这个节拍就是时钟。stm32芯片会以一定的频率,在芯片内部同步各种器件。
  2. 时钟的分类
    可以使用三种不同的时钟源来驱动系统时钟 (SYSCLK):
    HSI 振荡器时钟(在stm32芯片内部,不需要额外的电路支持)
    HSE 振荡器时钟(需要外部的晶振/时钟电路)
    PLL时钟(利用锁相环技术)’
  3. 补充小知识点:时钟频率越高,器件工作速度越快性能越强,功耗越高。但频率的选择也要考虑芯片的工作条件。
  4. 我们对芯片的时钟进行设置,可以改变定时器的频率
  5. 什么是定时器?
    简单来说,定时器能够帮助我们在特定时间点,实现我们期望的程序功能
    查询stm32F4的中文参考手册可以发现,F407系列的定时器种类有以下几种:
    2个高级控制定时器——TIM1和TIM8
    10个通用定时器——TIM2到TIM5、TIM9到TIM14
    2个基本定时器——TIM6和TIM7
    2个看门狗定时器
  6. 我们利用定时器可以实现什么?
    我们希望定时器完成计数时产生一个中断,利用这个定时器中断功能,可以使一些功能按照某个固定的时间频率,得到触发。

实现原理

  • 目的:我们希望led灯0.5秒进行一次状态翻转
  • 需要:创造有一个0.5秒为周期的定时器

  • 周期的计算方式:1/ (定时器时钟频率/( 预分配系数+1)) *( 寄存器重载计数+1)

  • 举例子:
    定时器的时钟频率为84MHz,设置预分配系数为8399,那么这个定时器的频率84MHz/(8399+1),也就是为10000Hz。那么这个定时器每一次计数的时间是,1/10000,也就是0.0001秒。设置寄存器重载计数值为4999,那么定时器每一次中断的时间,就是0.0001×(4999+1),也就是0.5秒。

  • 查阅数据手册可以看到,TIM6时钟挂在了APB1总线上

  • 这是F407的时钟树

    通过时钟树的右下角部分我们可以看到,if (APBx × PRESC = 1)×1 else ×2)
    意思就是说
    如果预分频系数是/1,外设时钟和定时器时钟都是168/1 = 168MHz
    如果预分频系数不是/1,比如是/4,那么外设时钟是168/4=42MHz,定时器时钟是42MHz×2 = 84MHz
    这就是上图的含义

在CubeMX的时钟设置界面中,我们可以很清楚的看懂以上的知识。我们可以在CubeMX中修改一些数字,可以看看会发生什么事情

步骤

  1. 和之前一样,我们新建一个属于是stm32F407的工程,在这个工程中我们对第一个led灯的管脚进行设置。根据数据手册,我们查询到第一个led灯的管脚为PA15,我们和之前的文章一样,设置它为GPIO_Output。
  2. 首先我们打开上方菜单栏的“Clock Configuration”,这时会出现当前芯片的时钟设置界面,我们注意到主系统时钟(HCLK)目前是16MHz。
  3. 我们注意到主系统时钟的位置,也就是,HCLK(MHz)下方有一行蓝色的小字,写到“168MHz max”。意思是说,该芯片的主系统时钟最大可以设置到168MHz。
  4. 由于当前我们的任务,不用考虑芯片的功耗,因此我们将“16”的位置改写成“168”,然后回车确定(图中是108,我笔误了)。CubeMX会自动帮我们生成时钟配置的方案。CubeMx弹出如下的界面,询问我们是否要使用CubeMX给的分配方案,我们选择是的“OK”。
  5. 这样,我们已经成功的将系统时钟改为了168MHz了
  6. 我们在左侧的菜单栏中找到“Timers”,点击“TIM6”,出现了如下界面
  7. 我们发现“Activated”选项没有被勾选上,将它勾选上。这时会弹出TIM6的配置界面
  8. 我们将“Prescaler(PSC-16 bits value)”,也就是预分配系数设置为“8399”;将“Counter Period(AutoReload Register - 16 bits value)”,也就是重装载计数设置为“4999”。其余选项保持不变。
  9. 像之前一样,进行工程剩余的配置后,点击生成代码。
  10. 在生成的代码中,我们找到tim.c文件,里面有如下的一些代码,可以看出这些就是我们刚才设置的内容
  11. main.c文件中的主函数中,我们添加如下的一句话
       HAL_TIM_Base_Start_IT(&htim6);
    
  12. main.c文件中的用户定义代码的位置,我们添加以下的代码,用于描述TIM6中断时进行的操作
    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    {
        if(htim->Instance==TIM6)
        {
            HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_15);
        }
    }
    
  13. 下载代码到开发板中,按下复位按钮,我们会发现led1以0.5秒的速度进行状态翻转

总结

这篇文章简单介绍了一下定时器,并通过CubeMX设置的方式,利用定时器中断完成了led灯的控制