1、STM32F103ZET6时钟说明

  STM32F103ZET6的时钟树图如下所示:

  STM32F103ZET6有很多个时钟源,分别有:

  HSE:高速外部时钟信号。

  HSI:高速内部部时钟信号。

  LSI:低速内部时钟信号。

  LSE:低速外部时钟信号。

  HSI和LSI是芯片内置的时钟源,它们的频率大小是固定的,HSI是8MHZ,LSI是大约40KHZ。

  时钟树中的序号1是高速外部时钟信号HSE:

  HSE是由有源晶振或无源晶振通过OSC_OUT和OSC_IN脚提供的,从图片中可以看到,HSE频率从4MHZ到16MHZ不等。当使用有源晶振时,时钟从OSC_IN引脚进入,OSC_OUT引脚悬空;当使用无源晶振时,时钟从OSC_IN和OSC_OUT进入,并且要配谐振电容。HSE最常使用的就是8MHZ的无源晶振。

  时钟树中的序号D是外部低速时钟LSE:

  LSE是由有源晶振或无源晶振通过OSC32_OUT和OSC32_IN脚提供的。LSE一般使用的是32.768KHZ的无源晶振。

  时钟树中的序号2是选择PLL(倍频后的时钟)的时钟源:

  从图中可以看出,PLL时钟的来源可以是HSE或HSI/2,通过PLLSRC(CFGR寄存器的bit16)来选择使用哪一个时钟源。HSI是8MHZ的内部高速时钟信号,HSI会根据温度和环境的情况频率会有漂移,一般不作为PLL的时钟来源。一般使用HSE作为PLL的时钟源。

  时钟树中的序号3是设置PLL的倍频因子:

  可以对PLL的时钟来源进行倍频,然后得到PLLCLK时钟源。倍频因子可以通过时钟配置寄存器CFGR的bit21~bit18:PLLMUL[3:0]来配置,分别可配置成2、3、4、5、6、7、8、9、10、11、12、13、14、15、16倍频。举个例子来说,如果选择HSE作为PLL的时钟源,而且HSE=8MHZ,且将PLL的倍频因子设置为9倍频,那么PLLCLK=9*8MHZ = 72MZH。需要注意的是PLLCLK的频率不要超过72MHZ,想跑超频也可以,最大可以跑到128MHZ,不过一旦出问题ST是不负责的。

  时钟树中的序号4是系统时钟SYSCLK时钟源的选择:

  从图中可以看出,系统时钟SYSCLK的来源可以选择为HSI、PLLCLK、HSE。可以通过时钟配置寄存器CFGR的bit1~bit0:SW[1:0]来选择系统时钟SYSCLK的来源,一般选用PLLCLK,将系统时钟SYSCLK设置为72MHZ。

  在SMT32刚上电的时候,由于还没有配置过时钟,所以用的是系统内部8MHZ的HSI时钟,也就是说上电的时候系统时钟SYSCLK的频率为8MHZ。

  时钟树中的序号5是AHB总线时钟HCLK:

  从图中可以看出AHB总线时钟HCLK是系统时钟SYSCLK经过AHB预分频器分频之后得到的时钟。时钟配置寄存器CFGR的bit7~bit4:HPRE[3:0]可以设置AHB总线时钟HCLK的分频系数,分频系数可以设置为:1、2、4、8、16、64、128、256、512等。一般分频系数设置为1,即HCLK = SYSCLK。

  时钟树中的序号B是CortexM3的系统滴答时钟SYSTICK:

  从图中可以看出系统滴答时钟SYSTICK的来源是AHB总线时钟HCLK经过8分频之后的时钟。AHB总线时钟HCK一般是不分频的,所以系统滴答时钟SYSTICK的频率就等于SYSCLK/8,如果SYSCLK为72MHZ,那么系统滴答时钟SYSTICK的频率就是9MHZ。

  时钟树中的序号6是APB1总线时钟PCLK1:

  这是APB1总线上外设的时钟。从图中可以看出,APB1总线时钟PCLK1的最大频率为36MHZ,所以挂载在APB1总线时钟PCLK1上的外设,最大时钟都是36MHZ,除了APB1总线时钟PCLK1上的定时器除外。

  从图中可以看出,如果APB1总线时钟PCLK1的分频系数为1(即不分频),那么挂载在APB1总线上的定时器的频率就是APB1总线时钟PCLK1的频率;如果APB1总线时钟PCLK1的分频系数不为1(即分频),那么挂载在APB1总线上的定时器的频率就是APB1总线时钟PCLK1的频率的2倍。

  一般将APB1总线时钟PCLK1的时钟配置为36MHZ,如果AHB总线时钟HCLK设置为72MHZ,那么APB1总线时钟PCLK1的分频系数就设置为1。

  时钟树中的序号7是APB2总线时钟PCLK2:

  这是APB2总线上外设的时钟。从图中可以看出,APB2总线时钟PCLK2的最大频率为72MHZ,所以挂载在APB2总线时钟PCLK2上的外设,最大时钟都是72MHZ,除了APB2总线时钟PCLK2上的定时器除外。

  从图中可以看出,如果APB2总线时钟PCLK2的分频系数为1(即不分频),那么挂载在APB2总线上的定时器的频率就是APB2总线时钟PCLK2的频率;如果APB2总线时钟PCLK2的分频系数不为1(即分频),那么挂载在APB2总线上的定时器的频率就是APB2总线时钟PCLK2的频率的2倍。

  APB2总线时钟PCLK2可以通过预分频器设置,一般默认设置为1,即不分频。

  时钟树中的序号C是ADC的时钟:

  从图中可以看出,ADC的时钟源是由APB2总线时钟PCLK2经过分频后得到的。

  时钟树中的序号E是主时钟输出信号:

  从图中可以看出MCO的脚位可以输出主时钟的信号,MCO可以输出PLLCLK/2、HSI、HSE、SYSCLK等信号。

  一般将STM32F103ZET6的时钟配置如下:

  HSE = 8MHZ。

  PLLCLK = HSE * 9 = 72MHZ。

  SYSCLK = PLLCLK = 72MHZ。

  AHB总线时钟HCLK = SYSCLK/1 = 72MHZ。

  APB1总线时钟PCLK1 = AHB总线时钟HCLK/2 = 36MHZ。

  APB2总线时钟PCLK2 = AHB总线时钟HCLK/1 = 72MHZ。

