今日接手用stm32f100xx芯片开发的项目,以前用的是stm8s 和stm32f103xx芯片;因为在别人的项目代码的基础上做2次开发,但是发现那个代码main函数中没有对系统时钟的设置的相关函数,一直纳闷,但也没有深究,直至昨日 调试时出现串口收发数据出错,源代码在原项目的板子上串口发送、接收数据正常,同样程序在项目板子上收发的数据不正确, 两块板子芯片一样,串口收发管脚一样,最后发现原来板子外部晶振是8MHZ ,新板子外部晶振是12MHZ; 而在STM32固件库中,默认的外部晶振是8MHZ,由于时钟源不正确,导致波特率不正确,当然收发的数据也不正确了.....我勒个去!都怪自己平时看问题“不求甚解”。$ d# q/ C3 n. {; L
# Z* a1 p, ]" z+ J- A
(波特率与时钟源关系公式:IntegerDivider = ((PCLKx) / (16 * (USART_InitStruct->USART_BaudRate)))( u! N( n7 L. O/ Y) r9 u4 |
# q$ t; H% g& h/ e7 ^$ `
为了深入思考,我提出了一些疑问,通过解答这些问题更深入的了解时钟;
, V# n8 L1 Z/ L% z
$ u& ?4 R$ |0 T) h& k/ S问题一:对系统时钟的设置的相关函数,在main函数中找不到,那在哪里?还是说根本没有对系统时钟进行配置?
2 e- H+ v3 N* q+ T# v2 N
8 e. C* m7 W/ r9 _' A6 n问题二:既然用了外部晶振做系统时钟,那为什么没看到启动外部晶振的操作?
8 c8 b- y3 [1 m( H+ r8 a( C
4 x: o* i8 s% y0 \& \3 b问题三:串口的时钟源是什么?串口时钟源跟系统时钟的关系?/ ^4 N2 V( m x. H8 K1 ~4 S) f
0 V+ W7 n# {5 V; {8 P" r0 o问题四:程序中串口时钟源是怎样实现对波特率的关系的?9 N: m5 `( K6 Q" C/ ?( O8 g8 j( V Z# E
4 c* ~" o' p7 O* Z- x: z
现附上我找到上面3个问题答案做的一张框架图:希望博友参考此图理解我后面的内容:# k" p2 D% n$ o# U
. T) s/ H" E5 f7 c. d, z# k- u. X Q0 i1 l
0 `- c" }* c8 d( h, m' m在进入主题之前我们先了解一些必要的基础知识----stm32系列芯片的种类和型号:* P, U1 u/ V( w
9 B7 I k1 ^3 ystartup_stm32f10x_cl.s 互联型的器件,STM32F105xx,STM32F107xx
' M1 i; m0 ]% v2 ^1 [startup_stm32f10x_hd.s 大容量的STM32F101xx,STM32F102xx,STM32F103xx
! U u7 P! _8 x% R8 ostartup_stm32f10x_hd_vl.s 大容量的STM32F100xx9 u* d) f4 m9 e, T( _ }- s" I \
startup_stm32f10x_ld.s 小容量的STM32F101xx,STM32F102xx,STM32F103xx
# V6 q( Z+ Q- x, ustartup_stm32f10x_ld_vl.s 小容量的STM32F100xx; ^3 ]# p1 o* ~, P# u# W
startup_stm32f10x_md.s 中容量的STM32F101xx,STM32F102xx,STM32F103xx, A& n3 @( f G1 ^9 X6 _8 o, m* v
startup_stm32f10x_md_vl.s 中容量的STM32F100xx (我项目中用的是此款芯片 stm32f100CB)3 m( L; o* J ]6 p5 C; L. `
startup_stm32f10x_xl.s FLASH在512K到1024K字节的STM32F101xx,STM32F102xx,STM32F103xx4 a! f9 t3 M, l; X5 q& @1 U1 ?0 E
4 M5 `, R% u7 Q3 d) u. Rcl:互联型产品,stm32f105/107系列2 _- H1 w0 I- w5 R8 \3 Q+ H
vl:超值型产品,stm32f100系列
& n. H0 m9 {$ Dxl:超高密度产品,stm32f101/103系列, N& @/ ?* L# x! l% A8 }+ m7 v
ld:低密度产品,FLASH小于64K
4 O, I6 C$ l5 g( z5 emd:中等密度产品,FLASH=64 or 128
; a6 p9 ~/ }8 M+ t! V5 p- thd:高密度产品,FLASH大于128% [. q7 {( {. o4 ]# L
8 ^3 L" o) j i. d: M
4 o% J2 j7 `! f- `/ U% O7 h
(下图中的startup_stm32f10_ld.s应改为:startup_stm32f10x_md_vl.s)
7 U1 Z( c# T, w$ O: h8 l: g, \/ l% M* b6 I( S
1 d9 a% @1 u6 |5 T( S' n7 F/ `- F
. k0 ~' s; y% y0 f% c
问题一:对系统时钟的设置的相关函数,在main函数中找不到,那在哪里?还是说根本没有对系统时钟进行配置?; @. A3 \7 E& \8 R" H
& }6 Y& N8 M6 t( ]& H0 A8 P
解答:高人指点,我看了一下启动文件startup_stm32f10x_md_vl.s,其中有一段汇编:
" p2 k7 ]+ O' f* N! W: n4 n$ p
Y- }# Z& q/ S" A3 R% l! K: C6 L! K<strong>; Reset handler routine1 J; Z P3 B, E( K7 I# m3 H
Reset_Handler PROC8 i% y9 }# u5 R% |, f# ^
EXPORT Reset_Handler [WEAK]
" g( K7 E! s) {5 E" h' k IMPORT __main
% {8 t1 A5 d4 Y7 @ IMPORT SystemInit- p/ N2 M5 M8 O
LDR R0, =<span style="color:#ff0000;">SystemInit4 n6 @# q: k8 Y) n7 f7 s: v
</span> BLX R0/ F( A1 \$ _0 i* X% e- J/ e
LDR R0, =__main
3 b9 ~0 n/ }: Y1 j BX R0
8 M8 E1 I% N0 z2 ] ENDP, K6 B7 l4 ^8 d* k! s. O
</strong>
& U3 n* A) y, @; v& R2 N Z1 h
- z6 a; L; F$ o* K: p8 }# a+ H( U; ^7 n其中,
- D8 c8 z+ b8 F! ^% a) x, _
1 k0 u2 p. N g: f0 i( q( f7 a+ iIMPORT __main IMPORT SystemInit //IMPORT 声明了需要引用C语言中的main函数、systeminit函数,( X$ l, M, }0 k5 T; z X+ k7 b( w
LDR R0, = systeminint //把systeminit 函数地址放到r0 寄存器;
. ]: o8 T! A' ]; A# E% N2 ^) y* p
BLX R0 //跳到到R0 寄存器中的地址执行;1 a9 T" p+ `* [4 S
5 X5 F& w; b$ }
所以,在跳到main函数执行前,已经在SystemInit 函数中把系统时钟给设置好了;4 A& W* U7 c3 m1 `/ s
; N+ M( Q" ~0 [9 }$ J( D4 a. }
, H1 C9 `( I' @6 Q9 K3 F4 t9 Z. L7 w& L( K
问题二:既然用了外部晶振做系统时钟,那为什么没看到启动外部晶振的操作?
0 O @( `1 H+ d. d
# _9 G. z) D* k我们在解答这个问题前,先到SystemInit函数里面做更深入的了解:7 c6 }" c$ w. z' M) u, i z/ s+ ]
+ K. C9 H& u& l4 ^4 [$ d- <strong>void SystemInit (void)
8 j7 B/ M. o% k9 v& x- T/ B- x - { r+ q8 s! ^6 M& _7 d/ R
- /* Reset the RCC clock configuration to the default reset state(for debug purpose) */
* i- M8 _ x: E% Y. Z- l - /* Set HSION bit */# E3 K2 `( B, ^5 i
- RCC->CR |= (uint32_t)0x00000001;
; W$ @% g+ o, A0 M. ~ - " f$ y* A7 n/ N7 u2 o5 _
- /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */' i- m, N! E5 g: D- y2 d8 g
- #ifndef STM32F10X_CL1 w* m% {: \; E0 J6 v
- RCC->CFGR &= (uint32_t)0xF8FF0000;
g! D8 }! ~, h) K4 g9 P2 |; e5 k - #else
9 H& K+ b8 k% O2 `( p - RCC->CFGR &= (uint32_t)0xF0FF0000; U( c' f# f/ J, S
- #endif /* STM32F10X_CL */ 3 a G7 Z0 }( x
- , n S) ]1 P3 _" {% d4 n
- <span style="color:#006600;"> /* Reset HSEON, CSSON and PLLON bits */: t4 h! O l# y% o% Z
- RCC->CR &= (uint32_t)0xFEF6FFFF;2 _; J7 X( l/ d3 \; N& E5 V
- % H8 C2 c% M2 S1 B( @! V$ Q
- /* Reset HSEBYP bit */
: e9 ?6 P, p/ O - RCC->CR &= (uint32_t)0xFFFBFFFF;
0 g9 b2 s& ]7 q3 N, \
. a: Z/ L' p2 R9 g+ s+ M4 D: e) b; w- /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */4 q7 q! R3 f C9 q2 F: M/ P8 N
- RCC->CFGR &= (uint32_t)0xFF80FFFF;* o# Q" Q: l- j6 _4 o
- </span>- g7 X7 Q. u' Y3 @$ v
- #ifdef STM32F10X_CL
# d8 U9 ?- J. d4 a - /* Reset PLL2ON and PLL3ON bits */% k$ L' H8 {/ s* J0 G+ X" B1 |& ~
- RCC->CR &= (uint32_t)0xEBFFFFFF;; D, m4 }1 _* e. t A
0 P& d: c2 G! D. m& B6 f o- /* Disable all interrupts and clear pending bits */& J- E3 q( j1 ~* y; \% p, u
- RCC->CIR = 0x00FF0000;
# S4 S4 k! y5 x/ r/ E - * t0 j/ t. e/ V6 h- F- l4 V
- /* Reset CFGR2 register */
9 I1 y1 n% j' l- q- x/ p - RCC->CFGR2 = 0x00000000;
% @! s( `1 w0 Y - #elif defined (STM32F10X_LD_VL) || <span style="color:#006600;">defined (STM32F10X_MD_VL) </span>) k- P" I% ]2 s
- /* Disable all interrupts and clear pending bits */0 u1 J/ A3 E6 B) {: h; Q
- RCC->CIR = 0x009F0000;
0 Y5 p. p6 l8 e# u9 Z& {. Z7 s1 w/ C8 m - ' I$ ~( Z3 W) p {" f
- /* Reset CFGR2 register */( n' k" H* ^8 ~9 L
- RCC->CFGR2 = 0x00000000;
$ T L9 c. w9 q& K# F - #else
~3 D1 [* u8 _5 R) G - /* Disable all interrupts and clear pending bits */" S$ H! U% a5 @- S0 p* B- {
- RCC->CIR = 0x009F0000;' I( @! ^: o5 H: O, o
- #endif /* STM32F10X_CL */8 U- ], r! |" _' D+ }1 |3 U
) T1 i# v! F/ L( ~& q0 ^- /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */
4 v3 A0 F g! K: a - /* Configure the Flash Latency cycles and enable prefetch buffer */
2 E, ~) l' v3 S9 b - <span style="color:#ff0000;">SetSysClock();$ w, T2 {9 r/ }; y7 g% o y% w
- </span>4 v: B* R6 y- d, s
- #ifdef STM32F10X_HD
& [) @& ^/ s. }# j( x p/ O - #ifdef DATA_IN_ExtSRAM6 Z5 k$ ^0 t3 b1 q: Z/ _
- SystemInit_ExtMemCtl(); : @# T4 e* Y* ?' Y* s; W1 b' \" x
- #endif /* DATA_IN_ExtSRAM */' {, |) ?" v/ q+ b* P/ D' W6 d2 n
- #endif /* STM32F10X_HD */
! P# B6 A, Z" w8 }5 W( n, H - 6 r' Q2 N' {9 `% }- A9 m' t5 p( M
- }</strong>
复制代码
0 m: d5 e* ]8 h* R# I8 j/ D7 a4 ^我们进入setsysclock()函数,看其中作了哪些操作:1 O+ {( ]; n v0 Z% S, V5 L+ C% h0 P
3 [* x0 R3 d" B' T1 R
- /**
8 u7 B2 N, n" M - * @brief Configures the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers.
]8 ^8 Y; R8 v, F5 i - * @param None
% [ v% [0 t7 X2 d - * @retval None
: S$ z* o2 y% T/ L - */
6 z+ C( U( N6 t - static void SetSysClock(void)* E1 q9 @6 o- d/ ~" {
- {
3 Y [1 W) L" K5 A# ~ - #ifdef SYSCLK_FREQ_HSE
[ i0 F5 L' S7 o - SetSysClockToHSE();1 s- i- v/ P: a( Q9 r
- #elif <span style="color:#ff0000;">defined SYSCLK_FREQ_24MHz</span> N7 _% a0 ~0 ? @4 e
- <span style="color:#ff0000;">SetSysClockTo24();9 E: O8 U7 M4 V$ P
- </span>#elif defined SYSCLK_FREQ_36MHz- H$ G+ ^: k, I- l
- SetSysClockTo36();5 w1 d* q& Y" y0 v
- #elif defined SYSCLK_FREQ_48MHz
0 I3 |( S# m* U" F3 G M - SetSysClockTo48();
7 S. M. m) A! X. f" J7 o- W - #elif defined SYSCLK_FREQ_56MHz
" F0 d: I- \) u+ b - SetSysClockTo56();
: Y# f0 q6 {) P - #elif defined SYSCLK_FREQ_72MHz$ ?, n# ?/ w0 l ^( o$ y
- SetSysClockTo72();
: I5 ]% k \% ~% _0 K( X/ q - #endif
复制代码 + D3 A, |) M" n0 A
我项目中用的是此款芯片 stm32f100CB,内部晶振是24MHZ, 所以应进入执行SetSysClockTo24() 函数:
! A2 G: [9 n3 V3 x, S% M
* B# s) T2 \/ B G- /**
" ?5 ^% H0 y ^9 t, ~2 a; g - * @brief Sets System clock frequency to 24MHz and configure HCLK, PCLK2
# }! y5 H2 T) } w# t; S - * and PCLK1 prescalers.
6 e0 o- c; k( I0 x/ u. j+ ^ - * @note This function should be used only after reset.
# V' `2 D, W; S) L k( v - * @param None
1 L+ t' g- c( R: p! I - * @retval None, t" u% P. n% S. V1 ~
- */
9 a2 G' j, n [ - static void SetSysClockTo24(void)5 h, ~6 c, v8 @. ?) K- g+ Z
- {- P4 m, r/ r! O/ o& R- E
- __IO uint32_t StartUpCounter = 0, HSEStatus = 0;: W! f! w# y) ~) V2 A4 t
- ! n& N/ r0 z( J( R
- /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/
8 [7 `4 w3 d, I2 p1 U2 [ - /* Enable HSE */ |% O/ ]: j: ]
- <span style="color:#ff0000;"> RCC->CR |= ((uint32_t)RCC_CR_HSEON); //开启外部晶振</span>
# E! M+ C) e b c, m z4 ^) N - $ q2 p. P/ U u" k- _; s! m. a- D
- /* Wait till HSE is ready and if Time out is reached exit */1 D2 s) `2 m4 w k
- do/ Y7 ~2 n# u7 v9 R
- {
* q1 U, D0 x8 b/ K, m3 @3 w - HSEStatus = RCC->CR & RCC_CR_HSERDY;
2 j w1 C& b4 l9 D( e3 L3 p - StartUpCounter++;
8 w. @ b( b3 I! K+ A - } while((HSEStatus == 0) && (StartUpCounter != HSEStartUp_TimeOut));- I, n5 h2 S3 M9 A% h# B$ F4 T
- ! _; J5 x: }+ J
- <span style="color:#ff0000;">if ((RCC->CR & RCC_CR_HSERDY) != RESET)//等待外部晶振起振. `: r9 m, I* I$ T, E
- </span> {3 j4 B( l! I, ^# l0 q/ ~0 L
- HSEStatus = (uint32_t)0x01;, q! K; U* x6 W
- }7 W+ E* f+ y( o. i) _
- else
2 ~; X$ }5 g$ S Y( O, S0 B - {
, e, s/ A7 I- t - HSEStatus = (uint32_t)0x00;0 x6 f% b# q: P7 ?
- }
+ w& y; L7 m4 m - 1 D+ ]) D# n6 L5 e
- if (HSEStatus == (uint32_t)0x01)
0 H3 J/ ?9 @7 L |& { - {
" ^, \& W, V! O2 a - #if !defined STM32F10X_LD_VL && !defined STM32F10X_MD_VL , J2 T6 q1 `5 G" {7 w' ]! _; a' N7 x
- /* Enable Prefetch Buffer */) }- s( Y V" o3 g) g$ c
- FLASH->ACR |= FLASH_ACR_PRFTBE;0 A1 D# Y" D% X/ e" p
4 n2 S+ B& ?0 p- s# N: t: H9 N- /* Flash 0 wait state */
4 F: G& M9 u/ p, D# Y - FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
/ s( b X; h/ p+ m/ ~& ~$ M* n - FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_0;
z7 A0 v8 s: U& c% m - #endif' K6 Z7 a8 G2 Y4 b
- 5 T8 T+ ]3 N2 y+ G
- <span style="color:#009900;"> /* HCLK = SYSCLK */
8 P) q: v9 X5 ~+ H - RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;2 Q2 N) l: p# {, ?* D3 [+ I9 ^
- 8 g+ Y* }9 O3 p& B7 f. m' D+ P
- /* PCLK2 = HCLK */
% n- t7 g( L% k K - RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;1 Q# a# H/ t9 U) l( |
- 0 A7 q9 M9 h4 v6 C1 r
- /* PCLK1 = HCLK */1 N8 b4 I T" o; ^: _+ l8 M
- RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV1;3 b' L( L7 Y- l" P/ W' t" U
- </span>
6 \; @' e l; j5 Y# j* U' s - #ifdef STM32F10X_CL! a- J$ I2 Z# z& r2 N
- /* Configure PLLs ------------------------------------------------------*/
' a2 ^3 j/ p2 `! k7 d. o4 L, z - /* PLL configuration: PLLCLK = PREDIV1 * 6 = 24 MHz */
. A+ P2 A8 s4 F6 E) k& ` - RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);: j5 ~% S4 a( o e5 d4 n5 N
- RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | : @6 o& n3 c" _# [: W
- RCC_CFGR_PLLMULL6); 3 W3 G& h' J2 ?3 ]2 U0 Z5 O$ a
- - O/ j; L5 M/ ^; j
- /* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
/ U# Y$ q# f9 q1 W2 ]. [ - /* PREDIV1 configuration: PREDIV1CLK = PLL2 / 10 = 4 MHz */
/ J& W" m- U+ n' R1 l+ a' w* P: N - RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |
) U8 ^6 l% Y8 f. U/ M - RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);
! q$ X$ ~! t# s* \: Z - RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
8 F/ i; ^, k5 J. t - RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV10);
, R, {; ^0 \. g6 v# d. V7 ?+ R - ! Q! ]; N$ u( m! \4 B2 |
- /* Enable PLL2 */) U' c. N5 D3 e: P6 p
- RCC->CR |= RCC_CR_PLL2ON;
5 ?2 G0 v1 F @ - /* Wait till PLL2 is ready */# X( M/ c$ ]8 F h( B: [" s
- while((RCC->CR & RCC_CR_PLL2RDY) == 0)& f) e& s% {5 L5 C E6 H7 ]5 y
- {
, Q2 J X0 Q- s2 R& u - } $ L8 g( I e: d4 Y8 r
- <span style="color:#3366ff;">#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL)
3 p$ d/ q/ O, S _9 y, g - /* PLL configuration: = (HSE / 2) * 6 = 24 MHz */8 ?# w- S' E; {) e4 a
- RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
" T7 Z/ K* W/ p - RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_PREDIV1 | RCC_CFGR_PLLXTPRE_PREDIV1_Div2 | RCC_CFGR_PLLMULL6);
/ ~7 J0 ~- M2 p# S, g - </span>#else / n" @9 } l1 V4 m$ w9 E/ n
- /* PLL configuration: = (HSE / 2) * 6 = 24 MHz */- F! F5 }2 t! o+ K
- RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));' R- x8 X% z; K; w4 {6 Y
- RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLXTPRE_HSE_Div2 | RCC_CFGR_PLLMULL6);
6 Y) s& \# T, T - #endif /* STM32F10X_CL */# q' L! |7 s# N! |
- . H+ o8 }$ x, J6 L1 O! ^
- /* Enable PLL */
+ H! o# G# d# t ^6 j, d) f - RCC->CR |= RCC_CR_PLLON;
) @8 q7 q, s# f) b# }1 x - 3 \1 q% C& k( G2 }5 _- T
- /* Wait till PLL is ready */
% P- W& E' T% p - while((RCC->CR & RCC_CR_PLLRDY) == 0)
& _+ [# f' Y3 y, G- T/ f - {* P' q0 D: _* c8 M9 D5 C) Q
- }0 u8 d* q+ e% x" j* v5 j; @( [
- " [" |- Z1 K. J0 S4 ?& b
- /* Select PLL as system clock source */+ |% I! A" S0 j* R7 q7 q
- RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); Y5 {4 [) `9 T. p t k, g
- RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; ' b7 l, o- O- O7 l4 J2 b* J, L: y
- ) |3 T: c( W3 M1 U$ z$ s
- /* Wait till PLL is used as system clock source *// P) m+ i" l _9 L: v# H! K2 R$ E2 X
- while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08), `1 C7 K+ {) U. T, |
- {
# w3 k* Z% `' O- I2 P! G( I - }
5 s6 ~( O$ T2 {! f9 K0 Y* H; X5 @2 K - }
) Q0 L* E5 p# @$ a - else% y3 K7 p/ C: ]/ N
- { /* If HSE fails to start-up, the application will have wrong clock
4 Q( r2 z; I* Z) L+ N - configuration. User can add here some code to deal with this error */; b& j2 a: |: w P
- }
+ f4 i1 w q; @2 l) ], N+ _ - }" i. ?/ z- k) X$ v e" }: A4 B
- #elif defined SYSCLK_FREQ_36MHz
复制代码
, F' {7 W, r1 D: m# ` t' X8 a+ d! s
解析:
4 x: p% ^* q0 K, F) @# e! u! @9 N. Q: E1 a( N' V+ }
void SetSysClockTo24函数中主要做了下面几件事:(不同颜色功能分别对应上面对应颜色代码部分)' {8 q! z' o; j
% H1 j" W) _) w! V* W, P; ~1.启动外部晶振作为系统时钟源;- W* r' J4 E8 r* H* |& O" ]
y; l1 A' w, Y9 {) n2.等待外部晶振起振;
$ Y3 ]; d z% N" Y0 y4 n n1 J: ]
2 U. Q* n+ g) {; g: J+ i) Z% n( B3.(起振后)对系统时钟源进行分频:(默认外部是HSE--8MHZ晶振) PLL configuration: = (HSE / 2) * 6 = 24 MHz* V3 v3 R0 Y& j1 l
6 s, g* }- ^& \4. 配置HCLK、PCLK1、PCLK2 与系统时钟源的关系;+ D0 z0 x0 Z6 P M. V
) k* j2 K" O, @' h
$ r2 j8 ~ z, P* } e5 f) n% M4 V7 U7 ?7 B$ n' ?
问题三:串口的时钟源是什么?串口时钟源跟系统时钟的关系?8 i2 b% L! p# Q1 q5 r
" B: E ?5 Q$ D {( r4 z) V; H回答这个问题前,我们先来看stm32f100芯片手册数据图(第12页):
# |/ p) ^0 D: m0 k6 _5 F" e0 y' r* G. U: }1 |3 I
* s; M2 s# l5 x+ w
& x& I( W, z7 T F, A3 i从图里面我们可看出串口1的时钟源是PCLK1;5 T* z8 X6 Z$ u4 h ^
. V- K. G/ Z, c: ]2 ]1 `上面问题2的代码中我们看到PCLK1是时钟源24MHZ的1分频,即还是24MHZ;9 {. [4 }# f7 b- T: G
: u' _0 c* J* @ g. z4 B4 u/ P$ ^7 r5 e* Z# }' g7 N3 C2 n
( _: o4 Q+ p3 D. [% n- `) c/ T' n问题四:程序中串口时钟源是怎样实现对波特率的关系的?9 z8 A3 G$ I, P9 j- N, l
' v5 G5 V( L2 M# E) U! y
由问题3我们知道串口时钟源是24mhz,依据公式:IntegerDivider = ((PCLKx) / (16 * (USART_InitStruct->USART_BaudRate)))6 |! C+ S9 _1 B6 X O
+ [* p+ ^: }1 k7 ^库中自动设置IntegerDivider 存入寄存器中;
, g' L3 J, @( ^& a
) r8 y4 a" l. _4 G6 |
& A& W8 o9 m0 T* H* ?$ r(1)
" O! k3 t5 w6 A& H4 M) p3 e4 H% a# H9 a, v
在KEIL下可以在项目的选项C/C++/PREPROMCESSOR symbols的Define栏里定义,比如STM32F10X_CL+ i2 w; u6 p% ~- h/ E& ^
* `7 X+ l p% \ z3 U- _. F$ m
也可以在STM32F10X.H里用宏定义6 ]7 [8 Y/ }2 U) \
#if !defined (STM32F10X_LD) && !defined (STM32F10X_LD_VL) && !defined (STM32F10X_MD) && !defined (STM32F10X_MD_VL) && !defined (STM32F10X_HD) && !defined (STM32F10X_XL) && !defined (STM32F10X_CL)
! { d5 m& V! W' R: D/ E4 y% K0 R. J; Y8 i& E
#define STM32F10X_HD
/ h- u+ y6 Z2 S: P( m; C' H- _8 R9 G
#endif B; }0 N# b1 A G2 e D' {& v
' ^: o' l, H1 `: [- P(2)+ r. l/ c; y* X# ~, B, m5 F
如果芯片更换,除了做如上所述的更改外,还需以下几步
2 c( P7 U J3 B/ ^第一步 system_stm32f10x.c的系统主频率,依实际情况修改4 @* B1 }9 Y$ R4 }
#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL)3 @& K2 c6 `; L+ [- O7 ^7 e
- v6 O" u5 {* G8 R$ B
#define SYSCLK_FREQ_24MHz 24000000
% `+ Y3 p; W B: P i#else
+ }$ Z' y- w5 A8 k' ?4 F#define SYSCLK_FREQ_72MHz 720000000 _- |! u- C+ ^4 S
#endif0 \: I! \7 k7 k' }5 T G
另外外部时钟在文件:stm32f10x.h 依实际修改
2 m! O$ a `# k7 R6 Z( ?第二步 定时器的参数依系统主时钟做适当修改
7 Q! F) t$ n; Q, l3 E第三步 flash地址misc.h中的NVIC_VectTab_Flash 0x08000000 要与KEIL选项target的IROM1的地址一致,如果是IAP程序,依ISP程序占用大小,APP的FLASH地址向后延,比如0X8002000,那么KEIL选项target的IROM1的地址也要就0x8002000,SIZE因为ISP占用了2000,所以就为0x40000-0x2000,即只能填写0X3E000+ l* z7 J3 H& I" j* M
1 `4 N( m5 z, t0 I ISP程序与APP程序连接
9 C) L8 O- d( L0 J. }8 e1 s 打开 User 选项卡 在 Run User Programs Before Build/Rebuild 中,勾选 Run#1,并在2 Q8 x- {0 y* ~( f @8 q1 p+ I# E
其中填入
2 i \, {2 _; T% r1 d6 T D:\Keil\ARM\BIN40\fromelf.exe --bin -o ./obj/Project.bin ./obj/Project.axf# |& F7 S/ V. f
其中,Project.bin 和 Project.axf 要和 Output 选项卡中的 Name of Executable 的名字
" C! `! \) Y+ H: X/ {9 I: o" t( ^: o3 M% j
IAP我的总结
" z8 ^, L. H% ?1 先FLASH_Unlock();, U4 C, Q6 y e
2 小于或等于128K的STM每页为1k bytes,大于128K的每页为2K BYTES,减去从地址0x8002000占用的0x2000后,算出页数,比如IAP占用8K,则64K的MD的STM32F系列用for(i=0;i<(64-8);i++) FLASH_ErasePage(0x8002000+0x400*i);循环按页擦除FLASH9 C7 ^0 L& V( C {) m c
3 按从外部串口获取到的数据,FLASH_ProgramWord(address,dat);//注意是按4字节方式写入的
5 w" f% f, N W$ | if (*(uint32_t*)address!= dat)//字编程后校验
% |. [& N/ p) F; T$ i0 k! z- |% k3 G' s$ K9 u0 c: T7 g- \
# u2 P# X I( l r/ D5 {; I$ W* Z0 O0 S: G6 I9 h
|