STM32的RCC(Reset and Clock Control)时钟控制

stm32f103c8的时钟是72MHz, stm32f401ccu6的时钟是80M, 开发板板载两个晶振, 一个高速一个低速

时钟源

STM32时钟的走向, 从时钟源一步步分配给系统和外设, stm32系统一共有四个时钟源, 依次是

  1. 高速内部时钟(HSI): 以内部RC振荡器产生, 频率为8Mhz,但相较于外部时钟不稳定.
  2. 高速外部时钟(HSE): 以外部晶振作为时钟源, 晶振频率可取范围为4 - 16Mhz,一般采用8Mhz的晶振.
  3. 低速内部时钟(LSI): 从内部RC振荡器产生, 频率为40khz, 也是主要提供给实时时钟模块.
  4. 低速外部时钟(LSE): 以外部晶振作为时钟源, 主要是提供给实时时钟模块, 所以一般选用32.768khz,该频率下定时器方便取整.

时钟分倍频路径

以最常用的高速外部时钟为例, 从时钟源往下游的每一个环节:

  1. 最左端的OSC_OUT和OSC_IN 这两个引脚分别连接到外部晶振的两端

    这个晶振一般为8Mhz
  2. 第一个分频器PLLXTPRE

    在这个分频器中, 可以选择设置二分频, 或者不分频. 这里选择不分频
  3. 开关PLLSRC

    这个开关可以选择HSE或者HSI作为其时钟输出, 这里选择HSE
  4. 锁相环/倍频器 PLL

    可以设定2到16的倍频因子(PLLMUL), 经过PLL的时钟称为PLLCLK. 这里设置倍频因子为9, 产生的PLLCLK为72Mhz

    1. USB预分频器, PLLCLK在输入到SW前流向这里, 这个PLLCLK也作为USB的时钟
  5. 开关SW

    通过这个开关, 可以切换SYSCLK的时钟源, 有HSI,PLLCLK,HSE三个选择. 经过这个开关之后就是STM32的系统时钟(SYSCLK)了. 选择PLLCLK时钟则SYSCLK就为72Mhz
  6. AHB预分频器, SYSCLK经过AHB预分频后输入到其他外设. 本例中AHB不分频, 直接输入到HCLK, FCLK或者SDIOCLK等时钟
    • AHB总线、内核、内存和DMA使用的HCLK时钟
    • 8分频后送给Cortex系统定时器时钟,即SysTick
    • 自由运行时钟FCLK
    • APB1分频器, PCLK1,最大频率36MHz, 供APB1外设使用. 另一路送给定时器Timer, 1倍频或2倍频
    • APB2分频器, PCLK2,最大频率72MHz, 供APB2外设使用. GPIO外设是挂载在APB2总线上的
    • ADC分频器。ADC分频器经过2、4、6、8分频后送给ADC1/2/3使用,ADC最大频率为14M
    • 二分频, SDIO使用

与代码相关的时钟

  1. SYSCLK: 系统时钟, 是STM32大部分器件的时钟来源, 主要由AHB预分频器分配到各个部件
  2. HCLK: 由AHB预分频器直接输出得到, 它是高速总线AHB的时钟信号, 提供给存储器, DMA及Cortex内核, 是Cortex内核运行的时钟, CPU主频就是这个信号
  3. FCLK: 也是由AHB输出得到, 是内核的“自由运行时钟”. “自由”表现在它不来自时钟HCLK. 因此在HCLK停止时FCLK也可以继续运行. 也就是说, 即使CPU休眠了, 也能够采样到外部中断和跟踪休眠事件. 低功耗模式下使用
  4. PCLK1: 外设时钟, 由APB1分频得到, 最大可为36Mhz, 提供给APB1总线上的外设使用
  5. PCLK2: 外设时钟, 由APB2预分频输出得到, 最大为72Mhz, 提供给APB2总线上的外设

时钟源使能和配置

