|
一、芯片FLASH容量分类: 
" g- T7 Z" o: D+ o T* O1 H
可以看到我们今天介绍的这款芯片的flash大小是64K的,网上也有人说它可以支持到128K,但是官方给出的解释是前64K是有保证的,后面的无法保证,所以想要使用的小伙伴需要慎重。
* a4 R& v5 Q, P+ X现在芯片的flash大小我们知道了,下面就可以看看这个flash是怎么划分的了,通过芯片数据手册,我们能看到今天说的STM32F103C8T6是属于中等容量的设备。 
既然是中等容量的设备了,那我们就来看看flash划分吧,在STM32的闪存编程手册中有这样一段话:按照不同容量,
" d& i, v% a/ w3 `, x" F6 x存储器组织成:
3 {% S2 ~( J) m1 q' s32个1K字节/页(小容量)
' x l; N& v, Q% l T O+ |4 T128个1K字节/页(中容量)
+ p, H7 k+ x2 }$ c. O _- T256个2K字节/页(大容量)
: b O7 t f: A- E这段话怎么理解呢,就是告诉我们小容量的设备(内存是6K和32K)的设备是由1K字节每页组成的,; Q0 _; E4 t `" S9 ^. f: g
中容量的设备(内存是64K和128K)的设备是由1K字节每页组成的,
! |+ t: r3 e5 D9 o- \. n大容量的设备(内存是256K、384K和512K)的设备是由2K字节每页组成的,: Y5 b5 Q2 n9 Y8 O
举个例子吧:
2 F3 z! `. S# {: f* j; o, T6 b一个芯片的存储容量是64K,这64K是什么呢,就是64*1024个BYTE,一个BYTE是由8位0或1组成的,(比如0000 1111 这8个二进制数组成了一个字节,用十进制来说就是15)4 S2 I) \/ _+ L: T+ K9 Q/ Q z
小结一下:64K的flash可以存储64*1024个字节的数据。# R! _$ z% x, e/ D) ^: U
咱们继续说,这64K的数据怎么划分,存储是按照页为单位进行存储的,一页1K的容量,也就说一页可以存储1024个字节* D3 R" K: W/ T9 ?$ F
一共是多少页?
+ n, @) x9 m& U! ~答案是:64页,我们看一下官方是不是这么说的 
在闪存编程手册里确实是这么说的,所以我们刚才说是64页是正确的 ( {9 M! U. R% o! f% H
二、 读写步骤:# ~9 @+ ~( ?9 m; p1 o1 f" p) Y3 H
上面我们知道了芯片是怎么分类的,下面我们就重点来讲解一下芯片是怎么读写的。
" t! ?% s1 n7 t& e3 p/ j/ E, m内部flash我们参照HAL库或者标准库,直接调用ST公司给我们封装好的库进行编程就可以了,这里我用的是标准库,有兴趣的小伙伴可以去看看HAL库, E4 w* }$ p& t
是不是有小伙伴会疑问什么是标准库,什么是HAL库?: l2 l$ k+ Q m$ |* P/ q5 Z. l1 o
在这里给大家解释一下,这两个库都是ST公司,直接把寄存器封装成函数,供大家直接调用某一个函数,就可以完成各种寄存器的配置,不容大家直面芯片的寄存器,方便阅读和使用,因为每个函数的名称功能都是不一样的,在调用前可以参考函数的注释,在F0和F4的标准库里甚至有每个函数的用法,不知道为什么在F1的库里把使用步骤去掉了。
7 D& B! G( `% N0 i, X. r+ G. M咱们继续,读写的话库函数分为: - /*------------ Functions used for all STM32F10x devices -----*/8 s+ \/ Y l6 _$ H& D( q) f
- - z) V R6 n5 j& j& r2 a! {
- void FLASH_SetLatency(uint32_t FLASH_Latency);" }% Q+ Z; l8 g1 h
- @5 [6 n3 ]1 z7 x$ Q C1 E
- void FLASH_HalfCycleAccessCmd(uint32_t FLASH_HalfCycleAccess);8 I# P6 y+ Z1 @2 q- ?
-
* G( i- l B( O6 d3 t* M - void FLASH_PrefetchBufferCmd(uint32_t FLASH_PrefetchBuffer);2 F& o3 v' X% c( t8 _( y3 k
-
1 q/ ]. _+ n6 ~3 S9 I$ F M - void FLASH_Unlock(void);
. x& O3 v5 K; z# o - 8 q% z, b7 a/ I( e
- void FLASH_Lock(void);
4 x$ t) |) {. r- a6 N v' U -
5 A) v( r2 e' d! {% y- c& U - FLASH_Status FLASH_ErasePage(uint32_t Page_Address);# l7 T2 { {0 E6 d* ], q! m
-
: k9 i5 y- F" N( z - FLASH_Status FLASH_EraseAllPages(void);. B7 I8 F3 t5 q( {' v* [
-
5 v% Q8 v8 Y7 p0 e: r# | - FLASH_Status FLASH_EraseOptionBytes(void);/ A& J; X3 n, f' Y# e9 x
- 1 {6 s: X; m- d0 u* ^( C
- FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data);
# L1 O# w. x. \! A0 G2 M -
6 j; Q( {7 [7 C* U0 r; a - FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);
1 E% }7 Q% G/ c0 T* j. s0 D- k -
- C; F& }% P$ w7 k - FLASH_Status FLASH_ProgramOptionByteData(uint32_t Address, uint8_t Data);. ]& u" E) Z/ _" X
-
: a3 _ Q0 `- m+ ~# G; s% ^5 z - FLASH_Status FLASH_EnableWriteProtection(uint32_t FLASH_Pages);5 d3 T, {/ \! ^
-
4 F( _9 [9 K0 X/ Y* S4 n9 |& `* G - FLASH_Status FLASH_ReadOutProtection(FunctionalState NewState);+ L& D+ g( u" { G$ ?
-
+ X! x) [9 F7 r* l - FLASH_Status FLASH_UserOptionByteConfig(uint16_t OB_IWDG, uint16_t OB_STOP, uint16_t OB_STDBY);9 G, C5 a- P0 p( r7 v* W
-
5 Q- f: |& h& v; w9 ]5 T9 M - uint32_t FLASH_GetUserOptionByte(void);) T0 [: n( t; X9 H: h( m
- : i. l+ n2 T& T+ q8 y4 q4 l
- uint32_t FLASH_GetWriteProtectionOptionByte(void);* ^8 E% F( j. ]
-
& V4 I$ }9 ~3 v) n6 r6 @ - FlagStatus FLASH_GetReadOutProtectionStatus(void);( o4 N. k5 x5 ~
-
- T& }- n8 j7 l) o& ]4 I - FlagStatus FLASH_GetPrefetchBufferStatus(void);. L. Q- E1 G" D, m2 x( x' Y8 V& a
-
9 B0 g- r& q1 l$ e( w. E/ w0 h - void FLASH_ITConfig(uint32_t FLASH_IT, FunctionalState NewState);
: z* v9 T! p' J( q7 r6 \3 v - ' i% [, o1 M3 R5 p4 t
- FlagStatus FLASH_GetFlagStatus(uint32_t FLASH_FLAG);: D! h, w, ], [4 i4 x; U
-
; u+ w* b, @( {& A' x - void FLASH_ClearFlag(uint32_t FLASH_FLAG);
1 ?0 ?! Y. V5 S; I% V! ` - f( q ]) r( `3 n9 F; g1 k
- FLASH_Status FLASH_GetStatus(void);
' T/ B5 g0 J8 ^) f1 G0 N! q$ A - ( l1 ]6 R9 G/ \
- FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout);
( Y* @$ t( A7 p1 L -
9 ]; t4 E% w) T+ S - $ m2 P8 X6 ^+ g. M5 \, H) w
- 5 t' `$ D$ [5 S* o2 x
- /*------------ New function used for all STM32F10x devices -----*/
0 R4 Y/ g/ N, |/ J# x" U* m; q - 9 W" _. L( U8 }7 n0 j& \2 b
- void FLASH_UnlockBank1(void);
( |; s2 u! \3 I6 m - {! E8 ~! a+ M# y
- void FLASH_LockBank1(void);* n5 }' G3 T' d1 u2 S/ K, l
- 3 m' o$ u/ T& {3 U2 C/ A- A3 \
- FLASH_Status FLASH_EraseAllBank1Pages(void);
& {8 J2 A: \! a$ R- p8 X -
5 Q7 J! h$ ] B - FLASH_Status FLASH_GetBank1Status(void);* F/ x. S7 w% O. _$ \" X X
-
4 W6 W' w2 ?+ s* `+ C3 K - FLASH_Status FLASH_WaitForLastBank1Operation(uint32_t Timeout);
复制代码 3 V+ S3 Z6 y, Y6 B
& ^. x9 T( n5 ^+ n+ W在这里就不一个一个的详细说了,我们说一下常用的就行
0 C$ G2 V1 A# z3 s2 T! W S# G1. 解锁 void FLASH_Unlock(void);; |' C, s3 O3 }' Z
" ~4 l: ~, Z) n" n+ I2. 上锁 void FLASH_Lock(void);
7 [6 b# l3 \. o. M2 R* _. P! {8 X. y& R. }% y( ^
3. 页擦除 FLASH_Status FLASH_ErasePage(uint32_t Page_Address);4. 半字写入9 t+ d( ^/ Q! d* `
FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);上面这4个函数就是我们最常用的。下面说一下数据写入的步骤,第一步:解锁第二步:判断写入的数据是否被擦除过,也就是判断写入的地址内存放的是不是0xFFFF 这里要重点说一下,为什么要判断是不是0xFFFF而不是判断是不是0xFF呢?因为我们每次写入数据都要写入半字,也就是两个字节的数据才行,而且写入的地址只能是2的整数倍,不能是奇数。这里大家注意一下。第三步:写入数据 STM32F103C8T6只能按照半字的方式进行数据写入,写入前的数据必须是0XFFFF,因为FLASH数据写入,只能写0,不能写1,这也就是为什么我们要先确保写入前的数据是被擦除了的原因。第四步:上锁第五步:验证写入是否正确其实第五步可以省略。我们看看官方给的写入过
1 q6 G1 u. x2 g9 e
* C [. D, B# W: k* o1 q好了,其实是一样的。& O/ Q( s9 j" L- w7 t; B7 S
下面我就和大家来分享一下(百分之九十九参考的正点原子的例程)
 - //不检查的写入1 G( s3 O2 y0 q+ W6 q% H' b( c9 c. ?
- " W+ z# B8 _8 P j7 F& K ]. K
- //WriteAddr:起始地址9 v' u' ]' ^2 E( ~
- $ i g" ?; m7 [: _
- //pBuffer:数据指针
U8 ]& s+ p) A" _& P5 X' W) l( l -
( m2 q3 W1 a1 ]& x - //NumToWrite:半字(16位)数
, {1 e, [3 N/ c; C- d - ' o" W2 p9 j& ^ \6 H5 i
- void STMFLASH_Write_NoCheck(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite) / l7 Q. {- c4 O F/ x. s; |
-
7 T. X v) ]+ h5 u+ s/ i - {
! D) Q% J0 s/ U3 V% X - 4 ~8 B& A2 l, @! S
- u16 i;! Q5 P/ `9 q8 ^- v# x
-
; }6 f- \. w/ X% q& c1 _, T' u - for(i=0;i<NumToWrite;i++)
) N' B/ H% y8 l - ( I; Y' Q$ {4 X% Q: u, e9 Y
- {1 C" c9 j4 R8 ?! O7 ?
-
' R5 }+ }# @5 v( F* L - FLASH_ProgramHalfWord(WriteAddr,pBuffer);; j8 C* H$ y v$ n
-
/ U3 ^- Q1 z& v: j, K, W - WriteAddr+=2;//地址增加2.& [+ z( r0 {+ o- Q, g1 T
- 0 L- A) X* L `- K7 R) E" q
- } ' {/ G, K: }# i& e
- w5 w- v" ~* o y6 e7 N+ i
- }
复制代码- //从指定地址开始写入指定长度的数据
3 j& G$ M( M" H" e5 q; P - : k2 ]- y4 Y3 p- y1 U, C2 Z
- //WriteAddr:起始地址(此地址必须为2的倍数!!)
o* h% o7 H3 T' N0 ] - * c$ S8 c; b# y4 A% g
- //pBuffer:数据指针
' j/ n& Q( I' P* N1 o5 f6 ?* T - 0 A7 J. z4 O# }1 V+ E: D: k
- //NumToWrite:半字(16位)数(就是要写入的16位数据的个数.)
6 m$ y b8 B1 G f6 W - ) f p3 E& L$ p9 W5 L2 A- |
-
( ~" a# s, C5 C/ Q* S, I" G; F -
0 e; Z8 t2 q \ - u16 STMFLASH_BUF[STM_SECTOR_SIZE/2];//最多是2K字节: ?4 T2 `/ c6 h
- # h& d1 f- q' r" w. O
- void STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)
1 C% Y$ k7 l$ K' [ -
3 \- M" ]2 t- Z, ^- z - {
+ B/ `$ ~/ a# S4 m - 2 v k1 m6 K+ H# ^' u. P9 U
- u32 secpos; //扇区地址1 T8 f; p9 r. V$ V7 G$ {
- / z% x' c( Y% f. H. r; `) w& i
- u16 secoff; //扇区内偏移地址(16位字计算)8 o- X6 q+ o* V9 ?
-
5 j& j; _2 r* p; k: M6 r: s* ]) c% f - u16 secremain; //扇区内剩余地址(16位字计算)
! v; R0 F, t3 ~* P - X E; R/ C5 C- g
- u16 i;
! g/ X4 R! y% D; X -
7 i/ o- H! S9 ~- l. s( v' E - u32 offaddr; //去掉0X08000000后的地址$ }* R$ p/ u, l: {! k% u+ R
- & S$ Y) a2 R2 q% A
- if(WriteAddr<STM32_FLASH_BASE||(WriteAddr>=(STM32_FLASH_BASE+1024*STM32_FLASH_SIZE)))return;//非法地址
, x5 M$ Y6 [8 L( T0 k0 s - ! }( X8 p; o) [7 W' R! E& J- S
- FLASH_Unlock(); //解锁4 M% |8 N4 f" j& v" o/ T
-
& f1 F4 E/ q, u7 @3 U2 w - offaddr=WriteAddr-STM32_FLASH_BASE; //实际偏移地址.3 i1 q; n5 N, d2 b
-
% e' j, n( E: P: l - secpos=offaddr/STM_SECTOR_SIZE; //扇区地址 0~127 for STM32F103RBT6
8 A' J0 f7 ]0 x9 L( { - 8 \7 o2 q7 s/ ~' g
- secoff=(offaddr%STM_SECTOR_SIZE)/2; //在扇区内的偏移(2个字节为基本单位.)( y/ \+ B3 s9 M( V6 h; q, R* y" A
- 2 j9 V2 k6 R5 ~+ X
- secremain=STM_SECTOR_SIZE/2-secoff; //扇区剩余空间大小
t8 }# r8 F- q$ J -
- b) F6 }, d+ ^1 Q% Z: k: N. L - if(NumToWrite<=secremain)
7 p& S6 u6 ? Z& \" c6 H - 7 v; Y) i1 u: @* u
- {
; I. L' D. t' {8 E4 v& G, X/ T -
" s4 c2 a! O/ m4 _ - secremain=NumToWrite;//不大于该扇区范围
' x4 g- @% m5 K5 R6 s k( b& s -
# M/ ]! p3 f) J& D- M - }
6 G6 A$ { J2 K% I A! q, }) b - ' N& x1 D' W( o; c
- while(1) ' Z$ G5 [% E& }9 ]0 V; c9 G
-
/ w! j: B) R/ N* O; J - { " Q. w, U) {5 I% J
- 1 c5 j' B, F" c& q8 C! y1 D: M4 V" M
- STMFLASH_Read(((secpos*STM_SECTOR_SIZE)+STM32_FLASH_BASE),STMFLASH_BUF,STM_SECTOR_SIZE/2);//读出整个扇区的内容
8 w( g5 M9 t% V. M -
* ]0 Z" \; [) i+ T- ]8 o0 S* Y - for(i=0;i<secremain;i++)//校验数据
, p5 H5 z. W- z" q* v - 5 z# H3 \7 G+ [9 ^0 \2 N2 A
- // for(i=0;i<(STM_SECTOR_SIZE/2);i++)//校验数据
# F" Z8 I" g8 {% j& ]% B - ?4 W) r1 ?( [ [+ |* ^
- {
5 u% D% @% y7 \8 Z9 n# I, Z -
' O0 [% \. W4 ] - if(STMFLASH_BUF[secoff+i]!=0XFFFF)break;//需要擦除
/ o2 s+ W I/ A" d - 6 ^2 `1 c& q1 X' J: R; ]
- // if(STMFLASH_BUF!=0XFFFF)break;//需要擦除
; i1 K5 }# N# K6 v - : z3 Y( {; h# m% @ ?* R- M
- }
$ H, b+ B' G/ `9 s# @0 g - ( s4 B# W6 }: }" }5 @1 D9 y7 K/ G
- FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
9 ]0 S# o& J$ M0 e! L! v -
. r$ m+ b# h$ O. @) U+ |) e - if(i<secremain)//需要擦除
! k: H4 Z2 @+ |# `6 E. s* v; h% B% F! G - / E1 B; l4 n' U1 f" L
- // if(i<(STM_SECTOR_SIZE/2))//需要擦除2 @; r9 C, X: g- a
-
& H- e' \# l% C6 Z" V - {" ^2 O5 F- S4 }/ F4 f4 n2 `4 o
-
: U0 q) `/ ?+ C2 c& w+ u' M2 { - FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
U' I m* a8 a - 4 s' Q& v; _# b) x- ?
- - Z4 C# f9 L6 p
-
% u0 j0 r* k$ t# z - FLASH_ErasePage(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE);//擦除这个扇区; w0 q! X* f) ~; A2 G3 @
-
* R, Z d! n5 @ - for(i=0;i<secremain;i++)//复制
" x4 u8 V" v9 g' k: z -
/ p9 K7 k7 V0 ?! s8 q+ \6 z8 A - {! k: G! X' p( W( `- y5 y. R
-
2 g9 |) B' D% ^ - STMFLASH_BUF[i+secoff]=pBuffer; ; ]1 V& Y. U9 B( p' e4 U; w9 k
- & k Z2 }1 W4 Q
- }1 @- u0 w" F$ @* \. I
-
$ M, c( s" s3 j# h3 K. V - STMFLASH_Write_NoCheck(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//写入整个扇区
& R7 `! J6 Y* o! b' p2 G1 X0 t# k - - g. K) N0 L2 x: |7 \. B1 T
- }else STMFLASH_Write_NoCheck(WriteAddr,pBuffer,secremain);//写已经擦除了的,直接写入扇区剩余区间.
/ U1 n; a: o9 {8 n -
- P% H- L+ Y7 W - if(NumToWrite==secremain)break;//写入结束了% ^- W' N5 I! p+ a8 s( c8 y
-
; q2 A8 ?: O: k- D t8 l - else//写入未结束
- L q6 K: [0 ^& u8 W -
+ j/ L8 ~# u$ l8 x" R) b7 C$ y2 l - {
3 f7 ~8 N- i9 d1 z) j4 _7 } -
# ~; `. l H8 ` - secpos++; //扇区地址增1
3 |% @2 w" d0 w9 w -
2 L, R. e+ k6 f0 D, i8 F - secoff=0; //偏移位置为0 / J9 p; g0 G$ S" {# Q. f
- ( u3 m9 _, O3 g/ S4 E2 @$ F
- pBuffer+=secremain; //指针偏移
. F5 W- j, C7 T1 X+ ]& l$ N9 u - ( | Y: V. G% ~# d- [ g$ b- X
- WriteAddr+=(secremain*2); //写地址偏移
J& C" L6 ~; v: o% m; _ -
) P/ R; y& f( b) s3 j - NumToWrite-=secremain; //字节(16位)数递减
2 P: n6 w/ ^! z( k1 _ - , X8 k" S& t5 a% k- {
- if(NumToWrite>(STM_SECTOR_SIZE/2))" f; D7 B; R* ?( C! D
-
! B7 P7 a0 i' H - {7 \+ @; O. o, r) G7 [8 h) p
-
4 `7 ?6 z8 Q3 M7 y; g - secremain=STM_SECTOR_SIZE/2;//下一个扇区还是写不完
2 Z8 x% P" ?# k6 _; y/ ]' O2 Y5 O/ A -
, }* |( J& d& m! R - }8 [- z E6 v9 q$ Z# k$ h
- 1 K4 `, K1 |1 L8 A
- else 2 d& y$ ~" A/ }) w6 ~0 L
-
" ~7 S. x( G0 h) {( u5 V - { 5 ~/ u# {9 S2 F, _) d& _
-
4 |! x! w" m9 E1 u3 [ - secremain=NumToWrite;//下一个扇区可以写完了
" y: n8 o9 e T- x: i! r -
9 n: _0 V" U3 K - }
9 j' r5 ? ~ n7 H9 V5 T5 P -
2 `* m2 ]0 l9 Y2 u7 } - } ! R, y4 e8 o2 {# X0 ?" p
-
+ |( K2 E( K/ e4 E8 N2 Q9 H - } 4 Y) V/ s Q* f8 O
-
; ?7 j; j5 H5 a3 j - FLASH_Lock();//上锁5 \. F5 G: B3 B5 `7 C- R. Q& i
-
# G- Y% V9 u( d - }% M& U7 p( I) {1 K+ q
-
复制代码 L E. v2 R# K: `
5 ^& W/ @0 U9 w) h& F4 w最终我们调用STMFLASH_Write()函数进行数据的写入,是不是有没看懂的小伙伴,我给大家解释一下写入的过程吧
% i1 a; R( }) i4 c, e& m- _4 y; _* P! B) W7 b/ `/ j8 U0 p
这个STMFLASH_Write()函数,是说给定一个写入的地址、数据和写入的个数,然后按照给定的地址开始写数据,注意红色字体。1 a' y3 H9 }' ?$ }0 b7 G
写数据是怎么做的呢
7 {( M2 d4 A5 ^' M/ c9 F首先是整理一下写入的页地址和需要写入多少页,每一页写入的话起始地址是什么3 P* ^: z. z# l& m$ n
然后开始一页一页的写,当遇到跨页写入的时候,把第二页的地址写进去,写的个数继续写入就行- i: T2 t# t5 ^" g, y' n/ S0 N+ Y' H
如果还有不明白的可以在下面留言,我给大家解答( y' S1 E p# E: y c
还有一个地方很重要,就是我修改了库函数
7 m) Y7 N1 ], f( f; _& o9 E+ o
0 h" A: E& B+ o- /**
% A. }! u% y {9 W' |9 ^ - * [url=home.php?mod=space&uid=247401]@brief[/url] Programs a half word at a specified address.8 w9 _0 i" F5 b, N
- * [url=home.php?mod=space&uid=536309]@NOTE[/url] This function can be used for all STM32F10x devices.6 b3 ^* a V6 K
- * @param Address: specifies the address to be programmed.$ p& b' g7 _* X# y* Y
- * @param Data: specifies the data to be programmed.
. x: v* Z/ ^5 Q( [1 G# L - * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG,, ~: `4 q& f( X$ d- `
- * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. , M4 M2 b" W5 L: q
- */ j, C) N/ Q- [' W) ^- \" ^
-
; W4 D3 Q# N8 l8 {: [ - FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)1 f7 `0 J' O# Y' D3 e% X
-
% s: W' X1 D( A m9 g, b - {6 g% b8 u* T. J- h- o/ D3 B
- + |) H: I4 h9 J0 `9 m7 H2 M$ J
- FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
' k) q& b8 O, i, w( G+ P - 4 z+ j b9 Q% h! E
- FLASH_Status status = FLASH_COMPLETE; p( v5 k- q Q" k' w1 K
- 9 ] C$ M5 u3 C2 G+ I% H
- /* Check the parameters */- M' S! g& u! p4 g/ s
-
2 V) M' s2 |6 x - assert_param(IS_FLASH_ADDRESS(Address));3 @- n' o; D5 V% x5 H/ @. R( D
- 4 d- T0 F- c; R' a9 V, j8 i: J
- $ f$ \5 {# S# r0 M- ~
-
# o/ n, F; q' n# A - #ifdef STM32F10X_XL7 K- P- S& n, x9 Q* X4 `
-
M& r/ z1 }& ]/ n - /* Wait for last operation to be completed */
5 {# K5 c9 V) W! l T -
$ m. d* M( C6 z# _2 J - status = FLASH_WaitForLastOperation(ProgramTimeout);& @) }9 j; K2 Y9 q
-
! a( J# _; X& l -
2 r1 r0 w. Q3 b# o6 v* U* I -
% @9 B4 r* Y N; S" }& q' E% t - if(Address < FLASH_BANK1_END_ADDRESS). m' X# x! U! z. A3 v
-
2 ]2 s! x# \+ `6 g - {
z* L* k. { G/ O3 ?& D -
7 J5 S, V1 u# d. K7 q - if(status == FLASH_COMPLETE)7 g$ _6 |; s( Y+ }
-
+ x; f7 `+ }& m# U+ c. Q - {
' B% O! H' A, `7 q( K -
) B7 |5 K$ H' { - /* if the previous operation is completed, proceed to program the new data */
7 [+ `0 ]2 N6 _, A$ }" [' W% n -
& ~' q6 [) C# f6 @ - FLASH->CR |= CR_PG_Set;) ?+ L" c2 m% v0 ^4 ?
-
6 j% q" j8 ?6 R. h2 Z! r - 1 u" {5 s5 Y( T Z# `9 F
-
9 |4 `& Z5 _5 S - *(__IO uint16_t*)Address = Data;
2 n. b! H/ T9 b# T, B0 W - 2 ?4 b" G& j$ J: Y% W% H
- /* Wait for last operation to be completed */
+ G i. K' F0 w( l - % J1 ^$ ^7 { j+ q: ]7 i
- status = FLASH_WaitForLastBank1Operation(ProgramTimeout);
( E$ _6 F- M$ w, \* s, F3 O% {3 N -
' d' l# |8 |6 m1 [) P -
+ F4 w! i# X- Y( o: F -
; B1 i0 _# [% h0 _! t2 h4 m! ? - /* Disable the PG Bit *// S& i, P( \5 |/ X' j; M7 s8 w
-
6 \3 v( _( F6 T - FLASH->CR &= CR_PG_Reset;
6 M7 ^% D/ t* i5 O) L2 s3 \ - + g5 ^" L- v+ J9 {# p5 D: @
- }
) c* |0 H1 H- z _7 T! |7 _ - ' A2 P4 g4 O7 B3 Z0 V* _
- }8 _3 V1 _% }# X; A+ ~. o
-
5 m- s) r5 s7 R: n/ T6 _0 z - else! x9 ?: `8 `( m+ n
- , [' l9 a" ~3 y7 ^! _ p
- {: P% l4 g2 ~$ V; v0 H
- 7 _1 B% \1 d. b, F' V
- if(status == FLASH_COMPLETE)$ w0 Q. H3 W1 T o7 s! k- X$ c
-
/ K* Z' ]! G7 _& b8 K# |! z! z - {
# i. ~, n5 x3 E4 V; C u) T6 d -
1 X+ P. h7 q& y0 B - /* if the previous operation is completed, proceed to program the new data */
5 \0 C2 a7 b; h; ?4 A& ` -
- f! x: z7 E& ^+ H8 J: G4 }4 A; [ - FLASH->CR2 |= CR_PG_Set;0 V/ {$ x' a b! f; ?& J
-
6 v( N' R( e$ O3 w' K p' h1 y2 w - 1 k/ ~' V9 c% u6 f# y9 Y6 A# \0 h
-
5 E/ H" H! {* m& ^+ o - *(__IO uint16_t*)Address = Data;$ [8 _7 f# S9 S% J/ b3 V; y* \ w: {
-
7 G7 | P" v! s- r- U - /* Wait for last operation to be completed *// {# H. J" P' P$ u: `8 e. Q1 O
- $ _3 y/ s- {% c: r
- status = FLASH_WaitForLastBank2Operation(ProgramTimeout); W1 O: h* D4 ^4 ^& d5 p
- 0 V0 ^5 M+ K1 S* s* o' A
-
) q( ?" x5 g( V! J' \ - 3 k; _% Y8 v) i2 o9 f2 W) N
- /* Disable the PG Bit */
; S9 L/ o3 A, }2 B -
r2 S8 y3 O. T - FLASH->CR2 &= CR_PG_Reset;4 g2 l' H9 Z9 L$ i/ O4 U
-
3 P$ f4 Q& d& Z+ m - }. l# W6 G s% X6 @* T
- 1 {- \6 m6 w8 ]* U5 z2 B+ t
- }& l2 Z7 t( w& Q: ^& d: F
- " }0 P- b0 _/ D2 S! F2 S
- #else* L" P: {2 `: d3 Y+ O* U- E
- * P5 M- A; Q, v
- /* Wait for last operation to be completed */- N9 {4 F, ?, J8 k% z
- : S# y$ {$ m5 T/ b4 V
- status = FLASH_WaitForLastOperation(ProgramTimeout);
; T& q. d7 L# H7 { - V( b2 e. |5 }. m* ~
-
3 H* }5 U$ M. ?) }$ P -
% a/ [7 [7 t( F/ g - if(status == FLASH_COMPLETE)3 L3 f5 i7 Z9 T' S* E4 a
- / m% y4 P1 s* A
- {
, `: H" d0 m$ g. {- W4 ^ -
6 c7 q" L, K: b) o. x$ ^ - /* if the previous operation is completed, proceed to program the new data */
! X, F2 ~$ _& @ -
8 q8 c/ p7 o+ b* z; P" c% q. ^ - FLASH->CR |= CR_PG_Set;9 o8 T6 @! q* |: m, {: ^- u
-
2 s+ F' ]& O: E - + k7 B9 m7 J( K6 Q
-
+ G3 V- g# R0 N7 z" i - *(__IO uint16_t*)Address = Data;
B0 D. M1 C& ^4 r; v - " ^1 e q( i$ m" A/ i8 @* I* E& n6 Y
- /* Wait for last operation to be completed */
+ l: A1 }) ^! i: ^% z -
+ C, @: M5 V( U% f, S - status = FLASH_WaitForLastOperation(ProgramTimeout);' W! M! |7 x. B* o# `/ ^
-
( \$ P7 q$ S7 n N6 w7 x -
0 ?' A2 _% q2 W$ A -
s; ?& r4 g9 G - /* Disable the PG Bit */; z. Y" \& ~3 V2 c9 }# ]3 \
-
5 l9 S: |2 y. O7 E - FLASH->CR &= CR_PG_Reset;
9 Y3 w U' P5 r4 g$ y -
T) i( S, |% }% g" v# f - }
# Q/ D" p( {; N/ A$ a; A5 L2 V - " T9 \! V! ^" f2 a; _& k. y" t1 V9 r
- #endif /* STM32F10X_XL */
/ l' C7 a. S! c, o$ o1 y - # P9 U/ @" w7 P% B l) N$ Q
-
a& f7 R9 X `% y: k - , {- Z1 E5 d9 k! }+ B/ A
- /* Return the Program Status */
+ q0 P" c4 y1 h5 |9 b - $ c( t+ u& q' T: F
- return status;
' z) T7 Y# o7 ~7 q* z -
3 U' U) a, z0 i, q; s' l$ P - }
复制代码

+ t& @4 t) t* W+ E4 j ?5 o4 T, C2 V H$ P) u& w2 d( F
大家能看出来吗?就是红色字体部分,增加了一个每次写入前清除所有异常状态。
" Q, x! w1 L1 H; y5 Z! d为什么添加这个呢?
5 C6 C3 V, r. N6 }% b3 U因为,如果你写入的数据的地址没有擦除,你就写入的话会导致异常状态的发生,而这个异常状态时要手动清除的,如果你没有清除这个异常状态,而继续写入数据的话,那么你后面写入任何数据都会报错,均写不进去,所以我在这里增加了一个异常状态清除,如果前面写入的数据报错了,不会影响我接下来的数据写入。
' y9 o5 Y# C8 V这里大家就清除为什么了吧。. O8 f8 o8 [ `$ c5 I
写数据会了,那么再说一下读数据,其实这里读数据要比外部flash读取容易的多,我们直接读取地址,返回的就是地址存放的数据,是不是很简单
( P5 i; z- u. ~' v, `9 B, W看下面的函数 
4 z W" X# ~/ N. X/ e' G- , G0 Z2 j1 p( d3 W" X5 n
- //读取指定地址的半字(16位数据)
+ S5 W- |7 r4 u; z# H# D0 s, ?1 X - - M. O, q7 W( b; b1 y1 D- y
- //faddr:读地址(此地址必须为2的倍数!!): a6 O" `% q$ y/ O! E/ z
-
/ n4 s8 t* h; d( m+ Q9 l- O - //返回值:对应数据.
- R& T1 A) p/ H& w -
9 _) _/ u0 z4 _6 J - u16 STMFLASH_ReadHalfWord(u32 faddr)
! m6 |' d% y5 B - % V/ n& c/ T. Z( ~ y# M( m# k2 g1 g
- {" \. D" ?+ _& T! m. n2 e# p& G
- ) _5 ~4 r; X) m
- return *(vu16*)faddr;
+ y2 ~* N" P I9 M8 E; |! ~ - % C" V1 @% @; \0 s' P
- }
: _% w2 O( X5 M' z -
' D }- _; G8 u3 i3 b" f6 V -
+ N; v7 q0 c: D; u! p% o -
' a% m6 }% r2 b, d0 ?7 f$ r ? - //从指定地址开始读出指定长度的数据, l( U+ O1 F7 D' {
-
, a! `4 S/ o0 _2 y. j2 I - //ReadAddr:起始地址
: L& o0 t0 Y* D+ I -
. h8 P6 ?0 T# p% ]5 i8 W - //pBuffer:数据指针5 J9 Z7 ?7 h8 D
-
0 m% ?" n% P8 I" r: X - //NumToWrite:半字(16位)数
v( I7 Q8 N8 a) i. @2 Y7 A -
5 W! Q! i" G K2 A& |- C -
* l4 F, ]9 @6 V+ G" e -
H, @! K6 H! k. v0 ^" ? - void STMFLASH_Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead) ) _! K0 W+ I$ x$ n1 ]' B& B
- . c V8 t8 P9 t h1 S
- {. e' f. q; r/ Q* E% r
- / P/ i2 o5 B- O- ]. P, B8 A9 a1 ]
- u16 i;. p: [7 O8 k/ f- i' N( j
- r3 }/ U, v# y( D
- for(i=0;i<NumToRead;i++)4 q4 r- [' E& `' B( z' `
- ( m: ^0 t" Y/ S, y' m
- {
p. R2 C9 F1 p a7 u2 B - 2 z* m% ^; P! s1 s0 r. I
- pBuffer=STMFLASH_ReadHalfWord(ReadAddr);//读取2个字节.8 A G& \) T/ }
-
' {% A5 M" A& f: l- M - ReadAddr+=2;//偏移2个字节.
( _& d8 k4 s* ^2 Y -
" Q( i* k3 o1 A; z4 ^' d: [) i - }9 U" s6 z# S( R+ G8 c4 ^
-
9 ?3 O$ |2 @( N. C6 i0 C, w+ T - }
* H3 z9 Z; H; m( C -
复制代码
0 w7 A$ a/ V. ~* Z6 o- [3 R+ X有没有很开心,读写数据就是这么简单就完成了。
* {+ {1 _% T' \- ~( @3 O c+ }& A
# _: [& @7 i/ G7 E" D! b---------------------
: f+ {* i( D) @1 m2 w作者:binoo7 $ | S3 p1 ]+ n7 e0 v# v9 @" @0 b
|