一.库开发的优势
' P7 U1 c4 @4 Z- K7 G. ]/ R! P# v 开发速度快,便于移植。+ r* j" W+ W$ B. H( t8 H
+ {1 |8 W! |) c8 ?+ v
二.stm32F7xx几个重要文件( P- g' l; d6 u7 H" R; x
1. HAL库关键文件( k; o( x; ]# k$ b; G) q
4 j! _( c# t9 t; D) O
% `" c: e3 g' m* V! K
& n0 N8 S% i8 [" J- {2.stm32f7xx_it.c/h
+ [3 } C9 K) H; x. p& L% m6 @' U 中断服务函数。基本都是空函数,我们可以去掉里面的函数,把中断服务函数写在任意可见的文件中。% s% g+ M n- j( x7 y% y
. z' O- B" ^6 w3 o5 U+ _0 t9 V; R: V3 P* ^
$ c8 B6 D7 {7 m: Z5 E
3.stm32f7xx.h9 } `0 B2 K4 X/ Z1 B
所有F7系列的顶层头文件。通过条件编译包含某型号的头文件(此宏一般在target——c/c++里面定义STM32F767xx,后面都以stm32f767为例)。0 m* U: U {6 F# c) \8 m
" k8 U& F* N; o! l
- #if defined(STM32F756xx)
* g# z5 ]: O9 x0 K - 9 w1 e8 ~$ n# D
- #include "stm32f756xx.h"# ?2 }2 o/ W8 C* I
- 9 B8 n4 f. t/ Z- k) y# x- _) M
- #elif defined(STM32F746xx)
4 z3 v/ R( I) @$ N% t& }8 |
! R, X3 S' _/ \; K- |+ Z: _- #include "stm32f746xx.h"$ ?. C! u" l2 x# N+ T! T- l+ H6 V
8 Y1 h" Z9 {- G6 h$ A* P( _5 |- #elif defined(STM32F745xx)
( v7 N/ d! f* z - ' h! i! i6 d/ P# Q
- #include "stm32f745xx.h"; t* y4 h: q, i( l
9 [- B; s9 B5 h8 ?( y- #elif defined(STM32F765xx)
- O6 l7 H$ i3 }) F: X% Y( u' Y - 7 i) u( T! z9 H) h R3 O
- #include "stm32f765xx.h"( E8 Q2 y% Y9 J% ? ]; j0 K8 w
. P8 b Q7 x4 C' z: U- #elif defined(STM32F767xx)- U6 v; e4 x: q& i
* F! o+ h5 r8 t! ?$ a! U. t- #include "stm32f767xx.h"
$ P$ u. f9 _9 R" T, n
4 a6 A0 C$ }% a( f8 h- #elif defined(STM32F769xx)0 H/ Q4 e* t. ~" V, J, R
- |9 E, C. y7 C( X$ c5 o- h8 x
- #include "stm32f769xx.h"; }/ G. P2 s( Z8 \8 q# N; B7 e
& ?2 g& P7 ~3 e! {6 a- #elif defined(STM32F777xx)
p% D* h) u) M9 O5 w - 2 {/ r3 U2 w. j/ I( i
- #include "stm32f777xx.h"
. H& ^7 {$ |4 I0 k - 2 v& w" u( _$ b& ]: B* ^0 q# \
- #elif defined(STM32F779xx)
$ S" G0 B# Z3 |4 e# G3 T - 2 E, C7 @' r6 @
- #include "stm32f779xx.h" : v5 d9 z* f8 |+ q
- $ k/ @3 v1 \9 b1 p' s2 Z
- #else) y! h9 l8 q# @8 y# Z8 M+ X
- / Y0 ? W7 L7 F
- #error "Please select first the target STM32F7xx device used in your application (in stm32f7xx.h file)"
9 W: p& n5 ?! q% Z& w# x7 D" n- l! ~
2 l' O9 b: ]) t' t5 h: u- #endif; ~/ A" K4 _6 R
复制代码 3 L9 J( P/ I" K% G! A* D
4.stm32f767xx.h9 c4 U" M* c+ a' X+ P9 N3 e8 n8 z; N
主要就是寄存器的声明(一堆结构体和宏定义)。5 y ^/ d$ {0 D: F1 }
" X0 `: u% L2 c5 L( T( D; {, v; _5.system_stm32f7xx.c/h
3 Y3 H. O& F5 A7 f' @. C 主要定义了SystemInit和SystemCoreClockUpdate两个函数,后续会在这个文件里面加一个SetSysClock()函数. SystemInit主要是时钟系统的初始化和中断向量偏移地址设置(有bootloader的向量偏移需要修改)。SystemCoreClock是一个全局的值(这个在FreeRTOS的时钟配置的时候需要)。
# w( A5 ]0 k! |" q# L
! ?" U% B$ N! [7 D5 x& t6.stm32f7xx_hal_msp.c
3 j+ t) U3 i" V0 k3 A B 带MspInit的函数进行MCU级别硬件初始化设置,通常被上一层调用(如HAL_UART_Init——HAL_UART_MspInit)。
" r4 _0 F; V. Z; D* p% {3 m9 N' v I& N" L2 \; F5 j4 b
7.startup_stm32f767xx.s
- k& J, G) t# Z启动文件,上电先运行SystemInit,再运行到main。
2 N; D9 j; N: p# Z) J% e5 d3 w! _# l0 X3 ^. ~
- ; Reset handler: P0 m! ~8 f# r5 r# Y6 z
( {) c; `; L! d. [( h- Reset_Handler PROC3 D5 U+ e) I+ K' g: K) o
- 7 J. F/ C/ {! P
- EXPORT Reset_Handler [WEAK]% d0 A4 n( N( k0 O. f
1 S7 M ~% ~, I# R. S- IMPORT SystemInit
' }4 N% j6 L, v5 R! z$ x6 o* r - T* d- V+ E) V$ b( j1 x
- IMPORT __main/ r5 B" u, f3 Z0 Y1 }- w
: k0 @8 ], r4 l& x0 U' T
1 f: X/ a- z+ P: v2 J3 E5 j
, Q$ ^+ {# e2 e8 n- E0 _; P- LDR R0, =SystemInit( b# z$ Y! d3 @2 w+ D4 q
8 P. Z1 e2 J! [5 E' {" v+ \- BLX R0% T: L0 W7 e0 I V3 Q) M
- 9 R: I q" i3 d" X
- LDR R0, =__main5 V, P: }& b3 X% l
7 X# ]" O& D# j( S/ t0 t- BX R03 y. l8 a7 \# s0 n$ T" S! x& y
- / h |" C, v6 m6 m4 y1 T: R% ^
- ENDP
) Z9 w: S/ P, `' F
复制代码
& p2 l1 ^# B9 _8 ^0 Y2 _7 A
& T) x, ^5 o2 b* M7 K三.HAL库中__weak修饰符2 X6 |/ ]( |: M9 d
weak:弱。被__weak修饰的函数就是“弱函数”,我们可以在自定义的文件中重新定义此函数(去掉__weak),编译器会执行我们自定义的函数。HAL库中一般在回调函数时用到。HAL中默认定义一个空的回调函数,保证编译器不会报错。0 c8 g k) z6 u. m) L. ?7 j% X
5 U2 J& t' }( [+ p1 K; y+ b7 P: t4 a
四.程序的执行过程1 Q$ @, I# J0 [6 M
Reset_Handler —— SystemInit —— main —— HAL_init —— SetSysClock —— xxxInit…(FreeRTOS:xTaskCreate —— xTaskCreate)+ P8 y4 p& |- j4 y
+ l0 R2 P& X! u4 j! v# h
五.启动文件
6 m% Z: k& _" d9 _主要指令:
5 M, P4 F+ ~( L2 d; o; J9 ]/ f& W. G B- s
5 A/ i( a' Q4 C4 b% B4 R
% d6 M9 h J9 B, S1 {8 v) V0 C6 B# K) w' K; j: b, ?
5 l) `8 @& I0 S( {
d7 F$ s+ v7 s5 V& R/ E; T, @. H3 v" tStack——栈,Stack_Size EQU 0x00000400 (局部变量,函数形参,函数调用等),值可以人为修改(不能超过内部SRAM)。
( N" s# j, ^- c! f- [/ H
* i$ T2 o, n8 m8 o! F9 gHeap——堆,Heap_Size EQU 0x00000200(动态内存分配malloc/free), X0 b5 M: R$ Y! _
4 Q- J, j' w$ ]# z `- H0 n# N向量表——中断向量服务函数
" g7 E7 ^, M" a b2 H/ p+ |% C6 @( @% k0 [3 q
复位程序——先进入SystemInit——main
% U# A& \3 |% U: b) r: D! p8 b Z$ S3 I( u, V9 F) ~" V1 h! K ]
关于启动文件详细描述请参考:STM32启动文件详细说明
9 `" W+ a$ b1 p7 V" @& ]6 T `3 I; Q% U: X$ F: f8 B
六.时钟设置(设置系统时钟)1 T: t+ R$ L% l( N; ^, ], r: F
- /************************* PLL Parameters *************************************/
* p% S" z( n% `" I7 D" H: l9 w - //时钟设置函数# X8 R- q6 R! @$ v" |
- //Fvco=Fs*(plln/pllm);& W" [9 v' W9 ]+ o8 G. [
- //Fsys=Fvco/pllp=Fs*(plln/(pllm*pllp));7 Y7 {& E: ]( H4 s
- //Fusb=Fvco/pllq=Fs*(plln/(pllm*pllq));: B7 _* [2 B& B) c5 @! f; o
. {( \2 h! X* r- //Fvco:VCO频率) N% b) _# E4 V1 W
- //Fsys:系统时钟频率
; i% Z; y! {) C) ~3 l( P2 r - //Fusb:USB,SDIO,RNG等的时钟频率
; N7 y' B: d _1 x - //Fs:PLL输入时钟频率,可以是HSI,HSE等." l! E8 Z4 c) e# M% H/ J
- //plln:主PLL倍频系数(PLL倍频),取值范围:64~432.( _* J$ K/ Z; k( W- i0 f
- //pllm:主PLL和音频PLL分频系数(PLL之前的分频),取值范围:2~63.
* J& I! }- E0 O2 [% n. b - //pllp:系统时钟的主PLL分频系数(PLL之后的分频),取值范围:2,4,6,8.(仅限这4个值!)
4 y% E' S& e! y9 `" O7 ^4 [ g - //pllq:USB/SDIO/随机数产生器等的主PLL分频系数(PLL之后的分频),取值范围:2~15.
' ~: V7 G2 L% W2 q - 5 z9 _: d* P1 k/ p" K6 M8 K
- //外部晶振为25M的时候,推荐值:plln=432,pllm=25,pllp=2,pllq=9.
' ^% g7 Q! H% ]5 _; F7 H3 \ - //得到:Fvco=25*(432/25)=432Mhz& W) Z0 b7 B/ ^4 n7 X
- // Fsys=432/2=216Mhz
+ g4 d: ~8 i& V( c, ~ - // Fusb=432/9=48Mhz+ J0 x- L8 ^. [! ^
- #define PLL_M 25: W+ F4 b A# Y0 `) i! E r$ @# a
- #define PLL_Q 9! B: s# R$ H) M- \1 K! o4 A- ~$ Y
- #define PLL_N 432
8 \! N. i' d4 i% \ - #define PLL_P 2
. Q& H& J# R! y( T6 h2 b
! O( X& J- r/ y4 b" H4 H3 i% l- void SetSysClock(void)
' w, n/ l* u0 V5 k - {" x) L2 D' @' f; d4 M& u
- HAL_StatusTypeDef ret = HAL_OK;; H4 E0 [$ R$ _
- RCC_OscInitTypeDef RCC_OscInitStructure;9 w Y2 O* Z6 {/ X5 G! s, y
- RCC_ClkInitTypeDef RCC_ClkInitStructure;
" J r) r/ D7 f1 M
$ |, E8 t7 L* v; H- // __HAL_RCC_PWR_CLK_ENABLE(); //使能PWR时钟
/ I e* t5 q, s7 p' M - 1 p) H/ S* H7 n3 }9 `) o" U& A
- RCC_OscInitStructure.OscillatorType = RCC_OSCILLATORTYPE_HSE; //时钟源为HSE B1 z4 Y5 k' O N' G' ?. M, L
- RCC_OscInitStructure.HSEState = RCC_HSE_ON; //打开HSE0 x+ D, [; v. J
- RCC_OscInitStructure.PLL.PLLState = RCC_PLL_ON; //打开PLL- L7 {( d, z {9 } O% S- h3 G8 U
- RCC_OscInitStructure.PLL.PLLSource = RCC_PLLSOURCE_HSE; //PLL时钟源选择HSE
. d+ J8 Y9 }' _2 _- L: z$ e" B - RCC_OscInitStructure.PLL.PLLM = PLL_M; //主PLL和音频PLL分频系数(PLL之前的分频); M2 q1 }, S0 V' o
- RCC_OscInitStructure.PLL.PLLN = PLL_N; //主PLL倍频系数(PLL倍频)8 `3 c; r4 ~1 w( w! U+ o; G
- RCC_OscInitStructure.PLL.PLLP = PLL_P; //系统时钟的主PLL分频系数(PLL之后的分频)
! b/ t3 e: c: c( ~ - RCC_OscInitStructure.PLL.PLLQ = PLL_Q; //USB/SDIO/随机数产生器等的主PLL分频系数(PLL之后的分频)
8 ^1 T7 R; q$ p* i v- \( O - ret = HAL_RCC_OscConfig(&RCC_OscInitStructure); //初始化
6 P/ l6 m$ P6 Q - if(ret != HAL_OK) while(1);
( B) U7 _& I0 l, _( L$ Z; ]5 V
# H3 G" c( A5 d, y/ Q- ret = HAL_PWREx_EnableOverDrive(); //开启Over-Driver功能6 H. n6 n" P0 j
- if(ret != HAL_OK) while(1);
6 V$ i _+ _9 ~1 K- l; j
6 X5 }' d a- J6 C4 ?- //选中PLL作为系统时钟源并且配置HCLK,PCLK1和PCLK2
7 `: }+ g" j8 N - RCC_ClkInitStructure.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);6 v: V( g# L1 ~, I" o4 G+ K7 E3 o
- RCC_ClkInitStructure.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; //设置系统时钟时钟源为PLL
" q5 D) ?$ V1 z8 r - RCC_ClkInitStructure.AHBCLKDivider = RCC_SYSCLK_DIV1; //AHB分频系数为18 O& D6 E+ Z: [' W# U
- RCC_ClkInitStructure.APB1CLKDivider = RCC_HCLK_DIV4; //APB1分频系数为4
, P7 U. I, k- @0 x$ w - RCC_ClkInitStructure.APB2CLKDivider = RCC_HCLK_DIV2; //APB2分频系数为2
3 z3 ^. u' c+ o/ D) F6 W) e3 w - , R6 m% b1 f9 V. I# V; ^5 o: A
- ret = HAL_RCC_ClockConfig(&RCC_ClkInitStructure, FLASH_LATENCY_7); //同时设置FLASH延时周期为7WS,也就是8个CPU周期。
4 m- f5 ^+ Z! }4 I h; o - if(ret != HAL_OK) while(1);' S6 L+ `& A0 q: t3 k
- }
{9 N0 m' d3 ~0 W6 t+ f$ `
复制代码
: ^& ~, Q3 j3 t5 x# T
( [: y6 e$ u2 X# g6 ^6 b
$ S5 V, F0 c& j. _. ^/ E' e9 X# B. |& y
$ F$ q6 ?$ q* u
5 A6 O% d& M1 m |