在配置好时钟系统之后, 如果要使用某些外设, 例如GPIO, ADC, 还要使能这些外设时钟. 如果在使用外设之前没有使能外设时钟, 这个外设不能正常运行.

STM32时钟系统的配置代码分为两部分, 一部分在 CMSIS 目录下的 system_stm32f10x.c 中的SystemInit()函数, 用于初始化. 另一部分在 FWLib 目录下的 stm32f10x_rcc.c 中, 用于操作时钟系统. 对于系统时钟来说, 默认情况下是在SystemInit函数的SetSysClock函数中判断的, SetSysClock 函数的定义如下

static void SetSysClock(void)
{
#ifdef SYSCLK_FREQ_HSE
SetSysClockToHSE();
#elif defined SYSCLK_FREQ_24MHz
SetSysClockTo24();
#elif defined SYSCLK_FREQ_36MHz
SetSysClockTo36();
#elif defined SYSCLK_FREQ_48MHz
SetSysClockTo48();
#elif defined SYSCLK_FREQ_56MHz
SetSysClockTo56();
#elif defined SYSCLK_FREQ_72MHz
SetSysClockTo72();
#endif
}

这段代码设置系统时钟的频率为72MHz,其宏定义为:

#define SYSCLK_FREQ_72MHz  72000000

如果想设置系统时钟频率为36MHz,只需注释掉上面的宏定义,并加入如下定义即可:

#define SYSCLK_FREQ_36MHz  36000000

设置完系统时钟后可以通过变量 SystemCoreClock 获得系统时钟的值,在 system_stm32f10x.c 中该变量的定义为:

#ifdef SYSCLK_FREQ_HSE
uint32_t SystemCoreClock = SYSCLK_FREQ_HSE;
#elif defined SYSCLK_FREQ_24MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_24MHz;
#elif defined SYSCLK_FREQ_36MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_36MHz;
#elif defined SYSCLK_FREQ_48MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_48MHz;
#elif defined SYSCLK_FREQ_56MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_56MHz;
#elif defined SYSCLK_FREQ_72MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_72MHz;
#else /*!< HSI Selected as System Clock source */
uint32_t SystemCoreClock = HSI_VALUE;
#endif

当系统时钟频率设置为72MHz大小时:

  • PLL时钟:72MHz
  • SYSCLK时钟:72MHz
  • AHB总线时钟(使用SYSCLK为时钟源):72MHz
  • APB1总线时钟:36MHz
  • APB2总线时钟:72MHz

时钟源使能中AHB, APB1, APB2的区别

这三个对应了各自总线上的外设时钟的开启和关闭, 在STM32F10x中

AHB总线 RCC_AHBPeriphClockCmd

void RCC_AHBPeriphClockCmd  ( uint32_t  RCC_AHBPeriph, FunctionalState   NewState)

RCC_AHBPeriph 可用的参数(可以是组合)

  • STM32_Connectivity_line_devices
RCC_AHBPeriph_DMA1
RCC_AHBPeriph_DMA2
RCC_AHBPeriph_SRAM
RCC_AHBPeriph_FLITF
RCC_AHBPeriph_CRC
RCC_AHBPeriph_OTG_FS
RCC_AHBPeriph_ETH_MAC
RCC_AHBPeriph_ETH_MAC_Tx
RCC_AHBPeriph_ETH_MAC_Rx
  • other_STM32_devices
RCC_AHBPeriph_DMA1
RCC_AHBPeriph_DMA2
RCC_AHBPeriph_SRAM
RCC_AHBPeriph_FLITF
RCC_AHBPeriph_CRC
RCC_AHBPeriph_FSMC
RCC_AHBPeriph_SDIO
Note:
SRAM and FLITF clock can be disabled only during sleep mode.

APB1总线 RCC_APB1PeriphClockCmd

void RCC_APB1PeriphClockCmd ( uint32_t  RCC_APB1Periph, FunctionalState NewState)

