STM32F103RCT6开发板M3单片机教程05--RCC配置
. X6 D3 m* H* x0 O8 e3 N! E& E" ]/ K
( D h6 Z7 w+ w5 K9 z3 ]6 F1 L. K* b h1 C% t5 t( L
前言, k1 ^3 a/ \# ^1 C5 B. K
首先了解一下是什么RCC(Reset Clock Control),复位和时钟控制(RCC)% v1 K8 w5 K7 p/ \
小容量产品是指闪存存储器容量在16K至32K字节之间的STM32F101xx, STM32F102xx和STM32F103xx微控制器。
. Y. h8 f+ ^6 E- X- h. s$ F% \中容量产品是指闪存存储器容量在64K至128K字节之间的STM32F101xx, STM32F102xx和STM32F103xx微控制器。
; i& ^) [' \, |, \& r1 `% j* g大容量产品是指闪存存储器容量在256K至512K字节之间的STM32F101xx和STM32F103xx微控制器。5 r) U V6 z1 V& c
除非特别说明,本章节描述的模块应用于整个STM32F103xx微控制器系列,因为我们使用是STM32F103RCT6开发板是mini最小系统板。
9 L8 z0 r$ {8 L4 e4 }5 [本教程使用是(光明谷SUN_STM32mini开发板)8 `2 z1 d( C$ u2 @2 R
/ j1 E2 \6 B) S, m" s) z D# O
4 {2 [5 [/ x- n) R! S
一、复位" ^5 t! H [, P
STM32F10xxx支持三种复位形式,分别为系统复位、上电复位和备份区域复位。
9 O$ T/ N( Y& x" y' Z. C
* L6 T( r1 d# `* R* J* X, j) J
4 H: c9 L" U( g2 d% V1.1 系统复位$ d7 k- B$ v/ F. _& q6 E6 _* w
系统复位将复位除时钟控制寄存器CSR中的复位标志和备份区域中的寄存器以外的所有寄存器6 T4 G+ {$ S( C" q, X$ s
, u' g; b/ O& b9 C
当以下事件中的一件发生时,产生一个系统复位:
& S$ `0 z: X8 ^1. NRST管脚上的低电平(外部复位); O2 N Z+ y& \/ I3 M! ^$ z( k
2. 窗口看门狗计数终止(WWDG复位)$ m3 B) j% R6 M6 H, f
3. 独立看门狗计数终止(IWDG复位)
# k; y9 ]6 Y0 Z% C' U2 k. k" P+ K4. 软件复位(SW复位)0 R1 U3 Y. R# Q7 }3 [1 P; M
5. 低功耗管理复位6 U& z: T+ A1 |. }5 x4 a* I
可通过查看RCC_CSR控制状态寄存器中的复位状态标志位识别复位事件来源。
& ]2 m. _# U9 _2 I8 G$ V& y3 m软件复位) B" z% F) k% H m% r1 D9 \
通过将Cortex™-M3中断应用和复位控制寄存器中的SYSRESETREQ位置’1’,可实现软件复位。请参考Cortex™-M3技术参考手册获得进一步信息。( b8 e$ n' W# K6 B9 T9 n
低功耗管理复位" E, b1 ^" v. ?% r
在以下两种情况下可产生低功耗管理复位:
3 K/ p) e; x: r1. 在进入待机模式时产生低功耗管理复位:
6 D* l5 [" _: i; N2 `* m2 L% y+ ?通过将用户选择字节中的nRST_STDBY位置’1’将使能该复位。这时,即使执行了进入待机模式的过程,系统将被复位而不是进入待机模式。! h: `, {# x8 {" r; m
2. 在进入停止模式时产生低功耗管理复位:
5 ]/ O. o" ?: `6 n通过将用户选择字节中的nRST_STOP位置’1’将使能该复位。这时,即使执行了进入停机模式的过程,系统将被复位而不是进入停机模式。$ v Q# d' _* ~8 e
关于用户选择字节的进一步信息,请参考STM32F10xxx闪存编程手册。8 S% g9 r! a( U
0 V3 D2 C8 n' ^4 h! }0 I- F8 X" O
1.2 电源复位
0 n$ k* _( f% }当以下事件中之一发生时,产生电源复位:
; u# I2 B7 p+ g! G1. 上电/掉电复位(POR/PDR复位)* q/ e8 _3 l1 D6 \0 g* T4 z
2. 从待机模式中返回8 y; R5 E4 t& I4 O; T. P
电源复位将复位除了备份区域外的所有寄存器。 (见图3)5 M, ?6 ?9 {7 T, }
图中复位源将最终作用于RESET管脚,并在复位过程中保持低电平。复位入口矢量被固定在地/ J# H J1 @0 p6 p1 W
址0x0000_0004。更多细节,参阅stm32f10xxx参考手册表36。 4 a4 F# |' A8 K* e2 Y; D
" P1 ], v, j0 t# O8 x s
1 s% K, I! ^) G, v: k4 K
% \5 x0 T6 @9 n P6 d7 V, v1.3 备份域复位3 ^! Q5 D9 o9 R# h* B& L
当以下事件中之一发生时,产生备份区域复位。& Z: w# @8 H8 A, T$ U; e
1. 软件复位,备份区域复位可由设置备份区域控制寄存器RCC_BDCR中的BDRST位产生。
! }$ T" I9 ?( _# }2. 在VDD和VBAT两者掉电的前提下, VDD或VBAT上电将引发备份区域复位。
7 o$ C: S. O/ t* B4 M3 [, S f6 Z0 b* ]* p% e( m4 u4 f
$ h2 M5 c& b) H9 a7 |. r% w二、 时钟8 [/ ]4 @' R$ K. Z
4 H4 T% L, R6 Q! ]) M4 M三种不同的时钟源可被用来驱动系统时钟(SYSCLK):, ~. w/ }: g2 u- n; s) [0 ^
● HSI振荡器时钟, J2 ^8 B4 Q0 I8 |1 B+ g
● HSE振荡器时钟, ]) U5 J, R# Q. V- ?
● PLL时钟
9 L0 D9 K7 b7 A/ X) O* H$ S- H: _这些设备有以下2种二级时钟源:
( a. y0 X6 s8 J: S( z$ _● 40kHz低速内部RC,可以用于驱动独立看门狗和通过程序选择驱动RTC。 RTC用于从停机/待机模式下自动唤醒系统。! `, I9 V2 @! P" e
0 l4 b7 O$ J4 I% k● 32.768kHz低速外部晶体也可用来通过程序选择驱动RTC(RTCCLK)。' r7 r) p) B- L+ K6 k0 Z( F! t
当不被使用时,任一个时钟源都可被独立地启动或关闭,由此优化系统功耗。8 u' @3 W7 H1 U3 X
复位和时钟控制 STM32F10xxx参考手 " q0 d) t- [5 Z9 n3 _5 ^( }
1.3 备份域复位
( ^& J) ?( w) q3 b当以下事件中之一发生时,产生备份区域复位。
! c0 h) R% D s v" X1. 软件复位,备份区域复位可由设置备份区域控制寄存器RCC_BDCR中的BDRST位产生。
8 a2 o0 b- b# G6 ^2. 在VDD和VBAT两者掉电的前提下, VDD或VBAT上电将引发备份区域复位。) ?/ q9 }! |% a- A6 Y
$ |. B# e( |9 E
2 S; g+ u' s I2 j9 l) X6 t
更多细节,参阅 STM32F10xxx参考手册
) G2 ~# Q4 @. ]7 P1 }* R [size=14.6667px] e- P# x8 u2 b& D& m3 I
RCC设置流程: 1、将RCC寄存器重新设置为默认值 RCC_DeInit 2、打开外部高速时钟晶振HSE RCC_HSEConfig(RCC_HSE_ON) 3、等待外部高速时钟晶振工作 HSEStartUpStatus = RCC_WaitForHSEStartUp(); 4、设置AHB时钟 RCC_HCLKConfig 5、设置高速APB时钟 RCC_PCLK2Config 6、设置低速APB时钟 RCC_PCLK1Config 7、设置PLL RCC_PLLConfig 8、打开PLL RCC_PLLCmd(ENABLE) 9、等待PLL工作 while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET) 10、设置系统时钟 RCC_SYSCLOCKConfig 11、判断是否PLL是系统时钟 while(RCC_GetSYSCLKSource()!=0x08) 12、打开要使用的外设时钟 RCC_APB2PerphClockCmd()/RCC_APB1PeriphClockCmd()
$ q$ t. J4 c. V) w了解基础知识下面实操吧
5 ]. Y. c9 _4 L3 N" d以前我们其实也有配置,但不具体,基本都本MCU默认的配置,真正用好STM32,还得熟悉RCC.
& \! L5 }8 g; i7 Y0 n, }+ `3 c; ?: j' Z3 |. {9 z5 G4 N; m/ Q$ |7 b1 I
程序编码3 i7 n: q# J9 q% h
: ~. z# @4 m+ G8 ?; k
8 k3 q2 K7 t- l" Y3 F
复制上节工程文件夹打开(这个方法比较方便)
- s+ W0 o7 D5 Z& Z, f/ {- 码字:编辑main.c, 在上节基础上增加RCC配置函数。
- /**********************************************************************************' u6 f; K( r: O+ |. g; O ?* L
- * Sun STM32 mini Demo
: b/ l8 a' S2 q% j
% l! _; M# f1 u- k7 |- * Description( v! t7 _; A. O
-
- Y) _( D6 |. d; r7 o2 T3 e; s - RCC Config Demo; | l r Z% x- I5 A
9 r) q% q( F f& y8 M9 @-
7 ~# i: M! @. e5 r2 J - * Version Date Auther Reversed History1 q) P( ]' R- t, F
- ----------------------------------------------------------------------------
! m- J* c& ~$ f9 c - V1.0.0 2021-11-07 Lojam Fan Fisrt Created * V2 J; N% h3 i9 f0 x% u$ x6 M. L
-
' q3 ?6 B, r! x$ n4 _: d - * (C) Sunshine Silicon Corporation
, `* R" r# c# C7 `% w2 j, m - * Website: http://www.sunsili.com http://sunsili.taobao.com http://bbs.sunsili.com1 f4 D* y2 w$ Y' \# u% B
- * E-Mail : fan@sunsili.com* y& S7 I- ~4 E$ |
- ( v! x9 @5 o. C: y. b9 n5 X
- **********************************************************************************/ n# B% L; ?* h k- r; X
% P, x6 H P& U1 n" m7 W. u( r. h- #include "stm32f10x.h", L8 [) {9 z+ n/ c; [! q6 A; l
- #include "usart.h"( n& v [5 H5 o% K1 M8 y
- #include "SysTick.h"
. N& |* Y1 M$ U9 C s1 @ - #include "led.h". P( q7 v9 G! ^ O
- #include "key.h"
, X, ^1 c3 v/ I' {5 @ U7 @ - #include <stdio.h>
! n6 U, F g0 U; | {, a8 f
, g6 l: K5 b8 a- 9 u9 B" D7 G4 q5 Y
- extern vu8 Usart1_R_Buff[USART1_REC_MAXLEN]; //串口1数据接收缓冲区
- ]. u+ Q) r- k4 R6 ]6 r; @ - extern vu8 Usart1_R_State; //串口1接收状态. n* f$ b1 f1 s* Q
- extern vu16 Usart1_R_Count; //当前接收数据的字节数
* r4 H* }' D- }( t, P
; l% `9 Q3 m0 J1 n: Z- void RCC_Configuration(void);
( Y1 K* Q t4 A' r4 w% b) y, a" K2 b - : M4 J1 E p6 C# L
- /*******************************************************************************
' {" P$ q" R# @, T; R9 M - * 函数名 : main
9 S& o* T5 R# p - * 描述 : 主函数,用户程序从main函数开始运行! I& b# g3 Q O/ h* q+ u: A
- * 输入 : 无
" L2 F, o* l7 T- T0 W9 r5 | - * 输出 : 无
2 K. B2 l5 ^6 h0 f, R0 H1 o - * 返回值 : int:返回值为一个16位整形数
' \4 U. B6 i( G0 d' I: p% X - * 说明 : 无+ u3 O2 m7 v1 L6 n; y
- *******************************************************************************/ T$ v' y9 X! U2 a- _ ^
- int main(void)
, x1 }9 \1 [9 h1 |9 a+ T - {; ^' k( b1 @5 ^
- u8 keyVal;
2 [6 Q2 c6 F$ K( l( f6 W% F - RCC_Configuration();6 v, ~; v6 F3 \4 u1 k
- SysTick_Init_Config();
$ I0 r3 j* u$ q8 g0 Q - USART1_Init_Config(115200);//USART1初始化配置
/ w2 z6 A- D- y7 G4 Z/ S - LED_GPIO_Config();# F$ r) [. k6 e/ i' k
- Key_GPIO_Config();
+ N- ?' a, g- ^6 m5 h2 t - printf ("*===================================================*\n");- @3 G) \( a: y
- printf ("* * Name: Sun STM32 mini Demo Code. *************\n");
! \5 l |0 Z/ p6 U8 ^ - printf ("* * (C) Sunshine Silicon Corporation *************\n");
5 J- h% m: _8 h W2 f& t, U8 w1 W - printf ("* * Website: http://www.sunsili.com *************\n");
# R6 P* \0 q2 u - printf ("* * E-Mail : fan@sunsili.com *************\n");( s4 o s) q/ \! u
- printf ("*===================================================*\n");) W& |) z0 i9 [
- printf ("* Sun STM32 mini Key Demo code .*\n");
/ A( v$ h( S$ t8 {1 L - s) n& [% s' h, a2 S1 O
- while (1)
+ a) @" M& N; _! v( N - {* ^( F9 o: U/ `! n2 J7 l$ E
- keyVal = Key_Down_Scan();( T C* R+ W# ?! ^7 p
- if(Usart1_R_State == 1)//一帧数据接收完成
2 b- d: |# M$ y' H5 J/ H I - {
}& N2 X1 b5 M - USART1_SendData((u8 *)Usart1_R_Buff, Usart1_R_Count); //USART1发送数据缓冲区数据(发送刚接收完成的一帧数据)
0 I. C2 o- r& V( t( @6 D/ b - Usart1_R_State =0;
$ i& ?- W6 z2 t" l5 r" l - Usart1_R_Count =0;
0 d: L# i Z& w" X3 B3 J' Y& q - }( @# d+ m1 ~, ^3 B/ ]
- if(keyVal)
8 y+ {; J+ r3 P! }, C3 z - {7 k; ?6 }: O( e% G8 u
- printf("KeyVal:%d\r", keyVal);+ ?9 X* L6 M1 {2 r
- if(keyVal & 0x01) LED3_ON(); W1 X8 f1 t8 y. j' _$ i
- else if(keyVal & 0x02) LED4_ON();
0 H* h: s3 s+ f" q- P1 X - }9 i/ G, D+ l8 _, |
- else LED_ALL_OFF();+ ]1 j4 T. \+ ]% A5 e* K! V4 E; ~
- }
1 D2 E2 u' @4 t6 q - }
0 r5 U9 c9 s$ W& Y* H( G( q - ' {4 ?( W, b! S" {
9 i+ x; o* s2 j% C) \) M- /*******************************************************************************
/ q) s5 s, l5 p. C) ] - * 函数名 : RCC_Configuration* f/ n, J4 N: {
- * 描述 : 设置系统时钟为72MHZ(这个可以根据需要改)
5 h" O% ] N1 ~: ~5 Q- M( w. g - * 输入 : 无
9 Y* X$ p# h2 s6 @ - * 输出 : 无
. R; j5 E2 ? S( Y8 z6 ~; i - * 返回值 : 无
6 u0 N1 i( ^& d3 }5 g - * 说明 : STM32F107x和STM32F105x系列MCU与STM32F103x系列MCU时钟配置有所不同* k! j3 t" Q! c* {' Y
- *******************************************************************************/- `' t+ x! V4 f
- void RCC_Configuration(void)$ D5 P, N" H% @7 K! q
- {
: G. y+ q# _1 e2 o- O) b, ` - ErrorStatus HSEStartUpStatus; //外部高速时钟(HSE)的工作状态变量
8 F; p+ e* O1 ~ - 7 ^' ]- z3 _1 f g
- RCC_DeInit(); //将所有与时钟相关的寄存器设置为默认值. f. `0 ^5 T$ ~' i6 X9 M8 o
- RCC_HSEConfig(RCC_HSE_ON); //启动外部高速时钟HSE 0 \4 u2 M8 ^" ]' x
- HSEStartUpStatus = RCC_WaitForHSEStartUp(); //等待外部高速时钟(HSE)稳定1 n( _2 M; {! X1 K
- 2 _& u( o; G l! q7 k% p
- if(SUCCESS == HSEStartUpStatus) //如果外部高速时钟已经稳定6 t- a! R& r4 C3 K2 L+ _( n# K
- {
6 o4 V5 |8 N8 X$ T - /* Enable Prefetch Buffer */
* @* c Y% w3 \5 P6 @3 o - FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //Flash设置
! q# W O# ]: { w' @9 X; \ - /* Flash 2 wait state */
% }9 N6 B" v5 V3 h - FLASH_SetLatency(FLASH_Latency_2);
$ j$ i) \$ Z) W - ( I- x0 U9 p* T# C* ^
- t R* L. O" p5 n5 m* \
- RCC_HCLKConfig(RCC_SYSCLK_Div1); //设置AHB时钟等于系统时钟(1分频)/72MHZ+ a) |, L9 t4 x' L+ z {( o6 J* {
- RCC_PCLK2Config(RCC_HCLK_Div1); //设置APB2时钟和HCLK时钟相等/72MHz(最大为72MHz)
! O6 I5 ~+ i& @9 b( M - RCC_PCLK1Config(RCC_HCLK_Div2); //设置APB1时钟是HCLK时钟的2分频/36MHz(最大为36MHz)
& ?# Q2 a( V4 A2 \9 J6 c3 j# @5 r - - m8 h/ X$ F8 h$ [6 B
- RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //PLLCLK = 8MHz * 9 = 72 MHz " J& I, O0 C2 }, g2 I1 a2 Z
- ! u3 f; s( [' M: d7 s
- + |* l6 h% ?8 T. K7 [. n% T
- RCC_PLLCmd(ENABLE); //使能PLL
# o& @$ q5 ]: w0 L2 T- Q - while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); //等待PLL稳定
. v+ g2 E; e2 {" ? - , ~0 S# l. }, j" t$ h
- RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //设置系统时钟的时钟源为PLL
4 Y! V) f% ^7 _, v7 D, E - 2 I% F0 I1 O) I1 B& J2 p" c* }
- while(RCC_GetSYSCLKSource() != 0x08); //检查系统的时钟源是否是PLL
& F! E8 a- Q# W - RCC_ClockSecuritySystemCmd(ENABLE); //使能系统安全时钟 * r; c7 v3 D1 s3 _
-
, O" k! _( g; [ ^ - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE | RCC_APB2Periph_AFIO,ENABLE);
: A% Z5 M* z5 [# ] - }- s: \( v! j9 g7 x- B& [7 R
- }
/ ?& N% `, T, _# `- k+ o
) R9 D- s7 r" t- 1 x6 M G9 c+ { ?3 k
- + ?0 S2 _* ]( m7 v0 y% ^0 `% D
- /******************* (C) COPYRIGHT SUNSHINE SILICON **************************
9 L+ X8 D: P! s9 g7 W6 R% V, c9 x - ******************** END OF FILE main.c *******************/
复制代码
& x0 ^) P# L" u+ |, {* \$ g- 编译调试
0 X3 ~6 o W1 L9 v3 e) N4 c 保存直接编译,发现编译出错,提示FLASH_PrefetchBufferCmd 和 FLASH_SetLatency函数未定义。解决方法添加库文件stm32f10x_flash.c' b6 T8 f9 w+ R! O+ t2 f
重新编译,通过。! S3 a- P: r: n p; x
调试
2 Y+ ?/ G% R3 T$ A; k7 C; c( Z: ~2 W/ w
方法不再重复,经过前两节练习,大家应该是会了.3 ]2 p4 Q% Q. {/ r# v: h# `% b( B8 E
效果与前一节是一样,只是我们多了RCC配置。现在效果一样,但是真正项目里RCC是配置不一样,是致命的。# P# l* G L/ }! B+ E
5 t' \6 E: K( l. ]+ r- ?0 a课后作业
m. R1 d% u$ T& i5 j改变CPU运行频率
. w: c( `" u- ]5 l- L" h1 ^
; n2 B) b/ M3 P! C3 \工程源码) v' i! C/ J- E9 u) f4 J
(回复后,可查看 下载)# m- _+ O; a2 J6 P+ Z* z# r# I
|