你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32 SPI程序示例

[复制链接]
STMCU小助手 发布时间:2022-3-27 17:00
01. SPI简介
9 F% z! [( n+ B/ @" c9 a: \9 mSPI 是英语 Serial Peripheral interface 的缩写,顾名思义就是串行外围设备接口。是 Motorola首先在其 MC68HCXX 系列处理器上定义的。SPI 接口主要应用在 EEPROM,FLASH,实时时钟,AD 转换器,还有数字信号处理器和数字信号解码器之间。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为 PCB 的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议,STM32F4 也有 SPI 接口。
/ P7 Y/ c( z" H& o8 I" l( T- U: Q" J( M# d
02. 功能描述8 `9 w7 p$ w8 U" G
使用 STM32F4 自带的 SPI来实现对外部 FLASH(W25Q128)的读写,并将结果显示在 TFTLCD 模块上。* `; \) D6 z" s/ h1 U# ?& d

2 A6 P; ^' f7 G3 c' D3 C# n' g: T# [03. 硬件模块1 q5 p1 i. U) Y1 t& Z
开机的时候先检测 W25Q128 是否存在,然后在主循环里面检测两个按键,其中 1 个按键(KEY1)用来执行写入 W25Q128 的操作,另外一个按键(KEY0)用来执行读出操作,在 TFTLCD 模块上显示相关信息。同时用 DS0 提示程序正在运行。* C0 f4 _9 B5 A, i
所要用到的硬件资源如下:
0 R7 U5 I& h/ p0 N1 W2 u9 I1) 指示灯 DS0; x9 ^4 N) L$ l3 y/ R8 m
2) KEY_UP 和 KEY1 按键
$ `& F1 C- l! b7 c: c" ]1 M! n6 C3) TFTLCD 模块2 S, @& t2 ^" [8 a$ i
4) SPI8 Z3 k7 a; b- _" E0 w1 R( z
5) W25Q128
! F$ b, y1 `* S3 S  u
* x7 s/ `3 S; r9 p) K! O8 j& p {7_[%D]0MBS3MDCC4{_A@{U.png
0 U! P+ T( T8 e! J$ h5 C; ~' V! j( u0 j5 k, M& V
04. 软件设计
+ v. U( j6 }& {4 ?, {! f* w. lspi.h
1 G5 i4 f" |+ Q
  1. #ifndef __SPI_H8 Z# N! L. x+ p3 d  {( i
  2. #define __SPI_H- _/ w3 J/ S5 k+ g7 U" X
  3. #include "sys.h"
    1 J3 b+ _: q: c* g' L* D+ H7 g
  4.                                                                                                                      
    " a' p" h9 B* w1 L) ~& J# G
  5. void SPI1_Init(void);                         //初始化SPI1口. l; F5 S, K8 N; p$ M9 }2 L5 P
  6. void SPI1_SetSpeed(u8 SpeedSet); //设置SPI1速度   
    % r+ g4 y& W/ O; V
  7. u8 SPI1_ReadWriteByte(u8 TxData);//SPI1总线读写一个字节
    7 c4 c+ i6 u% @  _# g
  8.                  ( _$ @$ ]8 J7 U3 O. G
  9. #endif
复制代码
. {) ]8 ?7 W% b
spi.c
! e6 W9 ]' Z5 `! X- g4 p& b9 n* G/ i$ ^" `- S9 U
  1. #include "spi.h"
    : x. J# `9 K% h/ S
  2. 6 c: D9 j6 }9 c3 j" e2 C
  3. 1 l# X$ K; k1 R+ R) T+ ^4 P; R
  4. //以下是SPI模块的初始化代码,配置成主机模式                                                   4 C4 w1 c3 e% @" l" y- t1 g
  5. //SPI口初始化& C% l6 b. O& M' ]( l/ n" W
  6. //这里针是对SPI1的初始化
    % h2 D) t- [5 s# [( R
  7. void SPI1_Init(void)
      f7 \6 \/ E' P* H+ p
  8. {         
    . b# ~" w7 M/ ^, H: G6 {
  9.   GPIO_InitTypeDef  GPIO_InitStructure;
    ! G& U, H+ ~3 b4 i
  10.   SPI_InitTypeDef  SPI_InitStructure;
    7 H' I3 ^0 s. Z8 S6 T
  11.         
    ' w7 ~* r+ G7 S4 B( W
  12.   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟
    + h9 ^& x6 B# r2 p
  13.   RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);//使能SPI1时钟
    8 B" ~: }' S5 {/ z

  14. % ?' P: ~' O- \$ ^1 M2 v# ~
  15.   //GPIOFB3,4,5初始化设置
    + @; i$ o7 V! N3 p/ k: F
  16.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;//PB3~5复用功能输出        
    + Y2 q5 ^7 I' p4 i& X
  17.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能- H* f! p1 x6 J; d; N. p( T: B2 A) i
  18.   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出* z0 e; H# M) p
  19.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz) D) s& Y4 n, t( K
  20.   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉! `; ~5 T' B/ ^: V; A2 S
  21.   GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
    ' ], @! f5 \* ]6 t
  22.         
    ) r  m2 n6 S& G! e: K
  23.         GPIO_PinAFConfig(GPIOB,GPIO_PinSource3,GPIO_AF_SPI1); //PB3复用为 SPI1$ \3 M2 u# U$ f5 [. I9 f5 p
  24.         GPIO_PinAFConfig(GPIOB,GPIO_PinSource4,GPIO_AF_SPI1); //PB4复用为 SPI16 e! U9 `% d3 g& m4 ?3 M) [$ I7 c
  25.         GPIO_PinAFConfig(GPIOB,GPIO_PinSource5,GPIO_AF_SPI1); //PB5复用为 SPI1
    : q1 U% l$ U8 ?+ U6 F) b3 v% T1 s9 e& l

  26. $ ]$ N$ a( q; T+ Q. K# _% Q
  27.         //这里只针对SPI口初始化
    $ v& z7 K" u. }, ~
  28.         RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,ENABLE);//复位SPI1& u1 R- P; {; B# t4 b& Y5 p( ~
  29.         RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,DISABLE);//停止复位SPI1  i* ]( O: k6 e

  30. 0 R! ~3 g2 T( ]! {+ R" c6 M% i) g/ i
  31.         SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工  ]1 N# L2 O5 t0 U7 k+ S
  32.         SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                //设置SPI工作模式:设置为主SPI
    ) |1 k* a+ Y$ Y/ s" s5 a* [
  33.         SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;                //设置SPI的数据大小:SPI发送接收8位帧结构
    6 t6 v$ y  e  k5 L2 J
  34.         SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;                //串行同步时钟的空闲状态为高电平0 [) N' O% t; e/ o; U
  35.         SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;        //串行同步时钟的第二个跳变沿(上升或下降)数据被采样, J) J; l3 s* D1 p6 m; {
  36.         SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制* Z! _6 J9 j7 v4 l" \6 b9 o# e8 z: \/ V
  37.         SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;                //定义波特率预分频的值:波特率预分频值为2568 l5 u$ x0 E8 _6 a6 U
  38.         SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;        //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始7 w( O% Y9 h' x4 Z0 F, h
  39.         SPI_InitStructure.SPI_CRCPolynomial = 7;        //CRC值计算的多项式) P1 W% b, c4 h. Y" p9 {
  40.         SPI_Init(SPI1, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
    2 ?. ]- y( @6 \1 H# V. z( F! j
  41. / j5 s/ R  N/ }8 _0 I4 Q
  42.         SPI_Cmd(SPI1, ENABLE); //使能SPI外设, A* D- k; Z( r
  43. 2 D) N5 ?. s0 b- ?! I$ G
  44.         SPI1_ReadWriteByte(0xff);//启动传输                 
    . @  U- S  O% t1 h
  45. }   / e' _0 z* ^; r0 d1 t: u
  46. //SPI1速度设置函数
    0 \5 Y2 q5 F- D1 F. b% ^* c" c2 b/ f* ~
  47. //SPI速度=fAPB2/分频系数
    ( p  u( n) d3 c1 b% u
  48. //@ref SPI_BaudRate_Prescaler:SPI_BaudRatePrescaler_2~SPI_BaudRatePrescaler_256  2 ]: j7 v, S+ R
  49. //fAPB2时钟一般为84Mhz:& g. @2 p* Z- B2 v0 ?, F
  50. void SPI1_SetSpeed(u8 SPI_BaudRatePrescaler)3 d, ?% j8 z9 K; }; W7 ?5 j
  51. {
    / v$ m8 g! Z( o2 ]
  52.   assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));//判断有效性8 k' _' Y* B9 a; |- V: \
  53.         SPI1->CR1&=0XFFC7;//位3-5清零,用来设置波特率, d6 W/ S6 [0 M' [( D, q
  54.         SPI1->CR1|=SPI_BaudRatePrescaler;        //设置SPI1速度
    : o* u( J. A/ l5 E: K' X. m5 T7 X
  55.         SPI_Cmd(SPI1,ENABLE); //使能SPI1
    , z- a% H) L0 a6 X  F
  56. } ) u( i* l# l4 G3 A
  57. //SPI1 读写一个字节
      h1 ^( @# B3 V5 q/ [6 C
  58. //TxData:要写入的字节
    + e5 M  E. c9 O1 j. o# Q
  59. //返回值:读取到的字节
    . s- Y1 i5 r" a+ [  P$ J/ k, [5 L. |
  60. u8 SPI1_ReadWriteByte(u8 TxData)4 _2 b, e  d  e& V% D+ M- S
  61. {                                          
    ' S! k6 O- K1 @( I1 }

  62. ( w6 U. v& `& G
  63.   while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET){}//等待发送区空  
    ' \2 @. S& h* Z2 k- {% E# G. ~
  64.         
    3 g2 I3 f7 v+ q, W" u# l
  65.         SPI_I2S_SendData(SPI1, TxData); //通过外设SPIx发送一个byte  数据
    ' _) c; ^! C; @- Q2 I5 P
  66.                
    $ ~5 d4 z; ~4 W; n* g& y
  67.   while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET){} //等待接收完一个byte  
    ) X7 F5 C9 h4 |( J3 n( t0 c
  68. 8 c. A3 m$ V  Q0 y" I
  69.         return SPI_I2S_ReceiveData(SPI1); //返回通过SPIx最近接收的数据        
    4 j: w" v% F5 d* U" U& c0 A
  70.                      ! h- `* R) M4 @" S2 }( b* E
  71. }$ x) A' t0 ^% h% L8 G( y0 K
复制代码

+ f5 H& |$ n. B1 m. m8 `2 ~w25qxx.h; k$ X2 @$ i! l& w
6 u; M; Y) y9 d& D- \- B. a( U$ p
  1. #ifndef __W25QXX_H7 A) \7 b) s* j# I
  2. #define __W25QXX_H                           
    / Y6 C! e( p1 U: _
  3. #include "sys.h"  : t9 N! c$ [# P* E
  4. ) A' B8 P- V3 Q# [8 q2 p1 ^  @
  5. //W25X系列/Q系列芯片列表           
    + L5 i' C3 O" T% O
  6. //W25Q80  ID  0XEF13
    1 M7 E0 I7 y) A  n1 ?
  7. //W25Q16  ID  0XEF14
    ) a9 U! z* L3 v) ]; d
  8. //W25Q32  ID  0XEF15: @/ E7 ?, [. n) Z' G$ Z
  9. //W25Q64  ID  0XEF16        + I% t" q* z8 v
  10. //W25Q128 ID  0XEF17        
    : b2 ^# b2 l( c% \
  11. #define W25Q80         0XEF13         4 g# a$ ^1 E5 g6 h% L
  12. #define W25Q16         0XEF14
    ' N( S9 r! e5 x4 ~/ \* j8 `+ F1 Z
  13. #define W25Q32         0XEF15, P- a4 c/ Q2 G& r* V
  14. #define W25Q64         0XEF16: u3 |0 q# t' K1 x$ Z$ @4 _% @+ e
  15. #define W25Q128        0XEF17
    ' V% I. E: O1 T0 V/ W+ h
  16. 9 F" t  q, H1 F7 n0 Y$ n7 \. K7 V
  17. extern u16 W25QXX_TYPE;                                        //定义W25QXX芯片型号                   5 X9 g, ?# q& Z3 |& C

  18. / @+ S+ _! x& T9 u# e* j9 Y
  19. #define        W25QXX_CS                 PBout(14)                  //W25QXX的片选信号
    3 Y( h9 ^: g- r; C! }. n) W

  20. % q/ X  Y; s, K6 b  u% N
  21. //
    ( D. Y& W4 `$ s8 P$ o
  22. //指令表) Z4 ^, J/ o1 S- F" |, V
  23. #define W25X_WriteEnable                0x06
    0 C* T7 G' P) C: [" L) G
  24. #define W25X_WriteDisable                0x04 3 t. y  g+ Q' o  _) C- q' M
  25. #define W25X_ReadStatusReg                0x05
    ' e. ]8 j7 R" h: B
  26. #define W25X_WriteStatusReg                0x01 % K$ |2 a% z4 q$ `5 |
  27. #define W25X_ReadData                        0x03
    ; f% l7 R* `  Y9 @% B
  28. #define W25X_FastReadData                0x0B - a- T- ?3 G6 s- i$ t2 b$ \9 U2 U* M
  29. #define W25X_FastReadDual                0x3B
    7 f7 g5 F1 R3 p9 F# T8 t
  30. #define W25X_PageProgram                0x02
    ! n" r/ z2 t6 ^/ }7 ~! B, `
  31. #define W25X_BlockErase                        0xD8 ! W. K# Y; |' K( y! E1 v
  32. #define W25X_SectorErase                0x20 , I) C4 a. w6 M% J; r; Q* h# @- x. B
  33. #define W25X_ChipErase                        0xC7 ( V  s4 r' U3 O
  34. #define W25X_PowerDown                        0xB9
    3 `# o4 B. P2 Q" Y, R
  35. #define W25X_ReleasePowerDown        0xAB / v- J4 F  \  p; H5 x, b
  36. #define W25X_DeviceID                        0xAB 8 o$ K/ V; ^  b$ s
  37. #define W25X_ManufactDeviceID        0x90
    % o# t" H6 I- u6 y1 W
  38. #define W25X_JedecDeviceID                0x9F
    7 a5 Y# z+ l- x9 }- c" Y
  39. ! o3 f4 \, w2 A
  40. void W25QXX_Init(void);
    $ D. E5 A+ G* A5 ?; J
  41. u16  W25QXX_ReadID(void);                              //读取FLASH ID
    * _/ Z% f, u$ j* u
  42. u8         W25QXX_ReadSR(void);                        //读取状态寄存器 ) a+ `: _4 c* a& b8 Y# T
  43. void W25QXX_Write_SR(u8 sr);                          //写状态寄存器0 Z# J. N) y8 ^/ V
  44. void W25QXX_Write_Enable(void);                  //写使能 1 e4 I/ m5 ^; l8 u* @
  45. void W25QXX_Write_Disable(void);                //写保护
    8 j/ r7 u# q! d/ l( a+ z
  46. void W25QXX_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite);+ h% D/ }6 ~! v& X* N
  47. void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead);   //读取flash9 y8 z3 Y9 d4 m
  48. void W25QXX_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite);//写入flash! n2 U8 m  P* z
  49. void W25QXX_Erase_Chip(void);                      //整片擦除
    5 m; b+ c7 V8 [
  50. void W25QXX_Erase_Sector(u32 Dst_Addr);        //扇区擦除3 u& z: r+ n" F
  51. void W25QXX_Wait_Busy(void);                   //等待空闲# r# X$ y8 w( q9 _8 n* s
  52. void W25QXX_PowerDown(void);                //进入掉电模式6 B% M  W( r( u3 F+ d
  53. void W25QXX_WAKEUP(void);                                //唤醒# Q3 t6 z! S, d" f* b4 b& l) R1 x
  54. #endif
复制代码

0 G$ V# g4 ]& d1 L# {w25qxx.c2 P( I- u! x! F9 w+ y. \: C
4 {# Y$ |4 H0 g* `- R: J6 m
  1. #include "w25qxx.h"
    * f: ?) c! T0 |3 K8 P0 X: ]+ p
  2. #include "spi.h"
      @$ M7 N7 W0 w, }0 A9 J
  3. #include "delay.h"           * w" Y) o/ h- I8 E; w
  4. #include "usart.h"        7 N3 |2 {: J& x, V0 D/ b, O. p

  5. " T* n5 y7 }2 k; c4 K
  6. % B: ?& V6 X5 U
  7. u16 W25QXX_TYPE=W25Q128;        //默认是W25Q128
    ; `9 ^  x  I- [; T2 t' l0 p2 H
  8. 3 R8 U# u, a4 A; f4 a
  9. //4Kbytes为一个Sector8 Q; S+ T0 b# p2 D7 x5 p
  10. //16个扇区为1个Block
    ) p( S5 T: Z7 Z
  11. //W25Q1283 ]2 D$ J& p6 l0 p
  12. //容量为16M字节,共有128个Block,4096个Sector
    ; D! R( I% L  J1 T0 S" K' {5 i
  13.                                                                                                          " _% d: U' w) _& R& N" M
  14. //初始化SPI FLASH的IO口
    3 V: m. r9 b- z' B
  15. void W25QXX_Init(void)1 j' [2 z$ L: A; W- }3 y3 J/ `4 F
  16. {
    # ^9 M; p; s' v* H' [, \
  17.   GPIO_InitTypeDef  GPIO_InitStructure;
    5 A8 u4 ^. ?. y+ j" D1 T' }7 H
  18. " i# y" U# X# T% Y) L* n
  19.   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟+ e; M4 ?7 G. C
  20.   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);//使能GPIOG时钟- o( I6 \6 O6 c5 V
  21. % j- X4 E9 H' m( d( H
  22.           //GPIOB142 L; _+ Z6 ^1 U7 g; `! P
  23.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;//PB14& `" Y: a4 s/ k6 T' A. W" f/ g
  24.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//输出! m4 q9 p" k6 {- e8 @, G4 p/ F
  25.   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
    0 v- o$ i# `9 m3 [8 P& Z
  26.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz/ C5 Z" l& h- q7 K7 ~3 |
  27.   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
    + k+ ?' |, M# w# }9 r) N/ Z
  28.   GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化. w. S* t! z$ l( @; z4 n% X
  29. & M0 [! F8 @# |% ^7 d3 ~8 W
  30.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;//PG7
    + l; d, C' i6 i& C, k( z* l
  31.   GPIO_Init(GPIOG, &GPIO_InitStructure);//初始化
    8 a( ~! S6 U+ ~9 }

  32. * i9 Q; I( f! U. d6 C8 M( L
  33.         GPIO_SetBits(GPIOG,GPIO_Pin_7);//PG7输出1,防止NRF干扰SPI FLASH的通信
    & ^! i, f8 C3 q8 u
  34.         W25QXX_CS=1;                        //SPI FLASH不选中4 ~! t. t3 _3 e. _5 J* H6 i
  35.         SPI1_Init();                                           //初始化SPI
    ! ^8 M) c! u$ h4 E: b. x
  36.         SPI1_SetSpeed(SPI_BaudRatePrescaler_4);                //设置为21M时钟,高速模式 . ^4 v( `) i' X$ X2 ~
  37.         W25QXX_TYPE=W25QXX_ReadID();        //读取FLASH ID.
    + z/ y6 ^/ v1 |2 ?8 A; r
  38. }  
    7 x8 Z% Z2 ]( m1 Z3 M% v- J( h
  39. $ m- A: Y& b( Y- g; D
  40. //读取W25QXX的状态寄存器) R, U# o2 V( b  ~3 l* o" L' W
  41. //BIT7  6   5   4   3   2   1   05 P0 x9 B% ]& A# _7 k2 |- B; B
  42. //SPR   RV  TB BP2 BP1 BP0 WEL BUSY+ Y( Y1 d5 h( l0 |1 R  n6 ~( l) A
  43. //SPR:默认0,状态寄存器保护位,配合WP使用
    " O2 s' `  _. }5 Y4 h) ~
  44. //TB,BP2,BP1,BP0:FLASH区域写保护设置: M+ s% K. |1 \$ ^$ t8 v
  45. //WEL:写使能锁定5 W' @! {/ J5 y/ |" E9 U# q: |  o/ X/ l
  46. //BUSY:忙标记位(1,忙;0,空闲)/ O. U  W% o$ J) w2 }
  47. //默认:0x008 ?& \  q2 d: d; r* p
  48. u8 W25QXX_ReadSR(void)   
    ; I& W% b( S  [6 q, ^2 E. P
  49. {  : R  T" i& H, D2 i
  50.         u8 byte=0;   
    1 L6 J8 ^7 n9 |  D* P/ P# }
  51.         W25QXX_CS=0;                            //使能器件   
    % G# U; O0 V6 |" f% ~/ P, N
  52.         SPI1_ReadWriteByte(W25X_ReadStatusReg);    //发送读取状态寄存器命令   
    , T0 [  P- E' o9 t" A; M2 j8 H
  53.         byte=SPI1_ReadWriteByte(0Xff);             //读取一个字节  ' _  A0 S, N. L0 [( Y
  54.         W25QXX_CS=1;                            //取消片选     
    % t3 ~2 E! ]0 s: m* k
  55.         return byte;   8 X7 @) i. Y; C& g' r; U, g
  56. } ( H' j& ~, N: m& q- i
  57. //写W25QXX状态寄存器
    : R* E  b- n! f/ q( b8 U
  58. //只有SPR,TB,BP2,BP1,BP0(bit 7,5,4,3,2)可以写!!!  U% I  k% r9 ~2 ~; n
  59. void W25QXX_Write_SR(u8 sr)   ! i' k4 H1 Y: i  ^' j, X- r8 q, u
  60. {   " S6 Y/ ]7 i* F5 ~* k
  61.         W25QXX_CS=0;                            //使能器件   
    2 L' P2 P) @+ m5 F2 V
  62.         SPI1_ReadWriteByte(W25X_WriteStatusReg);   //发送写取状态寄存器命令   
    - X' J. C3 y: [5 R# {/ Z$ G( [) T
  63.         SPI1_ReadWriteByte(sr);               //写入一个字节  6 z, u2 ]$ [7 E- M' J1 X
  64.         W25QXX_CS=1;                            //取消片选                  
    ; Z4 C9 k1 r. n. R; e% y
  65. }   3 S6 _4 Q5 N4 l9 Z2 o. i1 `# e5 C
  66. //W25QXX写使能        . U9 D; a- F& P; |5 L/ s) n
  67. //将WEL置位   
    " z6 B  N: W2 |# [" q
  68. void W25QXX_Write_Enable(void)   $ u9 p3 y% [& L3 W0 ]
  69. {
    4 n1 Z* |" _; ~2 K
  70.         W25QXX_CS=0;                            //使能器件   ( a5 M# _/ ^0 e" F/ J
  71.     SPI1_ReadWriteByte(W25X_WriteEnable);      //发送写使能  
    & ?% ^$ w9 E. h5 q7 s% }
  72.         W25QXX_CS=1;                            //取消片选                   5 O! p1 y  g3 ~% d% |, x7 m
  73. } 7 u3 |: o2 ]4 R
  74. //W25QXX写禁止        , d9 F3 r( ~9 A7 L# E; _: i# \4 s
  75. //将WEL清零  $ e/ @+ ~) Z6 m
  76. void W25QXX_Write_Disable(void)   
    . K5 u% z+ m4 G2 c, ]9 \
  77. {  1 c. K5 J4 l2 O1 x
  78.         W25QXX_CS=0;                            //使能器件   & J: r, b& W% S$ o' z% i  Y8 p  n
  79.     SPI1_ReadWriteByte(W25X_WriteDisable);     //发送写禁止指令   
    : g, Y! k5 Y6 k8 l- Z
  80.         W25QXX_CS=1;                            //取消片选                  
    . D0 d- ~( y; b
  81. }                 0 ]$ ?3 ~) |9 J9 M# C8 T
  82. //读取芯片ID
    # A# [0 \6 y; [# \
  83. //返回值如下:                                   
    ( E6 B/ t1 S4 o
  84. //0XEF13,表示芯片型号为W25Q80    i9 \( R! G' E  z' t! B# Y. k
  85. //0XEF14,表示芯片型号为W25Q16   
    + l% b( X$ W6 x; m) m
  86. //0XEF15,表示芯片型号为W25Q32  + C1 n' x1 F# @# Z
  87. //0XEF16,表示芯片型号为W25Q64 ) {4 s) q+ p0 d2 q
  88. //0XEF17,表示芯片型号为W25Q128           
    / a$ Y3 Z, d; C
  89. u16 W25QXX_ReadID(void)" u+ ?2 L4 B6 Y0 A: j
  90. {- y! ?1 r/ Q8 z( H( k7 U$ p
  91.         u16 Temp = 0;          0 V3 `  O5 c# m# _8 N% t
  92.         W25QXX_CS=0;                                    - ?  Z2 ?3 z) y- h# x3 M
  93.         SPI1_ReadWriteByte(0x90);//发送读取ID命令            7 U/ u# [8 I! H6 `: |! f% D' d3 c
  94.         SPI1_ReadWriteByte(0x00);            
    - C- `+ R' V- M/ T
  95.         SPI1_ReadWriteByte(0x00);            
    , ?! l$ f" f2 E
  96.         SPI1_ReadWriteByte(0x00);                                     4 U: X) f* _9 h& h. `* L
  97.         Temp|=SPI1_ReadWriteByte(0xFF)<<8;  
    . c8 r) K% r8 W4 G  c6 s; ~. M
  98.         Temp|=SPI1_ReadWriteByte(0xFF);         * w( x# Q+ r* g' R/ t6 S1 `2 P$ e! X
  99.         W25QXX_CS=1;                                    $ L4 i# @' ?! s; \4 b- Q
  100.         return Temp;+ r! T4 B/ F) ^1 w
  101. }                       - H3 e7 y. U8 `
  102. //读取SPI FLASH  
    * k2 k) @1 M! ]" g/ L
  103. //在指定地址开始读取指定长度的数据
    9 |6 g1 l6 H! {. \
  104. //pBuffer:数据存储区
    ! I3 s' \1 u* ~% Z7 J
  105. //ReadAddr:开始读取的地址(24bit)
    $ q) N7 P5 \* q5 D7 E, G) S
  106. //NumByteToRead:要读取的字节数(最大65535)
    . T/ [) @" }$ Y& Z( V; `4 \2 l
  107. void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)   2 h$ H% ~5 _/ ~/ z- p
  108. { # m7 K# o" c3 X+ W7 J: m% \0 x
  109.          u16 i;                                                                                       
    ' N' q# p1 L( Y) P
  110.         W25QXX_CS=0;                            //使能器件   
    ) h8 c  a3 \) Q" D1 Y
  111.     SPI1_ReadWriteByte(W25X_ReadData);         //发送读取命令   
    ; s- E% y' i' c" H, w! ^1 u4 `: F
  112.     SPI1_ReadWriteByte((u8)((ReadAddr)>>16));  //发送24bit地址   
    + `; V6 k' W6 H
  113.     SPI1_ReadWriteByte((u8)((ReadAddr)>>8));   
    9 ^' O! v4 a( K8 l
  114.     SPI1_ReadWriteByte((u8)ReadAddr);   
    + w$ g, S# G  J$ A
  115.     for(i=0;i<NumByteToRead;i++)$ N$ K# W: J8 ^* |
  116.         {
    - y+ A1 M1 O0 o2 G. C
  117.         pBuffer=SPI1_ReadWriteByte(0XFF);   //循环读数  + }( |5 r9 Q2 v" L4 j5 W* z
  118.     }
    2 Q( L! [1 g& f* Y  x9 I8 p) E, k
  119.         W25QXX_CS=1;                                                    8 Y: K- C9 J, P6 b4 R' T
  120. }  6 |3 x4 t& }0 |0 Y
  121. //SPI在一页(0~65535)内写入少于256个字节的数据! @9 T) Q" x! {! z
  122. //在指定地址开始写入最大256字节的数据
      @4 y. Z# k4 B  @+ J
  123. //pBuffer:数据存储区0 }. I) w* z# }/ D% |7 `1 C
  124. //WriteAddr:开始写入的地址(24bit)0 ?/ _1 J$ V( V6 @. R: c* ^
  125. //NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!!         # F$ W8 _3 [' e! \
  126. void W25QXX_Write_Page(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)4 I5 o# }. G: N% Q+ n' l% u
  127. {
    , }! @8 M6 j. s2 K! A6 K
  128.          u16 i;  
    ' g2 O6 q8 j$ c+ q+ k7 V
  129.     W25QXX_Write_Enable();                  //SET WEL
    1 x5 E9 C7 D6 F; H" h
  130.         W25QXX_CS=0;                            //使能器件   
    * \9 b: u7 s9 w4 m/ T( t; S
  131.     SPI1_ReadWriteByte(W25X_PageProgram);      //发送写页命令   / A/ K( y1 ~  @+ m9 g
  132.     SPI1_ReadWriteByte((u8)((WriteAddr)>>16)); //发送24bit地址   
    % W2 o; V. q' H' I0 s
  133.     SPI1_ReadWriteByte((u8)((WriteAddr)>>8));   # w" h- t' j+ r: y. h2 m9 _
  134.     SPI1_ReadWriteByte((u8)WriteAddr);   
    2 h( p% |- i6 a/ p' J- {
  135. for(i=0;i<NumByteToWrite;i++)SPI1_ReadWriteByte(pBuffer);//循环写数  ) O5 e% C" X9 r0 k1 a
  136.         W25QXX_CS=1;                            //取消片选
    8 o- r; g: d# @9 |1 K$ H  A
  137.         W25QXX_Wait_Busy();                                           //等待写入结束5 u: j  `" G' U3 m; q- j4 {- I
  138. }
      X9 a7 w8 `  Z: I
  139. //无检验写SPI FLASH 9 A4 W* v+ P4 z0 `6 A" J1 X
  140. //必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!+ }, P4 B) e0 g# X4 z8 H
  141. //具有自动换页功能 6 A7 n+ D/ `3 \( `: G" `& \
  142. //在指定地址开始写入指定长度的数据,但是要确保地址不越界!
    2 r7 `# z- d  _8 R
  143. //pBuffer:数据存储区
    / `8 ?1 S- Q) x9 R4 Q
  144. //WriteAddr:开始写入的地址(24bit)& y! P/ X& @2 l$ K" \$ {
  145. //NumByteToWrite:要写入的字节数(最大65535)
      F! y; L4 H& M: I( j2 J6 `
  146. //CHECK OK
    6 w& a  d- S  v5 p* [! g
  147. void W25QXX_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)   
    ( u* P; K5 X* e$ i; v6 U
  148. {                                           ; \, @8 z! x0 E3 G* }' u0 h; m8 D! d' H
  149.         u16 pageremain;           ! i" V9 v& o- M; n7 p
  150.         pageremain=256-WriteAddr%256; //单页剩余的字节数                             
    2 N# E* u9 p$ n$ m# d
  151.         if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256个字节  K0 j6 Z( d- r3 c
  152.         while(1)
    ! C# J, k7 Y2 k5 |7 I+ |
  153.         {           - n6 T1 h; d; z* S# r0 T
  154.                 W25QXX_Write_Page(pBuffer,WriteAddr,pageremain);
    , D* y2 j3 r: p) c# D) t8 k5 ^/ q
  155.                 if(NumByteToWrite==pageremain)break;//写入结束了
    0 q2 h/ a$ z! N; t1 F; Q% V
  156.                  else //NumByteToWrite>pageremain
    : Y+ q# ~9 N" y6 N. o
  157.                 {* x0 d2 z* Y- X0 |- x
  158.                         pBuffer+=pageremain;
    * ^  p3 Y  Y8 j. p
  159.                         WriteAddr+=pageremain;        
    ! ?' y' k: F8 N

  160. ; Q: W$ |& V+ m% j
  161.                         NumByteToWrite-=pageremain;                          //减去已经写入了的字节数
    / r4 x4 C7 q) D  C9 E
  162.                         if(NumByteToWrite>256)pageremain=256; //一次可以写入256个字节
    $ p1 ~, m3 m5 k6 ~
  163.                         else pageremain=NumByteToWrite;           //不够256个字节了, V& U4 v4 _2 @5 f# p2 U4 X  x6 A
  164.                 }' V' g* @& Z$ o, ]
  165.         };            
    6 B- F1 Q5 Q0 K; i- I3 P" K# J
  166. }
    9 N; A+ u# `9 ^& p8 M
  167. //写SPI FLASH  ; k) W- T) B2 X6 s; I2 I9 p+ r
  168. //在指定地址开始写入指定长度的数据
    * K7 R: s/ M9 ]# @! |; h: C0 [
  169. //该函数带擦除操作!. ^! f3 O, A4 V
  170. //pBuffer:数据存储区
    & p" L6 U0 H2 Y
  171. //WriteAddr:开始写入的地址(24bit)                                                ; {  q& L4 m. [
  172. //NumByteToWrite:要写入的字节数(最大65535)   4 r2 l+ i( ^5 l8 X  G
  173. u8 W25QXX_BUFFER[4096];                 % d6 L3 W, n5 n9 l; h
  174. void W25QXX_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)   
    6 K/ V( W; {5 T( L1 e: v) ~* q
  175. {
    5 g0 f9 u7 v& G1 d6 q
  176.         u32 secpos;, }: o( n3 d, i8 K9 {
  177.         u16 secoff;
    7 D+ }, [0 o: L$ Z! W
  178.         u16 secremain;           
    1 r6 J; ], W$ _
  179.          u16 i;   
      d6 E! ?  R/ \2 J. r
  180.         u8 * W25QXX_BUF;          ; p: p  u# S! S6 k. J9 L. |) p: V
  181.            W25QXX_BUF=W25QXX_BUFFER;             ' F! D2 C! }- i& F% q3 S
  182.          secpos=WriteAddr/4096;//扇区地址  
    ! o1 O& m$ m" [$ y
  183.         secoff=WriteAddr%4096;//在扇区内的偏移. \8 i: O" u- p& ]5 |
  184.         secremain=4096-secoff;//扇区剩余空间大小   - ^' y7 m( s6 c
  185.          //printf("ad:%X,nb:%X\r\n",WriteAddr,NumByteToWrite);//测试用
    6 Q! M3 C. N3 @+ J9 J9 H1 ~
  186.          if(NumByteToWrite<=secremain)secremain=NumByteToWrite;//不大于4096个字节) j% g6 B" I5 }0 p( h, U
  187.         while(1) ' U. B; n  F" d2 @
  188.         {        
    $ d' {2 ~3 P9 j/ G! y$ K* ]
  189.                 W25QXX_Read(W25QXX_BUF,secpos*4096,4096);//读出整个扇区的内容' F3 C' l. ~: o% j( k
  190.                 for(i=0;i<secremain;i++)//校验数据0 [. e2 c$ g% ]' q
  191.                 {
    , y% B9 \: O4 {# X4 [! W
  192.                         if(W25QXX_BUF[secoff+i]!=0XFF)break;//需要擦除            
    1 p8 ]+ a, W) \1 ?. }6 r7 a
  193.                 }. g+ ^$ s, A6 b, u
  194.                 if(i<secremain)//需要擦除
    * F$ n) D. q  P5 ^
  195.                 {: o# ]; c, k' M: d: F7 n0 M
  196.                         W25QXX_Erase_Sector(secpos);//擦除这个扇区
    1 W9 O2 V" r* s% T# X. q. d
  197.                         for(i=0;i<secremain;i++)           //复制' z& c+ d# ]" e# {, s' l6 O
  198.                         {
    9 S0 e! T5 m3 _) U3 w0 p" c) i1 F; N) e  X
  199.                                 W25QXX_BUF[i+secoff]=pBuffer;         
    $ q* _- z. s1 K5 m
  200.                         }
    $ u% A7 F5 }' m+ Y5 |
  201.                         W25QXX_Write_NoCheck(W25QXX_BUF,secpos*4096,4096);//写入整个扇区  ! F% E% h9 C6 a8 x' ?
  202. 3 W  E$ T: p0 J& ?4 i$ q
  203.                 }else W25QXX_Write_NoCheck(pBuffer,WriteAddr,secremain);//写已经擦除了的,直接写入扇区剩余区间.                                    4 L! @+ y" @% W2 \1 {+ p7 B
  204.                 if(NumByteToWrite==secremain)break;//写入结束了* U/ n8 ^6 J* x' |& e7 @
  205.                 else//写入未结束. S# v" J2 {: ~0 T. o
  206.                 {3 Y# ^, t8 [! m/ T% i
  207.                         secpos++;//扇区地址增1
    ' B; h& U) ?- N- F
  208.                         secoff=0;//偏移位置为0         
    ( V# D1 P! s3 p# W1 Q2 E1 I

  209. ' X* g2 X2 O0 E) a  W
  210.                            pBuffer+=secremain;  //指针偏移9 q% D" B  B+ f6 b  B. A+ |
  211.                         WriteAddr+=secremain;//写地址偏移           : h: G, P- q& u+ [; v
  212.                            NumByteToWrite-=secremain;                                //字节数递减
    . m) c/ C7 W" }* v; W" v
  213.                         if(NumByteToWrite>4096)secremain=4096;        //下一个扇区还是写不完
    / ^' Z, o1 G: ^1 i5 x
  214.                         else secremain=NumByteToWrite;                        //下一个扇区可以写完了4 w0 x2 ^/ n4 j, v( d9 [3 l
  215.                 }         3 j+ H8 O- u' ?8 L% x) m, ^
  216.         };         
    2 y' u& N. a" B  b8 w! C* c
  217. }& a8 P6 i1 {" l/ s
  218. //擦除整个芯片                    ~0 b9 y; w3 t7 k, E; e5 T! u
  219. //等待时间超长...) e6 l1 L4 W1 h: R+ ~# E/ Y  l
  220. void W25QXX_Erase_Chip(void)   3 t9 M" R9 M2 }3 H, u6 }
  221. {                                   
    ) Y& j1 f2 I; f' G0 k  u
  222.     W25QXX_Write_Enable();                  //SET WEL 6 U( U8 D5 T9 L  A
  223.     W25QXX_Wait_Busy();   + B0 z) c7 G" G& r+ R/ S
  224.           W25QXX_CS=0;                            //使能器件   
    ) j( U" |  v; _+ k( `+ S
  225.     SPI1_ReadWriteByte(W25X_ChipErase);        //发送片擦除命令  4 i; E( i) s4 S, [6 d8 S
  226.         W25QXX_CS=1;                            //取消片选                   6 G3 v  A% I2 [
  227.         W25QXX_Wait_Busy();                                      //等待芯片擦除结束
    - \, o, ^6 n( e! ?- t
  228. }   
    - H  {+ g) H3 N/ g( D
  229. //擦除一个扇区& P/ r3 d# j. T/ Q6 ]$ b
  230. //Dst_Addr:扇区地址 根据实际容量设置
    4 e8 K1 i" f& m& U# N3 d
  231. //擦除一个山区的最少时间:150ms% m* a1 s8 {/ A6 E8 r. Z
  232. void W25QXX_Erase_Sector(u32 Dst_Addr)   . j* `6 x5 C) h  v# l1 G1 r; T$ j
  233. {  ( g& @1 P% D" ~1 F" q  w# X# v
  234.         //监视falsh擦除情况,测试用   
    1 c/ u0 c7 I# N" b5 m
  235.          printf("fe:%x\r\n",Dst_Addr);          * K5 b# f* q$ K& v( }
  236.          Dst_Addr*=4096;, H) y. \* V# e2 Y. v
  237.     W25QXX_Write_Enable();                  //SET WEL          ) S- K+ f6 p" D$ |& Q2 v9 A1 u
  238.     W25QXX_Wait_Busy();   
      l, X* `4 l3 T# w8 M- @
  239.           W25QXX_CS=0;                            //使能器件   " e$ i( W; J4 B/ g9 W) C5 G( M" B  r
  240.     SPI1_ReadWriteByte(W25X_SectorErase);      //发送扇区擦除指令 0 t: O1 d# j7 @2 x. T: x
  241.     SPI1_ReadWriteByte((u8)((Dst_Addr)>>16));  //发送24bit地址   
    * k/ d6 k5 a* r- }+ }9 Q
  242.     SPI1_ReadWriteByte((u8)((Dst_Addr)>>8));   , n# N; z3 R4 o) U( y
  243.     SPI1_ReadWriteByte((u8)Dst_Addr);  
    9 b& r7 O1 `3 b# ~; c- P" [
  244.         W25QXX_CS=1;                            //取消片选                   + J9 R7 o  x' s
  245.     W25QXX_Wait_Busy();                                      //等待擦除完成+ T$ I% I# V) y/ _" h) t
  246. }  
    4 q* j, U. v% a) `
  247. //等待空闲
    - Y0 q+ B& G3 Z% ]9 @% I
  248. void W25QXX_Wait_Busy(void)   
      i9 v! H# S$ W& l8 J; x( l
  249. {   
    " U! V- m! |+ a  o; d7 \. d
  250.         while((W25QXX_ReadSR()&0x01)==0x01);   // 等待BUSY位清空
    % [) q5 L0 d- {) @; R
  251. }    B, u, j6 e1 G. O$ E0 b! i
  252. //进入掉电模式3 q+ h, t1 u$ Z
  253. void W25QXX_PowerDown(void)   
    3 }  u9 ], r) |
  254. {
    5 X- P) P4 k' L' U) e
  255.           W25QXX_CS=0;                            //使能器件   
    ! M' q* c) `: z% X: f
  256.     SPI1_ReadWriteByte(W25X_PowerDown);        //发送掉电命令  4 W( s) v+ Y  O& G! n# {- l
  257.         W25QXX_CS=1;                            //取消片选                   + P. r; w; @! [& W& F2 l
  258.     delay_us(3);                               //等待TPD  1 I% d; h. ~. j; O0 C" r; e
  259. }   
    , a; S: `/ p3 x, |- L, O
  260. //唤醒
    2 R3 R3 e  H! ]# I4 g" a
  261. void W25QXX_WAKEUP(void)   
      T5 Q* F2 |4 v7 G
  262. {  
    - l4 `2 O2 l" u
  263.           W25QXX_CS=0;                            //使能器件   : j8 Q; i8 i6 ]3 Z" R. F
  264.     SPI1_ReadWriteByte(W25X_ReleasePowerDown);   //  send W25X_PowerDown command 0xAB   
    & o; \5 X2 q5 {, F1 }
  265.         W25QXX_CS=1;                            //取消片选                  
    - p# i/ [- \( f3 G/ X/ a3 u& a
  266.     delay_us(3);                               //等待TRES1* }' y$ o* w6 \) e$ [. V1 s
  267. }   
