一.库开发的优势% l# h; p% n. ~0 ~/ l
开发速度快,便于移植。
; w1 q8 x+ S. L' ^
) B! n$ I0 _+ z# s7 q" t$ B二.stm32F7xx几个重要文件
w; `: t" I& z! t1. HAL库关键文件5 L3 r0 g0 V0 R( ?9 q
5 z# w1 i+ _: l; L
! h) Y6 x9 y$ I4 z/ e8 k0 c: t
2 Y" V, D" B/ c, t; U
2.stm32f7xx_it.c/h
! U% k( m' M7 ?3 |) [4 t! l6 g3 l 中断服务函数。基本都是空函数,我们可以去掉里面的函数,把中断服务函数写在任意可见的文件中。- J A# n+ J! h2 w+ B+ v1 ~& C
+ I* [& Y- j! W+ v. k8 X' t
# K& E/ H& A2 [
+ t7 [( @" ]6 v- `6 @+ E3.stm32f7xx.h& r/ J# ^& t/ y6 d) g' |
所有F7系列的顶层头文件。通过条件编译包含某型号的头文件(此宏一般在target——c/c++里面定义STM32F767xx,后面都以stm32f767为例)。3 _2 D2 ~7 s3 ~1 e8 r& s
e2 o) P4 S. ~2 e
- #if defined(STM32F756xx)* V! r4 i! q/ o4 e8 K) {
8 ?% U: F) i0 d" l- #include "stm32f756xx.h" y0 i8 b6 z$ I: o
- % _- O% V7 C' J7 ~7 z
- #elif defined(STM32F746xx)* R9 X+ @' B' Q+ M) q2 d
) J5 S2 N3 F) E7 _7 z- #include "stm32f746xx.h"3 A. B! {$ }: q V" Q
: r) x5 M, V6 @- #elif defined(STM32F745xx)$ y; T* ]/ i! c
) A! V6 Y( f2 c. F% J6 U- #include "stm32f745xx.h" l& @9 w, p0 q5 [
7 x0 a9 }- j7 _- #elif defined(STM32F765xx)
. g$ |$ R! F6 n8 \
4 l$ e3 R5 A& @& v# B* _- #include "stm32f765xx.h"
) K- j. M$ U$ z' i! a4 n
, N* i3 H5 Z+ U- #elif defined(STM32F767xx)0 J5 F; c* a- q
- " M) h) l$ F- T$ ?, s
- #include "stm32f767xx.h"
; g0 O+ h2 y! g* G8 R
/ c8 C6 Y# B# ] A3 K0 l- #elif defined(STM32F769xx)" ?; F# K2 s# [# d5 ]; f4 d
- & k2 A- B1 H4 s- h
- #include "stm32f769xx.h"
( ?$ I% N# d4 \. |& q: b
% J7 v% [2 Z/ t/ G$ s! e- #elif defined(STM32F777xx)* s8 _. t7 A3 F0 }2 F y& ~
9 @: Q' B0 r* t" \* W- #include "stm32f777xx.h"
5 p9 D8 A- A4 h: u; q0 ?; W - 4 o5 ~8 r/ T. T a `3 ~+ q, K
- #elif defined(STM32F779xx)
& K" }; u' f2 R7 M( Q4 K8 E
* ~* e/ y3 ?/ ?4 K# n8 m- #include "stm32f779xx.h"
~, C4 q1 S3 J3 J. V
3 C8 c: r# |7 N" g& e! @- #else' v/ T. r8 s7 j% F
- c, a6 q) H, ~9 s$ B3 s- #error "Please select first the target STM32F7xx device used in your application (in stm32f7xx.h file)"
& s/ H, P* ~% y* A
; x1 Z7 d% t! n1 s( N7 r, h- #endif* t7 k! T) M, W, O& l
复制代码
3 }* d; v$ p6 ~3 H2 e9 ^4.stm32f767xx.h, a/ W- ]2 T/ E5 s/ Q5 T/ j
主要就是寄存器的声明(一堆结构体和宏定义)。
, f# X% y, `' @0 c6 E2 i9 _' a
. {6 v( s7 |4 }5.system_stm32f7xx.c/h
2 c! _* F! Y ] 主要定义了SystemInit和SystemCoreClockUpdate两个函数,后续会在这个文件里面加一个SetSysClock()函数. SystemInit主要是时钟系统的初始化和中断向量偏移地址设置(有bootloader的向量偏移需要修改)。SystemCoreClock是一个全局的值(这个在FreeRTOS的时钟配置的时候需要)。& q# g2 N& Q' p6 V6 ~, P8 Z5 C
, _* L9 _, Y! y; f3 q
6.stm32f7xx_hal_msp.c M r# ^" [; G. r
带MspInit的函数进行MCU级别硬件初始化设置,通常被上一层调用(如HAL_UART_Init——HAL_UART_MspInit)。) q' ?' ^ W/ B5 l: ?9 Q$ O
! a+ V, [) ^- `$ ^' Y7.startup_stm32f767xx.s- Y# C m# D+ u) }6 T+ M
启动文件,上电先运行SystemInit,再运行到main。
, j8 `9 U/ N& e! ^
- r/ ~5 ~1 O4 x! [- ; Reset handler( p& x8 Y4 n. S& |# O% l
- ) f3 A T/ s. j- `, d; }
- Reset_Handler PROC
5 k+ `# Q& A& d! `8 R G$ r! m& ?
0 y v6 E8 y# u' O/ N- EXPORT Reset_Handler [WEAK]6 ]1 h% }. u( \
/ ?) `1 G9 A" @2 p7 B5 M- IMPORT SystemInit( Y6 Z9 Z0 r3 V8 y
- ; i% z# z/ M+ ]/ U4 r& v
- IMPORT __main
! y2 J1 r& C% b/ B+ \/ G ^5 [
( [2 c. X: n5 b+ @
: g5 n% J; \5 M' M& X+ S. ^/ @! ]
6 I9 {3 Y- s5 Q4 b+ J: N- LDR R0, =SystemInit
. r8 @0 ?5 N( a* Y- b. f: M1 E - ! Z0 k- e7 b" U$ {9 {2 a7 t# b0 Q4 w
- BLX R0
2 ]4 }0 y( W) m5 S* D9 u - ) G y( S( g8 b. |; {. ]; O) D
- LDR R0, =__main% @' j+ d) f% Z3 ~4 q
D* C3 c. V" D- BX R01 }$ F% v* P& ?2 G; P
- G: Y4 O. p+ h- ENDP* h, p: j% c/ Y. |; X! b
复制代码
2 j* S) F5 O! ~- ]) F) Q# C- C, y4 n
三.HAL库中__weak修饰符
- {# b# J {3 q; z! @3 f. s2 _ weak:弱。被__weak修饰的函数就是“弱函数”,我们可以在自定义的文件中重新定义此函数(去掉__weak),编译器会执行我们自定义的函数。HAL库中一般在回调函数时用到。HAL中默认定义一个空的回调函数,保证编译器不会报错。/ v% { N0 j4 V+ k" ?& i0 f
# T3 @' _( Y. m6 D% k- s* ^
四.程序的执行过程
5 I8 A h% X( D4 f3 s Reset_Handler —— SystemInit —— main —— HAL_init —— SetSysClock —— xxxInit…(FreeRTOS:xTaskCreate —— xTaskCreate)# V7 j7 ?2 _ v( U0 F
3 s" [$ M# B, f: o
五.启动文件
/ Y' e Q0 G' c0 @# e主要指令:
/ r/ F# f! f0 I6 H/ d- W6 Y& G* X
5 ~; n1 d2 `& \) y4 q2 w/ U0 `$ v# b, C6 a: C3 L+ \
9 C5 g+ b5 H$ t
# Z; j5 @1 f7 f6 j( r
z& C, X c/ o, j: v
* A* W( E; g& x) Z, X9 \Stack——栈,Stack_Size EQU 0x00000400 (局部变量,函数形参,函数调用等),值可以人为修改(不能超过内部SRAM)。% u0 H4 E" q0 w2 Z. ~" c# `( f1 o
( o! K% D" B' J: M5 G
Heap——堆,Heap_Size EQU 0x00000200(动态内存分配malloc/free)# T" W2 J9 D) g
$ T6 ~3 c0 X6 J# ?向量表——中断向量服务函数
. Z* C1 `- F/ o& u5 y4 G6 g( l. ^. M# {' \5 `/ M
复位程序——先进入SystemInit——main- i) z; O& ~6 A1 z7 o
$ ]) ?( X( t0 u, I5 E8 G5 N+ K关于启动文件详细描述请参考:STM32启动文件详细说明- J7 B' z5 [( h) G
9 R% P* z0 H: G1 q0 V六.时钟设置(设置系统时钟)
) D7 d4 m# g- F/ ]0 v" k/ {- /************************* PLL Parameters *************************************/1 l, ]% e( {0 H9 n7 }9 A( R, F* ?
- //时钟设置函数
8 P- @/ ~2 L1 Q- {& ` L& j - //Fvco=Fs*(plln/pllm);
# G# l$ S8 p( Y - //Fsys=Fvco/pllp=Fs*(plln/(pllm*pllp));
1 N6 G% K; t7 e- {! f - //Fusb=Fvco/pllq=Fs*(plln/(pllm*pllq));7 D4 L$ S% Y% j) P7 d3 W
, m/ N. `4 _& v; K# U: e& ~$ t) @- //Fvco:VCO频率
1 u' B% J" _% D* {+ {7 b) h - //Fsys:系统时钟频率
2 @& p. n5 T1 d; T - //Fusb:USB,SDIO,RNG等的时钟频率# l% x4 B; m6 D+ \4 @: e
- //Fs:PLL输入时钟频率,可以是HSI,HSE等.
& o. _2 h# N2 P! a8 {& i) | - //plln:主PLL倍频系数(PLL倍频),取值范围:64~432.8 R# X3 J' j0 S. ]# w0 d* X6 D
- //pllm:主PLL和音频PLL分频系数(PLL之前的分频),取值范围:2~63.! p% @3 `/ _7 Q6 [9 M% I' O' y; s
- //pllp:系统时钟的主PLL分频系数(PLL之后的分频),取值范围:2,4,6,8.(仅限这4个值!)0 c v" x8 G+ k5 T
- //pllq:USB/SDIO/随机数产生器等的主PLL分频系数(PLL之后的分频),取值范围:2~15.
" v' R+ r# P7 l* k6 O3 @5 M - 5 d* T x# n5 ]8 V
- //外部晶振为25M的时候,推荐值:plln=432,pllm=25,pllp=2,pllq=9.
$ H. W7 T2 D- g8 W4 D - //得到:Fvco=25*(432/25)=432Mhz( x' h. r, v" x2 e
- // Fsys=432/2=216Mhz$ ], \9 h! k I" R8 {& c/ g
- // Fusb=432/9=48Mhz
- c0 G! W1 I4 l% ?/ Q. t1 i - #define PLL_M 25& A: T" m5 b" {8 O8 t. W4 W
- #define PLL_Q 9
: r1 I: w" r# m3 s- K- d. h' o - #define PLL_N 432
, s" \' V* @* a5 d( L+ i - #define PLL_P 2* S" ]& E0 s6 _( z% R, b
; }/ O; {. k' c# f* Q- void SetSysClock(void)
+ `* y8 y; M! I0 s; K" P - {
$ ? k2 X* L: b+ D. [9 z) t - HAL_StatusTypeDef ret = HAL_OK;
+ e' [" x* M( B. `) K3 B - RCC_OscInitTypeDef RCC_OscInitStructure;% L1 I& a% _* b' p! R1 u. _
- RCC_ClkInitTypeDef RCC_ClkInitStructure;
: T" f" ]2 A, \+ }) ` - / U; F- D& |# q3 R1 n: [; ^* I
- // __HAL_RCC_PWR_CLK_ENABLE(); //使能PWR时钟
, ?& y5 f y; g - 1 V6 h3 ^% G! T. s$ V6 M3 _" U& |+ B
- RCC_OscInitStructure.OscillatorType = RCC_OSCILLATORTYPE_HSE; //时钟源为HSE" Q' {3 P9 y8 u/ z
- RCC_OscInitStructure.HSEState = RCC_HSE_ON; //打开HSE7 N6 ^; G) Q9 \2 g7 }4 T5 d7 Q
- RCC_OscInitStructure.PLL.PLLState = RCC_PLL_ON; //打开PLL
) s( F0 |/ Q& }' y( k- v1 y0 L. x3 U - RCC_OscInitStructure.PLL.PLLSource = RCC_PLLSOURCE_HSE; //PLL时钟源选择HSE
# W# ]0 s7 {! M - RCC_OscInitStructure.PLL.PLLM = PLL_M; //主PLL和音频PLL分频系数(PLL之前的分频)
& t+ e0 n1 w3 l; w {& `# ? A - RCC_OscInitStructure.PLL.PLLN = PLL_N; //主PLL倍频系数(PLL倍频)
2 q! ~2 o3 y+ T, T0 X/ O - RCC_OscInitStructure.PLL.PLLP = PLL_P; //系统时钟的主PLL分频系数(PLL之后的分频)
; u/ q; k H! ]. F" ]6 w - RCC_OscInitStructure.PLL.PLLQ = PLL_Q; //USB/SDIO/随机数产生器等的主PLL分频系数(PLL之后的分频)8 A8 v) M# g7 S8 n
- ret = HAL_RCC_OscConfig(&RCC_OscInitStructure); //初始化" N& h# r1 _5 V1 z, x
- if(ret != HAL_OK) while(1);. f4 _! K/ n% C+ a3 ^
- 0 V) G* D" P, x+ H9 _2 w" O
- ret = HAL_PWREx_EnableOverDrive(); //开启Over-Driver功能& U$ H4 D( Z% V# H' W
- if(ret != HAL_OK) while(1);
2 c8 w; x) p, k2 t - : w! X- |: n. N: o7 ^2 F
- //选中PLL作为系统时钟源并且配置HCLK,PCLK1和PCLK2
) q. x; L5 I6 F- f - RCC_ClkInitStructure.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);5 q) D7 R0 n+ P
- RCC_ClkInitStructure.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; //设置系统时钟时钟源为PLL1 q+ V, R5 A9 j* o' f
- RCC_ClkInitStructure.AHBCLKDivider = RCC_SYSCLK_DIV1; //AHB分频系数为1% W# ~7 @" F( S' @: Y4 y+ ]4 d
- RCC_ClkInitStructure.APB1CLKDivider = RCC_HCLK_DIV4; //APB1分频系数为4- o0 |3 d. r* s
- RCC_ClkInitStructure.APB2CLKDivider = RCC_HCLK_DIV2; //APB2分频系数为2. \$ G5 M, o( u+ P' n( U. h
a5 C& ]; Q" e9 q- ret = HAL_RCC_ClockConfig(&RCC_ClkInitStructure, FLASH_LATENCY_7); //同时设置FLASH延时周期为7WS,也就是8个CPU周期。! g8 W( X/ _* K$ R2 N* Z
- if(ret != HAL_OK) while(1);3 D3 m$ W. @. ^+ ~9 W& G$ s
- }
% X$ A5 ^6 j# R
复制代码
3 G/ w$ ?% ~4 \9 _8 N/ J8 `1 i& I6 l2 |
2 c# L, `+ }( M3 v6 C ?. n& ?
8 N7 U0 L/ p; s# f |