STM32时钟初始化函数SysInit详解
stm32启动文件详解及SystemInit函数分析
DCD SysTick_Handler ; SysTick Handler
; External Interrupts
DCD WWDG_IRQHandler ; Window Watchdog
DCD PVD_IRQHandler ; PVD through EXTI Line detect
DCD TAMPER_IRQHandler ; Tamper
DCD RTC_IRQHandler ; RTC
DCD FLASH_IRQHandler ; Flash
;__main函数由编译器生成,负责初始化栈、堆等,并在最后跳转到用户自定义的main()函数,来到C的世界。
Stack_Size EQU 0x00000400 ;//定义堆栈大小
AREA STACK, NOINIT, READWRITE, ALIGN=3 ;//定义一个数据段 按8字节对齐 ;AREA 伪指令用于定义一个代码段或数据段 NOINIT:指定此数据段仅仅保留了内存单元,而没有将各初始值写入内存单元,或者将各个内存单元值初始化为0
;链接器检查要求堆栈八字节对齐的任何代码是否仅由保持堆栈八字节对齐的代码直接或间接地调用。
PRESERVE8 ;//指示编译器8字节对齐
Байду номын сангаас THUMB ;//指示编译器以后的指令为THUMB指令
;中断向量表定义
; Vector Table Mapped to Address 0 at Reset
;中断函数仅仅实现了Reset_Handler,其他要么是死循环,要么仅仅定义了函数名称
;STM32被设置为从内部FLASH启动时(这也是最常见的一种情况),当STM32遇到复位信号后,
STM32入门教程系统时钟SysTick
STM32入门教程系统时钟SysTickSTM32 入门教程系统时钟 SysTick(一) 背景介绍在传统的嵌入式系统软件按中通常实现 Delay(N) 函数的方法为:for(i = 0; i <= x; i ++);x --- 对应于对应于 N 毫秒的循环值对于STM32系列微处理器来说,执行一条指令只有几十个ns,进行 for 循环时,要实现 N 毫秒的 x 值非常大,而且由于系统频率的宽广,很难计算出延时 N 毫秒的精确值。
针对 STM32 微处理器,需要重新设计一个新的方法去实现该功能,以实现在程序中使用Delay(N)。
(二) STM32 SysTick 介绍Cortex-M3 的内核中包含一个 SysTick 时钟。
SysTick 为一个 24 位递减计数器,SysTick 设定初值并使能后,每经过 1 个系统时钟周期,计数值就减 1。
计数到 0 时,SysTick 计数器自动重装初值并继续计数,同时内部的COUNTFLAG 标志会置位,触发中断(如果中断使能情况下)。
在 STM32 的应用中,使用 Cortex-M3 内核的 SysTick 作为定时时钟,设定每一毫秒产生一次中断,在中断处理函数里对N 减一,在Delay(N) 函数中循环检测 N 是否为 0,不为 0 则进行循环等待;若为0 则关闭 SysTick 时钟,退出函数。
注:全局变量 TimingDelay , 必须定义为 volatile 类型 , 延迟时间将不随系统时钟频率改变。
(三) ST SysTick 库文件使用ST的函数库使用systick的方法1、调用SysTick_CounterCmd() -- 失能SysTick计数器2、调用SysTick_ITConfig () -- 失能SysTick中断3、调用SysTick_CLKSourceConfig() -- 设置SysTick时钟源。
4、调用SysTick_SetReload() -- 设置SysTick重装载值。
STM32时钟总结剖析
STM32时钟总结一、时钟基本概念 (2)二、时钟树 (7)三、STM32上电后时钟的过程. (7)3.1 执行SystemInit ()函数 (7)3.2 执行SetSysClock()函数. (8)3.3 执行SetSysClockTo72()函数 (8)3.3.2 判断外部高速时钟源是否稳定 (8)3.3.4 FLASH 配置. (9)3.3.5 系统时钟配置是HCLK,PCLK2为HCLK,PCLK1为HCLK的一半93.3.6 配置PLL 在这里修改倍频值。
RCC_CFGR_PLLMUL9L 93.3.7 失能PLL;判断PLL是否Readay;选择PLL 为系统时钟,一直等到时钟稳定 (9)四、时钟源的选择 (10)4.1 系统默认配置时钟8*9=72M (10)4.2 配置HSI(高速内部时钟)为系统主时钟(永远不变8M)104.3 配置HSE为系统主时钟。
8M(和外部晶振有关)114.4 配置PLLCLK为系统主时钟. (11)4.5 程序 (11)五、配置HCLK,PCLK,1 PCLK2. (11)、时钟基本概念钟。
当时钟源被直接或通过PLL间接作为系统时钟时,它将不能被停止。
稳定阶段的延迟或PLL 稳定),从一个时钟源到另一个时钟源的切换才会发生。
在被选择时钟源没有就绪时,系统时钟的切换不会发生。
直至目标时钟源就绪,才发生切换。
时钟安全系统(CSS)时钟安全系统可以通过软件被激活。
一旦其被激活,时钟监测器将在HSE振荡器启动延迟后被使能,并在HSE时钟关闭后关闭。
如果HSE时钟发生故障,HSE 振荡器被自动关闭,时钟失效事件将被送到高级定时器TIM1的刹车输入端,并产生时钟安全中断CSSI,允许软件完成营救操作。
此CSSI中断连接到Cortex ?M3的NMI中断。
一旦CSS被激活,并且HSE时钟出现故障,CSS中断就产生,并且NMI 也自动产生。
NMI 将被不断执行,直到CSS中断挂起位被清除。
STM32单片机Systick函数的使用方法
STM32单片机Systick函数的使用方法STM32单片机Systick函数的使用方法在“嵌入式学习006_Systick使用(一)”中,详细介绍了SysTIck中寄存器的使用方法,用到了很多函数,实际上到了3.5版本的标准固件库中,移除了相关驱动函数,用户必须调用CMSIS.h中定义的函数,其中CMSIS只提供了一个SysTIck设置的函数,替代了STM32原来有的所有的驱动函数,这样做的目的,可能是简化SysTIck 的设置,可是降低了用户对SysTIck的可控性。
在CMSIS中提供的函数是SysTick_Config(uint32_t ticks); 该函数设置了自动重载入计数器(LOAD)的值,SysTick IRQ的优先级,复位了计数器(V AL)的值,开始计数并打开SysTick IRQ中断。
SysTick时钟默认使用系统时钟。
其中这个函数定义在Core_cm3.h中,源代码如下所示:static __INLINE uint32_t SysTick_Config(uint32_t ticks){if (ticks 》SysTick_LOAD_RELOAD_Msk)return (1);SysTick-》LOAD= (ticksNVIC_SetPriority (SysTick_IRQn,(1《《__NVIC_PRIO_BITS)- 1);SysTick-》V AL= 0;SysTick-》CTRL= SysTick_CTRL_CLKSOURCE_Msk |SysTick_CTRL_TICKINT_Msk|SysTick_CTRL_ENABLE_Msk;return (0);}从上面的函数中可以看出,这个函数把Systick的初值,中断优先级,使能中断,开启定时器都完成了。
大大简化了程序。
其中ticks 代表的是初值。
例如系统时钟是72Mhz 那么要产生1ms的时基,那么我们可以这样去写。
STM32学习笔记
STM32学习笔记——SystemInit()函数第一课时钟频率STM32F103内部8M的内部震荡,经过倍频后最高可以达到72M。
目前TI的M3系列芯片最高频率可以达到80M。
在stm32固件库3.0中对时钟频率的选择进行了大大的简化,原先的一大堆操作都在后台进行。
系统给出的函数为SystemInit()。
但在调用前还需要进行一些宏定义的设置,具体的设置在system_stm32f10x.c文件中。
文件开头就有一个这样的定义://#define SYSCLK_FREQ_HSE HSE_Value//#define SYSCLK_FREQ_20MHz 20000000//#define SYSCLK_FREQ_36MHz 36000000//#define SYSCLK_FREQ_48MHz 48000000//#define SYSCLK_FREQ_56MHz 56000000#define SYSCLK_FREQ_72MHz 72000000ST 官方推荐的外接晶振是8M,所以库函数的设置都是假定你的硬件已经接了8M 晶振来运算的.以上东西就是默认晶振8M 的时候,推荐的CPU 频率选择.在这里选择了:#define SYSCLK_FREQ_72MHz 72000000也就是103系列能跑到的最大值72M然后这个C文件继续往下看#elif defined SYSCLK_FREQ_72MHzconst uint32_t SystemFrequency = SYSCLK_FREQ_72MHz;const uint32_t SystemFrequency_SysClk = SYSCLK_FREQ_72MHz;const uint32_t SystemFrequency_AHBClk = SYSCLK_FREQ_72MHz;const uint32_t SystemFrequency_APB1Clk = (SYSCLK_FREQ_72MHz/2);const uint32_t SystemFrequency_APB2Clk = SYSCLK_FREQ_72MHz;这就是在定义了CPU跑72M的时候,各个系统的速度了.他们分别是:硬件频率,系统时钟,AHB总线频率,APB1总线频率,APB2总线频率.再往下看,看到这个了:#elif defined SYSCLK_FREQ_72MHzstatic void SetSysClockTo72(void);这就是定义72M 的时候,设置时钟的函数.这个函数被SetSysClock ()函数调用,而SetSysClock ()函数则是被SystemInit()函数调用.最后SystemInit()函数,就是被你调用的了所以设置系统时钟的流程就是:首先用户程序调用SystemInit()函数,这是一个库函数,然后SystemInit()函数里面,进行了一些寄存器必要的初始化后,就调用SetSysClock()函数. SetSysClock()函数根据那个#defineSYSCLK_FREQ_72MHz 72000000 的宏定义,知道了要调用SetSysClockTo72()这个函数,于是,就一堆麻烦而复杂的设置~!@#$%^然后,CPU跑起来了,而且速度是72M. 虽然说的有点累赘,但大家只需要知道,用户要设置频率,程序中就做的就两个事情:第一个: system_stm32f10x.c 中#define SYSCLK_FREQ_72MHz 72000000第二个:调用SystemInit()。
STM32启动文件详解及SystemInit函数分析
1/6/afeibfp/archive/2013/01/08/2850408.html <2013年1月>日一二三四五六303112345678910111213141516171819202122232425262728293031123456789昵称:afeibfp 园龄:2年5个月粉丝:0关注:0+加关注搜索找找看 谷歌搜索常用链接我的随笔我的评论我的参与最新评论我的标签更多链接我的标签51单片机(2)多字节除法(2)汇编(2)随笔分类(2)转发(2)随笔档案(16)2013年1月 (14)2011年9月 (2)最新评论1. Re:014:针对mdk 中STM32程序无法使用printf ,产生停留BEAB BKPT 0xAB 处问题的解决(转)不点那个MiclroLIB 就行了--blakeliu阅读排行榜1. 001:无符号双字节除以单字节(51单片机,汇编源码)(418)2. 004:STM32启动文件详解及SystemInit 函数分析(转)(389)3. 014:针对mdk 中STM32程序无法使用printf ,产生停留BE AB BKPT 0xAB 处问题的解决(转)(312)4. 010:请教STM32用JLINK V8 SWD 输出调试信息到ITM V iewer 的问题(转)(208)5. 009:semihost/ITM 机制浅析以及使用JLINK 通过ITM 调试stm32单片机(转)(190)评论排行榜1. 014:针对mdk 中STM32程序无法使用printf ,产生停留BE AB BKPT 0xAB 处问题的解决(转)(1)2. 013:ADS semihosting 与硬件重定向(转)(0)3. 012:Keil 调试技术(转)(0)4. 011:Nuvoton(新唐) Cort ex M0 使用semihost 输入输出办法(转)(0)5. 010:请教STM32用JLINK V8 SWD 输出调试信息到ITM V iewer 的问题(转)(0)推荐排行榜博客园首页新随笔联系管理订阅 随笔- 16 文章- 0 评论- 1afeibfp004:STM32启动文件详解及SystemInit 函数分析(转)1 ;先在R A M 中分配系统使用的栈,R A M 的起始地址为0x 2000_00002 ;然后在R A M 中分配变量使用的堆3 ;然后在C O D E 区(f l a s h )分配中断向量表,f l a s h 的起始地址为0x 0800_0000,该中断向量表就从这个起始地址开始分配4 ;分配完成后,再定义和实现相应的中断函数,5 ;所有的中断函数全部带有[w e a k ]特性,即弱定义,如果编译器发现在别处文件中定义了同名函数,在链接时用别处的地址进行链接。
STM32中sysTick的设置
STM32中sysTick的设置(转)我不得不说意法半导体确实有点风骚!甚至有点变态。
我对ST文档 STM32F10XXX参考手册的编辑水平真是不敢恭维。
手册中好多说明都是含糊不清,甚至将好多对初学者来说很重要的地方都一笔带过,让人着实摸不着头脑。
比如前面我说过的关于NVIC嵌套向量中断控制器的介绍,这部分我认为是非常重要的,但当你看完他这部分介绍,你根本不会设置中断服务程序,他有哪些寄存器都不知道,更别说去设置了,NVIC的详细介绍是在Cotex-M3中有详细的介绍,不多说。
今天我们说的是systick定时器。
systick定时器和我上面说的情况一样,在手册中根本没有介绍。
我费了九牛二虎之力才在一个犄角格拉里找到systick定时器的英文版的说明。
在Cotex-M3有介绍,为什么要找STM32的介绍,是因为功能设置上还有点区别。
首先看一下systick定时器的作用,下面是Cotex-M3里的一段话:SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号:15)。
在以前,大多操作系统需要一个硬件定时器来产生操作系统需要的滴答中断,作为整个系统的时基。
例如,为多个任务许以不同数目的时间片,确保没有一个任务能霸占系统;或者把每个定时器周期的某个时间范围赐予特定的任务等,还有操作系统提供的各种定时功能,都与这个滴答定时器有关。
因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,以维持操作系统“心跳”的节律。
Cortex‐M3处理器内部包含了一个简单的定时器。
因为所有的CM3芯片都带有这个定时器,软件在不同 CM3器件间的移植工作得以化简。
该定时器的时钟源可以是内部时钟(FCLK,CM3上的自由运行时钟),或者是外部时钟( CM3处理器上的STCLK信号)。
不过,STCLK的具体来源则由芯片设计者决定,因此不同产品之间的时钟频率可能会大不相同,你需要检视芯片的器件手册来决定选择什么作为时钟源。
STM32时钟初始化函数SysInit详解
花了一天的时间,总算是了解了SystemInit()函数实现了哪些功能,初学STM32,,现记录如下(有理解错误的地方还请大侠指出):使用的是3.5的库,用的是STM32F107VC,开发环境RVMDK4.23我已经定义了STM32F10X_CL,SYSCLK_FREQ_72MHz函数调用顺序:startup_stm32f10x_cl.s(启动文件)→SystemInit() → SetSysClock () →SetSysClockTo72()初始化时钟用到的RCC寄存器复位值:RCC_CR = 0x0000 xx83; RCC_CFGR = 0x0000 0000;RCC_CIR = 0x0000 0000; RCC_CFGR2 = 0x0000 0000;SystemInit()在调用SetSysClock()之前RCC寄存器的值如下(都是一些与运算,或运算,在此就不赘述了):RCC->CR = 0x0000 0083; RCC->CIR = 0x00FF0000; RCC->CFGR2 = 0x00000000;至于这些寄存器都代表着什么意思,详见芯片资料RCC寄存器,该文重点不在此处;SetSysClock()函数如下:static void SetSysClock(void){#ifdef SYSCLK_FREQ_HSESetSysClockToHSE();#elif defined SYSCLK_FREQ_24MHzSetSysClockTo24();#elif defined SYSCLK_FREQ_36MHzSetSysClockTo36();#elif defined SYSCLK_FREQ_48MHzSetSysClockTo48();#elif defined SYSCLK_FREQ_56MHzSetSysClockTo56();#elif defined SYSCLK_FREQ_72MHz//我的定义的是SYSCLK_FREQ_72MHz,所以调用SetSysClockTo72()SetSysClockTo72();#endif}SetSysClockTo72()函数如下:static void SetSysClockTo72(void){__IO uint32_t StartUpCounter = 0, HSEStatus = 0;/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*//* Enable HSE */RCC->CR |= ((uint32_t)RCC_CR_HSEON);/* Wait till HSE is ready and if Time out is reached exit */do{HSEStatus = RCC->CR & RCC_CR_HSERDY;StartUpCounter++;} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));if ((RCC->CR & RCC_CR_HSERDY) != RESET){HSEStatus = (uint32_t)0x01;}else{HSEStatus = (uint32_t)0x00;}if (HSEStatus == (uint32_t)0x01){/* Enable Prefetch Buffer */FLASH->ACR |= FLASH_ACR_PRFTBE;/* Flash 2 wait state */FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;/* HCLK = SYSCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;/* PCLK2 = HCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;/* PCLK1 = HCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;#ifdef STM32F10X_CL/* Configure PLLs ------------------------------------------------------*//* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz *//* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5); /* Enable PLL2 */RCC->CR |= RCC_CR_PLL2ON;/* Wait till PLL2 is ready */while((RCC->CR & RCC_CR_PLL2RDY) == 0){}/* PLL configuration: PLLCLK = PREDIV1 * 9 = 72 MHz */RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 |RCC_CFGR_PLLMULL9);#else/* PLL configuration: PLLCLK = HSE * 9 = 72 MHz */RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |RCC_CFGR_PLLMULL));RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);#endif /* STM32F10X_CL *//* Enable PLL */RCC->CR |= RCC_CR_PLLON;/* Wait till PLL is ready */while((RCC->CR & RCC_CR_PLLRDY) == 0){}/* Select PLL as system clock source */RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;/* Wait till PLL is used as system clock source */while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08){}}else{ /* If HSE fails to start-up, the application will have wrong clockconfiguration. User can add here some code to deal with this error */}}1:AHB, APB1,APB2时钟确定//HCLK = SYSCLK ,从下面的分析可以得出SYSCLK是使用PLLCLK时钟的,也就是72MHZ (至于72MHZ如何得来,请看下面分析)//那么就是HCLK(AHB总线时钟)=PLLCLK = 72MHZ//AHB总线时钟等于系统时钟SYSCLK,也就是AHB时钟= HCLK = SYSCLK = 72MHZ /* HCLK = SYSCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;//PLCK2等于HCLK一分频,所以PCLK2 = HCLK,HCLK = 72MHZ, 那么PLCK2(APB2总线时钟) = 72MHZ//APB2总线时钟等于HCLK的一分频,也就是不分频;APB2 时钟= HCLK = SYSCLK = 72MHZ/* PCLK2 = HCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;//PCLK1 = HCLK / 2;PCLK1 等于HCLK时钟的二分频,那么PCLK1(APB1) = 72MHZ / 2 = 36MHZ//APB1总线时钟等于HCLK的二分频,也就是APB1时钟= HCLK / 2 = 36MHZ/* PCLK1 = HCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;2:如何得出SYSCLK(系统时钟)为72MHZ(外部晶振25MHZ)//记得参考英文芯片资料的时钟树P115页和RCC时钟寄存器进行理解RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);RCC_CFGR2_PREDIV2_DIV5: PREDIV2 = 5;5分频也就是PREDIV2对输入的外部时钟5分频,那么PLL2和PLL3没有倍频前是25 /5 = 5MHZRCC_CFGR2_PLL2MUL8 : PLL2MUL = 8;8倍频8倍频后,PLL2时钟= 5 * 8 = 40MHZ; 因此PLL2CLK = 40MHZRCC_CFGR2_PREDIV1SRC_PLL2 : RCC_CFGR2的第16位为1,选择PLL2CLK 作为PREDIV1的时钟源RCC_CFGR2_PREDIV1_DIV5:PREDIV1 = 5;PREDIV1对输入时钟5分频PREDIV1CLK = PLL2CLK / 5 = 8MHZ以上是对RCC_CFGR2进行的配置--------------------------------------------------------------------------------------RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 |RCC_CFGR_PLLMULL9);RCC_CFGR_PLLXTPRE_PREDIV1 :操作的是RCC_CFGR的第17位PLLXTPRE,操作这一位和操作RCC_CFGR2寄存器的位[3:0]中的最低位是相同的效果RCC_CFGR_PLLSRC_PREDIV1 :选择PREDIV1输出作为PLL输入时钟;PREDIV1CLK =8MHZ,所以输入给PLL倍频的时钟源是8MHZRCC_CFGR_PLLMULL9 :PLLMUL = 9;PLL倍频系数为9,也就是对PLLCLK = PREDIV1CLK * 8 = 72MHZ以上是对RCC_CFGR进行的配置---------------------------------------------------------------------------------------------------RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; //选择PLLCLK作为系统时钟源--------------------------------------------------------------------------------------------------至此基本配置已经完成,配置的时钟如下所述:SYSCLK(系统时钟) = 72MHZAHB总线时钟 = 72MHZAPB1总线时钟 = 36MHZAPB2总线时钟 = 72MHZPLL时钟 = 72MHZPLL2时钟 = 40MHZ。
STM32-Systick时钟
针对STM32 3.5的库版本的SysTick编写的简单定时时钟的LDE灯闪烁,网上的大多Systick滴答时钟都是2.0版本的库,由于现在都是3.5库函数,所以,会出现编译错误,没有定义等问题,找了好久,这个问题才解决#include "stm32f10x.h"void Delay(u32 nTime);//声明延迟函数void GPIO_Configuration(void);int main(void){RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);GPIO_Configuration();while(SysTick_Config(SystemCoreClock/1000)!=0);//配置SysTick,装入初始值,装载值根据时钟源频率而定,72MHz时钟源则产生1ms中断需要装载值为(72000000/1000)while(1){GPIO_ResetBits(GPIOC,GPIO_Pin_7|GPIO_Pin_9);GPIO_SetBits(GPIOC,GPIO_Pin_6|GPIO_Pin_8);Delay(1000);GPIO_ResetBits(GPIOC,GPIO_Pin_6|GPIO_Pin_8);GPIO_SetBits(GPIOC,GPIO_Pin_7|GPIO_Pin_9);Delay(1000);GPIO_Write(GPIOC,0x0140);Delay(1000);GPIO_Write(GPIOC,0x0280);Delay(1000);}}void GPIO_Configuration(void){GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;GPIO_Init(GPIOC,&GPIO_InitStructure);}volatile u32 TimingDelay;//定义全局变量,其声明在stm32f10x_it.c中void Delay(u32 nTime)//定义延迟函数TimingDelay=nTime;//将延迟数赋予全局变量while(TimingDelay!=0);}其中,在stm32f10x_it.c中:extern volatile u32 TimingDelay; 声明全局变量void SysTick_Handler(void){TimingDelay--;}3.2 结果编译烧入开发板后,LED等以1s的时间精确交替闪烁。
STM32-时钟配置与使用
STM32-时钟配置与使⽤0、前⾔RCC-复位和时钟控制器可以实现配置系统时钟SYSCLK,配置AHB(HCLK)总线时钟,配置外设APB1(PCLK1)和APB2(PCLK2)时钟库函数的标准配置为PCLK2=HCLK=SYSCLK=PLLCLK=72M,PCLK1=HCLK/2=36M系统初始化时会调⽤函数实现时钟配置。
#ifdef SYSCLK_FREQ_HSEuint32_t SystemCoreClock = SYSCLK_FREQ_HSE; /*!< System Clock Frequency (Core Clock) */#elif defined SYSCLK_FREQ_24MHzuint32_t SystemCoreClock = SYSCLK_FREQ_24MHz; /*!< System Clock Frequency (Core Clock) */#elif defined SYSCLK_FREQ_36MHzuint32_t SystemCoreClock = SYSCLK_FREQ_36MHz; /*!< System Clock Frequency (Core Clock) */#elif defined SYSCLK_FREQ_48MHzuint32_t SystemCoreClock = SYSCLK_FREQ_48MHz; /*!< System Clock Frequency (Core Clock) */#elif defined SYSCLK_FREQ_56MHzuint32_t SystemCoreClock = SYSCLK_FREQ_56MHz; /*!< System Clock Frequency (Core Clock) */#elif defined SYSCLK_FREQ_72MHzuint32_t SystemCoreClock = SYSCLK_FREQ_72MHz; /*!< System Clock Frequency (Core Clock) */static void SetSysClock(void){#ifdef SYSCLK_FREQ_HSESetSysClockToHSE();#elif defined SYSCLK_FREQ_24MHzSetSysClockTo24();#elif defined SYSCLK_FREQ_36MHzSetSysClockTo36();#elif defined SYSCLK_FREQ_48MHzSetSysClockTo48();#elif defined SYSCLK_FREQ_56MHzSetSysClockTo56();#elif defined SYSCLK_FREQ_72MHzSetSysClockTo72();#endif在system_stm32f10x.c⽂件中可更改宏定义改变系统时钟频率#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)/* #define SYSCLK_FREQ_HSE HSE_VALUE */#define SYSCLK_FREQ_24MHz 24000000#else/* #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#endif1、时钟树主要时钟HSE:⾼速外部时钟,可由有源晶振或⽆源晶振提供,4-16MHzPLL以HSE为来源时可设置不分频或2分频PLL:锁相环时钟源,可配置来⾃HSE或HSI/2PLLCLK:锁相环时钟,可设置倍频[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]SYSCLK:系统时钟PCLK2:APB2总线时钟,由HCLK通过⾼速APB2预分频得到,分频因⼦[1,2,4,8,16]其他时钟USB时钟:由PLLCLK通过USB预分频器得到,分频因⼦[1,1.5]Cortex系统时钟:由HCLK8分频得到,⽤来驱动内核的系统定时器SysTickADC时钟:由PCLK2经ADC预分频得到,分频因⼦[2,4,6,8]RTC时钟:由HSE/128或LSE或LSI得到MCO时钟:输出时钟,可由PLLCLK/2,HSI,HSE,SYSCLK配置2、时钟配置相关库函数配置函数/*将RCC外设初始化为复位状态*/void RCC_DeInit(void);/*使能HSE,可选参数RCC_HSE_OFF,RCC_HSE_ON,RCC_HSE_Bypass*/void RCC_HSEConfig(uint32_t RCC_HSE);/*等待时钟源启动稳定,返回SUCCESS,ERROR*/ErrorStatus RCC_WaitForHSEStartUp(void);/*配置PLL时钟源和PLL倍频因⼦RCC_RLLSource:RCC_PLLSource_HSE_Div1,RCC_PLLSource_HSE_Div2,RCC_PLLSource_HSI_Div2RCC_PLLMul:RCC_PLLMul_2 [2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]*/void RCC_PLLConfig(uint32_t RCC_PLLSource, uint32_t RCC_PLLMul);/*配置系统时钟,可选参数RCC_SYSCLKSource_HSI,RCC_SYSCLKSource_HSE,RCC_SYSCLKSource_PLLCLK */void RCC_SYSCLKConfig(uint32_t RCC_SYSCLKSource);/*配置HCLK,可选参数RCC_SYSCLK_Div1 [1,2,4,8,16,64,128,256,512]*/void RCC_HCLKConfig(uint32_t RCC_SYSCLK);/*配置PCLK1,可选参数RCC_HCLK_Div1 [1,2,4,8,16]*/void RCC_PCLK1Config(uint32_t RCC_HCLK);/*配置PCLK2,可选参数RCC_HCLK_Div1 [1,2,4,8,16]*/void RCC_PCLK2Config(uint32_t RCC_HCLK);操作函数/*控制PLL开关,可选参数DISABLE,ENABLE*/void RCC_PLLCmd(FunctionalState NewState);/*获取状态,可选参数#define RCC_FLAG_HSIRDY ((uint8_t)0x21)#define RCC_FLAG_HSERDY ((uint8_t)0x31)#define RCC_FLAG_PLLRDY ((uint8_t)0x39)#define RCC_FLAG_LSERDY ((uint8_t)0x41)#define RCC_FLAG_LSIRDY ((uint8_t)0x61)#define RCC_FLAG_PINRST ((uint8_t)0x7A)#define RCC_FLAG_PORRST ((uint8_t)0x7B)#define RCC_FLAG_SFTRST ((uint8_t)0x7C)#define RCC_FLAG_IWDGRST ((uint8_t)0x7D)#define RCC_FLAG_WWDGRST ((uint8_t)0x7E)#define RCC_FLAG_LPWRRST ((uint8_t)0x7F)返回SET,RESET*/* - 0x08: PLL used as system clock*/uint8_t RCC_GetSYSCLKSource(void);使⽤HSE配置系统时钟1、开启HSE ,并等待 HSE 稳定2、设置 AHB、APB2、APB1的预分频因⼦3、设置PLL的时钟来源,和PLL的倍频因⼦,设置各种频率主要就是在这⾥设置4、开启PLL,并等待PLL稳定5、把PLLCK切换为系统时钟SYSCLK6、读取时钟切换状态位,确保PLLCLK被选为系统时钟/* 设置系统时钟:SYSCLK, AHB总线时钟:HCLK, APB2总线时钟:PCLK2, APB1总线时钟:PCLK1* PCLK2 = HCLK = SYSCLK* PCLK1 = HCLK/2,最⾼只能是36M* 参数说明:pllmul是PLL的倍频因⼦,在调⽤的时候可以是:RCC_PLLMul_x , x:[2,3,...16]* 举例:HSE_SetSysClock(RCC_PLLMul_9); 则设置系统时钟为:8MHZ * 9 = 72MHZ* HSE_SetSysClock(RCC_PLLMul_16); 则设置系统时钟为:8MHZ * 16 = 128MHZ,超频慎⽤** HSE作为时钟来源,经过PLL倍频作为系统时钟,这是通常的做法*/void HSE_SetSysClock(uint32_t pllmul){__IO uint32_t StartUpCounter = 0, HSEStartUpStatus = 0;// 把RCC外设初始化成复位状态,这句是必须的RCC_DeInit();//使能HSE,开启外部晶振,野⽕开发板⽤的是8MRCC_HSEConfig(RCC_HSE_ON);// 等待 HSE 启动稳定HSEStartUpStatus = RCC_WaitForHSEStartUp();// 只有 HSE 稳定之后则继续往下执⾏if (HSEStartUpStatus == SUCCESS){//----------------------------------------------------------------------//// 使能FLASH 预存取缓冲区FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);// SYSCLK周期与闪存访问时间的⽐例设置,这⾥统⼀设置成2// 设置成2的时候,SYSCLK低于48M也可以⼯作,如果设置成0或者1的时候,// 如果配置的SYSCLK超出了范围的话,则会进⼊硬件错误,程序就死了// 0:0 < SYSCLK <= 24M// 1:24< SYSCLK <= 48M// 2:48< SYSCLK <= 72MFLASH_SetLatency(FLASH_Latency_2);//----------------------------------------------------------------------//// AHB预分频因⼦设置为1分频,HCLK = SYSCLKRCC_HCLKConfig(RCC_SYSCLK_Div1);// APB2预分频因⼦设置为1分频,PCLK2 = HCLKRCC_PCLK2Config(RCC_HCLK_Div1);// APB1预分频因⼦设置为1分频,PCLK1 = HCLK/2RCC_PCLK1Config(RCC_HCLK_Div2);//-----------------设置各种频率主要就是在这⾥设置-------------------//// 设置PLL时钟来源为HSE,设置PLL倍频因⼦// PLLCLK = 8MHz * pllmulRCC_PLLConfig(RCC_PLLSource_HSE_Div1, pllmul);//------------------------------------------------------------------//// 开启PLLRCC_PLLCmd(ENABLE);// 等待 PLL稳定while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET){}// 当PLL稳定之后,把PLL时钟切换为系统时钟SYSCLKRCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);// 读取时钟切换状态位,确保PLLCLK被选为系统时钟while (RCC_GetSYSCLKSource() != 0x08){}}else{// 如果HSE开启失败,那么程序就会来到这⾥,⽤户可在这⾥添加出错的代码处理// 当HSE开启失败或者故障的时候,单⽚机会⾃动把HSI设置为系统时钟,// HSI是内部的⾼速时钟,8MHZwhile (1){使⽤HSI配置系统时钟1、开启HSI ,并等待 HSI 稳定2、设置 AHB、APB2、APB1的预分频因⼦3、设置PLL的时钟来源,和PLL的倍频因⼦,设置各种频率主要就是在这⾥设置4、开启PLL,并等待PLL稳定5、把PLLCK切换为系统时钟SYSCLK6、读取时钟切换状态位,确保PLLCLK被选为系统时钟/* 设置系统时钟:SYSCLK, AHB总线时钟:HCLK, APB2总线时钟:PCLK2, APB1总线时钟:PCLK1* PCLK2 = HCLK = SYSCLK* PCLK1 = HCLK/2,最⾼只能是36M* 参数说明:pllmul是PLL的倍频因⼦,在调⽤的时候可以是:RCC_PLLMul_x , x:[2,3,...16]* 举例:HSI_SetSysClock(RCC_PLLMul_9); 则设置系统时钟为:4MHZ * 9 = 72MHZ* HSI_SetSysClock(RCC_PLLMul_16); 则设置系统时钟为:4MHZ * 16 = 64MHZ** HSI作为时钟来源,经过PLL倍频作为系统时钟,这是在HSE故障的时候才使⽤的⽅法* HSI会因为温度等原因会有漂移,不稳定,⼀般不会⽤HSI作为时钟来源,除⾮是迫不得已的情况* 如果HSI要作为PLL时钟的来源的话,必须⼆分频之后才可以,即HSI/2,⽽PLL倍频因⼦最⼤只能是16 * 所以当使⽤HSI的时候,SYSCLK最⼤只能是4M*16=64M*/void HSI_SetSysClock(uint32_t pllmul){__IO uint32_t HSIStartUpStatus = 0;// 把RCC外设初始化成复位状态,这句是必须的RCC_DeInit();//使能HSIRCC_HSICmd(ENABLE);// 等待 HSI 就绪HSIStartUpStatus = RCC->CR & RCC_CR_HSIRDY;// 只有 HSI就绪之后则继续往下执⾏if (HSIStartUpStatus == RCC_CR_HSIRDY){//----------------------------------------------------------------------//// 使能FLASH 预存取缓冲区FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);// SYSCLK周期与闪存访问时间的⽐例设置,这⾥统⼀设置成2// 设置成2的时候,SYSCLK低于48M也可以⼯作,如果设置成0或者1的时候,// 如果配置的SYSCLK超出了范围的话,则会进⼊硬件错误,程序就死了// 0:0 < SYSCLK <= 24M// 1:24< SYSCLK <= 48M// 2:48< SYSCLK <= 72MFLASH_SetLatency(FLASH_Latency_2);//----------------------------------------------------------------------//// AHB预分频因⼦设置为1分频,HCLK = SYSCLKRCC_HCLKConfig(RCC_SYSCLK_Div1);// APB2预分频因⼦设置为1分频,PCLK2 = HCLKRCC_PCLK2Config(RCC_HCLK_Div1);// APB1预分频因⼦设置为1分频,PCLK1 = HCLK/2RCC_PCLK1Config(RCC_HCLK_Div2);//-----------------设置各种频率主要就是在这⾥设置-------------------//// 设置PLL时钟来源为HSE,设置PLL倍频因⼦// PLLCLK = 4MHz * pllmulRCC_PLLConfig(RCC_PLLSource_HSI_Div2, pllmul);//------------------------------------------------------------------//// 开启PLLRCC_PLLCmd(ENABLE);// 等待 PLL稳定while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET){}// 当PLL稳定之后,把PLL时钟切换为系统时钟SYSCLKRCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);// 读取时钟切换状态位,确保PLLCLK被选为系统时钟while (RCC_GetSYSCLKSource() != 0x08){}}else{// 如果HSI开启失败,那么程序就会来到这⾥,⽤户可在这⾥添加出错的代码处理// 当HSE开启失败或者故障的时候,单⽚机会⾃动把HSI设置为系统时钟,// HSI是内部的⾼速时钟,8MHZwhile (1){MCO输出MCO GPIO初始化/** 初始化MCO引脚PA8* 在F1系列中MCO引脚只有⼀个,即PA8,在F4系列中,MCO引脚会有两个*/void MCO_GPIO_Config(void){GPIO_InitTypeDef GPIO_InitStructure;// 开启GPIOA的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);// 选择GPIO8引脚GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;//设置为复⽤功能推挽输出GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//设置IO的翻转速率为50MGPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;// 初始化GPIOA8GPIO_Init(GPIOA, &GPIO_InitStructure);}输出// MCO 引脚初始化MCO_GPIO_Config();// 设置MCO引脚输出时钟,⽤⽰波器即可在PA8测量到输出的时钟信号,// 我们可以把PLLCLK/2作为MCO引脚的时钟来检测系统时钟是否配置准确// MCO引脚输出可以是HSE,HSI,PLLCLK/2,SYSCLK//RCC_MCOConfig(RCC_MCO_HSE);//RCC_MCOConfig(RCC_MCO_HSI);//RCC_MCOConfig(RCC_MCO_PLLCLK_Div2);RCC_MCOConfig(RCC_MCO_SYSCLK);Systick系统定时器简介SysTick——系统定时器是属于 CM3 内核中的⼀个外设,内嵌在 NVIC 中。
STM32F4 第7讲 SystemInit时钟系统初始化函数剖析-M4
④、LSE是低速外部时钟,接频率为32.768kHz的石英晶体。RTC ⑤、PLL为锁相环倍频输出。STM32F4有两个PLL:
主PLL(PLL)由HSE或者HSI提供时钟信号,并具有两个不同的输出时钟。 ✓ 第一个输出PLLP用于生成高速的系统时钟(最高168MHz) ✓ 第二个输出PLLQ用于生成USB OTG FS的时钟(48MHz),随机数发生器 的时钟和SDIO时钟。
__IO uint32_t AHB2LPENR; /*!< RCC AHB2 peripheral clock enable in low power mode register, Address offset: 0x54 */
__IO uint32_t AHB3LPENR; /*!< RCC AHB3 peripheral clock enable in low power mode register, Address offset: 0x58 */
Address offset: 0x24 */
uint32_t RESERVED1[2]; /*!< Reserved, 0x28-0xB1ENR; /*!< RCC AHB1 peripheral clock register,
Address offset: 0x30 */
__IO uint32_t PLLCFGR;
__IO uint32_t CFGR;
/*!< RCC clock configuration register,
Address offset: 0x08 */
__IO uint32_t CIR;
STM32中的几个时钟SysTick、FCLK、SYSCLK、HCLK的详解
STM32中的几个时钟SysTick、FCLK、SYSCLK、HCLK的详解在STM32中,有五个时钟源,为HSI、HSE、LSI、LSE、PLL。
①、HSI是高速内部时钟,RC振荡器,频率为8MHz。
②、HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz。
③、LSI是低速内部时钟,RC振荡器,频率为40kHz。
④、LSE是低速外部时钟,接频率为32.768kHz的石英晶体。
⑤、PLL为锁相环倍频输出,其时钟输入源可选择为HSI/2、HSE或者HSE/2。
倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz。
其中40kHz的LSI(低速内部时钟)供独立看门狗IWDG使用,另外它还可以被选择为实时时钟RTC的时钟源。
另外,实时时钟RTC的时钟源还可以选择LSE(低速外部时钟),或者是HSE(高速外部时钟)的128分频。
RTC的时钟源通过RTCSEL[1:0]来选择。
STM32中有一个全速功能的USB模块,其串行接口引擎需要一个频率为48MHz的时钟源。
该时钟源只能从PLL输出端获取,可以选择为1.5分频或者1分频,也就是,当需要使用USB模块时,PLL必须使能,并且时钟频率配置为48MHz 或72MHz。
()另外,STM32还可以选择一个时钟信号输出到MCO脚(PA8)上,可以选择为PLL输出的2分频、HSI、HSE、或者系统时钟。
系统时钟SYSCLK最大频率为72MHz,它是供STM32中绝大部分部件工作的时钟源。
系统时钟可由PLL、HSI或者HSE提供输出,并且它通过AHB分频器分频后送给各模块使用,AHB分频器可选择1、2、4、8、16、64、128、256、512分频。
其中AHB分频器输出的时钟送给5大模块使用:①、送给AHB总线、内核、内存和DMA 使用的HCLK时钟。
②、分频后送给STM32芯片的系统定时器时钟(Systick=Sysclk/8=9Mhz)③、直接送给Cortex的自由运行时钟(free running clock)FCLK。
STM32 SysTick 系统时钟 超简易定时器SysTick
STM32 SysTick 系统时钟超简易定时器SysTick/*** @brief Configures the SysTick. 系统时钟配置函数main.c* @param None* @retval None*/void SysTick_Configuration(void){/* Setup SysTick Timer for 100 msec interrupts */if (SysTick_Config((SystemCoreClock) / 10))// 1/10s=100ms{ /* Capture error */ while (1);}NVIC_SetPriority(SysTick_IRQn, 0x0);}/*** @brief This function handles SysTick Handler. 系统时钟中断函数stm32f10x_it.c* @param None* @retval None*/void SysTick_Handler(void){/* Generate TIM1 COM event by software */TIM_GenerateEvent(TIM1, TIM_EventSource_COM);}SysTick_Config(SystemFrequency / 10) 函数的形参就是systick 重装定时器的值。
systck 计数频率为每秒72000000 次,所以72000 次就是1/10 秒,也就是100ms。
SysTick 是1 个24bit 递减计数器,通过对SysTick 控制与状态寄存器的设置,可选择HCLK 时钟(72M)或HCLK 的8 分频(9M,缺省是这个)作为SysTick 的时钟源。
SysTick 的重装寄存器决定了定时器频率。
若SysTick 的时钟源是72M, SystemFrequency = 72000000Hz 所以SysTick_Config(SystemFrequency / 1000);就是1ms 时基。
基于LinkedInSTM32F4时钟系统初始化设置
{
#if(__FPU_PRESENT == 1)">SCB-》CPACR |=((3UL《《10*2)|(3UL《《11*2));
#endif
RCC-》CR |=(uint32_t)0x00000001;
RCC-》CFGR = 0x00000000;
RCC-》CR
在设置完相关寄存器后,接下来SystemInit函数内部会调用SetSysClock函数。这个函数比较长,我们就把函数一些关键代码行截取出来给大家讲解一下。这里我们省略一些宏定义标识符值的判断而直接把针对STM32F407比较重要的内容贴出来:
static void SetSysClock(void)
基于LinkedInSTM32F4时钟系统初始化设置
LinkedInSTM32F4时钟系统初始化是在system_stm32f4xx.c中的SystemInit()函数中完成的。对于系统时钟关键寄存器设置主要是在SystemInit函数中调用SetSysClock()函数来设置的。我们可以先看看SystemInit()函数体:
RCC-》CFGR |= RCC_CFGR_PPRE2_DIV2;
RCC-》CFGR |= RCC_CFGR_PPRE1_DIV4;
RCC-》CFGR |= RCC_CFGR_PPRE2_DIV1;
RCC-》CFGR |= RCC_CFGR_PPRE1_DIV2;
RCC-》PLLCFGR = PLL_M |(PLL_N《《6)|(((PLL_P》》1)-1)《《16)|
#endif
这里默认固件库配置的是25000000,我们外部时钟为8MHz,所以我们根据我们硬件情况修改为8000000即可。
STM32的SYSTICK详解
STM32的SYSTICK详解摘自网络什么是SYSTICK:在单任务引用程序中,因为其架构就决定了它执行任务的串行性,这就引出一个问题:当某个任务出现问题时,就会牵连到后续的任务,进而导致整个系统崩溃。
要解决这个问题,可以使用实时操作系统(RTOS).因为RTOS以并行的架构处理任务,单一任务的崩溃并不会牵连到整个系统。
这样用户出于可靠性的考虑可能就会基于RTOS来设计自己的应用程序。
这样SYSTICK存在的意义就是提供必要的时钟节拍,为RTOS的任务调度提供一个有节奏的“心跳”。
微控制器的定时器资源一般比较丰富,比如STM32存在8个定时器,为啥还要再提供一个SYSTICK?原因就是所有基于ARMCorte某_M3内核的控制器都带有SyTick定时器,这样就方便了程序在不同的器件之间的移植。
而使用RTOS的第一项工作往往就是将其移植到开发人员的硬件平台上,由于SYSTICK的存在无疑降低了移植的难度。
SyTick定时器除了能服务于操作系统之外,还能用于其它目的:如作为一个闹铃,用于测量时间等。
要注意的是,当处理器在调试期间被喊停(halt)时,则SyTick定时器亦将暂停运作。
时钟的选择:用户可以在位于Corte某_M3处理器系统控制单元中的系统节拍定时器控制和状态寄存器(SyTickcontrolandtaturegiter,SCSR)选择ytick时钟源。
如将SCSR中的CLKSOURCE位置位,SyTick会在CPU频率下运行;而将CLKSOUCE位清除则SyTick会以CPU主频的1/8频率运行。
3.5版本的库函数与以往的有所区别不存在tm32f10某_ytick.c文件,故原来的一些函数也不存在,比如SyTick_SetReload(u32reload);SyTick_ITConfig(FunctionalStateN ewState);等在3.5版本的库函数中与ytick相关的函数只有两个第一个,SyTick_Config(uint32_ttick),在core_cm3.h头文件中进行定义的。
STM32时钟配置函数
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; #endif 这个就是用来指引程序的,日后再聊。
SetSysClock()函数代码: static void SetSysClock(void) {
/* Reset CFGR2 register */ RCC->CFGR2 = 0x00000000;
#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
/* Disable all interrupts and clear pending bits */ RCC->CIR = 0x009F0000;
备注:此文档为个人实际操作经验,鄙人非大神,如有错误还请指教,谢谢
1 原库函数
注:黑色字体为函数代码,紫色的为注释,红色的是我的理解。 cl:互联型产品,stm32f105/107 系列 vl:超值型产品,stm32f100 系列 xl:超高密度产品,stm32f101/103 系列 ld:低密度产品,FLASH 小于 64K md:中等密度产品,FLASH=64 or 128 hd:高密度产品,FLASH 大于 128
#ifdef DATA_IN_ExtSRAM SystemInit_ExtMemCtl();
#endif #endif 我用的是 STM32F103ZET6,属于 STM32F10X_HD 型,但是不会定 义 DATA_IN_ExtSRAM,所以不去执行 SystemInit_ExtMemCtl(),这 个函数我们后续再看,下面的代码是:SetSysClock();完事向下执行, #ifdef VECT_TAB_SRAM
04_系统初始化函数及时钟配置
04_系统初始化函数及时钟配置1初始化初始化函数在system_stm32f4xx.c⽂件中void SystemInit(void){SetSysClock();}主要⽬的在于配置主系统时钟。
static void SetSysClock(void){主要⼯作在于1 选择HSE或HSI做时钟,⽤HIS做时钟源,可以避免晶振不起振的问题。
2 配置主PLL3 分频配置AHB 及APB1 APB2}2 STM32F407时钟树STM32中有5个时钟源,从上到下依次列出为:1LSE外部低速时钟,典型值为32.768Khz频率范围为0~1000KHz,主要供RTC单元使⽤。
2 LSI内部低速RC时钟,典型值为32KHz,并不准确,⽽是在15~47Khz变化,给看门狗使⽤或在停机和待机模式下保持运⾏,供⾃动唤醒单元(AWU)使⽤。
3 HSI内部⾼速RC振荡器,典型值16Mhz,精度为1%,若没有外接晶振,可启⽤内部晶振。
4HSE外部⾼速时钟典型值25Mhz,选择晶振范围为4~26Mhz。
⾼精度晶振。
5PLL锁相倍频,我认为严格的讲,这个不算是时钟源,它是由HSI或HSE倍频得到,⼀般作为系统时钟。
再往下是时钟输出单元。
我们下⾯详细讲解⼀下系统时钟。
如下图所⽰:系统时钟可以选择HSE HSI或PLL中的⼀种,⼀般是选择PLL,因为HSI和HSE都不能达到168MHz,⽽PLL经HSE或HIS分频后倍频,使得系统时钟可达到168Mhz。
上图详细指明系统时钟SYSCLK的配置⽅法。
外部晶振HSE = 25MHz经25分频达到1Mhz ,经PLL倍频336,然后2分频为168MHz的PLL时钟,这些参数在⽂件system_stm32f4xx.c中配置以上截图的参数对应上图的参数。
SYSCLK选择PLL作时钟源,为168Mhz系统时钟SYSCLK分频给AHB使⽤,AHB总线最⾼时钟为168Mhz,AHB分频给APBx(APB1与APB2)使⽤。
SysTick_Config简单理解
SysTick_Config简单理解这个函数在core_cm3.h中成功配置返回0 SysTick_Config(tick) tick为时钟周期的个数 1/f为时钟周期//中断⼀次的时间为T=tick*(1/f),f为SysTick的时钟周期Systick_config优先级设定的理解 NVIC_SetPrioritySystick模块初始化配置函数(Systick_config)中设定模块中断优先级的函数为:NVIC_SetPriority((SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);参数SysTick_IRQn为systick基址,这个没什么好说的关键在参数 (1<<__NVIC_PRIO_BITS) - 1);这个参数即占先优先级值,其中—NVIC_PRIO_BITS是stm32.h中的宏定义,库函数默认为4,表⽰⽤4位表⽰占先优先级,因为m3内核只有4位⽤来表⽰占先优先级和响应优先级,那么响应优先级就剩下0位了,也就是没有响应优先级之分,按照上式计算若NVIC_PRIO_BITS为4则占先优先级为15,即最低优先级值依次可类推,即 (1<<__NVIC_PRIO_BITS) - 1);表⽰的是可⽤的最低优先级(1<<4为16,—1为15),将后⾯那个红⾊的1改为其他值即可改变此模块占先优先级进⼊NVIC_SetPriority函数可解释上述观点:NVIC->IP[(uint32_t)(IRQn)] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff);<< (8 - __NVIC_PRIO_BITS)) 即表⽰占先优先级的寄存器的那⼏位,priority为占先优先级,即上⾯带过来的实参 (1 <<_NVIC_PRIO_BITS)-1不知我的理解对否,还请指正,共同提⾼。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
花了一天的时间,总算是了解了SystemInit()函数实现了哪些功能,初学STM32,,现记录如下(有理解错误的地方还请大侠指出):使用的是3.5的库,用的是STM32F107VC,开发环境RVMDK4.23我已经定义了STM32F10X_CL,SYSCLK_FREQ_72MHz函数调用顺序:startup_stm32f10x_cl.s(启动文件)→SystemInit() → SetSysClock () →SetSysClockTo72()初始化时钟用到的RCC寄存器复位值:RCC_CR = 0x0000 xx83; RCC_CFGR = 0x0000 0000;RCC_CIR = 0x0000 0000; RCC_CFGR2 = 0x0000 0000;SystemInit()在调用SetSysClock()之前RCC寄存器的值如下(都是一些与运算,或运算,在此就不赘述了):RCC->CR = 0x0000 0083; RCC->CIR = 0x00FF0000; RCC->CFGR2 = 0x00000000;至于这些寄存器都代表着什么意思,详见芯片资料RCC寄存器,该文重点不在此处;SetSysClock()函数如下:static void SetSysClock(void){#ifdef SYSCLK_FREQ_HSESetSysClockToHSE();#elif defined SYSCLK_FREQ_24MHzSetSysClockTo24();#elif defined SYSCLK_FREQ_36MHzSetSysClockTo36();#elif defined SYSCLK_FREQ_48MHzSetSysClockTo48();#elif defined SYSCLK_FREQ_56MHzSetSysClockTo56();#elif defined SYSCLK_FREQ_72MHz//我的定义的是SYSCLK_FREQ_72MHz,所以调用SetSysClockTo72()SetSysClockTo72();#endif}SetSysClockTo72()函数如下:static void SetSysClockTo72(void){__IO uint32_t StartUpCounter = 0, HSEStatus = 0;/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*//* Enable HSE */RCC->CR |= ((uint32_t)RCC_CR_HSEON);/* Wait till HSE is ready and if Time out is reached exit */do{HSEStatus = RCC->CR & RCC_CR_HSERDY;StartUpCounter++;} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));if ((RCC->CR & RCC_CR_HSERDY) != RESET){HSEStatus = (uint32_t)0x01;}else{HSEStatus = (uint32_t)0x00;}if (HSEStatus == (uint32_t)0x01){/* Enable Prefetch Buffer */FLASH->ACR |= FLASH_ACR_PRFTBE;/* Flash 2 wait state */FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;/* HCLK = SYSCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;/* PCLK2 = HCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;/* PCLK1 = HCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;#ifdef STM32F10X_CL/* Configure PLLs ------------------------------------------------------*//* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz *//* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5); /* Enable PLL2 */RCC->CR |= RCC_CR_PLL2ON;/* Wait till PLL2 is ready */while((RCC->CR & RCC_CR_PLL2RDY) == 0){}/* PLL configuration: PLLCLK = PREDIV1 * 9 = 72 MHz */RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 |RCC_CFGR_PLLMULL9);#else/* PLL configuration: PLLCLK = HSE * 9 = 72 MHz */RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |RCC_CFGR_PLLMULL));RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);#endif /* STM32F10X_CL *//* Enable PLL */RCC->CR |= RCC_CR_PLLON;/* Wait till PLL is ready */while((RCC->CR & RCC_CR_PLLRDY) == 0){}/* Select PLL as system clock source */RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;/* Wait till PLL is used as system clock source */while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08){}}else{ /* If HSE fails to start-up, the application will have wrong clockconfiguration. User can add here some code to deal with this error */}}1:AHB, APB1,APB2时钟确定//HCLK = SYSCLK ,从下面的分析可以得出SYSCLK是使用PLLCLK时钟的,也就是72MHZ (至于72MHZ如何得来,请看下面分析)//那么就是HCLK(AHB总线时钟)=PLLCLK = 72MHZ//AHB总线时钟等于系统时钟SYSCLK,也就是AHB时钟= HCLK = SYSCLK = 72MHZ /* HCLK = SYSCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;//PLCK2等于HCLK一分频,所以PCLK2 = HCLK,HCLK = 72MHZ, 那么PLCK2(APB2总线时钟) = 72MHZ//APB2总线时钟等于HCLK的一分频,也就是不分频;APB2 时钟= HCLK = SYSCLK = 72MHZ/* PCLK2 = HCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;//PCLK1 = HCLK / 2;PCLK1 等于HCLK时钟的二分频,那么PCLK1(APB1) = 72MHZ / 2 = 36MHZ//APB1总线时钟等于HCLK的二分频,也就是APB1时钟= HCLK / 2 = 36MHZ/* PCLK1 = HCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;2:如何得出SYSCLK(系统时钟)为72MHZ(外部晶振25MHZ)//记得参考英文芯片资料的时钟树P115页和RCC时钟寄存器进行理解RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);RCC_CFGR2_PREDIV2_DIV5: PREDIV2 = 5;5分频也就是PREDIV2对输入的外部时钟5分频,那么PLL2和PLL3没有倍频前是25 /5 = 5MHZRCC_CFGR2_PLL2MUL8 : PLL2MUL = 8;8倍频8倍频后,PLL2时钟= 5 * 8 = 40MHZ; 因此PLL2CLK = 40MHZRCC_CFGR2_PREDIV1SRC_PLL2 : RCC_CFGR2的第16位为1,选择PLL2CLK 作为PREDIV1的时钟源RCC_CFGR2_PREDIV1_DIV5:PREDIV1 = 5;PREDIV1对输入时钟5分频PREDIV1CLK = PLL2CLK / 5 = 8MHZ以上是对RCC_CFGR2进行的配置--------------------------------------------------------------------------------------RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 |RCC_CFGR_PLLMULL9);RCC_CFGR_PLLXTPRE_PREDIV1 :操作的是RCC_CFGR的第17位PLLXTPRE,操作这一位和操作RCC_CFGR2寄存器的位[3:0]中的最低位是相同的效果RCC_CFGR_PLLSRC_PREDIV1 :选择PREDIV1输出作为PLL输入时钟;PREDIV1CLK =8MHZ,所以输入给PLL倍频的时钟源是8MHZRCC_CFGR_PLLMULL9 :PLLMUL = 9;PLL倍频系数为9,也就是对PLLCLK = PREDIV1CLK * 8 = 72MHZ以上是对RCC_CFGR进行的配置---------------------------------------------------------------------------------------------------RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; //选择PLLCLK作为系统时钟源--------------------------------------------------------------------------------------------------至此基本配置已经完成,配置的时钟如下所述:SYSCLK(系统时钟) = 72MHZAHB总线时钟 = 72MHZAPB1总线时钟 = 36MHZAPB2总线时钟 = 72MHZPLL时钟 = 72MHZPLL2时钟 = 40MHZ。