可用参数(可以是组合)

RCC_APB1Periph_TIM2,
RCC_APB1Periph_TIM3,
RCC_APB1Periph_TIM4,
RCC_APB1Periph_TIM5,
RCC_APB1Periph_TIM6,
RCC_APB1Periph_TIM7,
RCC_APB1Periph_TIM12,
RCC_APB1Periph_TIM13,
RCC_APB1Periph_TIM14 RCC_APB1Periph_SPI2,
RCC_APB1Periph_SPI3, RCC_APB1Periph_USART2,
RCC_APB1Periph_USART3,
RCC_APB1Periph_USART4,
RCC_APB1Periph_USART5, RCC_APB1Periph_I2C1,
RCC_APB1Periph_I2C2, RCC_APB1Periph_USB,
RCC_APB1Periph_CAN1,
RCC_APB1Periph_BKP,
RCC_APB1Periph_PWR,
RCC_APB1Periph_DAC,
RCC_APB1Periph_CEC,
RCC_APB1Periph_WWDG,
  • USART: 除了1都是
  • I2C: 都是
  • SPI: 除了1都是

APB2总线 RCC_APB2PeriphClockCmd

void RCC_APB2PeriphClockCmd ( uint32_t  RCC_APB2Periph, FunctionalState   NewState)

可用参数(可以是组合)

RCC_APB2Periph_AFIO,

RCC_APB2Periph_GPIOA,
RCC_APB2Periph_GPIOB,
RCC_APB2Periph_GPIOC,
RCC_APB2Periph_GPIOD,
RCC_APB2Periph_GPIOE,
RCC_APB2Periph_GPIOF,
RCC_APB2Periph_GPIOG, RCC_APB2Periph_ADC1,
RCC_APB2Periph_ADC2,
RCC_APB2Periph_ADC3, RCC_APB2Periph_SPI1, RCC_APB2Periph_USART1, RCC_APB2Periph_TIM1,
RCC_APB2Periph_TIM8,
RCC_APB2Periph_TIM9,
RCC_APB2Periph_TIM10,
RCC_APB2Periph_TIM11
RCC_APB2Periph_TIM15,
RCC_APB2Periph_TIM16,
RCC_APB2Periph_TIM17,
  • 所有的GPIO都是
  • 所有的ADC

系统时钟 SysTick系统定时器

STK(SysTick Timer)系统定时器

STK(SysTick Timer)系统定时器是CM3内核的外设, 内嵌在 NVIC. 系统定时器 是一个24bit的向下递减的计数器, 计数器每计数一次的时间为 1/SYSCLK, 一般我们设置系统时钟 SYSCLK 等于 72M. 当重装载数值寄存器的值递减到 0 的时候, 系统定时器就产生一次中断, 以此循环往复. 因为 SysTick 是属于 CM3 内核的外设, 所以所有基于 CM3 内核的单片机都具有这个 系统定时器, 使得软件在 CM3 单片机中可以很容易的移植. 系统定时器一般用于操作系统, 用于产生时基, 维持操作系统的心跳.

SysTick Register 系统定时寄存器

SysTick—系统定时器有4个寄存器, 在使用 SysTick 产生定时的时候, 只需要配置前三个寄存器, 最后一个校准寄存器不需要使用

