一.库开发的优势
* M1 b9 t8 C# F4 K7 ~. m 开发速度快,便于移植。
' ~7 Z: A# Q: a7 R, \
- S9 \/ \9 Y+ G0 N+ p6 }二.stm32F7xx几个重要文件/ g( U% a7 h" A
1. HAL库关键文件, {* s8 ?( N8 K. z2 Z
3 x) [6 C' a' ?2 D) M! R
2 ~3 l4 a9 K2 c: h' u: \" u
8 }6 q/ N* H* W. D2.stm32f7xx_it.c/h
" @' C/ Q0 D! e 中断服务函数。基本都是空函数,我们可以去掉里面的函数,把中断服务函数写在任意可见的文件中。
" Z0 |6 |) U6 T7 d9 g
9 Y1 j% M) p7 X0 @7 ?. ?8 _6 x" q7 ]2 c! w
* B1 J4 x: d/ G6 r: h# ]& Z3.stm32f7xx.h2 N6 I0 ^) ~* R) D
所有F7系列的顶层头文件。通过条件编译包含某型号的头文件(此宏一般在target——c/c++里面定义STM32F767xx,后面都以stm32f767为例)。+ ?& N7 w. {) Z8 n h/ M
& ?6 `* V h8 W6 M4 R1 W- #if defined(STM32F756xx), W7 i8 `1 X; B4 y7 p
- ( W- G! o; q: v& l% F" w0 J0 l
- #include "stm32f756xx.h"! O& k7 d% o! b$ \
- 4 Y: w/ X c6 C
- #elif defined(STM32F746xx)- M+ E% H9 m/ ^$ `* ^# t2 N
3 |& E* Z# B9 m4 A- #include "stm32f746xx.h"+ e! `0 P( X- K5 x1 R' k; j
0 w) d. M& V9 |' t/ G- #elif defined(STM32F745xx)
; c6 N9 s2 g! B$ M' z e - ]8 c: M) n; r3 K
- #include "stm32f745xx.h". ^* A4 C0 n x" R+ c' U1 Z( {3 G
, ^9 }( J6 F& V! ?# I) I/ e- #elif defined(STM32F765xx)/ a/ ^- ?) t' _- w
" \: t$ [4 @* T- #include "stm32f765xx.h"
% V$ v5 b0 H9 Z9 ^# @. v( _8 Z
) n' \. @9 Z1 C6 G9 W- #elif defined(STM32F767xx)
& U3 i- b0 @7 Y' H7 g# j - J( i3 ^( I p6 y7 w% H p! C
- #include "stm32f767xx.h"! ~4 k, m6 y; } ?6 e1 r5 h: _
# f* \* J ? c' j+ D- #elif defined(STM32F769xx)& R: P, u9 w7 z4 ]& M" }9 k# M
% P! z, |" w4 J- #include "stm32f769xx.h"8 h k9 h1 Y/ }1 D0 Z0 J) a( m
: ?6 o8 ~% j( i1 j- k6 B; o" h5 C- #elif defined(STM32F777xx)
) i* n# J I2 }# o
2 E% I4 o9 A- K- #include "stm32f777xx.h"
+ F! t6 N/ H; K* f3 _5 P
# V* C. ?% d0 I B, V- #elif defined(STM32F779xx)
* L- _& I! s' y( [, a! T8 L
' a2 L9 i6 } U" ]) m d0 v- #include "stm32f779xx.h" 3 p0 Z7 E7 h: Y: n5 L8 m
- ; P5 j" c; ?: k( r R T# d+ Z3 Y* D
- #else2 H) a" b; b" j4 v; u: ]- h! _# o
0 F" }& M6 c( ?% p) a. ~( Q5 y- #error "Please select first the target STM32F7xx device used in your application (in stm32f7xx.h file)"% V# ]% s9 Q6 p2 K$ I. ~4 n( J& Q+ }/ \( G
( ]' J3 t, g" Z" ~1 i- #endif
$ h9 z0 |1 r3 n9 ^' m/ S
复制代码
9 F Q- H% Z' ^5 K7 [4.stm32f767xx.h2 l, C: T( [- Y
主要就是寄存器的声明(一堆结构体和宏定义)。+ [7 _# x2 |: r/ q
% F5 }- b$ w2 f% S1 b N5.system_stm32f7xx.c/h
& D9 G2 K* S% J# ~ 主要定义了SystemInit和SystemCoreClockUpdate两个函数,后续会在这个文件里面加一个SetSysClock()函数. SystemInit主要是时钟系统的初始化和中断向量偏移地址设置(有bootloader的向量偏移需要修改)。SystemCoreClock是一个全局的值(这个在FreeRTOS的时钟配置的时候需要)。
, `1 ^+ U- Z0 o0 U/ \9 \7 j/ [9 H( ^4 k
6.stm32f7xx_hal_msp.c
0 T# G) ^) ~+ S1 ^% i5 Y0 X7 e 带MspInit的函数进行MCU级别硬件初始化设置,通常被上一层调用(如HAL_UART_Init——HAL_UART_MspInit)。* n: O$ \0 t: ?6 o, n! l
! c$ ?+ J! Y8 _7.startup_stm32f767xx.s2 j" k5 `+ C% {( w
启动文件,上电先运行SystemInit,再运行到main。' \( t) L) n5 t) M+ }3 @+ J
5 ]$ s& m, k" I) V
- ; Reset handler3 f9 V* B2 F& ~
- * H# z& l7 E# u5 d
- Reset_Handler PROC
. B3 v! u7 x1 N' `4 t) {# I - ) F. [4 Z* Z( |5 _1 [6 C9 ?, z! R$ D$ ~
- EXPORT Reset_Handler [WEAK] {* A( P8 Y j( z' q* q) l
! O! x o' k, Z- IMPORT SystemInit" O' Y; d p+ q7 m0 Z0 k
- " T5 x& E* j; c" w% }
- IMPORT __main, U, \9 X2 E6 r0 |+ R$ i' l' A$ L9 [
- : H! ~+ e/ ]$ s% i1 V
. J: Y3 }+ W R2 s* t6 I
9 v! D3 l4 H5 g7 P2 `2 x6 @7 L- LDR R0, =SystemInit {3 b; t" z) x% N4 H& z5 Y2 a9 Y- w
- * F% |6 t! E! t( S- P& g! ]6 u
- BLX R0
9 o5 l: J4 s0 f! P' U) P - ' e Z9 K# d) ~) }, q, A! L$ o
- LDR R0, =__main
( }. D0 v8 x3 c, b# @: W6 n - 6 [ E; _/ u. T0 A/ W7 P0 M" m2 Q
- BX R0
. a/ o7 w" k9 y$ q' j; J; B/ X. m - & z" M) S# F& `0 l
- ENDP
R8 [. X: Y# H6 I. E( c! a
复制代码
4 ]# r- l/ ~0 t1 ~7 O) Q" k, a2 E ~8 [: t% v* j5 h
三.HAL库中__weak修饰符
1 r- i8 @0 f: H. f/ O weak:弱。被__weak修饰的函数就是“弱函数”,我们可以在自定义的文件中重新定义此函数(去掉__weak),编译器会执行我们自定义的函数。HAL库中一般在回调函数时用到。HAL中默认定义一个空的回调函数,保证编译器不会报错。. l9 o& v z; p0 g ]1 N
3 @9 `# f o' v' l! U" w
四.程序的执行过程, t# n4 M* g' ^! O
Reset_Handler —— SystemInit —— main —— HAL_init —— SetSysClock —— xxxInit…(FreeRTOS:xTaskCreate —— xTaskCreate)
% I7 `/ d- G( _+ X9 }9 v0 a6 E: P
/ J: p: N7 h+ s) ?" `. d; K五.启动文件
7 P9 T0 k m: @" @主要指令:; Q) R, A$ _- O8 Z
1 b) W( |2 ]: E/ y
: e4 n9 J; ^) M1 P2 \1 T2 {: o/ }" U3 v% {3 |
8 ]* y2 F# d$ y1 Q/ x) ^1 H" ?5 n* H0 G9 p
. a; V1 O/ ^& a J9 z4 N
Stack——栈,Stack_Size EQU 0x00000400 (局部变量,函数形参,函数调用等),值可以人为修改(不能超过内部SRAM)。3 O- w( N7 J5 S4 n' [! Z
( T4 k3 B( r' }9 w+ @Heap——堆,Heap_Size EQU 0x00000200(动态内存分配malloc/free). H* O( S4 e5 K
* H7 e! V5 Q- T' [1 ]& x向量表——中断向量服务函数, z' w$ b6 U( U4 W
0 b/ u; m( V' g9 [% Q* I% l2 X复位程序——先进入SystemInit——main
4 M6 n* `( V# }" o, L; r/ J1 e; I
! s3 k$ \* K, m) q2 C+ J: Z关于启动文件详细描述请参考:STM32启动文件详细说明) {/ H. Q, r& Y' K2 {! `" R8 J
/ l6 i& w- h# S5 A/ l
六.时钟设置(设置系统时钟)! J2 o% Y' \8 W; L
- /************************* PLL Parameters *************************************/
4 `0 i$ ^6 j& l; K - //时钟设置函数, @# h6 t9 E8 y/ ~
- //Fvco=Fs*(plln/pllm);
( q3 q3 b: p+ }" W* t - //Fsys=Fvco/pllp=Fs*(plln/(pllm*pllp));
! b& B5 ?8 T% a# j - //Fusb=Fvco/pllq=Fs*(plln/(pllm*pllq));
1 C2 A# K1 @& i, w; p/ ~! y
7 p. V* B0 n9 \1 {- //Fvco:VCO频率 D+ c. }" [# Y2 w$ ] e* `5 y
- //Fsys:系统时钟频率3 j% u! X! t; E) d# d5 \
- //Fusb:USB,SDIO,RNG等的时钟频率
: H. A; y- F2 Q# S - //Fs:PLL输入时钟频率,可以是HSI,HSE等.+ w9 f0 b+ L3 h$ e% K
- //plln:主PLL倍频系数(PLL倍频),取值范围:64~432.
6 E2 \1 r! |) S$ j- s/ |+ O - //pllm:主PLL和音频PLL分频系数(PLL之前的分频),取值范围:2~63.
( H; N8 u" [/ p! N$ Y - //pllp:系统时钟的主PLL分频系数(PLL之后的分频),取值范围:2,4,6,8.(仅限这4个值!)
& z+ w# n$ F5 a3 Q - //pllq:USB/SDIO/随机数产生器等的主PLL分频系数(PLL之后的分频),取值范围:2~15.0 s' `4 |1 `- `+ G7 z1 {
" i1 c3 C. q4 h% F: Z0 k6 ?- //外部晶振为25M的时候,推荐值:plln=432,pllm=25,pllp=2,pllq=9.
6 f, P5 x0 v. q! N- p - //得到:Fvco=25*(432/25)=432Mhz
5 L' |) p6 Z* [. K) k) q! _ - // Fsys=432/2=216Mhz8 x7 f4 ?/ l; d3 F
- // Fusb=432/9=48Mhz' `% M" W1 E$ r( Z9 j
- #define PLL_M 25/ t( m" |8 l& ~3 S+ H
- #define PLL_Q 9
' m A; r1 _ `* t& ~; _ - #define PLL_N 432: Q" ?# O# s! w' A( Q! Q. q5 [
- #define PLL_P 2
1 Z) p1 }1 e. @
. ?/ c+ O9 P4 U- void SetSysClock(void)
/ E4 O2 d/ ^ |) k7 Y) g, F: P - {
* m0 H8 g. E( W2 n - HAL_StatusTypeDef ret = HAL_OK;
# h0 B8 a, G& k - RCC_OscInitTypeDef RCC_OscInitStructure;
( Y0 p6 q5 F7 g: |% x0 m. { - RCC_ClkInitTypeDef RCC_ClkInitStructure;' a# w8 U& D) T
0 i6 M' q1 U" g* o3 l9 k- // __HAL_RCC_PWR_CLK_ENABLE(); //使能PWR时钟
: O4 h/ I: v) h: B% P2 v5 A4 ~
, L3 k$ |, [+ p- D8 Y; w; f- RCC_OscInitStructure.OscillatorType = RCC_OSCILLATORTYPE_HSE; //时钟源为HSE& ^3 p& T& v' y0 p# g* e5 s* \
- RCC_OscInitStructure.HSEState = RCC_HSE_ON; //打开HSE
" e. l; v3 Q2 }4 @5 Y2 F - RCC_OscInitStructure.PLL.PLLState = RCC_PLL_ON; //打开PLL1 U8 H$ j4 t; K4 p) h4 Z
- RCC_OscInitStructure.PLL.PLLSource = RCC_PLLSOURCE_HSE; //PLL时钟源选择HSE7 y# M3 q( V4 F
- RCC_OscInitStructure.PLL.PLLM = PLL_M; //主PLL和音频PLL分频系数(PLL之前的分频)
5 t( J2 V+ [. {2 d - RCC_OscInitStructure.PLL.PLLN = PLL_N; //主PLL倍频系数(PLL倍频)7 z4 |" X9 ~% |! {
- RCC_OscInitStructure.PLL.PLLP = PLL_P; //系统时钟的主PLL分频系数(PLL之后的分频)
- E6 {& _( ]- N, b$ B" \ - RCC_OscInitStructure.PLL.PLLQ = PLL_Q; //USB/SDIO/随机数产生器等的主PLL分频系数(PLL之后的分频)
+ H2 A1 N( ? D, g' {' F - ret = HAL_RCC_OscConfig(&RCC_OscInitStructure); //初始化2 N! N9 w; ~& m+ q# j
- if(ret != HAL_OK) while(1);- [" v3 C: |6 a- f, o1 p
5 _( Q# ~7 I: L* U# A/ y- ret = HAL_PWREx_EnableOverDrive(); //开启Over-Driver功能
' G/ |& C; v* y - if(ret != HAL_OK) while(1);
/ _7 k4 F% q4 ], R* W
4 ~" _1 V0 W& U+ J- //选中PLL作为系统时钟源并且配置HCLK,PCLK1和PCLK2% d" B8 w9 i1 I; C& {# C. f; p
- RCC_ClkInitStructure.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);. B2 c" Z( @4 p2 K
- RCC_ClkInitStructure.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; //设置系统时钟时钟源为PLL
: P% B4 t# {" Q( T3 d - RCC_ClkInitStructure.AHBCLKDivider = RCC_SYSCLK_DIV1; //AHB分频系数为1$ U$ R% s' x/ e3 W( x
- RCC_ClkInitStructure.APB1CLKDivider = RCC_HCLK_DIV4; //APB1分频系数为4' P2 z& P% B+ L" r$ e9 _
- RCC_ClkInitStructure.APB2CLKDivider = RCC_HCLK_DIV2; //APB2分频系数为2
+ u/ ~9 `6 ?- i; o8 e - - F0 r! v- y' S' ^! |
- ret = HAL_RCC_ClockConfig(&RCC_ClkInitStructure, FLASH_LATENCY_7); //同时设置FLASH延时周期为7WS,也就是8个CPU周期。* ?0 j+ \* v- G1 ~8 Y5 g: e- S
- if(ret != HAL_OK) while(1);; g8 s+ ]5 @7 E% g
- }2 c5 z* ]3 c) A0 S2 S0 E
复制代码 * g. B8 ~3 i% M. x$ j. v5 ?9 n
* a* y4 K, U' B0 @6 `
8 D1 E$ R* x' Q z
4 {* A* z+ n; v4 Z+ k+ M3 H/ Y
" N6 v6 `4 W/ W# s7 `; ?4 c- X |