概述
+ W! A& y5 B% y+ W1 t本例程主要讲解如何对芯片自带Flash进行读写,用芯片内部Flash可以对一些需要断电保存的数据进行保存,无需加外部得存储芯片,本例程采用的是STM32F030R8T6,64K大小的Flash。
+ C) A& k5 v; ~0 c1 \, a T6 i5 z6 N8 [ e D
硬件准备
, y. l i( Y0 a+ B首先需要准备一个开发板,这里我准备的是NUCLEO-F030R8的开发板:3 n Q% o* X# C2 c) Q5 y$ c8 o
' H! Z; e+ w/ w
& N# l3 T$ w! `0 m6 g
0 @; Z* |8 `0 A% `2 j2 e选择芯片型号# R9 O5 Y/ C u8 y$ A/ M
使用STM32CUBEMX选择芯片stm32f030r8,如下所示:+ e8 H9 F1 O1 y* m! F8 t' ^
) @) R, U$ E& l0 Z7 w% Q* W) t
1 z9 ^+ P4 b* `4 R2 t5 A& I7 S
' u( v+ P9 Z4 F9 F) q
配置时钟源* F0 Y( l1 o" X
HSE与LSE分别为外部高速时钟和低速时钟,在本文中使用内置的时钟源,故都选择Disable选项,如下所示:) Y l4 ~; ]% [7 B
' X1 L3 U' R6 {. U" F- B
9 A% j8 T. _9 w) T" a# n
) `5 N9 x/ n' {5 f* O配置时钟树
& \8 n4 S8 q- x, ~* d( C0 N9 jSTM32F0的最高主频到48M,所以配置48即可:* w9 u' A( N1 C
; ~: a* |- q0 P
* U' J6 d6 t6 d- ?) w5 D
* Q! p$ a3 z: d% O1 Z串口配置
, C+ Q( I2 }& b) r% a6 S本次实验使用的串口1进行串口通信,波特率配置为115200。. [+ d, ?- x2 I8 J# w. @( K- H
2 e6 m! x$ L' x; Y
$ |1 K" T- m0 G6 t# {+ a& L
5 u% g5 J2 Z- a! ^# V: p7 u: z生成工程设置 g3 f0 i) O7 T1 U: |, N' ]
注意在生产工程设置中不能出现中文,不然会报错。
, n1 g# _5 H* z6 X# e
r8 q& Y! ~* \: K( E/ h" w9 L
$ C- `7 E4 R. o9 G% E' i, `: w: ?- g5 o- [
生成代码
& \4 J2 {* ^& E, `( N
+ ?0 C! o4 b! d; W: C4 O5 X
# l- n' g) x8 r2 [
6 @3 U* k# g$ X' _8 x6 E, W
配置keil
4 _7 B7 p5 Z/ J
5 |8 e. n* @4 P8 G! H' N+ w
" q: m/ h+ v& p( a" ?6 c! B
# |. v) w' A. M4 a+ ~% D代码
, N" u4 D5 O- ^, u ~在main.c中,添加头文件,若不添加会出现 identifier “FILE” is undefined报错。
* h; Q* n/ G* h! H3 s9 w* l
8 \8 X- J. E# B r+ r9 j; G- /* USER CODE BEGIN Includes */
, B$ ]1 H1 M4 L - #include "stdio.h"+ L- k) m" I' D% z7 q
- /* USER CODE END Includes */
复制代码
, Q" g" @2 r; Q* \函数声明和串口重定向:
8 B! R8 C/ O) l; K# H) I; M# A
3 ]$ s/ [' n, N4 C0 ?* H% z% K- /* USER CODE BEGIN PV */
6 e$ p- D/ i. L - void WriteFlashTest(uint32_t L,uint32_t Data[],uint32_t addr);//flash写函数0 V4 h0 x! U+ v8 S7 T% g9 `- j. ]
- void PrintFlashTest(uint32_t L,uint32_t addr);//flash读取
9 k+ G: C" O ~' D3 b; C2 ~ - #ifdef __GNUC__* H* ~8 l ^+ H; C" x& D
- #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
! n: }! Z) A7 u6 O) ] - #else
: `- _: E! I: P! p! b - #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)5 g* N' L6 g! ~( Y. x
- #endif /* __GNUC__ */: j8 _% e) z' @( p: C9 \& D0 Y" Z
# y- G4 M. |( r4 L5 ~* d* @ D" ]5 y
6 B$ s) i0 Z; B- int fputc(int ch, FILE *f)
/ F* C, l/ z X8 ~3 g - {
6 c8 O3 r& m: |# u; v! R: W - HAL_UART_Transmit(&huart1, (uint8_t *)&ch,1, 0xFFFF);5 X; k% e9 m$ _
- return ch;2 z2 W- T( ]- N: N6 J
- }
) {! Q3 N! ^2 ]0 Y: P2 t- V3 { - /* USER CODE END PV */
复制代码 3 j4 b& f0 S& U; Q
变量定义:
. e, p# D3 @7 \& E5 t: \5 Q7 [9 |$ A9 G# c7 C
- /* USER CODE BEGIN 0 */
$ Y! f% S! R( J - uint32_t WriteFlashData[3] = {0x11111111,0x22222222,0x33333333};//数据- S$ n# Q/ N2 ~/ M, _( _
- uint32_t addr = 0x08007000;
1 K; X! M5 k( `; ~" N - /* USER CODE END 0 */
复制代码
! p/ Q$ W$ Z' S7 D如果要对FLASH进行写入数据,需要执行以下四步:
2 |* Y7 K" J3 F( U9 c) A& a. y7 e3 S& J5 t
1.解锁FLASH* A8 s; p2 H6 s
2.擦除FLASH
( k. R7 I) s# {+ U/ n1 R3.写入FLASH
@4 y, Q# ? O1 W* g4.锁住FLASH
5 ^; ?3 x# J/ q! o擦除只能是按页或者整块擦除。
/ x% E+ ?- U; X" V( }2 Y( `9 b* l
STM32F030芯片内部的Flash存储器内存分布如下:
. a/ f3 d) b% j* V# V2 @% I5 z2 A2 J, V1 h
p2 I; A) x7 ^% g1 |; K& q% _
* w& U. T4 l' X* J! V' M6 t$ [0 SSTM32F030R8T6的Flash容量是64KB,所以只有63页,每页1KB。
8 q ~' P0 b! ]) O* c我们可以写入到页60中,即0x08007000-0x080073FF中。
M0 ^0 ]- ?$ a9 l# y8 H/ P由于单片机是32位,故连续写入多个uint32_t的数据时,地址应该依次增加4。
7 I* I& O: h: O
8 ?# _$ y! J* r& F- /* USER CODE BEGIN 4 */! V* N8 F! T2 }
# g7 C6 W" }! w! o8 v9 g- /*FLASH写入程序*/1 H$ o i) M* Z' {
- void WriteFlashTest(uint32_t L,uint32_t Data[],uint32_t addr)5 ^* z K+ C+ \! ]& c
- {
" d. {0 B9 ~' }( d" ^9 |; d - uint32_t i=0;
7 C# o- h Z' V" F4 i - /* 1/4解锁FLASH*/9 v0 q; w1 F, [: H+ O( ~
- HAL_FLASH_Unlock();7 }3 G# N7 h6 J* [' j3 s1 t
- /* 2/4擦除FLASH*/8 r0 M, _* E9 z' n' X) S1 S3 w( U
- /*初始化FLASH_EraseInitTypeDef*/
5 F: X' j) j ~7 ?8 ]% { - /*擦除方式页擦除FLASH_TYPEERASE_PAGES,块擦除FLASH_TYPEERASE_MASSERASE*/0 b0 N4 \: k3 |, K
- /*擦除页数*/: |0 `5 ~. o4 ]* S
- /*擦除地址*/
! ]6 h. c) z. R1 `- ` - FLASH_EraseInitTypeDef FlashSet;- _# x, G8 J+ u( i y5 E
- FlashSet.TypeErase = FLASH_TYPEERASE_PAGES;: J- l& C1 o# K5 N
- FlashSet.PageAddress = addr;+ Z! h1 D6 i1 T0 {* `
- FlashSet.NbPages = 1;5 ^4 I! A4 S( d+ T" y" _6 N+ i
- /*设置PageError,调用擦除函数*/
$ o/ Q: S5 C4 n0 p- y, b/ o - uint32_t PageError = 0;
- V. ~, \" V7 h" h7 l- q& ^5 q* ^" D - HAL_FLASHEx_Erase(&FlashSet, &PageError);4 S0 i: m5 J t
- /* 3/4对FLASH烧写*/
8 I- K0 v4 W: q6 E* u0 @ - for(i=0;i<L;i++)
% Z5 g1 V9 H( F3 D' Q6 | - {: j2 t; W ]/ A. g
- HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr+4*i, Data<i>);
( o3 S; V! W! f% H6 r4 E - }
$ m6 {' ~1 [# T, S - /* 4/4锁住FLASH*/5 a( m0 e# t1 B( [( ~+ w
- HAL_FLASH_Lock();- S( u5 z- b$ p7 _
- }
0 g" A$ |' f' h3 d+ B" n0 u - ) \$ C; `# X4 X
- / R1 N/ N; `8 i$ A8 E7 E G
- /*FLASH读取打印程序*/; Y+ u2 s2 Y5 }) x2 G3 j' Z
- void PrintFlashTest(uint32_t L,uint32_t addr)
8 N/ B4 L- M- J - {% Z/ j5 K3 q$ H% G
- uint32_t i=0;7 Y, B0 o- t7 \2 r/ p9 b- m
- for(i=0;i<L;i++)3 \, D: V+ V2 |+ ]$ \
- {) v, }6 H7 R5 g% g. C" I( d
- printf("\naddr is:0x%x, data is:0x%x", addr+i*4, *(__IO uint32_t*)(addr+i*4));
# o% D' U% U+ v) q4 Q - }
" a$ K5 O; g2 g; Q$ s; T -
$ Q- ^/ L, g' k; Q2 E0 F. I7 l - }
, _7 b1 K1 f; T. c+ V - /* USER CODE END 4 */
/ q8 J8 r6 y/ H! \6 O - </i>
复制代码
, M7 t! C, Z1 Z$ c主程序- /* USER CODE BEGIN WHILE */
4 _* n3 B/ R2 H7 M C K0 V - while (1)0 G( }( i" l1 h g# P
- {+ T- d, S7 A) ?
- /* USER CODE END WHILE */) K3 Z5 r& Q$ D4 b
- 2 o) w/ s3 \; p7 v
- /* USER CODE BEGIN 3 */
/ l$ m3 G' s! S% q" u" ~9 i o5 X - WriteFlashTest(3,WriteFlashData,addr);3 H: U5 v5 P, p5 L# E
- PrintFlashTest(3,addr);
1 m8 q, M- o7 m7 d, j* [ - HAL_Delay(5000);
T; a" E+ T$ k5 A! ^ c$ g+ R - }( o! i2 Z5 m% h) }8 G6 O: Y
- /* USER CODE END 3 */
复制代码 3 q" P) i5 ^# u+ S1 u) A
演示效果
# U; T+ \. \5 I( [- f$ f4 Z; @+ w6 Z, F& I
9 T {! _! J% i# { l6 V
, `* F: }1 @& o" y通过keil查看地址也可以看到,值正确写入。: g: U6 O n7 \8 K- q
; ?6 `+ {" ` W
4 N9 E ^) Y2 R* w, R
# U- r4 Q; X+ `3 C
9 ~3 m! Y$ @7 h8 o7 e' x/ Y
|