寄存器名称      寄存器描述
CTRL SysTick 控制及状态寄存器
LOAD SysTick 重装载数值寄存器
VAL SysTick 当前数值寄存器
CALIB SysTick 校准数值寄存器
  • STK_CSR控制寄存器, 寄存器低4位含义

    • 第0位:ENABLE,Systick 使能位 (0:关闭Systick功能;1:开启Systick功能)
    • 第1位:TICKINT,Systick 中断使能位(0:关闭Systick中断;1:开启Systick中断)
    • 第2位:CLKSOURCE,Systick时钟源选择 (0:使用HCLK/8 作为Systick时钟;1:使用HCLK作为Systick时钟)
    • 第3位:COUNTFLAG,Systick计数比较标志,如果在上次读取本寄存器后,SysTick 已经数到了0, 则该位为1, 如果读取该位, 该位将自动清零
  • STK_LOAD 重载寄存器
    • Systick是一个递减的定时器, 当定时器递减至0时, 重载寄存器中的值就会被重装载, 继续开始递减. STK_LOAD寄存器是个24位的寄存器, 最大计数0xFFFFFF
  • STK_VAL当前值寄存器

    也是个24位的寄存器, 读取时返回当前倒计数的值, 写它则使之清零, 同时还会清除在SysTick 控制及状态寄存器中的COUNTFLAG 标志

用SysTick产生1s的时间基准, 控制LED每隔1s闪一次

流程说明

  • 调用内建函数 SysTick_Config(SystemCoreClock / 100000), 就是10us产生一次SysTick中断,
  • 然后系统会去调用内建的中断处理函数 SysTick_Handler(void), 这个函数里对 TimingDelay--,
  • 在 Dealy_us() 里用while循环阻塞进程, 直到 TimingDelay 减为0才跳出阻塞

所以将 TimingDelay 变量设为多少, 就会产生多少毫秒的延迟. 在调用 Delay_us() 函数时, 传入的数值就是要延迟的10us数

  1. 设置重载寄存器的值
uint32_t TimingDelay = 0;

/**
* @brief 启动系统滴答定时器 SysTick
* @param 无
* @retval 无
*/
void SysTick_Init(void)
{
/* SystemFrequency / 1000 1ms 中断一次
* SystemFrequency / 100000 10us 中断一次
* SystemFrequency / 1000000 1us 中断一次
*/
if (SysTick_Config(SystemCoreClock / 100000)) {
/* Capture error */
while (1);
}
} /**
* @brief us 延时程序,10us 为一个单位
* @param
* @arg nTime: Delay_us( 1 ) 则实现的延时为 1 * 10us = 10us
* @retval 无
*/
void Delay_us(__IO uint32_t nTime)
{
TimingDelay = nTime; while (TimingDelay != 0);
} /**
* @brief 获取节拍程序
* @param 无
* @retval 无
* @attention 在 SysTick 中断函数 SysTick_Handler()调用
*/
void TimingDelay_Decrement(void)
{
if (TimingDelay != 0x00) {
TimingDelay--;
}
}
  1. 实现中断服务函数 SysTick_Handler
/**
* @brief This function handles SysTick Handler.
* @param None
* @retval None
*/
void SysTick_Handler(void)
{
TimingDelay_Decrement();
}
  1. 在main函数中实现LED延时亮灭
/* LED 端口初始化 */
LED_GPIO_Config(); /* 配置 SysTick 为 10us 中断一次,时间到后触发定时中断,
*进入 stm32fxx_it.c 文件的 SysTick_Handler 处理,通过数中断次数计时
*/
SysTick_Init(); while (1) { LED1_ON;
Delay_us(100000); // 100000 * 10us = 1000ms
LED1_OFF; LED2_ON;
Delay_us(100000); // 100000 * 10us = 1000ms
LED2_OFF; LED3_ON;
Delay_us(100000); // 100000 * 10us = 1000ms
LED3_OFF;
}

关于定时器时钟源

定时器的时钟源的频率, 是容易计算错误的地方, APB1和APB2到TIMx的路径上都有一个注释

TIM2,3,4,5,6,7 If(APB1 prescaler =1) x1 else x2

TIM1 If(APB2 prescaler =1) x1 else x2

system_stm32f10x.c 中存在一个频率配置,

//#define SYSCLK_FREQ_HSE    HSE_VALUE
//#define SYSCLK_FREQ_24MHz 24000000
//#define SYSCLK_FREQ_36MHz 36000000
//#define SYSCLK_FREQ_48MHz 48000000
//#define SYSCLK_FREQ_56MHz 56000000
#define SYSCLK_FREQ_72MHz 72000000

