Bootstrap

【笔记】STM32F4xx 时钟定时器

第五部分 时钟定时器

一、时钟

1. 时钟是什么?

T: 时钟周期,最小重复的信号单元的时间长度。
f: 频率Hz 单位时间内(电平)完成周期性变化的次数

2. 为什么需要时钟呢?

同步信号:大部分时钟逻辑电路需要时钟信号来同步

一个解决方案:

(1)T > 2 * delt_t (delt_t 电路单元中最大延时)T为clock信号的周期,50%

(2)输入信号只能在clock低电平(无效)改变,在clock的高电平时保持稳定

3. 时钟信号是怎么产生的?

“晶振”: 产生周期性的信号。8M 但是MPU的频率要求高168M,怎么办?

“分频/倍频”电路

分频: 把输入频率变小 倍频: 把输入频率变大

PLL: 锁相环 技术

4. STM32F4xx 时钟树

在这里插入图片描述

在STM32F4中,有5个最重要的时钟源,后三个是主要的时钟源。
LSI: Low Speed Internal 内部低速时钟
LSE: Low Speed External 外部低速时钟
HSI: High Speed Internal 内部高速时钟
HSE: High Speed External 外部高速时钟
PLLCLK 其中PLL实际是分为两个时钟源,分别为主PLL和专用PLL

在开发板上面, HSE_VALUE = 8M #define HSE_VALUE ((uint32_t)8000000)
分频器PLL_M=8,倍频器倍频系数PLL_N=336,分频器分频系数PLL_P=2,
PLL=8MHzN/ (MP)=8MHz336 /(82) = 168MHz(主PLL)
Cortex M4 F407主频 最高可达  168M Hz
用户可通过多个预分频器配置AHB总线、高速APB2总线和低速APB1总线的频率。
AHB 域 的最大频率为 168 MHz。AHB prescaler
M4 clock = AHB BUS clock = 168M
低速 APB1 域 的最大允许频率为 42 MHz。
APB1 BUS clock = AHB BUS Clock/(APB1 prescaler)= 168M / 4 = 42M
高速 APB2 域 的最大允许频率为 84MHz。
APB2 bus clock = AHB BUS Clock/(APB2 prescaler) = 168M / 2 = 84M

注意:STM32F405xx/07xx 和 STM32F415xx/17xx 的定时器时钟频率由硬件自动设置。

分为两种情况:

(1)如果 APB 预分频器为 1,定时器时钟频率等于 APB 域的频率。

(2) 否则,等于 APB 域的频率的两倍 (×2)。

  • 例子:

    TIM13在APB1总线上:

    APB1 prescaler = 4

    APB1 BUS clock = AHB BUS clock / APB1 prescaler= 168M / 4= 42M

二、定时器

定时器:用来定时的器件。

1. 定时器的基本原理

在STM32上,定时器由三个部分组成

(1)时基单元:Time Base Unit定时器的基本部件。

“计数器”可以设置为从设定值递减到0,也可以设置从0按照递增到设定值。然后产生一个溢出事件/中断,从而达到定时的功能。

例子:假设一个定时器TM的时钟频率f,设定的计数值为N,按照递减的方式计数,每隔(1/f)s就 -1 ,减到零时产生一个中断,时间为:(N+1)*(1/f)s

任务:延时2秒 168M 84M 168000000-1 84000000-1

核心部件:“计数器”,内部含3个寄存器

TIMx_ARR: Auto Reload Register 自动加载寄存器 <- -N
TIMx_CNT: Counter 计数器
TIMx_PSC: PreSCaler 时钟预分频

(2)输入捕获单元: 可以对一个或多个输入信号进行处理

有些定时器没有。
可以捕获一个或多个输入信号(看你这个定时器有几个输入通道 CHx_IN)
有什么用呢?如: 可以计算输入信号的频率
输入信号经过“输入捕获阶段”(数字滤波、多路复用、预分频等等),到信号检测,当检测到需要的信号状态变化时(上升沿/下降沿),就会把定时器时基单元中计数器的值,锁定到“捕获/比较寄存器”这样,就可能根据预先设定的定时器的参数(时钟频率,N值等等),就可以算出从开始到捕获这个信号状态的这一段的时间。

(3)输出比较单元: 可以输出一个或多个信号

有些定时器没有。
定时器还可以输出一个电平、并且可以根据“比较寄存器”的值,翻转电平的状态。
如: CCR: Capture Compare Register捕获/比较寄存器
定时器的第(2)输入捕获单元 和第(3) 输出比较单元 不同时用。
CNT >= CCR 输出一个高电平
CNT < CCR 输出一个低电平
作用:如PWM方波(实例中用)

