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

【实测教程】STM32CubeMX-STM32L4研究串口通信(SPI flash)

[复制链接]
STMCU小助手 发布时间:2023-1-14 18:12
一、开发板平台简介:
& t9 p+ {9 ]6 S1、开发板资源简介3 U4 Q# a. E3 L# _9 u
(1)开发板主芯片型号:STM32L431RCT6
. N1 }* y: Z! C. H+ X* X(2)开发板主芯片封装:LQFP-64_10x10x05P
/ f" g& l" {  C! H0 M7 s(3)开发板主芯片内核:ARM® Cortex®-M4
3 t( M: s$ b* c  Q, a(4)开发板主芯片主频:80MHz4 C3 i. a9 |1 m* n
(5)开发板主芯片Flash大小:256KB: o6 o3 o( k$ [
(6)开发板主芯片RAM大小:64KB
$ R) w9 y5 M( C9 p  z% u0 z (7)其他外设:请参考芯片手册
% r' J0 f( Z$ P6 `# x2 C6 R
& N" @8 i. P$ ~8 y1 {8 s2 W5 T# Q7 C
bb91345227434ee7a43a34bf3fe366e6.png   O, x- d1 u. E) m6 X3 f

& q! u5 L' A- ^& U. [; [8 T
929c0cce04aa4115a8623703982bf3e1.png
5 L6 O5 B0 B( X1 l. n8 t6 W! I
2 L; X6 ^3 _' ]2、串口简介
3 b' ?( b* m: X9 Y2 e3 o
         串口全称为串行通讯接口,即数据在通信线上一次传输一位,按先后一定顺序传输。我们通常所说的单片机串口准确来说应该是串行异步收发传输器(Universal Asynchronous Receiver/Transmitter,UART),使用TTL电平,串口需要RXD、TXD、GND三根线进行通信。
& A& E" k) G2 c6 N& c) W+ a5 J        (1)我们选用的STM32L431RCT6开发板串口1已通过USB转TLL串口芯片CH340G引出,使用时,只需要用公对公USB线连接电脑即可(注意也得需要安装CH340G驱动),后期验证试验也试验该串口1进行。
5 h* C4 [1 O( w0 O        (2)开发板上的其他串口已通过排针引出,为TTL电平,通信的时候需要注意选择对应的电平模块,如USB转TTL串口模块等。, V1 `( ?& p' k" F

7 ^# M1 T: [/ W+ K. i0 Q  二、新建工程+ s  Z' |" D$ P; v* }
1、新建STM32CubeMX基础工程

/ J; `) Q- o2 W, y; f5 O(1)打开STM32CubeMX,点击“File”-->"New Project"
' f7 X% x/ |3 m; e/ [7 E/ }2 w+ l* Q: V' h( W& z
2399170347904e959c855fefd5877f84.png * L5 U3 ?5 m, Q" N; n7 ^

7 _' Y% H8 ?4 C( n' L7 z(2)等待打开主芯片选项界面(大约1分钟时间)。
& Y! T. K  E3 c% z
( ?0 u% E- g6 ^: x* r  m: l
d74d2fdc60c9440483e2b7cf8d928e7f.png , v% i2 ]( \1 m
+ H. i9 z0 x% C5 I4 m
(3)昨天搜索框中输入(或选择)所需的主芯片型号(因为我们用的是STM32L431RCT6开发板,所以此处现在STM32L431RC),然后在右下角选择STM32L431RCTx(因为开发板主芯片是STM32L431RCT6),左键双击即可打开新建的项目。9 h. }& `" m4 j: C

! @$ ~& f. m/ d6 p% j3 ?
7b80345238d74bea82ce70e1a348f7b4.png ; m9 ]/ @) L% B2 T
. m) R1 L* _' q8 o5 W1 E/ O7 S4 t
9 G* U! O2 {$ _( j- B% m3 R
(4)选择时钟源。8 _1 ^- {4 y% ]/ ~/ ]
(1)因为开发板上有8M外部时钟,此处选择外部高速时钟(HSE)。4 l% R: `3 i# S7 Q: R8 [! L
(2)因为我们没有用到外部低速时钟(LSE),此处不做处理。
4 b3 Y. i+ c, B  d& A( {7 V+ T, g% t8 n
72119b971f62410fa8344f7f9fb9f389.png
) n* t# ~: g/ U$ L) n, }
( D# X, a3 p4 Z+ g: \7 t2、配置GPIO控制LED
% x# \+ T; O+ B6 O4 |) i备注:LED灯用来指示系统是否正常工作。' q6 g2 j  G, P( c) o9 L' Z
(1)查STM32L431RCT6开发板原理图得LED1控制引脚为PC0,则配置GPIO的引脚PC0。2 S/ Y" z( b+ `/ \# {( F
鼠标左键点击PC0,选择“GPIO_Output”,表示设置该引脚为输出模式。; [. i2 H, y6 }9 G% T& f
$ l  D8 _7 H: n  a
492907c1e71149819adbaee4516a2af4.png
/ ^; b/ |' N7 R: P, I2 H4 d0 h4 z
) E4 x2 w& [4 N
(2)根据自己的需求配置GPIO的参数,如输出方式、输出频率、上拉下拉等。因为GPIO控制LED的要求比较低,此处采用默认参数即可,不用修改。
3 h* ]  s/ ~0 X- u2 x; I8 v! p7 r- I
38ff4b80e1c5495ba3076a5158fd91fa.png
2 g/ ~* |9 |' k* k9 ]8 T/ Z- ?

8 r8 W! Q& E+ V, g3、设置串口1参数$ K+ l, M% d+ S1 R4 b0 K8 s. ]
1、查原理图得知,串口0使用STM32L431RCT6引脚为PA9-USART1_TX,PA10-USART1_RX,引脚设置如下:
# ^5 f( E& A: F
: M/ d, u- B6 F" h+ `2 {2 X( O
497b8ee0243e446784e64a3c31e8a26f.png
1 c& F1 L. d* Q7 y: v( H! \" i0 ~3 q" H6 P8 e$ J
(1)序号1用来设置串口收发引脚的选择。2 Q! ]; a5 V$ c* o
(2)序号2-3-4-5-6设置串口参数,如波特率115200、8位、NONE无奇偶校验等。
# B/ o; |. m( S* X7 |, I4 l" `  J' h! M) k3 {: z
4、配置SPI Flash接口
+ `3 E: t: ~: |8 A  |  t5 p(1)查看STM32L431RCT6开发板原理图得知,芯片原理图如下:6 a/ p2 t: @) D9 C/ p9 m* z. Y
4 d1 y5 c6 K6 m, l
11aaba64f3d34f9ea1e4cbbfc0fdc102.png
) }) k. f6 E$ L2 O3 o! P" U' ~0 ^1 j: A2 A* j
(2)SPI Flash接口对应芯片的PB12、 PB13、 PB14  PB15,芯片引脚配置如下:
8 W+ w- m+ q2 ]. ?% O4 O8 kPB12:SPI2_NSS,此处设置普通输出IO即可。不能配置成NSS。, R/ [! ], ^. f# j
PB13:SPI2_SCK
" R4 E' `  S. z$ X/ iPB14:SPI2_MISO9 G7 B* E9 B; y% |- B- w3 y7 H
PB15:SPI_MOSI- d+ x' d" `- d, K2 I3 @
. @0 C: R# b; [0 M
ade62d1658174af99a93e3928b62849c.png
" a/ ^' R) Q5 c
6 [% H- ~: F  q7 h% [
(3)设置SPI引脚参数,并选择 Full-Duplex Master 全双工主模式,此处不开启 NSS 即不使用硬件片选信号。/ K  o( q" E) v; _% D8 v& r

- t& x4 c( A/ V
c932367c299e46979e55a3e1a05d2c7e.png
* Z, a+ ]2 ?" Q0 v5 ~, {/ U" m) l7 N3 X; |! c9 S
(4)设置SPI基础参数以及时钟。
( |% ?' d! H8 Q! H3 X/ G) d+ s- ]0 Z, J* k0 |3 k# q
e5af1c8c0b0b4ac9a07d740b955028c0.png + v6 l) [5 L1 N# j8 m5 \
4 ]9 U+ e: P; I1 L. F" l
dcc8d73ddcbe4082a09165905ac71cf1.png
' V, R! Q. k8 O4 i0 J4 R! ^5 ~) @; }. j" a# G
4、配置项目工程参数
+ g- f! ~3 X$ N2 Q4 {# ]1 u(1)配置时钟树,用于系统内部时钟,以及各个外设时钟等。此处选择外部8M晶振作为主时钟频率,内部最大倍频80MHz。0 m+ m1 f5 h( p/ Q) b" l& a6 K
+ I+ z1 P  a. p5 J
7818db74b3594231bb1923c5425155c1.png
1 z) a/ N& y/ Q( i8 _
# F) f5 j1 Q4 o: ?. `0 g" h% R(2)完成配置工程。
" c7 Y8 Q2 W! R) r8 i5 M备注:需要注意代码生成过程中的继承关系,如图所示:需要保留开发者自己编写的代码时,请根据配置设置,不然生成代码后会删除自己编写的代码(从这个方面也可以看出开发者备份自己的代码是多么的重要。)
2 v1 h. }5 o& f/ L, o. q% K
& a8 F9 W$ r( d) z7 `9 _
efdb616174f54925b6eac31109f227b5.png
. s" k2 f, _1 I& T1 M" J" @9 M) [( O
2 m8 m' A$ J, T. c5 }; ]
41c3f2716e4e4eda8f62fa3a1d871322.png
  H1 ^# ?/ n6 J& p* Y) Q6 Y

; H9 G! A2 r2 V. M(3)生成代码。
4 ?1 F9 O  O8 W7 u7 ]
) o; H- t3 B+ E3 V% z
8eaa7d0babea40ee93f158481a6ee471.png 8 K" D& y! ^$ z9 a1 v' `* w  L
$ ]5 D' {) y# k( n% E" @
三、在KEIL 5中编写代码8 S" B4 M! E/ u( _) f
1、使用KEIL 5(MDK)打开项目工程文件

! r/ t; x8 I  c1 `(1)找到刚才新建工程的存储路径,安装项目名称,打开项目工程。/ l* i1 A. @* ^
1 i( F6 e& d' f! E8 D5 h, n
089f22b1faf8419f8f1fb3830cea3e8b.png
  l2 y2 A& _" P# K; R0 Q7 R) E% Y
- k! B, u8 E' T2 H' F2 C" F0 R(2)添加每隔500ms,LED1闪烁一次的系统提示,用于提示程序运行正常。
9 Q3 T3 {/ h/ o" ]4 A
+ q; S; Y4 }! o( V0 V
6ab72ceaeb7a41af833842fe5ba6f34d.png
9 e5 \1 n1 ]5 ^7 L) V
1 |; G" Y! M/ y( g2、添加使用printf函数打印log的代码$ k5 B, i! K+ @6 p+ ]! S$ R
(1)在项目选项中勾选Use Micro LIB选项,勾选该项目后,可以正常使用基本的C语言库。
: d( N3 P4 F3 q1 i( u) }2 \4 q  E9 O" p5 _% {) Q
3db54bee7a3e4fb78ecb85f0c26ece57.png
3 A. A+ \7 b. a% A6 F1 }. u4 \; o5 m8 \9 s
(2)printf函数会调用fputs函数,fputs函数为弱定义函数,即使用__weak修饰符修饰的函数,可通过自己编写函数定义覆盖原定义,我们在此处重写fputs函数。在usart.c中添加如下代码。
+ y8 e! S- f8 O7 R备注:开发者自己的代码需要注意添加位置,一定要放置到一对《USER CODE BEGIN和USER CODE END》之间,避免重新生成工程后被覆盖。
. w/ M1 ]! F9 b% \# a1 e& Z
& g7 N4 C* c: J  z
607544c9bb2b4ca995be69d71d763526.png
: F' p$ J2 U: a& ~

4 r5 M) `- U$ |* x, { 代码段如下:可直接复制使用。
! g; `1 i( [1 K# ^) a# x" O
  1. /* USER CODE BEGIN 1 */
    8 c. s0 m2 z2 x3 i4 s' z/ U
  2. ' H+ i8 h% D( r8 N% v+ `
  3. #include <stdio.h>4 ]' D8 e4 m' ^* _' K0 H1 b
  4. #ifdef __GNUC__. e% N7 E6 U2 D, I
  5.         #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)8 t* S9 N7 v5 x$ t8 J& w" `
  6. #else
    ' A# @" l0 x2 g" V
  7.         #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)- B  [4 v/ O& a9 M8 V( a* q& r
  8. #endif
    ; O# R% i8 O. R$ @- A( e
  9. PUTCHAR_PROTOTYPE2 T7 a" ]8 w4 \% J
  10. {
    4 t" K" l5 z9 h3 [
  11.                 HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);* i: Y2 ~4 h+ [, i
  12.                 return ch;
    , v, [/ r  @+ M0 X/ P
  13. }' A2 V* M5 X( c, D% A" F$ _! T2 H  Q

  14. 9 B, F. C, M6 ?" D5 i- x
  15. % p2 Y4 t( a1 T( K7 z, g  _
  16. /* USER CODE END 1 */
复制代码

6 j1 U7 M8 c4 n7 f

+ i6 U, e0 e. B% ^% U(3)使用printf打印log数据。需要注意main.c位置添加"stdio.h"头文件(printf的函数声明头文件)。
) _* m$ i2 q, y% G' P4 u

" O" b+ T. d" d) R1 k0 c
ad684ef90b44425198d2cd6b046d6d5b.png
, D  v9 R9 u- l! G. Y) ]- Y
) y- Z+ ?3 ?0 {
  1. printf("hello world,this is printf function!\r\n");   //printf 打印函数
    2 {+ p5 k+ P! Z( [
复制代码

- a) ]. z/ L3 ]' Z 3、在w25qxx.c文件中添加SPI底层驱动函数3 ^, e+ n. W- h* A% {
  1. #include "main.h"
    : D/ F% J4 Z6 V+ L& @4 \* q& c% g
  2. #include "spi.h"2 E% t" y; q' X
  3. #include "w25qxx.h"6 i' ]/ e4 x( B9 t
  4. /**  ^/ H, W$ u: E- F1 s( T, }# ^5 w
  5.   * @brief SPI1 读一个字节+ s, q) D" X- K" S/ ^
  6.   * @param None
    + X' w" q5 R, P) K  a6 J& l1 u
  7.   * @retval None
    / b/ f1 ~  `# D/ o
  8.   */9 Z4 j+ p! G3 |% }# S4 g2 p
  9. static uint8_t spi2_flash_read_byte(void)
    9 L" F4 y+ [! _$ c4 l! E, x* ^# K
  10. {4 f! |0 M0 d+ ]8 p  H
  11.     uint8_t t_data, r_data;7 i( c6 @) {' q" ]) m$ Q/ ]

  12. % x/ w# D1 G0 [8 I
  13.     if(HAL_SPI_TransmitReceive(&hspi2, &t_data, &r_data, 1, 0xFFFFFF) != HAL_OK)$ z! A, _/ l" e) _: c; O+ r, @/ t
  14.     {
    7 ?# r4 N( H9 d+ p' O+ u
  15.         r_data = 0xff;
    4 I' I3 V( N8 Q' h
  16.     }
    5 i) c! I; R: ?
  17.     return r_data;
    * Z3 b- p* `8 l6 q$ ~5 T
  18. }
    + u5 {' p# M9 `2 H9 D+ v5 c
  19. /**
    3 A: W) z+ S& j
  20.   * @brief SPI1 写一个字节/ f5 y3 \. Q, G( [5 K
  21.   * @param byte 写入的字节
    7 F0 L9 T+ X( Y' s7 a
  22.   * @retval 写状态 0成功 1失败& [* G' d, T; p' m2 S9 k
  23.   */
    $ W% O6 m1 I- a6 A0 H7 q
  24. static uint8_t spi2_flash_send_byte(uint8_t byte)
    0 n. q9 Y% k; F8 s/ O0 S1 u' Y
  25. {( j% y* S' _8 h/ r* P2 m  A
  26.     uint8_t r_data;' k! s, C2 J. N5 ?
  27. + C% T$ J  e. l4 ]9 l8 t' j3 _
  28.     if(HAL_SPI_TransmitReceive(&hspi2, &byte, &r_data, 1, 0xFFFFFF) != HAL_OK)
    ! y1 h0 g( M* @6 K) ^
  29.     {" j2 }, @1 h! y0 w5 d! a
  30.       return 1;
    ! S$ N* D4 L* o3 s$ L4 H
  31.     }
    % X) p8 D3 B! b
  32.     return 0;
    , J1 D2 N& r6 ^5 w6 W) N
  33. }
    " _0 ~9 b* B( o/ m. k- X
  34. /*** U  G1 h, ^' O% F& `3 z+ L9 q
  35.   * @brief FLASH 写使能
    + [+ g  G& m5 M, A* ~9 E" E
  36.   * @param None
    : S$ }$ |3 m3 a! ?
  37.   * @retval None6 p( ~2 Y# a  }) `' w
  38.   */
    ( V8 U. Z9 V  n
  39. static void spi2_flash_write_enable(void). \. U; K, ?7 B3 S! z$ p/ M: T
  40. {
    : D& N. Z  g9 R% e5 M7 z6 \8 t9 v
  41.     SPI_FLASH_CS_LOW();( u6 h; h# E* q4 q& O  H( C
  42.     spi2_flash_send_byte(W25X_WriteEnable);
    7 W4 w9 d* V' y2 r4 f
  43.     SPI_FLASH_CS_HIGH();
    ' v5 r7 e, E9 \' f- G5 e
  44. }
    1 t6 T, C" z" }8 A# w1 U& c) K
  45. /**" F; o6 H  M4 g! P; z. @2 e
  46.   * @brief FLASH 等待写结束% t( T: o  h0 Z. ~
  47.   * @param None
    ) |+ N0 ^, ?+ {5 W% G
  48.   * @retval None$ w; B  D$ A- ^! v& Q. i
  49.   */
    ( q$ S" Z! P$ x% R( L! F( q
  50. static void spi2_flash_wait_for_write_end(void), h4 G4 ~9 S- O8 H: i4 M3 X. ]
  51. {! T3 y7 m6 u8 {7 `& o% \6 ~
  52.   uint8_t state = 0;. `' b6 \- g: V" u; |
  53. , N* h8 e; C6 W$ z1 n
  54.    SPI_FLASH_CS_LOW();
    0 Y! \) \0 G# j0 M5 k+ j# ^& N

  55. & R$ D+ k; R  V/ ~; M% D6 b2 L: M
  56.                 spi2_flash_send_byte(W25X_ReadStatusReg);
    0 }! _2 L. ^2 Y' y
  57. " k2 d0 H) a4 X+ N, t
  58.   do
    5 Z* ?: @( ^. q, A4 p1 [* U) Q
  59.   {7 a" Z! A/ J6 M( @1 s1 v
  60.       state = spi2_flash_read_byte();
    : a9 N  w' R3 d0 H) W6 H: e
  61.   }
    9 V  {: v; l! L
  62.   while((state & 0x01) == SET);
    9 r2 Z& ~0 f4 K+ g/ N( D
  63. ( m5 }$ z$ L) v" Z
  64.   SPI_FLASH_CS_HIGH();
    3 G. f. R3 I% Q& j& A3 C6 P3 S
  65. }
    / P9 ~& B: I# p
  66. /**# ]& b$ f7 y" K0 N" @9 D- f
  67.   * @brief FLASH 读ID
    + n/ N' o0 f: M( }
  68.   * @param None! }, {2 _7 w) H# H" r' d
  69.   * @retval None
    ' I# h( A. J; d# Z" C4 z
  70.   */+ a% m- p! k7 b3 D: N
  71. uint32_t spi_flash_read_ID(void)2 |1 o& O& W2 B0 r
  72. {1 A+ |3 y1 H+ v2 T
  73.   uint32_t temp, temp0, temp1, temp2;' ^! Y% Y2 ^: K5 n9 k* d; ^; j  T

  74. 9 j2 X# ^, q% h9 B, y
  75.   SPI_FLASH_CS_LOW();7 X/ y4 o: V( E- {" M0 i% G8 F1 g
  76.   spi2_flash_send_byte(W25X_JedecDeviceID);
    2 M8 S; q. ]& l( M1 j" w) m

  77. 9 B2 u" Z- {  n8 O: M/ B
  78.   temp0 = spi2_flash_read_byte();5 e, i4 ?* r( m  U% a
  79.   temp1 = spi2_flash_read_byte();
    ( o4 Y/ o: U9 @0 M+ g$ G- i! H
  80.   temp2 = spi2_flash_read_byte();. j3 S+ P2 f9 F, v

  81. 2 L' ^7 O3 x, T6 f6 g6 V3 t1 c, @1 ?
  82.         SPI_FLASH_CS_HIGH();
    : N5 W  e7 K& k, e8 d  w

  83. 2 o" ], \, {/ e& ?5 ]( [
  84.   temp = (temp0 << 16) | (temp1 << 8) | temp2;
    + t% m& X& q" b& `* M' K1 O

  85. + Y4 w% u' t7 c8 ^" W1 L% e
  86.   return temp;
    2 F1 D7 }  A1 E- q4 a
  87. }. w% F; N) ]/ ^1 R" ~: c" l3 d
  88. /**
      u1 B3 m" @, ~. Q5 Q# L
  89.   * @brief 读FLASH5 F1 W! B' n- k) E" }& x
  90.   * @param addr 读flash的起始地址
    : K, b* R7 m) |7 v
  91.   * @param pdata 读到的数据存放起始地址3 b* `. K4 t7 Q( L- ?
  92.   * pdata size 读数据大小
    : E7 g9 r0 A' |  K8 G
  93.   * @retval None
    # }) k# m, K5 o# r0 ~7 {
  94.   */2 T# W' ~# s( x' _" _
  95. void spi2_flash_read(uint32_t addr,uint8_t *pdata, uint16_t size)
    0 g5 \4 ~1 [/ n* v! \
  96. {9 |8 y: u# K) u4 {7 V) D
  97.    SPI_FLASH_CS_LOW();! H! x9 ^1 j; f# _# R; h, P% }
  98. 3 w0 }8 @( b. U/ {1 u1 D# ~* J
  99.   spi2_flash_send_byte(W25X_ReadData);
    & w, F: O( G7 ?# Q' i

  100. ' \4 R3 X5 L: T: u- p# l
  101.   spi2_flash_send_byte((addr & 0xFF0000) >> 16);
    5 m6 s6 g$ ~$ i, J. y  p. M
  102.   spi2_flash_send_byte((addr & 0xFF00) >> 8);' a9 j- ^. ]' x+ k/ e0 |
  103.   spi2_flash_send_byte(addr  & 0xFF);
    9 V, O( ~" }- ~: @6 }7 f' Q
  104. 9 E+ X7 X2 ~& A7 L/ @* z
  105.   while (size--)
    0 @4 u5 G9 O4 b  u; v
  106.   {- ?/ z) ~1 Q; ~. G1 O
  107.     *pdata = spi2_flash_read_byte();
    " Z  n. ~+ V4 N; f; ^* i
  108.     pdata++;5 g; M, c2 _; g9 p. U
  109.   }2 a& j1 _6 z. C. [$ L# _
  110. . P* ]- D$ u8 ^) j- f
  111.         SPI_FLASH_CS_HIGH();
      v" N$ c+ L0 J
  112. }
    4 Q, B9 B  h$ H! g6 r8 `
  113. /**
    + ~# U1 G% u0 Y+ W$ B3 l7 F  T0 E
  114.   * @brief 按页写FLASH0 I* j& ^% T4 s6 @" ^$ _- G
  115.   * @param addr 写入flash的起始地址% t8 W4 u# D# g( y
  116.   * @param pdata 写入数据的起始地址5 ~! {1 K; d4 D3 ^# ^1 g
  117.   * pdata size 写数据大小# G8 A' [4 N0 J9 Y* K5 X8 r
  118.   * @retval None
    ; D  x! u4 d' I0 \' L
  119.   */
    & O) F' ^$ O8 j5 t9 C( Y
  120. void spi2_flash_page_write(uint32_t addr, uint8_t *pdata, uint16_t size)
    1 Q, ~% ~$ h: L  R3 }6 j: U
  121. {
    4 u3 |% ?; r5 N  m% E- `* n
  122.     uint16_t i;
    " ~9 G' X/ _6 n. H& K$ n$ X0 S0 c
  123. $ S& u: i! S7 ~0 I, \
  124.      spi2_flash_write_enable();
    ) @9 o  b& J+ a/ b

  125. * u  _, b1 z0 H8 I  y
  126.      SPI_FLASH_CS_LOW();- Y4 p$ e5 l' F1 D9 e
  127. ' a% h, K5 s! \6 \3 F
  128.     spi2_flash_send_byte(W25X_PageProgram);. R3 ?- ]" {1 {& l4 ]0 ?1 D
  129.     spi2_flash_send_byte((uint8_t)((addr)>>16));/ `5 }+ O4 o/ T" r- O1 c! ~! i
  130.     spi2_flash_send_byte((uint8_t)((addr)>>8));
    , `: u, i% k8 I0 i6 ?+ s
  131.     spi2_flash_send_byte((uint8_t)addr);
    " p; ]0 a4 L& n9 ]
  132. $ v( `; _; k4 P# @9 N7 h0 U* i
  133.     for(i = 0; i < size; i++)
    % A, K' f+ m& x# {/ N2 A
  134.     {: s: A1 Y5 F, {! Z& ^3 D
  135.         spi2_flash_send_byte(pdata[i]);! p  H8 Y+ {5 m( H' Z% o( V
  136.     }( A9 X4 ]5 a& b2 N* c. g) {

  137. 4 L9 O* N  P- e3 u
  138.     SPI_FLASH_CS_HIGH();9 o: I7 _6 h: v! Z3 _- I" ]
  139.     spi2_flash_wait_for_write_end();
    6 H. q0 H" Q# P6 |2 q3 E/ Y" F4 w
  140. }2 W) J' S' S0 S4 x
  141. /**
    : w9 q* }4 Z3 W" S" ?/ d4 P' g' @
  142.   * @brief 写FLASH% S2 i; }/ V; N8 T/ L$ P& Y8 b
  143.   * @param addr 写入flash的起始地址- u2 [# q$ Y) N9 c% ?
  144.   * @param pdata 写入数据的起始地址
    1 D/ S4 m  [6 |
  145.   * pdata size 写数据大小7 J' V: `+ |* V  k% r
  146.   * @retval None  n8 c% i$ ]+ Y, }- {
  147.   */8 J. e5 [2 O9 Z# ~" a9 m
  148. void spi2_flash_write(uint32_t addr, uint8_t *pdata, uint32_t size)6 X/ g+ D/ j! I* t  r5 u! ~% _
  149. {+ l4 D; G) G1 Z, K
  150.     uint32_t page_remain;
    " L) V9 p( t# J/ I( L

  151. 2 K/ }$ |0 Q; U! f7 v7 a
  152.     page_remain = 256 - addr%256;
    & `5 |( T1 j/ w& x3 x! |9 l

  153. $ G$ r$ J/ L* f
  154.     if(size <= page_remain)% h- L) |1 F$ |
  155.     {
    : Z5 _/ o2 x6 P
  156.         page_remain = size;
    + x- X  Y4 @; V& ~: }
  157.     }+ R0 m% v) a  t6 @
  158.     while(1)# B5 g' U4 i# ^/ {. ^
  159.     {6 @/ p  U7 a9 W( _6 W4 T$ @/ a
  160.         spi2_flash_page_write(addr, pdata, page_remain);
    : p4 ~- `/ m+ q9 D' C: F

  161. 6 x& q' M. j$ g. ?! \
  162.         if(size == page_remain)4 h$ K1 v% a& G4 b
  163.             break;+ W/ c# {% J9 [( T1 k( c
  164.          else
    . o, h7 u& M8 ^# {+ j5 v) ^5 D
  165.         {
    ( n6 A. b! _8 ^/ y
  166.              pdata += page_remain;' m- z, x' @/ Y0 T
  167.              addr += page_remain;7 b1 u. a9 a. d) l, }1 M6 C
  168. * e# Y5 U+ H/ u1 R  L0 R
  169.              size -= page_remain;
    : Z6 _' D! |( d
  170.             if(size > 256)" }" h% ]& n* L: |+ E( S
  171.                 page_remain = 256;& M* v. S7 k4 q! M! G
  172.             else
    0 O1 b' }( }' D6 I/ Q# Z7 y: H; D
  173.                 page_remain = size;7 K- R5 c0 L# E5 v
  174.         }% s, U( l; T* `
  175.     }
    $ I3 B- z. d" q$ f, u4 }
  176. }# Y9 r" t4 ]) A* }9 g* z
  177. /**7 t" N  _7 p$ R  R1 {
  178.   * @brief 擦除FLASH扇区
    ( k( \  |4 n' `6 f4 c1 k
  179.   * @param sector_addr 扇区的起始地址3 v8 K, M( ^" N$ b/ Z
  180.   * @retval None
    + `9 |7 X6 r* a2 i
  181.   */0 q$ u0 e; |% B: l# v: {
  182. void spi2_flash_sector_erase(uint32_t sector_addr)
    " ]: s# b% p4 f3 k
  183. {" F. {0 w( ]6 P; u
  184.     spi2_flash_write_enable();
    4 c$ ~- X' Q- }
  185.     spi2_flash_wait_for_write_end();; Z2 r  `. c8 m+ Z2 P/ {
  186. # }/ w( e7 `1 ?+ k: i$ w, J& Q8 E
  187.     SPI_FLASH_CS_LOW();
    # @9 w# B. k; W" ~
  188.     spi2_flash_send_byte(W25X_SectorErase);
    " h  U8 c( S9 j0 T
  189.     spi2_flash_send_byte((sector_addr & 0xFF0000) >> 16);+ l: [7 y' h+ P& ?, C
  190.     spi2_flash_send_byte((sector_addr & 0xFF00) >> 8);8 t! U; \8 n% I; p: P$ [
  191.     spi2_flash_send_byte(sector_addr & 0xFF);; u5 T: T/ b) S  P' Q. F' ?

  192. & C2 r' z: q# J  Z: T9 O
  193.     SPI_FLASH_CS_HIGH();# e9 V3 E3 C* U2 Z) u( B
  194. 2 ^# y# p( G6 `7 C5 U0 V; [  Y
  195.     spi2_flash_wait_for_write_end();
    9 |+ B' ^3 m0 C9 @# B# H
  196. }7 Q9 @. `" o1 s/ p0 b1 z

  197. $ m& `& M2 K4 X7 }
  198. /**
    8 W- u8 b5 c9 L+ m0 O0 x
  199.   * @brief 擦除FLASH块# j3 q+ C0 O" U3 B
  200.   * @param None' w8 t% E: C8 M
  201.   * @retval None
    % W: h1 g0 q1 L' S; _5 p' h
  202.   */% B0 I: O; j# v5 T2 |- I% l8 b
  203. void spi2_flash_block_erase(void)' g% _2 A1 H9 [4 b9 k" I! Y
  204. {2 s! s" t& w' a/ H. A6 a; G
  205.     spi2_flash_write_enable();
    , j1 `3 z6 _: X& i

  206. 4 N0 K, }  g7 f6 f( S% e/ l
  207.     SPI_FLASH_CS_LOW();
    3 e$ W; p6 C  S/ s; V4 {$ h
  208.     spi2_flash_send_byte(W25X_ChipErase);  [, w9 V" v( i* P# }: }
  209.     SPI_FLASH_CS_HIGH();
    $ C* k" I% }+ K- D
  210.   V1 e  h' T- u/ C5 g- r, E: V8 P
  211.     spi2_flash_wait_for_write_end();$ n# l+ m) P7 r  g
  212. }
    ) j$ h9 A: T! S9 Y' _, P* H; i
复制代码

  j( J# f9 e+ u; T. ~
$ A1 ?) |* S+ d) h4、在main.c中添加功能函数
7 o9 Q7 j: i- i2 W
  1. /**6 x/ h9 z6 j4 e' e6 ]2 a$ n  D: _3 b
  2.   * @brief  The application entry point.
    $ o9 O/ `+ ~. c1 K+ ?
  3.   * @retval int
    , _$ X1 E* D: }
  4.   */3 I: v$ \+ {+ V: T
  5. int main(void)+ J4 x" L- e8 E
  6. {
      ^2 G! b1 ]/ z0 ?# O: V
  7.   /* USER CODE BEGIN 1 *// ^/ _, n0 e2 }+ G& K
  8.         uint32_t w25q_chip_id=0;                                                                                        //读取芯片ID) b0 w0 x# \% k. @) B
  9.         uint8_t  onebyte_read[8]={0};                                                                                    //读取的数据0 d- i) g& d1 R: R: _0 S
  10.         uint8_t  onebyte_write[8]={0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80};                                //写入的数据* D% f- j! X+ d( Q" P* H
  11.   /* USER CODE END 1 */
    1 I2 K' ^* G* e
  12.   $ x) x7 F3 v( i( u/ @- k
  13. % M3 O' s( v2 H0 k- g
  14.   /* MCU Configuration--------------------------------------------------------*/& q) \3 q; G/ h6 W  r5 D1 \- a

  15. ) n; g. ^/ V( B5 D* a! D: X
  16.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */0 ]# D7 v" G% S! K; J
  17.   HAL_Init();2 I# h% Q. q9 @
  18. + {9 Z6 E8 `/ F: ~* U
  19.   /* USER CODE BEGIN Init */
    . V9 {, ~5 M1 _- e* T+ n5 x: X
  20. / @2 {3 ]7 d/ z! Q
  21.   /* USER CODE END Init */
    + b% }4 _$ b! f$ C/ i% V9 m
  22. $ }3 `2 i, n4 k0 X/ v
  23.   /* Configure the system clock */
    - M5 G) W" {: t1 H7 l
  24.   SystemClock_Config();
    7 \' J+ ?6 h0 n+ q
  25. 8 ~2 J3 q! d' z
  26.   /* USER CODE BEGIN SysInit */
    ( t4 |. b  B: v4 {4 \3 a$ y7 l

  27. : q7 r" ~6 n2 F* k! P
  28.   /* USER CODE END SysInit */( }/ ~- @" R; }# P2 |
  29.   U( a1 P  W( [+ p: |
  30.   /* Initialize all configured peripherals */
    ) W1 H& K+ a& I* b# D6 D  ?
  31.   MX_GPIO_Init();
      {7 K  Q. x+ c8 e6 J7 M5 y
  32.   MX_DMA_Init();
    ) N2 P8 s5 A* |
  33.   MX_USART1_UART_Init();
    0 g6 ]3 F; `. c) m0 P; H( c# v
  34.   MX_SPI2_Init();
    & \4 S* q) d" H8 g/ i! G
  35.   /* USER CODE BEGIN 2 */, o  H$ F0 T: z. @) r) ^( _
  36.         HAL_GPIO_WritePin(GPIOC,GPIO_PIN_0,GPIO_PIN_SET);                                                                //初始化LED1) C$ J; V6 q) A9 x; a4 e
  37.         w25q_chip_id=spi_flash_read_ID();                                                                                                                                //读取flash芯片ID
    . x( x5 J9 Q3 T: r# x
  38.         HAL_Delay(100);
    . f+ d# H/ l7 ~7 I! A
  39.         printf("hello world,spi_flash_read_ID==0x%0x!\r\n",w25q_chip_id); //printf 芯片ID
    4 o9 s6 B( _7 W, O5 c& K
  40.         spi2_flash_sector_erase(0x0);                                                                                                                                                        //写之前需要先擦除扇区                                                                                                                                       
    2 g! `0 Y$ @; L& V0 C
  41.         spi2_flash_write(0x0,onebyte_write,8);                                                                                                                //写八个字节  J  x8 y4 A" j, h1 q% w/ n4 M
  42.         spi2_flash_read(0x00,onebyte_read,8);                                                                                                                        //读取写入的字节
    % [: V  ~/ b; ]! G4 ^
  43.   /* USER CODE END 2 */6 ~/ W% }) |! ~. v5 N  ?  B4 b) a

  44. * w+ o# z5 p5 @" ?7 w
  45.   /* Infinite loop */, n8 J% e! [& D9 q, u% \$ \$ r
  46.   /* USER CODE BEGIN WHILE */
    0 s: J  m6 c. E1 J4 J  }
  47.   while (1)2 A) p+ h* q3 T4 m% y
  48.   {
      C5 y- n+ D! z/ q7 E
  49.     /* USER CODE END WHILE */: t* _0 }" |7 k) V3 r
  50. ' B2 y! R8 E3 Z3 _0 [
  51.     /* USER CODE BEGIN 3 */; H) U0 e& x/ ?
  52.                                 HAL_Delay(500);
    5 M3 r5 \% i. _% v7 p
  53.                                 HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);                                                                        //每隔500ms闪烁一次LED1. I" i0 e: i/ j6 P" Q" _# v/ H' T
  54.                                 printf("hello world,spi2_flash_read =0x%0x,0x%0x,0x%0x,0x%0x,0x%0x,0x%0x,0x%0x,0x%0x\r\n",onebyte_read[0],onebyte_read[1],onebyte_read[2],onebyte_read[3],onebyte_read[4],onebyte_read[5],onebyte_read[6],onebyte_read[7]);   //printf - P, D4 P7 Z! B0 C
  55.                                 
    6 n4 X+ h4 n. n, F4 |; A4 z# \
  56.   }
    3 l" ~3 q! V7 |6 Z$ `$ m5 b
  57.   /* USER CODE END 3 */
    + y) F3 F/ n6 r$ T  X. k3 L
  58. }
复制代码

! V1 B, z! Z. z' I
* w% J8 x# P1 A1 P 5、设置编程仿真下载模式
" V! R- M8 A- q2 o
(1)选择Options for target ...>>Debug>>J-Link/J-JTRACE Cortex,点击Settings>>选择Port(SW),可以看到搜索成功SW Device,表示芯片可用,可以下载。' F) F% ?, a/ u( D* G- A4 x
. R: e' o1 d: B) ~  ?: c
edefb6b9a2a14be3b1221ad6d5c7a8a2.png 5 j3 n8 C) F# G7 Z& A3 I2 q2 F1 |
1 \: r* [) d; Y# U0 ?
(2)点击Download(或者快捷键F8),即可下载程序。
1 {+ J/ p: N  Z& o! X7 i- S2 j; V" s1 A! i) \: \$ H. w
ba221842d5db40808aa129dd83c593d0.png 4 N  K+ ?: w* Z% K* ?
4 O4 W9 j& I6 R$ G/ N
(3) 如果下载程序后,没有看到LED1灯闪烁,可以按下述方式设置一下(Reset and run表示下载后自动复位和重启运行)。或者重新彻底断电再次上电(或按开发板的Reset按键复位MCU即可)。
, b5 [1 D1 K- }% @" J# O: F
, t% |# K# }3 d
9f8aa1a4e8f04041bcf5cb183facd100.png " `8 j" d+ s* i. |% l
% T% z  H& r* k* r. z2 m
6、查看串口printf函数打印log效果- S$ i" A) T$ U8 I  |! c6 G
(1)设置串口助手参数为:115200、NONE、8、 1(和代码中串口初始化参数一致)。% u; \. S; k  t
(2)设置成功后,就可以看到串口打印的效果。每隔500ms闪烁LED1指示灯一次,且串口输出一个log。
* k& U' t' B) c5 z9 `0 _+ W% X+ m; C
% V1 T8 d: N. F7 v. `, u' {
d829b0e14309464391254bf65851aca2.png
' f$ V( d- h- y1 s2 S1 `7 u! j; H
————————————————) ^* g( U( e! P
版权声明:智能小屋ZYXC
0 u6 _' M1 v" S+ G3 {4 @: |- T9 V! L+ n. V1 I
5 k4 h+ ]1 Z0 j( r4 W7 B
赞 收藏 评论0 发布时间:2023-1-14 18:12

举报

0个回答

所属标签

相似技术帖

官网相关资源

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