一.库开发的优势; [0 Z2 K7 {7 P$ t
开发速度快,便于移植。
' o; N$ t7 |% [, F. i
1 @, a& X {/ l8 @% l8 K' L2 F, i二.stm32F7xx几个重要文件
7 r9 r6 M1 `+ @( \& h6 J! {8 P1. HAL库关键文件
4 h& O, Z. g/ _7 n1 d- w6 X% g$ [ C2 F+ W/ n( ~
) t" j# w! y( N2 I
) }/ N% {. j; V2.stm32f7xx_it.c/h; v. z. s3 h% O7 U( q& h3 Z
中断服务函数。基本都是空函数,我们可以去掉里面的函数,把中断服务函数写在任意可见的文件中。
d7 s3 t5 c% k: {9 j( K! u* F! h6 P) J
- f" C( d5 T) f% M0 X3 K$ S8 t/ _9 A. A; i i1 B* I
3.stm32f7xx.h/ B0 }8 n( V+ R2 h
所有F7系列的顶层头文件。通过条件编译包含某型号的头文件(此宏一般在target——c/c++里面定义STM32F767xx,后面都以stm32f767为例)。9 C/ x1 G, {" s7 l
) `: |& i7 E9 t
- #if defined(STM32F756xx)
5 {! `7 ` r2 F$ v: G
( f: K8 e9 T/ g, V3 r4 S- #include "stm32f756xx.h"# c, ~5 D7 j$ q. ?, ^
- 6 \, a7 N P4 t
- #elif defined(STM32F746xx)& H, `. l: k H
- 0 v! u, l+ E' K* M/ X3 R4 {0 r r
- #include "stm32f746xx.h"
' |1 K' v3 r8 n" ]) w4 ` - 5 i" B6 k, n0 b7 i2 ~7 @: _
- #elif defined(STM32F745xx); |7 B( ]$ L/ ?7 C
- + q* j2 S1 c- X+ y8 q7 j
- #include "stm32f745xx.h"
4 B# b6 N$ q; ^, x3 q! u2 C; \
& l) |) u3 g% A) K0 x- #elif defined(STM32F765xx)
: K; o% {' y$ ?9 Y B
4 q( O* V9 ?8 D7 Z& w9 ?- #include "stm32f765xx.h"
2 }7 b+ N f0 i/ Q' _
5 E9 H2 O( p. [8 e( b+ M- #elif defined(STM32F767xx)
: N' a, ~; t( \! N! h$ g
. `# l' x1 e6 P5 R" o% _' d- #include "stm32f767xx.h"
8 Q- S, y, n3 O3 u, v! r& }0 o- E
' r( d2 |* J( z% P8 A$ c- #elif defined(STM32F769xx). |- V5 W" s$ |" W4 V0 c
- , H7 H: w# P# [$ [+ L
- #include "stm32f769xx.h"
" F9 ^9 Z$ w- X3 g; w: Y - 8 v6 `* I8 {% ~- u( ^1 F% R, y
- #elif defined(STM32F777xx)
2 u* r8 n" C( a( a0 A8 |
# A9 n7 S& N1 v) X/ V R- #include "stm32f777xx.h") f; o3 i3 s; N3 ^7 Q9 ?
; v& u, N1 e, B+ A- #elif defined(STM32F779xx)
9 I) V& ?5 W {0 Q, n
6 V5 D9 [- W s1 ?3 O; o- #include "stm32f779xx.h"
8 w, L1 n I5 W2 P* ~ - . A6 o- T9 a F/ X
- #else6 |) y0 D( z7 W% X- q5 U
- # ^; L8 i) e% }; ?3 v; |# Q5 B5 l- @
- #error "Please select first the target STM32F7xx device used in your application (in stm32f7xx.h file)"
5 E' s/ t: o" }& j
4 K& I5 N# g) M6 U- #endif0 v* L A8 @. D s V; e7 }
复制代码 ; e7 i; i1 ]' v% k
4.stm32f767xx.h
! ^* P; a) P8 A- D 主要就是寄存器的声明(一堆结构体和宏定义)。; ~, c+ b( Z; m- t
! l; v# j3 i7 ?5 L5.system_stm32f7xx.c/h
3 `& J, \, H% j+ |6 h& I4 q) m( \' {9 C 主要定义了SystemInit和SystemCoreClockUpdate两个函数,后续会在这个文件里面加一个SetSysClock()函数. SystemInit主要是时钟系统的初始化和中断向量偏移地址设置(有bootloader的向量偏移需要修改)。SystemCoreClock是一个全局的值(这个在FreeRTOS的时钟配置的时候需要)。
. N/ g$ e; W/ d: l3 R# }. @. F, y" Y/ \4 D6 P% X) p1 H
6.stm32f7xx_hal_msp.c
; O6 h# B! R% ^5 t5 F" ? 带MspInit的函数进行MCU级别硬件初始化设置,通常被上一层调用(如HAL_UART_Init——HAL_UART_MspInit)。- p+ O+ d" c( ?
4 h: H B. |( Q0 `9 }8 Y; ]3 p
7.startup_stm32f767xx.s
) s5 n* `2 K6 |0 |* X; U启动文件,上电先运行SystemInit,再运行到main。
+ u# g9 l* p L# j
, C: K- N/ a5 S4 J- ; Reset handler+ j' g) {+ W2 |& k9 f$ \2 s; n& d
- - K& g$ F; G3 g/ o
- Reset_Handler PROC
0 n0 ]/ ^7 L8 y2 w$ ^1 k7 ~ C* d
! D3 Z2 W7 \4 |# o2 h8 b- EXPORT Reset_Handler [WEAK]. b3 i- m4 r: z: M
- - l9 p$ H$ ?& @( J: w
- IMPORT SystemInit
* P+ W. B, I( C- i - . G* ]: u6 Y% S+ ^. `" I
- IMPORT __main
' r& F6 k( z5 _$ R& G3 _ - 2 J# W, D; u7 \: p! p
# U/ S( M' i6 P* b6 f- ; \* q. t7 q6 @1 O+ }( z
- LDR R0, =SystemInit. n! K1 C# q7 y
, Q. c8 ^4 A9 q) e- BLX R01 p1 O1 }( n% `- B! ~
) T3 Y8 D i& `$ U- LDR R0, =__main8 j- c* n$ x# z
- , B% T2 y7 T0 U+ \5 O
- BX R0( l; ^" X0 u- R$ C
- / [. [/ {. f# o5 U
- ENDP* ~9 m5 M7 B8 r1 o/ a( Z
复制代码 ( g$ `" g# @$ f7 A2 Q
' k @! L+ x$ G三.HAL库中__weak修饰符
1 P; k7 O2 S2 l weak:弱。被__weak修饰的函数就是“弱函数”,我们可以在自定义的文件中重新定义此函数(去掉__weak),编译器会执行我们自定义的函数。HAL库中一般在回调函数时用到。HAL中默认定义一个空的回调函数,保证编译器不会报错。# S1 L, i, g( n. S/ }' M
7 M7 B2 \' m, q6 n5 u四.程序的执行过程; f0 B6 k% t5 g5 P G7 c( o& m
Reset_Handler —— SystemInit —— main —— HAL_init —— SetSysClock —— xxxInit…(FreeRTOS:xTaskCreate —— xTaskCreate); b! z$ i* m: \" X' x' o8 @
0 z: M+ i6 B+ Q5 F" z( [/ e五.启动文件' h. t+ u. r/ t" C6 F/ n
主要指令:1 W5 a" x: h+ O- _/ L3 F. O
' A% k7 W4 _# L* ~
& [, \4 }; R# \$ s% T; T
; ]5 a- y7 w1 Z5 G5 O! X
6 U) W0 c3 a* f% X! G r% U( h% a
- \! }' n4 a7 K
+ l- `3 C& w* f2 ~, B- _" Z+ ^Stack——栈,Stack_Size EQU 0x00000400 (局部变量,函数形参,函数调用等),值可以人为修改(不能超过内部SRAM)。
' V+ Z+ @8 W1 ]4 w1 `7 P: A) o1 J& O% `7 @
Heap——堆,Heap_Size EQU 0x00000200(动态内存分配malloc/free)1 J& V3 w. m, j7 x [
% U3 N' c1 t1 P/ f& k- ^# U' j! {向量表——中断向量服务函数
% k; F, D1 l$ G+ d9 w4 r% p) h T4 J) e2 K F$ t* f
复位程序——先进入SystemInit——main
2 c. \- y4 N+ A* h
8 h" x* i/ R8 F9 K' i7 X关于启动文件详细描述请参考:STM32启动文件详细说明& E5 r1 j5 H% d
7 W( \" L4 |5 \4 _0 {* F) F4 a
六.时钟设置(设置系统时钟)5 Q; H8 a2 H: J$ Q7 t9 c4 p
- /************************* PLL Parameters *************************************/
) g" N3 t6 `' L0 S& y& a - //时钟设置函数3 ]" R/ `( {' G; {) y
- //Fvco=Fs*(plln/pllm);
# S( f- w5 _" p. j - //Fsys=Fvco/pllp=Fs*(plln/(pllm*pllp));8 w7 w: q. }5 I0 B( U( L) o# }# d
- //Fusb=Fvco/pllq=Fs*(plln/(pllm*pllq));
) m7 E! k3 T8 z+ {3 d Z0 G' o - 3 V D7 I5 Q' N: I- E( d& y
- //Fvco:VCO频率
! F8 h) M @2 `0 n* A, ?# f - //Fsys:系统时钟频率* @4 Q7 d: x: h- [! c
- //Fusb:USB,SDIO,RNG等的时钟频率
, g& ^& j/ w. F1 y: I+ Z5 u - //Fs:PLL输入时钟频率,可以是HSI,HSE等.7 `, ^- F1 B2 {7 X2 e
- //plln:主PLL倍频系数(PLL倍频),取值范围:64~432.
. X, q2 A1 A; e! e6 e - //pllm:主PLL和音频PLL分频系数(PLL之前的分频),取值范围:2~63.; y" O7 i) O" x
- //pllp:系统时钟的主PLL分频系数(PLL之后的分频),取值范围:2,4,6,8.(仅限这4个值!)% S- P6 K. u A. A# _: R+ T
- //pllq:USB/SDIO/随机数产生器等的主PLL分频系数(PLL之后的分频),取值范围:2~15.
$ }6 Z e1 b! ^" ? - ! L+ Q! F2 h+ y* B3 L4 S; k/ M! E
- //外部晶振为25M的时候,推荐值:plln=432,pllm=25,pllp=2,pllq=9.3 O% S4 T* j" X8 T+ g# p) j5 S
- //得到:Fvco=25*(432/25)=432Mhz' a. ]8 M# g% ~8 m; Y) Y
- // Fsys=432/2=216Mhz
6 F4 g6 U! B' n* k - // Fusb=432/9=48Mhz% k! k1 X1 y: x$ q; m
- #define PLL_M 25
7 P6 P$ \4 f F! _, a - #define PLL_Q 9
. b1 [7 _5 Z' ~4 O2 D, F+ | - #define PLL_N 4320 H1 f t8 n3 B" t% S/ g
- #define PLL_P 2
6 X8 y' Q: J1 x5 n - ) z9 z+ S3 N \8 Q9 ?1 c
- void SetSysClock(void)1 z+ w! H1 ^. |3 B+ I
- {
. n. Q% ?- [: N4 g! x2 M - HAL_StatusTypeDef ret = HAL_OK;1 u/ w" z3 R. x# }2 h
- RCC_OscInitTypeDef RCC_OscInitStructure;4 x. G: r0 z+ F; c/ C- B4 c# X
- RCC_ClkInitTypeDef RCC_ClkInitStructure;
; ]) P9 e0 l8 r* R- R; g
0 m3 k7 u5 L4 h& o: Z5 e) B- // __HAL_RCC_PWR_CLK_ENABLE(); //使能PWR时钟, x0 R1 \ B& p( r$ M3 o
0 m4 N& T* h: g2 ^- RCC_OscInitStructure.OscillatorType = RCC_OSCILLATORTYPE_HSE; //时钟源为HSE+ N6 T* M& H- Z
- RCC_OscInitStructure.HSEState = RCC_HSE_ON; //打开HSE2 E7 |3 B; p6 c
- RCC_OscInitStructure.PLL.PLLState = RCC_PLL_ON; //打开PLL& P+ ~9 c0 r J4 v! V! @
- RCC_OscInitStructure.PLL.PLLSource = RCC_PLLSOURCE_HSE; //PLL时钟源选择HSE
5 h' s/ k* E9 L5 k. g5 E7 g - RCC_OscInitStructure.PLL.PLLM = PLL_M; //主PLL和音频PLL分频系数(PLL之前的分频)
* E) ]% P2 X7 E7 ~0 l - RCC_OscInitStructure.PLL.PLLN = PLL_N; //主PLL倍频系数(PLL倍频)
" \, i0 M; V( N - RCC_OscInitStructure.PLL.PLLP = PLL_P; //系统时钟的主PLL分频系数(PLL之后的分频)8 ~' @ n8 o# _/ l- q h- ]
- RCC_OscInitStructure.PLL.PLLQ = PLL_Q; //USB/SDIO/随机数产生器等的主PLL分频系数(PLL之后的分频)
$ l( G Z& _( D3 k. i0 R' | - ret = HAL_RCC_OscConfig(&RCC_OscInitStructure); //初始化
* O g- H% ]9 {( t - if(ret != HAL_OK) while(1);
- Y6 D% l, B$ j5 F3 C - % @( E3 L% U* i
- ret = HAL_PWREx_EnableOverDrive(); //开启Over-Driver功能, X! V4 }6 d) ^- Q+ Z
- if(ret != HAL_OK) while(1);
2 M4 X6 [! X7 k6 S: v: w0 x3 t - # s8 |9 w+ |, B' q6 E* R) `5 L
- //选中PLL作为系统时钟源并且配置HCLK,PCLK1和PCLK2- F7 w& U1 a0 N% X
- RCC_ClkInitStructure.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
; L$ `; ]8 G6 S - RCC_ClkInitStructure.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; //设置系统时钟时钟源为PLL
* p, `0 P M! m, U% h d0 W3 Y. D. H - RCC_ClkInitStructure.AHBCLKDivider = RCC_SYSCLK_DIV1; //AHB分频系数为1
/ H6 U2 Z1 W% ~- R2 \$ B4 o - RCC_ClkInitStructure.APB1CLKDivider = RCC_HCLK_DIV4; //APB1分频系数为4
, Z1 W4 B: v9 n. q" h - RCC_ClkInitStructure.APB2CLKDivider = RCC_HCLK_DIV2; //APB2分频系数为2
* E2 v1 h4 z( h2 ^8 U* }" I - ! m7 V1 S O# ~0 }
- ret = HAL_RCC_ClockConfig(&RCC_ClkInitStructure, FLASH_LATENCY_7); //同时设置FLASH延时周期为7WS,也就是8个CPU周期。" @/ L7 l% b8 G! M( v
- if(ret != HAL_OK) while(1);
1 z" v8 ~: C! f - }
' A9 w4 h+ D7 T
复制代码
1 v p% Z2 [! V" T& X" D( A" p, `
$ ^2 j( S5 Q" o* x3 K* I' @" T' Z0 l" R* T4 k- ?/ E
. X; B2 o$ [! R: m' D
- C, s F" w1 |. i6 ]5 e H
|