2、HAL库版本配置时钟

  HAL库是通过HAL_RCC_OscConfig和HAL_RCC_ClockConfig这两个函数对STM32F103ZET6的时钟进行配置。函数如下:

void SystemClock_Config(void)
{ RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct; RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
   RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; if (HAL_RCC_OscConfig(&RCC_OscInitStruct)!= HAL_OK)
{
while();
} RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2)!= HAL_OK)
{
while();
}
}

  HAL_RCC_OscConfig函数的作用是选择时钟源,设置PLLCLK的时钟频率。

  HAL_RCC_ClockConfig函数的作用是配置系统时钟SYSCLK、AHB总线时钟HCLK、APB1总线时钟PCLK1、APB2总线时钟PCLK2的频率。

  HAL_RCC_OscConfig函数参数说明:

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE是选择外部高速时钟HSE。

  RCC_OscInitStruct.HSEState = RCC_HSE_ON是使能外部高速时钟HSE。

  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1是选择HSE时钟还是HSE/2时钟作为PLL的时钟输入。

    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON是使能PLL功能。

  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE是通过PLLSRC(CFGR寄存器的bit16)选择HSE作为PLL的输入时钟。

    RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9是设置PLL的倍频系数。

  HAL_RCC_ClockConfig函数参数说明:

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2是选择时钟类型。

  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK是选择系统时钟SYSCLK的时钟源。

  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1是设置AHB总线时钟HCLK的分频系数。

  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2是设置APB1总线时钟PCLK1的分频系数。

  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1是设置APB2总线时钟PCLK2的分频系数。

  从上面的程序还可以才看出,如果HAL_RCC_OscConfig和HAL_RCC_ClockConfig这两个函数如果配置不成功,那么就会进入死循环,无法运行下去。

3、寄存器版本配置时钟

  这里的配置时钟的函数是摘录了正点原子的时钟配置函数来进行说明,函数如下:

//系统时钟初始化函数
//pll:选择的倍频数,从 2 开始,最大值为 16
void Stm32_Clock_Init(u8 PLL)
{
  unsigned char temp=;
  MYRCC_DeInit(); //复位并配置向量表
  RCC->CR|=0x00010000; //外部高速时钟使能 HSEON
  while(!(RCC->CR>>));//等待外部时钟就绪
  RCC->CFGR=0X00000400; //APB1=DIV2;APB2=DIV1;AHB=DIV1;   PLL-=;//抵消 2 个单位
  RCC->CFGR|=PLL<<; //设置 PLL 值 2~16
  RCC->CFGR|=<<; //PLLSRC ON
  FLASH->ACR|=0x32; //FLASH 2 个延时周期
  RCC->CR|=0x01000000; //PLLON
  while(!(RCC->CR>>));//等待 PLL 锁定
  RCC->CFGR|=0x00000002;//PLL 作为系统时钟
  while(temp!=0x02) //等待 PLL 作为系统时钟设置成功
  {
    temp=RCC->CFGR>>;
    temp&=0x03;
  }
}

  在Stm32_Clock_Init函数中,设置了APB1总线时钟PCLK1为2分频,APB2总线时钟PCLK2为1分频,AHB总线时钟HCLK为1分频,同时选择PLLCLK作为系统时钟SYSCLK。Stm32_Clock_Init函数只有一个PLL的参数,是用设置PLL的倍频系数的。比如当HSE = 8MHZ,PLL的倍频系数设置为9,那么STM32将运行在72MHZ的速度下。

  MYRCC_DeInit函数实现外设的复位,并关断所有中断,同时调用向量表配置函数MY_NVIC_SetVectorTable,配置中断向量表。

//把所有时钟寄存器复位
void MYRCC_DeInit(void)
{
  RCC->APB1RSTR = 0x00000000;//复位结束
  RCC->APB2RSTR = 0x00000000;
  RCC->AHBENR = 0x00000014; //睡眠模式闪存和 SRAM 时钟使能.其他关闭.
  RCC->APB2ENR = 0x00000000; //外设时钟关闭.
  RCC->APB1ENR = 0x00000000;
  RCC->CR |= 0x00000001; //使能内部高速时钟 HSION
  RCC->CFGR &= 0xF8FF0000;
  //复位 SW[1:0],HPRE[3:0],PPRE1[2:0],PPRE2[2:0],ADCPRE[1:0],MCO[2:0]
  RCC->CR &= 0xFEF6FFFF; //复位 HSEON,CSSON,PLLON
  RCC->CR &= 0xFFFBFFFF; //复位 HSEBYP
  RCC->CFGR &= 0xFF80FFFF;//复位 PLLSRC, PLLXTPRE, PLLMUL[3:0] and USBPRE
  RCC->CIR = 0x00000000; //关闭所有中断
  //配置向量表
  #ifdef VECT_TAB_RAM
    MY_NVIC_SetVectorTable(0x20000000, 0x0);
  #else
    MY_NVIC_SetVectorTable(0x08000000,0x0);
  #endif
}

  MY_NVIC_SetVectorTable函数是用来配置中断向量表基址和偏移量的,决定向量表在哪个区域。

//设置向量表偏移地址
//NVIC_VectTab:基址
//Offset:偏移量
void MY_NVIC_SetVectorTable(u32 NVIC_VectTab, u32 Offset)
{
  SCB->VTOR = NVIC_VectTab|(Offset & (u32)0x1FFFFF80);//设置NVIC的向量表偏移寄存器
  //用于标识向量表是在CODE区还是在RAM区
}

4、通过MCO口输出系统时钟SYSCLK

  如果想验证时钟是否配置成功,可以通过MCO输出相应的时钟,通过示波器检验输出是否正确。

  MCO可以输出PLLCLK/2、HSI、HSE、SYSCLK等信号。