复制代码
5 D! L. X1 x( r$ P1 r3 z
main.c
4 C5 J) ?4 B0 y1 s: I
+ @# R" }, r% z/ H  [  K% d) j& h) ~
  1. #include "sys.h"' E3 w! y# [/ h9 v$ S- M8 {3 s  u
  2. #include "delay.h") m# q  A+ N' e* ]* h/ N
  3. #include "usart.h"3 X# r( ^3 g& }6 @) g% R
  4. #include "led.h"4 e) A9 R% p' O
  5. #include "lcd.h"$ F. U- K0 e" H1 r; p1 d; ~
  6. #include "spi.h"& h! j6 E3 |0 ]7 J
  7. #include "w25qxx.h"! V* T4 C6 c2 [: F1 N
  8. #include "key.h"  
    8 S0 ]% ~0 U% W* p
  9. % t* m3 o1 c8 S6 J( b
  10. % G" C8 M! H! l  G* @
  11. //要写入到W25Q16的字符串数组: b1 d3 {) E7 `
  12. const u8 TEXT_Buffer[]={"Explorer STM32F4 SPI TEST"};
    9 `$ {, H5 F$ C8 U8 K
  13. #define SIZE sizeof(TEXT_Buffer)         1 D/ j5 w9 w; E2 |& K6 B
  14.         
    9 E9 Z) d( J! t) N
  15. int main(void): {* e; a. J" H8 e( }
  16. {
    8 u* f' I3 ~* Z: ?
  17.         u8 key;
    7 G+ J5 s+ u; S
  18.         u16 i=0;
    3 J7 ^- e5 |$ m) S& r
  19.         u8 datatemp[SIZE];
    , [5 j2 X. }; p4 P
  20.         u32 FLASH_SIZE;. w9 M- f- O& i$ F; K: P
  21.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组27 z; H/ [$ y) v6 k
  22.         delay_init(168);     //初始化延时函数
    4 z7 W" n6 O& a* S+ R: A
  23.         uart_init(115200);        //初始化串口波特率为115200
    3 k+ W3 Y: X$ _8 H
  24.         LED_Init();                                        //初始化LED
      h" y! l/ n; X" M) X
  25.          LCD_Init();                                        //LCD初始化
    # j! H" E* X! F4 a
  26.         KEY_Init();                                 //按键初始化  * B& f% b5 k' Y; W% G) l' Y
  27.         W25QXX_Init();                        //W25QXX初始化
    0 m+ `4 w; D1 S, D- Y* c( x4 T8 B6 ?
  28.          POINT_COLOR=RED; 8 l4 F8 w  }  l0 A6 k# c
  29.         LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");        * @/ f; o3 N9 J/ D. o
  30.         LCD_ShowString(30,70,200,16,16,"SPI TEST");        
    4 W- j' C" |9 j$ O
  31.         LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");4 _7 y. @5 c6 [. W: d& a
  32.         LCD_ShowString(30,110,200,16,16,"2014/5/6");         6 N0 M; C  q9 l# e9 ]
  33.         LCD_ShowString(30,130,200,16,16,"KEY1:Write  KEY0:Read");        //显示提示信息                8 y, X& V4 T" k
  34.         while(W25QXX_ReadID()!=W25Q128)                                                                //检测不到W25Q1284 x! y9 s  ]( \+ J
  35.         {
    3 V: F* V& @! r- E" z+ p
  36.                 LCD_ShowString(30,150,200,16,16,"W25Q128 Check Failed!");
    9 Z$ H  ~8 ^9 `7 w% H9 u0 p! ~
  37.                 delay_ms(500);/ l+ e1 V) w' ?" S& u. H
  38.                 LCD_ShowString(30,150,200,16,16,"Please Check!      ");+ {( q3 c3 k+ J7 Y2 G
  39.                 delay_ms(500);
    ; _) H% u* F/ g" M" W& t
  40.                 LED1=!LED1;                //DS0闪烁
    1 K1 K' q$ h1 `1 L; I/ ]
  41.         }' F$ O- O" z; f& y0 a$ Z$ j7 e
  42.         LCD_ShowString(30,150,200,16,16,"W25Q128 Ready!");
    8 ?* z6 S$ P  Q1 g) ~9 N
  43.         FLASH_SIZE=16*1024*1024;        //FLASH 大小为16字节
    ; H6 O- c: T6 N% B5 V
  44.           POINT_COLOR=BLUE;                        //设置字体为蓝色         
    $ ~6 [3 @! N1 i, S; g9 R+ j
  45.         while(1)
    5 q& y7 @9 \% J; g
  46.         {+ w$ j0 }+ l0 c) I8 x0 q
  47.                 key=Key_Scan();
    ' E+ o1 C2 V" G- b$ z3 S8 J; ]
  48.                 if(key==KEY1_PRESS)//KEY1按下,写入W25Q1285 u% {& t' f. g% F2 S5 u0 v
  49.                 {! b; F& C  z. j0 k
  50.                         LCD_Fill(0,170,239,319,WHITE);//清除半屏    ; b0 _; u! f3 n- Z2 ~) C, t
  51.                          LCD_ShowString(30,170,200,16,16,"Start Write W25Q128....");& P: E: F- l) i; Q
  52.                         W25QXX_Write((u8*)TEXT_Buffer,FLASH_SIZE-100,SIZE);                //从倒数第100个地址处开始,写入SIZE长度的数据
    ( ?; `# r, N2 g% j9 L9 W
  53.                         LCD_ShowString(30,170,200,16,16,"W25Q128 Write Finished!");        //提示传送完成7 O* o9 E+ @: Z6 H; }- s
  54.                 }
      Y! t* `* h( k, _
  55.                 if(key==KEY0_PRESS)//KEY0按下,读取字符串并显示9 E" c9 s% E# O2 s# \
  56.                 {
    9 c; H5 v* ~6 o* A$ P  X. ]
  57.                          LCD_ShowString(30,170,200,16,16,"Start Read W25Q128.... ");
    3 d# Z  R5 j" j& J: E6 F6 w
  58.                         W25QXX_Read(datatemp,FLASH_SIZE-100,SIZE);                                        //从倒数第100个地址处开始,读出SIZE个字节; E2 B& Y1 V& f3 E; y2 w% D
  59.                         LCD_ShowString(30,170,200,16,16,"The Data Readed Is:   ");        //提示传送完成
    9 O; ]/ h( p7 Y
  60.                         LCD_ShowString(30,190,200,16,16,datatemp);                                        //显示读到的字符串
    * P- Y7 Q% e1 B; Q. }, d+ f
  61.                 } * n  W, J: \# b/ U/ E* k% I' w* g
  62.                 i++;  m# Q& ^( k7 v! q; E: z' Z) Z
  63.                 delay_ms(10);  a( U4 L. T+ A& F: R; }+ v2 X
  64.                 if(i==20)% ^7 t2 m. y. Q  A5 H7 R3 k/ I
  65.                 {( G6 Y) W& _: P( h- Z7 i2 U
  66.                         LED1=!LED1;//提示系统正在运行          Q% F& b" u) W2 @5 {
  67.                         i=0;6 Y$ H$ c1 V$ R; e' A) n4 W) w
  68.                 }                  
    " \9 s! g9 X$ N$ ?
  69.         }       7 Q' `% h9 k7 H4 i5 P! B! R
  70. }
复制代码
9 q$ \! ]' x) n) W3 X' @) z
05. 结果验证6 a" B5 O( G. F' l5 [# h
按 KEY1 按键写入数据,然后按 KEY0 读取数据。DS0 的不停闪烁,提示程序在运行。: v9 j- M2 x7 ^! T

4 ?0 b$ d6 t: l3 W# \
* S: W& Q0 T' y( `' G! q
赞 收藏 评论0 发布时间:2022-3-27 17:00

举报

0个回答

所属标签

相似技术帖

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版