2. STM32F4xx定时器概述

SysTick 系统定时器,作为整个系统的基本的时间单元。

所有Cortex M3/M4中都会内置于NVIC一个SysTick的定时器。这个定时器只有一个时基单元。并且在溢出时,会产生一个SysTick异常(中断)。

NVIC exception type #15. decrement 24-bit
它被内置于NVIC中,它能够产生一个SysTick异常(异常类型 #15).这个SysTick定时器

是一个简单的24bits的递减定时器,它可以运行在处理器的时钟频率上,也可以运行在一个外部的时钟频率上(通常在片上的时钟源)

在这里插入图片描述

在这里插入图片描述

  • SysTick控制及状态寄存器(地址:0xE000_E010)

    [0]:SYSTICK使能1/禁止0

    [1]:计数中断使能1/禁止0

    [2]:使用系统内核时钟168M 1 外部时钟源 0

    [16]:如果在上次读取本寄存器后,SysTick 已经数到了0,则该位为 1。如果读取该位,该位将自动清零。

  • SysTick重装载数值寄存器(地址:0xE000_E014)

    [23:0]:重载计数值,当倒数至零时,将被重装载的值。

  • SysTick当前数值寄存器(地址:0xE000_E018)

    [23:0]:当前计数值,读取时返回当前倒计数的值,写它则使之清零

3. 基本定时器(TIM6, TIM7)

只有时基单元

无输入输出引脚

计数器只有16bit,而且只支持递增模式

4. 通用定时器

  • TIM2~TIM5

    16bits(TIM3,TIM4)或32bits(TIM2,TIM5)计数器,可以配置为递增递减先递增后递减(0->N->0)的模式,多达4个独立通道,可用于:输入捕获输出比较PWM生成(边沿或中心对齐模式)、单脉冲模式输出

  • TIM9~TIM14

    16bits自动加载递增计数器,2个独立通道,可用于:输入捕获输出比较PWM生成(边沿或中心对齐模式)、单脉冲模式输出

5. 高级定时器(TIM1, TIM8)

16bits计数器,可以可以配置为递增递减先递增后递减(0->N->0)的模式,多达4个独立通道,可用于:输入捕获输出比较PWM生成(边沿或中心对齐模式)、单脉冲模式输出

“高级”:重复计数器(TIMx_RCR) : Repeation Counter Register

如果使用重复计数,则当计数器重复溢出的次数达到设定的重复计数器的值+1时,才会产生溢出事件/中断。

如果不用重复计数器,在每次计数器溢出时都会产生事件/中断。这个时候,和通用定时器没有区别。

6. 看门狗 watch dog

  • 问题引入

    “死机”:用户任何操作都没有反应,必须掉电重启

    掉电重启 —> 当你的程序出现"死机"/"跑飞了"这种情况时

    看门狗”复位:用于程序"死机、跑飞"时,自动复位系统。

  • 看门狗本质就是一个定时器,这个定时器有一个输出引脚,直接连到cpu的复位引脚上去。

  • 看门狗的操作

    配置好后,就会从一个值N - 0 => cpu复位。

    (1)当你的程序"死机、跑飞了", 看门狗 减至0时,就会复位系统

    (2)当你的程序正常情况下,看门狗 减至0时,也会复位系统 所以----当你程序正常情况,就要周期性地“喂狗”把定时器的值,赋值一个比较大的值。让他不要减至0!!!

  • 怎么喂狗:

    Thread Mode下(用户程序的业务处理逻辑中),周期性的喂狗。

三、蜂鸣器播放音乐

1、原理

在这里插入图片描述

根据蜂鸣器原理图可以发现,蜂鸣器可复用为 TIM13。同时根据总线地址表查询 TIM13 在 APB1 上。 有 BEEP—PF8—TIM13 在初始化的时候,要使用复用模式,控制蜂鸣器的发声频率,即可控制音调。

2、TIM初始化

typedef struct
{
  uint16_t TIM_Prescaler;         /*!< Specifies the prescaler value used to divide the TIM clock.
                                       This parameter can be a number between 0x0000 and 0xFFFF */
        
  uint16_t TIM_CounterMode;       /*!< Specifies the counter mode.
                                       This parameter can be a value of @ref TIM_Counter_Mode */

  uint32_t TIM_Period;            /*!< Specifies the period value to be loaded into the active
                                       Auto-Reload Register at the next update event.
                                       This parameter must be a number between 0x0000 and 0xFFFF.  */ 

  uint16_t TIM_ClockDivision;     /*!< Specifies the clock division.
                                      This parameter can be a value of @ref TIM_Clock_Division_CKD */

  uint8_t TIM_RepetitionCounter;  /*!< Specifies the repetition counter value. Each time the RCR downcounter
                                       reaches zero, an update event is generated and counting restarts
                                       from the RCR value (N).
                                       This means in PWM mode that (N+1) corresponds to:
                                          - the number of PWM periods in edge-aligned mode
                                          - the number of half PWM period in center-aligned mode
                                       This parameter must be a number between 0x00 and 0xFF. 
                                       @note This parameter is valid only for TIM1 and TIM8. */
} TIM_TimeBaseInitTypeDef; 
  • TIM_Prescaler:设置预分频的数值

    TIM_CLK: 计数器(定时器)的时钟

    TIM_CLK = Fin(定时器的输入时钟频率)/ (TIM_Prescaler + 1)

    if APBx prescaler == 1

    ​ 则: Fin = APBx BUS clock

    else

    ​ Fin = APBx Bus clock * 2

    TIM13 的计数器时钟:

    APB1 BUS clock = AHB BUS Clock/(APB1 prescaler)= 168M / 4 = 42M Fin = 42M × 2 = 84M

    假设 Fin=84000000/8400=10Khz

    TIM_Prescaler = 8399 (故在初始化时设置预分频为 8399)

  • TIM_CounterMode

    #define TIM_CounterMode_Up                 ((uint16_t)0x0000)
    #define TIM_CounterMode_Down               ((uint16_t)0x0010)
    #define TIM_CounterMode_CenterAligned1     ((uint16_t)0x0020)
    #define TIM_CounterMode_CenterAligned2     ((uint16_t)0x0040)
    #define TIM_CounterMode_CenterAligned3     ((uint16_t)0x0060)
    

    指定计数器模式:递增、递减、先递增后递减

3、TIM_OCInitTypeDef

定时器输入出通道/输入通道配置


typedef struct
{
  uint16_t TIM_OCMode;        /*!< Specifies the TIM mode.
                                   This parameter can be a value of @ref TIM_Output_Compare_and_PWM_modes */

  uint16_t TIM_OutputState;   /*!< Specifies the TIM Output Compare state.
                                   This parameter can be a value of @ref TIM_Output_Compare_State */

  uint16_t TIM_OutputNState;  /*!< Specifies the TIM complementary Output Compare state.
                                   This parameter can be a value of @ref TIM_Output_Compare_N_State
                                   @note This parameter is valid only for TIM1 and TIM8. */

  uint32_t TIM_Pulse;         /*!< Specifies the pulse value to be loaded into the Capture Compare Register. 
                                   This parameter can be a number between 0x0000 and 0xFFFF */

  uint16_t TIM_OCPolarity;    /*!< Specifies the output polarity.
                                   This parameter can be a value of @ref TIM_Output_Compare_Polarity */

  uint16_t TIM_OCNPolarity;   /*!< Specifies the complementary output polarity.
                                   This parameter can be a value of @ref TIM_Output_Compare_N_Polarity
                                   @note This parameter is valid only for TIM1 and TIM8. */

  uint16_t TIM_OCIdleState;   /*!< Specifies the TIM Output Compare pin state during Idle state.
                                   This parameter can be a value of @ref TIM_Output_Compare_Idle_State
                                   @note This parameter is valid only for TIM1 and TIM8. */

  uint16_t TIM_OCNIdleState;  /*!< Specifies the TIM Output Compare pin state during Idle state.
                                   This parameter can be a value of @ref TIM_Output_Compare_N_Idle_State
                                   @note This parameter is valid only for TIM1 and TIM8. */
} TIM_OCInitTypeDef;
  • TIM_OCMode:指定输出通道的模式

    #define TIM_OCMode_Timing                  ((uint16_t)0x0000)
    #define TIM_OCMode_Active                  ((uint16_t)0x0010)
    #define TIM_OCMode_Inactive                ((uint16_t)0x0020)
    #define TIM_OCMode_Toggle                  ((uint16_t)0x0030)
    #define TIM_OCMode_PWM1                    ((uint16_t)0x0060)
    #define TIM_OCMode_PWM2                    ((uint16_t)0x0070)
    

    其中 TIM_OCMode_PWM1:当 TIMx_CNT<TIMEx_CCRn 时,输出高电平,否则输出低电压

    占空比:在一个时钟周期中有效电平(高电平)所占的比值 选择 PWM1 占空比一目了然

  • TIM_OutputState: 设置为输出信号 TIM_OutputState_Enable

  • TIM_Pulse: 指定要比较的值(每个板子不一样,根据具体情况调参) (占空比系数)

  • TIM_OCPolarity: 指定输出极性。本实验中设置高电平为有效电平

4、beep.h

#ifndef _BEEP_H_
#define _BEEP_H_
#include "stm32f4xx.h"
#include "systick.h"
#include "key.h"
void beep_init(int);
void music_play(void);
#define L1 10000/131-1
#define L2 10000/147-1
#define L3 10000/165-1
#define L4 10000/175-1
#define L5 10000/196-1
#define L6 10000/221-1
#define L7 10000/248-1
#define M1 10000/262-1
#define M2 10000/294-1
#define M3 10000/330-1
#define M4 10000/350-1
#define M5 10000/393-1
#define M6 10000/441-1
#define M7 10000/495-1
#define H1 10000/589-1
#define H2 10000/661-1
#define H3 10000/700-1
#define H4 10000/786-1
#define H5 10000/882-1
#define H6 10000/990-1
#define H7 10000/1112-1
#define clap 400
#endif

5、beep.c

#include "beep.h"
#include "systick.h"
extern u8 status;
//蜜雪冰城主题曲
int music[]={
    M3, M5, M5, M6, M5, M3, M1, M1, M2, M3, M3, M2, M1, M2, 0,
    M3, M5, M5, M6, M5, M3, M1, M1, M2, M3, M3, M2, M2, M1, 0,
    M4, M4, M4, M6, M5, M5, M3, M2, 0,
    M3, M5, M5, M6, M5, M3, M1, M1, M2, M3, M3, M2, M2, M1
};
float time[]={
    0.5, 0.5, 0.75, 0.25, 0.5, 0.5, 0.5, 0.25, 0.25, 0.5, 0.5, 0.5, 0.5, 1, 1,
    0.5, 0.5, 0.75, 0.25, 0.5, 0.5, 0.5, 0.25, 0.25, 0.5, 0.5, 0.5, 0.5, 1, 1,
    1, 1, 0.5, 1.5, 1, 0.5, 0.5, 1, 1,
    0.5, 0.5, 0.75, 0.25, 0.5, 0.5, 0.5, 0.25, 0.25, 0.5, 0.5, 0.5, 0.5, 1, 1
};
void music_play()
{
    for(int i=0; i<sizeof(music)/4 ;i++){
        if(status == 1 && music[i] != 0){ //使得歌曲能够随时停止
            beep_init(music[i]);
            Delay_ms((int)(clap*time[i]));
            TIM_ARRPreloadConfig(TIM13, DISABLE);
            TIM_Cmd(TIM13, DISABLE);
        }
    }
}
void beep_init(int n)
{
    //0.clk enable PF8 GPIOF-AHB1 
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE); 
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM13, ENABLE);
    //1.GPIOF8 MODE-AF--TIM13
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.GPIO_Mode =GPIO_Mode_AF;
    GPIO_InitStruct.GPIO_OType =GPIO_OType_PP;
    GPIO_InitStruct.GPIO_Pin =GPIO_Pin_8;
    GPIO_InitStruct.GPIO_PuPd =GPIO_PuPd_NOPULL;
    GPIO_InitStruct.GPIO_Speed =GPIO_Speed_50MHz; 
    GPIO_Init(GPIOF, &GPIO_InitStruct);
    GPIO_PinAFConfig(GPIOF,GPIO_PinSource8, GPIO_AF_TIM13);
    //2.TIM13-TIMEBASE
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
    TIM_TimeBaseInitStruct.TIM_Prescaler =8399;//84M---10K
    TIM_TimeBaseInitStruct.TIM_CounterMode =TIM_CounterMode_Down;
    TIM_TimeBaseInitStruct.TIM_Period =n; 
    TIM_TimeBaseInit(TIM13, &TIM_TimeBaseInitStruct);
    //3.TIM13 OUT CH1---1
    TIM_OCInitTypeDef TIM_OCInitStruct;
    TIM_OCInitStruct.TIM_OCMode =TIM_OCMode_PWM1;
    TIM_OCInitStruct.TIM_OutputState =TIM_OutputState_Enable;
    TIM_OCInitStruct.TIM_OCPolarity =TIM_OCPolarity_High;
    TIM_OCInitStruct.TIM_Pulse =0.3*n;
    TIM_OC1Init(TIM13, &TIM_OCInitStruct); 
    TIM_OC1PreloadConfig(TIM13, TIM_OCPreload_Enable);
    //3.TIM13-ENABLE
    TIM_ARRPreloadConfig(TIM13, ENABLE);
    TIM_Cmd(TIM13, ENABLE);
}

6、mian.c

int main(void)
{
    key_init();
    while (1)
    {
        if(status==1)
        {
         music_play();
        }
    }
}

第一部分 嵌入式系统概述
第二部分 ARM指令系统
第三部分 通用 I/O (GPIO)
第四部分 中断机制
第五部分 时钟定时器

;