72MHz的情况

默认使用的是72MHz, 对应的在SetSysClockTo72(void)方法中,

/* PCLK2 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1; /* PCLK1 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
  • APB1为2分频, 以满足PCLK1最大36MHz的限制, 此时APB1到TIM2,3,4,5,6,7的倍频就是x2, 也就是TIM2,3,4,5,6,7的时钟源还是72MHz
  • 而APB2是1分频, 所以APB2到TIM1的倍频是x1, 所以TIM1也是72MHz

36MHz的情况

如果启用了 SYSCLK_FREQ_36MHz, 那么对应在SetSysClockTo36(void)方法中,

/* PCLK2 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1; /* PCLK1 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV1;
  • APB1变成了1分频, 此时APB1到TIM2,3,4,5,6,7的倍频就是x1, 也就是TIM2,3,4,5,6,7的时钟源变成了36MHz
  • 而APB2是1分频, 所以APB2到TIM1的倍频是x1, 所以TIM1也是36MHz

外设时钟 TIM1 - TIM8

STM32中一共有11个定时器

  • 2个高级控制定时器: TIM1, TIM8

    • 能够产生3对PWM互补输出的高级定时器, 常用于三相电机的驱动, 时钟由APB2的输出产生.
  • 4个普通定时器: TIM2 - TIM5
    • 16位自动重装载计数器
    • 向上计数模式: 从0开始计数, 计到 LOAD寄存器 TIMx_ARR 中的数值时, 清0, 依次循环
  • 2个基本定时器: TIM6, TIM7
    • 时钟由APB1输出产生
  • 2个看门狗定时器
  • 1个系统嘀嗒定时器

使用方法(TIM2时钟)

第一步:配置系统时钟

除此之外,还需将GPIO和TIM2外设时钟打开。

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

TIM2是挂在APB1上的, 调用RCC_APB1PeriphClockCmd函数, 而不是RCC_APB2PeriphClockCmd

第二步:配置中断

void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 4;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}

第三步:配置GPIO的模式, 输入模式还是输出模式

void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
}

第四步:定时器配置

void TIM2_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
//重新将Timer设置为缺省值
TIM_DeInit(TIM2);
//采用内部时钟给TIM2提供时钟源
TIM_InternalClockConfig(TIM2);
//预分频系数为36000-1,这样计数器时钟为72MHz/36000 = 2kHz
TIM_TimeBaseStructure.TIM_Prescaler = 36000 - 1;
//设置周期数,每计2000个数就产生一次中断
TIM_TimeBaseStructure.TIM_Period = 2000;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
//禁止ARR预装载缓冲器
TIM_ARRPreloadConfig(TIM2, DISABLE); //预装载寄存器的内容被立即传送到影子寄存器
//开启TIM2的中断
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
}

该函数完成两个功能

  1. 设定预分频系数TIM_Prescaler = 36000 - 1
  2. 设定自动重装载值TIM_Period = 2000

注意:上述只是配置好了TIM2,但还没有开启TIM2。

下面是完整代码

#include “stm32f10x_lib.h”

void RCC_Configuration(void);
void NVIC_Configuration(void);
void GPIO_Configuration(void);
void TIM2_Configuration(void);
void Delay(vu32 nCount); int main(void)
{
#ifdef DEBUG
debug();
#endif
RCC_Configuration();
NVIC_Configuration();
GPIO_Configuration();
TIM2_Configuration();
TIM_Cmd(TIM2, ENABLE); //开启定时器2
while (1)
{
}
} void RCC_Configuration(void)
{
ErrorStatus HSEStartUpStatus;
RCC_DeInit();
RCC_HSEConfig(RCC_HSE_ON);
HSEStartUpStatus = RCC_WaitForHSEStartUp()
if (HSEStartUpStatus == SUCCESS)
{
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
FLASH_SetLatency(FLASH_Latency_2);
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK2Config(RCC_HCLK_Div1);
RCC_PCLK1Config(RCC_HCLK_Div2);
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
RCC_PLLCmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) {}
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while(RCC_GetSYSCLKSource() != 0x08) {}
}
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
} void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
#ifdef VECT_TAB_RAM
NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
#endif
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 4;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
} void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
} void TIM2_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
//重新将Timer设置为缺省值
TIM_DeInit(TIM2);
//采用内部时钟给TIM2提供时钟源
TIM_InternalClockConfig(TIM2);
//预分频系数为36000-1,这样计数器时钟为72MHz/36000 = 2kHz
TIM_TimeBaseStructure.TIM_Prescaler = 36000 - 1;
TIM_TimeBaseStructure.TIM_Period = 2000;
//设置时钟分割
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
//禁止ARR预装载缓冲器
TIM_ARRPreloadConfig(TIM2, DISABLE); //预装载寄存器的内容被立即传送到影子寄存器
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
}

使用方法(TIM2延时)

这段放在timer.c里, 将接口放到头文件, 就可以在main中调用delay方法延时了.

void TIM2_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_DeInit(TIM2); TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock / 2000000) - 1; // 降频到2MHz
TIM_TimeBaseStructure.TIM_Period = 20 - 1; // (1/2M)*20 = 1/100K = 10 us
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//TIM_Cmd(TIM2, ENABLE); // 开启TIM2
printf("## TIM2 Initialized ##\r\n");
} void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {
if(TIM2_TimingDelay != 0x00) {
TIM2_TimingDelay--;
}
}
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
} void TIM2_Delay_10us(__IO uint32_t count)
{
TIM_Cmd(TIM2, ENABLE);
TIM2_TimingDelay = count;
while(TIM2_TimingDelay != 0);
TIM_Cmd(TIM2, DISABLE);
} void TIM2_Delay_ms(__IO uint32_t count)
{
TIM_Cmd(TIM2, ENABLE);
TIM2_TimingDelay = count * 100;
while(TIM2_TimingDelay != 0);
TIM_Cmd(TIM2, DISABLE);
}

参考

STM32的时钟控制RCC和外设定时器的更多相关文章

  1. stm32之时钟控制

    本文提到的有以下内容: 时钟系统与总线矩阵 SysTick系统定时器 RTC实时时钟 看门狗定时器 通用定时器 一.时钟系统与总线矩阵 stm32F4的时钟树如下图所示: 在STM32中,有五个时钟源 ...

  2. STM32的时钟系统RCC详细整理(转载)

    一.综述: 1.时钟源 在 STM32 中,一共有 5 个时钟源,分别是 HSI . HSE . LSI . LSE . PLL . ①HSI 是高速内部时钟, RC 振荡器,频率为 8MHz : ② ...

  3. STM32学习笔记(四) RCC外设的学习和理解

    RCC时钟模块并不好理解,初次接触我也是一头雾水,而且我真正掌握它的时候也比较晚,是我在学习uC/os-II,需要分析时钟时才有了深刻认识.但在学习中我却一定要把放在了前列,因为这是整个嵌入式最重要的 ...

  4. STM32系统时钟RCC(基于HAL库)

    基础认识 为什么要有时钟: 时钟就是单片机的心脏,其每跳动一次,整个单片机的电路就会同步动作一次.时钟的速率决定了两次动作的间隔时间.速率越快,单片机在单位时间内所执行的动作将越多.时钟是单片机运行的 ...

  5. STM32时钟系统之利用 systick 定时器来实现准确的延时。

    本篇文章带着大家来认识一下 STM32 的时钟系统,以及利用 systick 定时器来实现一个比较准确的延时. 我们首先从时钟说起,时钟在MCU中的作用,就好比于人类的心脏一样不可或缺.STM32 的 ...

  6. [转] STM32各种时钟的区别

    [原创]:http://m.oschina.net/blog/129357 我在原创的基础又从另一位博主处引用了一些内容. 时钟系统是处理器的核心,所以在学习STM32所有外设之前,认真学习时钟系统是 ...

  7. 【STM32】时钟

    1. 在STM32中,有五个时钟源,为HSI.HSE.LSI.LSE.PLL: ① HSI是高速内部时钟,RC振荡器,频率为8MHz: ② HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源 ...

  8. STM32学习笔记(五)——通用定时器计数延时

    STM32定时器概述 STM32F40x系列总共最多有14个定时器,定时器分为三类:基本定时器.通用定时器和高级定时器.它们的都是通过计数来达到定时的目的,和51的定时器差不多,基本原理都是一样的,就 ...

  9. STM8S学习笔记-时钟控制1

    1.图13可见,STM8S单片机主要有四种时钟源可供选择: 1).1-24MHz外部晶体振荡器(HSE). 2).最大24MHz外部时钟(HSE ext). 3).16MHz高速内部RC振荡器(HSI ...

  10. 解析stm32的时钟

    STM32 时钟系统  http://blog.chinaunix.net/uid-24219701-id-4081961.html STM32的时钟系统 ***   http://www.cnblo ...

随机推荐

  1. DC - 设计和工艺数据

    环境建立命令与变量 综合主要的三部分:RTL\目标工艺库\约束文件 DC综合过程中timing > area,在时序满足的条件下进行面积优化 RTL一般会映射为standcell(与非门),需要 ...

  2. ORA-00947:Not enough values (没有足够的值)

    1.问题 2.解决方式 大概率是关系表实际列数大于你所填的元素个数,请检查是否有疏漏的列即可. 我这里是以为代理键直接忽略不写即可,没有标明具体插入列,但是还是得标明才行 --创建图书目录表TITLE ...

  3. RSA趣题篇(简单型)

    1.n与p的关系 题目 ('n=', 288990088827100766680640490138486855101396196362885475612662192799072729620922966 ...

  4. Go-稀疏数组

    package main import "fmt" // 稀疏数组 // 1. 二维数组 // 2. 存在大量相同相同数据和少量不同数据 // 思维: 将大量相同数据转化为: (数 ...

  5. kafka学习之五_多个磁盘的性能验证

    kafka学习之五_多个磁盘的性能验证 背景 周末在家学习kafka 上午验证了grafana+kafka_exporter的监控 下午想着验证一把性能相关. kafka学习之三里面,有成套的脚本. ...

  6. 【转帖】Ethernet 与 Infiniband的网络特性对比

    一.两者定位 以太网(Ethernet): 应用最广泛,是最成熟的网络互联技术,也是整个互联网络大厦的基石,兼容性非常好,可实现不同的系统之间的互连互通 IB(Infiniband): 领域很专,作为 ...

  7. 【转帖】【笔记】python连接神通数据库

    https://www.cnblogs.com/wyongbo/p/17054924.html python连接国产神州通用数据库. 一.准备 下载whl及dll: 链接: https://pan.b ...

  8. ContextSwitch 学习与使用

    ContextSwitch 学习与使用 说明 github上面有一个简单的测试系统调用以及上下文切换的工具. contextswitch. 下载之后直接make就可以进行简单的测试 需要注意的是 部分 ...

  9. Docker 运行 Redis Rabbitmq seata-server ftp 的简单办法

    公司里面用到了很多组件, 发现安装二进制太麻烦了, 所以想用Docker 进行安装. 这里面简单给总结一下就不在折腾了.. 1. redis docker run -d -p 6379:6379 -- ...

  10. MySQL查询排序和分页

    连接数据库 mysql -hlocalhost -uroot -proot 排序查询语法: select 字段列表 from 表名 order by 字段1 排序方式1, 字段3 排序方式2,字段3 ...