STM32F103ZET6时钟的更多相关文章

  1. STM32学习笔记(一)时钟和定时器

    由于近期在准备海洋航行器比赛,正好趁此机会学习一下ARM,看到周围很多同学都在使用32,所以我也买了一块STM32F103ZET6,准备好好地学习一下. STM32的时钟系统相当的复杂,包含了5个时钟 ...

  2. MSP430F5529时钟系统深究

    1.为什么要进行时钟管理? 时钟系统是一个数字器件的命脉,对于普通的51单片机来说,它的时钟来源只有外部晶振,然后每12个振荡周期完成一个基本操作,所以也叫做12T单片机,但对于当前高级一点的单片机来 ...

  3. STM32F103ZET6通用定时器

    1.通用定时器简介 通用定时器是由一个可编程预分频器驱动的16位自动装载计数器构成.通用定时器可以应用于多种场合,如测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和PWM).使用通用定时 ...

  4. STM32F103ZET6 PWM输出

    1.通用定时器的PWM功能 STM32F103ZET6有4个通用定时器,分别是TIM2.TIM3.TIM4.TIM5. 通用定时器由一个可编程预分频器驱动的16位自动装载计数器构成. 通用定时器的很多 ...

  5. STM32F103ZET6的基本定时器

    1.定时器的分类 STM32F103ZET6总共有8个定时器,它们是:TIM1~TIM8.STM32的定时器分为基本定时器.通用定时器和高等定时器. TIM6.TIM7是基本定时器.基本定时器是只能向 ...

  6. STM32F103ZET6独立看门狗

    1.IWDG简介 STM32F103ZET6的独立看门狗(IWDG)是由内部LSI(内部约40KHZ低速时钟)时钟驱动的.由于IWDG是由内部低速时钟驱动,所以就算主时钟发生故障,IWDG依然能够工作 ...

  7. STM32F103ZET6 GPIO的使用

    1.GPIO简介 STM32F103ZET6有多个GPIO组,如GPIOA.GPIOB.GPIOC...等等.每个GPIO组具有16个IO口. GPIO组的寄存器都是类似的,每个GPIO组都有2个32 ...

  8. 新建基于STM32F103ZET6的工程-HAL库版本

    1.STM32F103ZET6简介 STM32F103ZET6的FLASH容量为512K,64K的SRAM.按照STM32芯片的容量产品划分,STM32F103ZET6属于大容量的芯片. 2.下载HA ...

  9. [源创] STM32F103ZET6 基于XMODEM 通讯的 BOOTLOADER案列IAP

    网上好多初学者 都想知道如何更好的用IAP,BOOTLOADER 功能 我给大家一个我自己的基于Xmodem的例子, 开发环境  KEIL 5.14 + STD标准库 芯片 STM32F103ZET6 ...

随机推荐

  1. vue 带参数的跳转-完成一个功能之后 之后需要深思,否则还会忘记

    我要写详细点,否则下次很容易忘记 写了一个页面,这个页面里面添加了 很多a 标签,跳转都是同一个页面,内容不一样,方法 首先 路由 设定好 routes:[ { path:'/aaa', name:' ...

  2. vue+webpack怎么分环境进行打包

    这里说下,webpack打包里面涉及到的东西,不止webpack,还有node的知识, node的全局变量process,process.env用于返回用户环境信息对象,因为是node的全局变量,所以 ...

  3. Flutter保持页面状态AutomaticKeepAliveClientMixin

    使用bottomNavigationBar切换底部tab,再切换回来就会丢失之前的状态(重新渲染列表,丢失滚动条位置). 解决方法 使用 AutomaticKeepAliveClientMixin 重 ...

  4. 微信SEO怎么做-最新微信SEO干货

    星辉信息科技进行微信SEO已经很多年了,结合多年的微信SEO经验通过浅谈微信SEO.微信SEO的3大优势.微信SEO的6个排名技巧.企业和个人微信SEO的4大优化战略来讲,可以完美解决B端C端微信获客 ...

  5. docker的安装使用

    目录 Docker 入门到精通 CentOS安装Docker 设置管理Docker的仓库 安装Docker Engine-Community Docker基础命令 开启关闭 镜像操作 容器操作 Doc ...

  6. ubuntu1804自带的vim和vi都是用什么版本?

    之前搜索vim一些命令时,经常看到有人说ubuntu自带的vim是是vim.tiny的,功能不全. 什么需要先卸载,再重装,真的是这样吗? 我查了一下,vim的版本号 vim --version vi ...

  7. golang 交叉编译 win开发 linux生产

    windows平台之下使用 go env 能看到go本身的配置的环境变量,其中红框框起来的变量是交叉编译需要改动的选项, 由于是win平台开发,但是跑起来的程序都是在linux,所以linux转win ...

  8. Linux系统是什么?亲身自学经历分享

    我是数字媒体专业学生,第一次接触LINUX的时候,是大一C语言课程里看到的,书上讲了C语言的发展历史.说到C语言的起源,就离不开UNIX系统.在20世纪60年代,贝尔实验室的研究员Ken Thomps ...

  9. c++第一周测验

    本次得分为:14.00/14.00, 本次测试的提交时间为:2020-03-08, 如果你认为本次测试成绩不理想,你可以选择再做一次. 1 单选(1分) 下面程序片段哪个没错? 得分/总分 A. in ...

  10. express模块中的req,res参数的常用属性方法

    express模块中的req,res参数的常用属性方法 const express = require('express'); const router = express.Router() rout ...