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

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

[复制链接]
STMCU小助手 发布时间:2023-1-14 18:12
一、开发板平台简介:
& F0 B: {& s1 o7 r/ O1、开发板资源简介8 ]) i/ V% q0 Y
(1)开发板主芯片型号:STM32L431RCT6
/ ]( B5 ^* {4 V% m) k(2)开发板主芯片封装:LQFP-64_10x10x05P
( T. t( H9 p# j/ z+ }& i(3)开发板主芯片内核:ARM® Cortex®-M4* e: y- d0 }+ C
(4)开发板主芯片主频:80MHz
( i, \6 ^( g* T4 W. ]+ u! W! R* `% @; u(5)开发板主芯片Flash大小:256KB
0 w2 S( j# R% d  R9 v: V. B" A) K9 ^(6)开发板主芯片RAM大小:64KB5 c# j2 Q* u, I: C% N
(7)其他外设:请参考芯片手册" a" D- ]. b3 a, Y$ I( h: j
* z% C, k1 V6 E( w( U- x  {
bb91345227434ee7a43a34bf3fe366e6.png
+ W. j8 t$ @$ S; t& b  N, u/ c9 y( z
929c0cce04aa4115a8623703982bf3e1.png
! u( u2 j8 P6 w2 j- {! x: A% w( \1 u$ \# w
2、串口简介
0 n! g9 W. _: t" O; t
         串口全称为串行通讯接口,即数据在通信线上一次传输一位,按先后一定顺序传输。我们通常所说的单片机串口准确来说应该是串行异步收发传输器(Universal Asynchronous Receiver/Transmitter,UART),使用TTL电平,串口需要RXD、TXD、GND三根线进行通信。
. G* N5 \" R/ }( f0 W6 E+ `        (1)我们选用的STM32L431RCT6开发板串口1已通过USB转TLL串口芯片CH340G引出,使用时,只需要用公对公USB线连接电脑即可(注意也得需要安装CH340G驱动),后期验证试验也试验该串口1进行。
0 t$ M* G6 e5 J3 u! Y' n        (2)开发板上的其他串口已通过排针引出,为TTL电平,通信的时候需要注意选择对应的电平模块,如USB转TTL串口模块等。0 `0 O7 z" s) l( X' Y
& t/ M4 J6 N+ \/ I
  二、新建工程8 n, |) @9 T6 R0 v: Z
1、新建STM32CubeMX基础工程
3 ~- V9 ?8 g/ M7 ]
(1)打开STM32CubeMX,点击“File”-->"New Project"
2 C& \* n5 N/ j0 v; H. c6 o/ K" X/ X) i1 R: e2 q& s" g
2399170347904e959c855fefd5877f84.png ; b4 u. F' ?! @! C7 C
6 r8 E* x' q9 q8 q' I" J1 \3 Q7 u
(2)等待打开主芯片选项界面(大约1分钟时间)。' ~$ z/ u' T5 Q0 u( G& g: w5 |

: b* T, D) r; n1 F' ?: v
d74d2fdc60c9440483e2b7cf8d928e7f.png : m* `% q: R9 {. s2 M

/ t1 k0 I- ?, {$ h% P0 n$ Y5 |(3)昨天搜索框中输入(或选择)所需的主芯片型号(因为我们用的是STM32L431RCT6开发板,所以此处现在STM32L431RC),然后在右下角选择STM32L431RCTx(因为开发板主芯片是STM32L431RCT6),左键双击即可打开新建的项目。6 U7 U; {* C8 Y4 ~

% [) a& Y# s$ J) |, {, a* c: ^
7b80345238d74bea82ce70e1a348f7b4.png
1 \8 P* X& j. K! h7 A3 ?! c0 t- m  P7 t; N2 F& B
- t% u  `& f- A8 h* ^, I, b
(4)选择时钟源。
6 L3 z0 e/ Q* T& J9 `(1)因为开发板上有8M外部时钟,此处选择外部高速时钟(HSE)。
& h  k- t3 g- z: m+ m1 ~(2)因为我们没有用到外部低速时钟(LSE),此处不做处理。# |% ~. Z" V: S' X
, K* x3 f4 y* x7 j
72119b971f62410fa8344f7f9fb9f389.png
8 i# M+ ?' _0 f7 U
. O7 ^2 d/ |1 x- M6 |2、配置GPIO控制LED. Q$ @7 y5 u- W6 T( Q) T2 w
备注:LED灯用来指示系统是否正常工作。+ X9 z  m2 s  o
(1)查STM32L431RCT6开发板原理图得LED1控制引脚为PC0,则配置GPIO的引脚PC0。
, T4 \$ _# T: N4 p% p+ q鼠标左键点击PC0,选择“GPIO_Output”,表示设置该引脚为输出模式。
8 q2 z: Z. G: @8 D" ~1 Z5 s
2 w6 ^; m. C. R5 m3 r& {, T  q
492907c1e71149819adbaee4516a2af4.png
! K! b  r! ?) |9 z6 u) P5 \

( L5 h4 D5 Z7 ]  ?7 I(2)根据自己的需求配置GPIO的参数,如输出方式、输出频率、上拉下拉等。因为GPIO控制LED的要求比较低,此处采用默认参数即可,不用修改。
$ x; Q" N9 `+ U/ ?4 R. t4 i/ ]
- g: _' c" s8 X. i9 ]$ M
38ff4b80e1c5495ba3076a5158fd91fa.png
  e6 ~1 g* q( B

: d1 P( M. k! a  g3、设置串口1参数
' L$ b: G- a5 |" N6 u1 t" ~" ^1、查原理图得知,串口0使用STM32L431RCT6引脚为PA9-USART1_TX,PA10-USART1_RX,引脚设置如下:
1 m+ U& j/ v$ z0 `. E! g1 M' l- U$ R/ d7 n( Y
497b8ee0243e446784e64a3c31e8a26f.png
2 R! N7 e3 l# c0 A+ }4 |" \$ s' q; E' W; Y1 T! q( R
(1)序号1用来设置串口收发引脚的选择。6 J9 ^6 w: d* ?% W# G$ ^; \8 b
(2)序号2-3-4-5-6设置串口参数,如波特率115200、8位、NONE无奇偶校验等。
3 H6 t4 V" S3 G1 C3 O: W+ }
+ H/ s( D/ G/ ~4、配置SPI Flash接口$ H) v7 ^4 v/ c9 e5 [
(1)查看STM32L431RCT6开发板原理图得知,芯片原理图如下:0 T7 a& ]$ j* d5 f' h1 E
% ]' x! E3 ^8 W5 V3 a, X, O& J
11aaba64f3d34f9ea1e4cbbfc0fdc102.png
8 a: @4 y6 p  e
* k) q1 l- ^9 A* K (2)SPI Flash接口对应芯片的PB12、 PB13、 PB14  PB15,芯片引脚配置如下:
$ E! N5 d1 T# m5 JPB12:SPI2_NSS,此处设置普通输出IO即可。不能配置成NSS。' ?) h" s- w4 ?3 B
PB13:SPI2_SCK
6 c$ s& G+ C* o9 w$ h( x$ b0 p# b4 wPB14:SPI2_MISO
2 ~3 l& @' v& u+ q) }: RPB15:SPI_MOSI
: q2 n- q6 L* A/ g
: c" p6 o4 {9 ~& }2 Y
ade62d1658174af99a93e3928b62849c.png
/ c' {$ h  T' K+ Z

+ H& b# {+ u' i# m4 |5 I$ W (3)设置SPI引脚参数,并选择 Full-Duplex Master 全双工主模式,此处不开启 NSS 即不使用硬件片选信号。5 ^5 V( H  d& g- Y

2 _. J+ ?0 G& `
c932367c299e46979e55a3e1a05d2c7e.png
3 U1 b: m) g9 z% B% V7 X# h& G4 d  H7 H, _/ }, d
(4)设置SPI基础参数以及时钟。
- I, f. b' _$ q+ @: W) h4 Z9 S$ d9 N5 w8 p, M% f( K
e5af1c8c0b0b4ac9a07d740b955028c0.png
" x. ^3 |2 m+ H1 o
& r% D( @( p6 I1 u( C
dcc8d73ddcbe4082a09165905ac71cf1.png 0 d  U  k  i4 ?3 U) m4 g+ E4 S

5 a5 F8 d! j5 A* M1 [ 4、配置项目工程参数; q0 g2 ^* N. V  o  n2 A0 K
(1)配置时钟树,用于系统内部时钟,以及各个外设时钟等。此处选择外部8M晶振作为主时钟频率,内部最大倍频80MHz。( p' }4 ~- ~% H; J: f; y3 [* m
* B% U+ V' W3 v6 l2 L3 x
7818db74b3594231bb1923c5425155c1.png 2 T# @! x% {2 U- E
" t9 y3 s1 Y' @: u
(2)完成配置工程。
6 x; s* Q- o1 V2 B* i5 F* n备注:需要注意代码生成过程中的继承关系,如图所示:需要保留开发者自己编写的代码时,请根据配置设置,不然生成代码后会删除自己编写的代码(从这个方面也可以看出开发者备份自己的代码是多么的重要。)
0 n8 e( C1 A' l( d4 C+ e1 H
* a6 I8 a4 u* b& G! n. M
efdb616174f54925b6eac31109f227b5.png   l* j  b. w! |. B; D; k! o0 N6 C

; p8 L' k6 y3 D1 ^
41c3f2716e4e4eda8f62fa3a1d871322.png ! `1 P2 R$ u; ~; s1 u/ q& M
; T- h7 b- E0 s& ^3 P
(3)生成代码。
3 Q3 _7 }! z9 x. S6 F. \9 M
! c: `/ O# x2 o3 R6 l5 `
8eaa7d0babea40ee93f158481a6ee471.png 9 H/ n! u# k0 l$ H% Y- v6 @4 e

/ l" w# P( x) {' `4 M 三、在KEIL 5中编写代码
# {# n2 |8 N4 ~" k1、使用KEIL 5(MDK)打开项目工程文件
5 S% y/ _" c6 B& u; ^
(1)找到刚才新建工程的存储路径,安装项目名称,打开项目工程。
2 J4 I- p+ L& m5 s% {0 z
' K3 e  q# d9 n# R) Z( M
089f22b1faf8419f8f1fb3830cea3e8b.png
- w' h+ N$ Y% o, \7 I
$ j) |" V9 Y0 ~$ N! d6 @(2)添加每隔500ms,LED1闪烁一次的系统提示,用于提示程序运行正常。: ?/ D) a; g& R# N
; c& E5 A1 o+ u' I) K
6ab72ceaeb7a41af833842fe5ba6f34d.png ' x3 _& T/ E* @& Y1 Y. V& V

) F( i; N! t( |4 C# v) i$ \2、添加使用printf函数打印log的代码9 B: G0 h+ U9 y1 e# I& Q$ F' @
(1)在项目选项中勾选Use Micro LIB选项,勾选该项目后,可以正常使用基本的C语言库。2 f' U' y! H# N7 C3 A

" y1 w" [3 ?* O
3db54bee7a3e4fb78ecb85f0c26ece57.png # v' |4 D6 @! x, w. X' W

& ^+ g7 D5 z: [, p+ c(2)printf函数会调用fputs函数,fputs函数为弱定义函数,即使用__weak修饰符修饰的函数,可通过自己编写函数定义覆盖原定义,我们在此处重写fputs函数。在usart.c中添加如下代码。3 ~: r# L6 S9 a8 S
备注:开发者自己的代码需要注意添加位置,一定要放置到一对《USER CODE BEGIN和USER CODE END》之间,避免重新生成工程后被覆盖。
3 x3 `5 o/ z0 w5 ?7 B, i6 |4 U) ]+ G
607544c9bb2b4ca995be69d71d763526.png ( M. A: Q* S* a5 A: A  u- {
! N, c) h6 n3 M
代码段如下:可直接复制使用。
+ O* {0 X1 f$ N6 m
  1. /* USER CODE BEGIN 1 */
    % ^- _5 k$ s- T4 x; p+ w! c
  2. ) O$ K8 @7 ?7 ~6 ~8 {$ @6 g
  3. #include <stdio.h>9 b; P& \3 c: v4 j8 g
  4. #ifdef __GNUC__
    / b  e2 X/ d2 ^( E) J5 Q5 {% o
  5.         #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)! {! E0 G) X% x+ l
  6. #else, n$ s- l4 ?! Y- h, M( m
  7.         #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
    9 }6 i; X' l' r: Y# F1 S, ~6 I
  8. #endif
    , `# E/ J) F/ Z7 N. |
  9. PUTCHAR_PROTOTYPE
    / y. h0 q6 X' h3 ~. M% c
  10. {
    1 U5 V7 y2 {) W6 f8 K/ M7 a6 M
  11.                 HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);# B9 K, u4 r- R5 G% M# v
  12.                 return ch;
    0 S) o- U. S( _2 r; A/ z' S
  13. }3 Q, r; J) M6 T0 W3 F6 B
  14. ; h* S. L$ o( E; r
  15. & m1 _8 X! Q" r6 ?0 I* i
  16. /* USER CODE END 1 */
复制代码

! `* a. j) E' _& Z/ h/ s
4 R# U6 `) _  ]7 X" {
(3)使用printf打印log数据。需要注意main.c位置添加"stdio.h"头文件(printf的函数声明头文件)。

$ s. X, [/ N$ E/ @2 d+ ~
) L3 }% D/ @) J* u% s  `8 F; o( h
ad684ef90b44425198d2cd6b046d6d5b.png ; d9 t1 v2 |& M, U5 a+ E

0 V- c' i' g6 v1 ~
  1. printf("hello world,this is printf function!\r\n");   //printf 打印函数2 w# S$ x0 h5 t0 G& Y6 U* F; X
复制代码

, i  j4 z. ], g$ N. g% \ 3、在w25qxx.c文件中添加SPI底层驱动函数
/ b( _( u2 R5 o- y; c2 N
  1. #include "main.h"
    5 O) y. S% ]! d# e! E) l% R( j
  2. #include "spi.h"
    9 M* ]& N2 J. x% |/ u$ V
  3. #include "w25qxx.h"8 Q: d4 i6 m$ |/ z% v. K) U; z
  4. /**+ C; s1 y# q4 m) D* S$ D
  5.   * @brief SPI1 读一个字节' w9 I3 x! m" }$ W8 J# s3 i
  6.   * @param None
    0 e( `. C: P% x% V7 M( n7 B( Z
  7.   * @retval None" A  s, z, c7 R7 Y' e# ~: `, p
  8.   */1 R* n, k: F- k' ?3 C& [% c2 |
  9. static uint8_t spi2_flash_read_byte(void)0 D2 n: U6 f2 e; h- C6 \
  10. {* N. A8 Q; C4 s; @4 O/ C
  11.     uint8_t t_data, r_data;
    ! a1 B  i/ _7 e: R
  12. + \: J. D0 Y$ A" s: O7 ~+ s
  13.     if(HAL_SPI_TransmitReceive(&hspi2, &t_data, &r_data, 1, 0xFFFFFF) != HAL_OK)0 X+ f3 C. @1 T8 g$ b, B
  14.     {
    - r* N  D# w5 a2 B  o2 h
  15.         r_data = 0xff;
    : {7 E9 ^) [( p. e! |* X2 ]9 i
  16.     }& J- F- s1 C: l) m6 |
  17.     return r_data;
    # Z+ l/ O* L- T, W$ K0 H2 c
  18. }. C% J/ k" J+ }$ l- r) M1 F
  19. /**3 ^, ~: Q) H4 H+ j
  20.   * @brief SPI1 写一个字节
    & E) O; `9 a( w& U6 F
  21.   * @param byte 写入的字节
    ' O8 U! E; x; S) ?& t2 `$ V- F
  22.   * @retval 写状态 0成功 1失败- X% _4 Q4 g% h2 B$ c
  23.   */" c. ]# \& q5 B
  24. static uint8_t spi2_flash_send_byte(uint8_t byte)- L1 U6 y% @! r3 t8 P1 m0 M# l
  25. {
    ' G' L' Z3 y# y
  26.     uint8_t r_data;6 ^# I, ]. A, ^6 ]7 ^& }0 F, H: s

  27. 2 W& ^  e+ v4 @2 }: n3 B
  28.     if(HAL_SPI_TransmitReceive(&hspi2, &byte, &r_data, 1, 0xFFFFFF) != HAL_OK)) d" H  G- g( \% [& C+ r5 f; [
  29.     {
    3 ^. Q4 P: q& i( |
  30.       return 1;
    " }( L3 }! ^1 H
  31.     }
    ) W' y4 T) C4 H& b7 \3 `+ e7 s% W
  32.     return 0;
    % i+ G5 m) r0 ^
  33. }
    8 S+ y, V" s2 z+ I( c/ X% q7 W. m% K
  34. /**
    9 E( Y0 B- Y5 R
  35.   * @brief FLASH 写使能
    / Q" M. p3 D! R: r( Z4 g. A1 g. X5 k
  36.   * @param None
    : W: z2 B5 T4 d  v. y) P
  37.   * @retval None! t0 F/ y" s8 _- R2 i" F
  38.   */
    & L  a1 d6 I- Y4 y' T! E
  39. static void spi2_flash_write_enable(void)$ X/ O. _8 v; {' T& x
  40. {
    6 P9 m8 e1 u7 R6 T( p7 P4 x
  41.     SPI_FLASH_CS_LOW();
    / r% d; j- y6 G& ?$ ~
  42.     spi2_flash_send_byte(W25X_WriteEnable);4 p; K8 K3 U+ x( C
  43.     SPI_FLASH_CS_HIGH();
    + O0 H& Z1 _# b' N3 T& {9 @) z
  44. }( n) \+ |/ M9 S8 i3 t$ B/ t9 m
  45. /**# x5 U) T0 W% n4 |# C5 h
  46.   * @brief FLASH 等待写结束+ _* g/ _5 V1 m' q
  47.   * @param None( a/ _& D* ]0 H+ F6 e# m
  48.   * @retval None- `* a1 v: b3 Y- f# J  ~
  49.   */7 c' p; |7 K& L9 s- \' I
  50. static void spi2_flash_wait_for_write_end(void)' b3 k  x* Y! i1 w) x5 d
  51. {
    " Z& B7 e) G3 N: U5 j3 Z4 E
  52.   uint8_t state = 0;% l2 R' u  |( i6 `8 ?$ e& L
  53. # c* `9 g: T0 n0 q; E- Y8 T
  54.    SPI_FLASH_CS_LOW();6 k* F! K! `& U# m* i& M! s

  55. 4 {5 m+ V6 I/ L7 h1 _
  56.                 spi2_flash_send_byte(W25X_ReadStatusReg);
    7 v& G$ p4 [. O- H$ v: o  a5 l) J
  57. 5 G2 T% a. a0 ^8 S" N+ `0 d
  58.   do, _, Y" M; W5 A% ?* P
  59.   {1 ^/ W! A7 x7 ]. \
  60.       state = spi2_flash_read_byte();7 P) D; `, }  B2 k/ n; ?
  61.   }
    4 C4 S3 h6 Z2 M8 ?4 m! x( n
  62.   while((state & 0x01) == SET);
    ( J1 P# a8 V6 F3 P" ?$ j, ]( B* z
  63. ; }9 y+ m" U1 Q, H0 G
  64.   SPI_FLASH_CS_HIGH();
    $ g/ z* }+ {% s, b) X
  65. }
    6 Q& `( A* t$ B2 n% ~
  66. /**
    6 q$ e9 y9 A; \
  67.   * @brief FLASH 读ID. \) `3 t! k% L& n8 q5 W' B
  68.   * @param None
    ) T4 X1 q6 n4 r( O1 U
  69.   * @retval None
    + b, R9 q+ W: J- ?# a5 I, b
  70.   */& T, ?1 l& ]8 g4 r. e# z8 K: v
  71. uint32_t spi_flash_read_ID(void); f3 x9 K" H; Q8 P) W1 _( S
  72. {0 [* c6 S. D  ?1 G
  73.   uint32_t temp, temp0, temp1, temp2;# L9 B, ^9 q$ ?
  74. 9 `) p; h1 G9 P
  75.   SPI_FLASH_CS_LOW();( P# J( r/ q' j
  76.   spi2_flash_send_byte(W25X_JedecDeviceID);
    - L, v3 v7 Y+ l

  77. ! y! G2 Z. t( d1 i) F/ h) m
  78.   temp0 = spi2_flash_read_byte();
    4 Y1 |6 [* s  |5 v: K) Z, a* F! [
  79.   temp1 = spi2_flash_read_byte();) Y  L( W, f# s9 U/ H
  80.   temp2 = spi2_flash_read_byte();1 S& Z/ S# ]2 `; O7 E; H, f8 G

  81. 0 u$ S- r/ z+ h1 v
  82.         SPI_FLASH_CS_HIGH();
    3 f* Z8 D* J6 A' v

  83. ( o+ P( f+ y" s8 R. B/ h% f9 x* o4 n
  84.   temp = (temp0 << 16) | (temp1 << 8) | temp2;7 r1 l% n* B+ o3 R0 I

  85. & B8 o! f- {" D
  86.   return temp;8 Z5 f2 s0 v9 _4 P, @
  87. }6 K' ?1 X7 {& e# J9 u8 u
  88. /**) P$ @5 L0 B4 n# G
  89.   * @brief 读FLASH5 X1 _& M4 T/ ^, v& \, W+ E
  90.   * @param addr 读flash的起始地址  I' k0 a' t: R( G
  91.   * @param pdata 读到的数据存放起始地址
    ' C8 V6 m1 L' U& g- J. v
  92.   * pdata size 读数据大小
    8 \2 p$ h& t& v  D+ o6 m- H1 L
  93.   * @retval None# f- b* W6 }# d3 ?! D
  94.   */+ b( v& c  V& k7 V  {) Y
  95. void spi2_flash_read(uint32_t addr,uint8_t *pdata, uint16_t size)- C  t2 U' j( {- A0 U/ h
  96. {
    0 R+ X: H% |& z# V
  97.    SPI_FLASH_CS_LOW();
    - s, v9 k1 e4 j' y7 w# h

  98. : t& S7 O. h& O$ h( P: S% b, `* G
  99.   spi2_flash_send_byte(W25X_ReadData);8 u. N2 {# f, F: s% H

  100. 3 P  ], E- L" v5 @
  101.   spi2_flash_send_byte((addr & 0xFF0000) >> 16);0 Z8 ]9 n* w6 M- i4 M* C$ j
  102.   spi2_flash_send_byte((addr & 0xFF00) >> 8);9 c+ p2 A. P/ Y4 x( L0 c3 l
  103.   spi2_flash_send_byte(addr  & 0xFF);" f: e" D. a3 n6 g3 \# d0 w, H' a

  104. 4 w1 N0 K% e) }4 f+ N
  105.   while (size--): U; j5 ~# F" ]2 R  }3 b
  106.   {
    ' H7 F5 ~, L( G. }
  107.     *pdata = spi2_flash_read_byte();
    8 s6 ?) H8 U2 B7 |) {
  108.     pdata++;
    - {' r6 Q9 B6 N6 M4 D7 o
  109.   }
    + d; a& \* z8 `0 H; f: v
  110. 3 e1 J9 N8 t( q. d6 N7 ^: a
  111.         SPI_FLASH_CS_HIGH();  `8 ]( N! l) ?8 Z) A
  112. }
    $ }6 |& f# c) V4 n( D. |( \
  113. /**6 ~) |# j! T% |) t
  114.   * @brief 按页写FLASH
    , f1 w0 L/ H0 j
  115.   * @param addr 写入flash的起始地址2 j- \% J7 B8 V* _
  116.   * @param pdata 写入数据的起始地址+ _$ @* T4 _* i6 _1 i
  117.   * pdata size 写数据大小
    , f/ q! V: e% R  f1 l4 E
  118.   * @retval None3 r# M: ?7 r# W7 }! J
  119.   */& N/ b% U6 b9 t
  120. void spi2_flash_page_write(uint32_t addr, uint8_t *pdata, uint16_t size)6 R1 G" O0 c5 x2 J
  121. {) t3 J, K! L9 I
  122.     uint16_t i;
    6 S& q' \. W: }9 J

  123. ) }$ Z; \7 l. c
  124.      spi2_flash_write_enable();
    9 W1 |/ r% Z$ c7 ?8 L
  125. 7 C0 J6 n! W' K6 H$ a/ X& h4 I4 Y
  126.      SPI_FLASH_CS_LOW();
    # U! {% c/ t6 A$ e" c* q& M6 w# L: N

  127. % ^& b# p7 K* U8 |) ~
  128.     spi2_flash_send_byte(W25X_PageProgram);: I( q3 P! s3 s2 B1 y
  129.     spi2_flash_send_byte((uint8_t)((addr)>>16));
    ' x- x3 r0 X. R9 B- Z, ?
  130.     spi2_flash_send_byte((uint8_t)((addr)>>8));  _/ `$ o# g* W# x3 A6 B6 R
  131.     spi2_flash_send_byte((uint8_t)addr);9 O- o7 N4 G0 e* h0 ^4 Y

  132. 9 e. a- d6 @; I' y0 z  h
  133.     for(i = 0; i < size; i++)
    ) _# S8 f+ L3 a' p9 s2 t  y- v
  134.     {
    6 ]$ U9 ^$ k6 g0 W% s
  135.         spi2_flash_send_byte(pdata[i]);. Q7 G/ u2 l% d- X/ j
  136.     }8 L/ ?* w. {$ c5 L- F$ O8 B

  137. 4 H6 l2 k7 i5 Z
  138.     SPI_FLASH_CS_HIGH();
    0 h  [, H6 J% v
  139.     spi2_flash_wait_for_write_end();; N8 ?0 M+ L, L
  140. }
    0 v9 c* B! k7 O
  141. /**, {# ?2 P$ b$ d; j2 L2 q
  142.   * @brief 写FLASH
    2 D5 B% ]. y! \1 _% Z
  143.   * @param addr 写入flash的起始地址6 J* h( n) ]: K8 Y! _# C7 Q  K
  144.   * @param pdata 写入数据的起始地址9 J; v0 }% ?$ F: y
  145.   * pdata size 写数据大小& C; \  D7 G5 d
  146.   * @retval None' A  M$ D7 ~& \. B. F: m
  147.   */
    9 q! x! x: A7 s3 K7 `
  148. void spi2_flash_write(uint32_t addr, uint8_t *pdata, uint32_t size)
    . `# r# v4 w( s1 J/ b& z
  149. {) i4 `* Z. s1 v4 L7 v) R6 _- k" C
  150.     uint32_t page_remain;0 @0 P$ d- ^/ g! N- l
  151. ( o" r$ n& N' r, P( s
  152.     page_remain = 256 - addr%256;
    . E4 c% h0 ^' {' N
  153. 1 L. r4 V7 ]2 r8 B
  154.     if(size <= page_remain)1 h! i* a# I% ~; ~
  155.     {4 y, q# b+ t8 c
  156.         page_remain = size;/ }/ i' ]- e' E( }. V- D
  157.     }3 U+ E$ V3 X0 x# c1 N* G
  158.     while(1)
    3 J7 C, S& h& s  e
  159.     {9 p  a/ w7 \0 E- f8 a0 @2 R
  160.         spi2_flash_page_write(addr, pdata, page_remain);
    / l- D6 X4 b: Z9 a( A
  161. ( H4 \8 T3 T4 P& P! i6 d6 l: Z6 |# p
  162.         if(size == page_remain)% o+ g/ }" X4 ?
  163.             break;
    ! V5 c+ w" M2 e& B9 E  x' A
  164.          else1 i5 L; d& j/ _0 q. U
  165.         {
    5 ?. \% ~; H: B' `5 r  Z8 M+ P
  166.              pdata += page_remain;
    4 e2 {- {* Z- K
  167.              addr += page_remain;3 |" B. s: h  ~9 v7 U' z3 x; P
  168. ! @; U. M. q0 i. m  v8 X
  169.              size -= page_remain;
    3 S+ \" M# W" Q' Z* M9 E4 W2 w
  170.             if(size > 256)
    - w6 e& Y% S' G/ A" c* j& a
  171.                 page_remain = 256;( D& Q, p# v0 j2 P  ~2 Q+ g
  172.             else2 z9 Z1 z$ K. E7 w
  173.                 page_remain = size;
    9 [( m3 j1 l' l, A
  174.         }5 s7 a: S: Z6 Q2 l7 ]) L
  175.     }- k0 H$ D" }* k0 }2 a3 t; r( l
  176. }
    - H: ^6 g1 T$ X6 `; ?
  177. /**
      G' l" R5 ^+ q6 v3 }7 C8 m
  178.   * @brief 擦除FLASH扇区# y* c1 T# V& ~1 e+ z. ]9 Z+ F9 D5 l
  179.   * @param sector_addr 扇区的起始地址" M2 v% D5 ^2 ]( [: o
  180.   * @retval None
    $ X. a3 J9 }2 Q: f
  181.   */; p, I/ M8 v& D" P
  182. void spi2_flash_sector_erase(uint32_t sector_addr)
    5 T- @- {$ g2 w, b9 x
  183. {  N9 @- B, W" T/ C
  184.     spi2_flash_write_enable();& u8 J) V# u! s+ s
  185.     spi2_flash_wait_for_write_end();/ i( ?/ q; D& i  _

  186. " i3 p9 \" \. u9 a6 r% F7 u, D! o
  187.     SPI_FLASH_CS_LOW();
    ' {0 ^) |8 g2 d1 s* J+ G& R
  188.     spi2_flash_send_byte(W25X_SectorErase);
    ; K+ G$ n; [# a
  189.     spi2_flash_send_byte((sector_addr & 0xFF0000) >> 16);
    0 _4 j( F4 S+ O( V) E
  190.     spi2_flash_send_byte((sector_addr & 0xFF00) >> 8);
    . m6 y" T. S5 `  U
  191.     spi2_flash_send_byte(sector_addr & 0xFF);- R1 P4 p8 `& {' A/ T! n8 c' M, ]3 A2 [
  192. & C  _* t, ]7 o6 r- A
  193.     SPI_FLASH_CS_HIGH();
    " a: J# h1 y- }) i6 Q! }6 V/ c% [9 _
  194. 6 m! G) y8 H. v* q0 h+ z- f
  195.     spi2_flash_wait_for_write_end();) h: b4 Z6 P+ |; j0 B
  196. }
    - S0 ]5 p/ @: _: r$ N: ?9 I

  197. ; W  X! x$ n) _3 l- e+ ~
  198. /**
    # n: q9 e% _, u$ n" R
  199.   * @brief 擦除FLASH块
    2 A3 n1 L! U0 C$ V8 |2 X
  200.   * @param None
    3 P& D5 ~% }0 j: `' `
  201.   * @retval None5 `+ _8 M1 K+ T6 y0 C/ f& X% G
  202.   */
    & |8 N: U: F: H( q7 t
  203. void spi2_flash_block_erase(void)
    & B3 j3 b, ?6 E4 t2 t9 P, f& T
  204. {
    2 |* {2 c# O" d" L, l
  205.     spi2_flash_write_enable();) k* V3 R! q  n
  206. 6 i& I0 j- ^$ p$ b& t1 N3 B% F' S
  207.     SPI_FLASH_CS_LOW();8 P& v$ g0 H6 q
  208.     spi2_flash_send_byte(W25X_ChipErase);
    6 z5 S2 h2 N  y) r  M/ e
  209.     SPI_FLASH_CS_HIGH();
    % u, ~  X; j3 |: }  s

  210.   H' i% Z/ I3 X2 p' ~
  211.     spi2_flash_wait_for_write_end();
    & D2 k! ?# f' W7 y2 q
  212. }
    % a( w" m/ W) Q" e2 q+ z7 y$ m
复制代码
6 I% X3 J: H. c' l, f3 O8 O" I8 o+ B

! Q; b' q0 ]. d4、在main.c中添加功能函数% D2 _# i% K; S6 d+ w
  1. /**
    ! n7 y0 J0 y+ \, D* l7 {/ u. |  s9 G
  2.   * @brief  The application entry point.
    3 I& J* g/ L4 m
  3.   * @retval int
    , |5 M( y6 J) T3 K% x
  4.   */
    - Z, h" w6 H1 @# A. Q1 _& V* x" o
  5. int main(void)
    + p4 k  w, M8 |
  6. {! C' L  w( u9 i, l/ w
  7.   /* USER CODE BEGIN 1 */
    ) m- ~$ p' s4 g3 P' B# O. G
  8.         uint32_t w25q_chip_id=0;                                                                                        //读取芯片ID% Z! @; `+ e7 B; K7 k
  9.         uint8_t  onebyte_read[8]={0};                                                                                    //读取的数据
    9 G+ b3 l  N" A9 i8 @& [3 x
  10.         uint8_t  onebyte_write[8]={0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80};                                //写入的数据
    " T0 l. w/ J0 R. ~
  11.   /* USER CODE END 1 */
    ( h2 Y% ^0 b' ]3 J6 @) v6 l7 l
  12.   
    5 ]; b" B3 P, D5 u( D/ F
  13. + _/ G; u- ^$ B7 U- h3 Q2 e
  14.   /* MCU Configuration--------------------------------------------------------*/
    2 @3 c4 r' J3 _: A0 ^3 k3 l
  15. ; C4 e$ N  D  l0 X
  16.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
      Y: m* q$ g- t+ f
  17.   HAL_Init();
    1 i: B/ t/ b9 \* V! Y# L
  18. - Y4 ]) B/ U: ?3 F! K. d$ \! q6 ?
  19.   /* USER CODE BEGIN Init */
    7 H$ M( f4 w+ w4 D- ^, {4 d1 _7 v# W
  20. 8 O( H& r- L8 g# y
  21.   /* USER CODE END Init */
    " P* M: h3 t- {* Z- c; u

  22. 4 A$ T" \2 z) U' @3 }2 Q
  23.   /* Configure the system clock */0 F- |; F! X1 g& L$ h; ^+ F. K/ _( _) g+ G
  24.   SystemClock_Config();3 f0 E* c- f  S* J& T0 j1 A# M
  25. 6 G; X- Q$ l6 r
  26.   /* USER CODE BEGIN SysInit */
    ) I5 j; Q" a6 \8 m; C6 y' u5 {0 ^

  27. 5 x5 ^; i  _0 E) O% R
  28.   /* USER CODE END SysInit */
    ; }# O) g* ?: V( t

  29. ; z0 S3 T. ~3 f' x5 a
  30.   /* Initialize all configured peripherals */% }5 q0 `5 C1 J7 y
  31.   MX_GPIO_Init();4 ?& ~" P% c% z$ S" t; v4 D: u; d2 S
  32.   MX_DMA_Init();
    4 A1 s7 }. X3 E( A5 E
  33.   MX_USART1_UART_Init();4 C5 G/ a/ z2 r! s& ]
  34.   MX_SPI2_Init();) E4 f" L4 F# [. y% g1 h% k; k
  35.   /* USER CODE BEGIN 2 */
    + L3 T; a. ]5 S2 a- e  i- W
  36.         HAL_GPIO_WritePin(GPIOC,GPIO_PIN_0,GPIO_PIN_SET);                                                                //初始化LED1
    8 Z4 t  B4 b* y/ R6 G% R
  37.         w25q_chip_id=spi_flash_read_ID();                                                                                                                                //读取flash芯片ID; C  c# D, ]! o, W9 L+ {( l
  38.         HAL_Delay(100);
    : L; F4 t5 a" |3 |1 \6 J4 \8 T5 d  C: \
  39.         printf("hello world,spi_flash_read_ID==0x%0x!\r\n",w25q_chip_id); //printf 芯片ID
    ! {: B6 R8 S2 _) }1 g
  40.         spi2_flash_sector_erase(0x0);                                                                                                                                                        //写之前需要先擦除扇区                                                                                                                                       
    4 Q( T, a8 e+ Q, W
  41.         spi2_flash_write(0x0,onebyte_write,8);                                                                                                                //写八个字节9 C" z) b" {- \* Z2 y
  42.         spi2_flash_read(0x00,onebyte_read,8);                                                                                                                        //读取写入的字节
    7 n' f% m& _; s5 r& h  s4 i( ?
  43.   /* USER CODE END 2 */
    % k, a. B7 F% i* S& w
  44. % m6 P* S% U! m7 b8 r( D' x/ C8 |% c
  45.   /* Infinite loop */
    1 X2 j- _8 S/ Z9 V6 w- W
  46.   /* USER CODE BEGIN WHILE */; r3 i# I% O& K# S1 k: @
  47.   while (1)- \  f9 Q1 B$ R  F9 Q% r4 o  w$ H
  48.   {
    7 j4 R1 T  N7 R+ C6 o7 Q
  49.     /* USER CODE END WHILE */
    ' z3 d% F7 g1 b: Q

  50.   s. f: t7 ~: p' P
  51.     /* USER CODE BEGIN 3 */% ~( F3 S# U  Y1 A; u
  52.                                 HAL_Delay(500);
    9 @# J! P$ w2 r' s+ a
  53.                                 HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);                                                                        //每隔500ms闪烁一次LED1
    / I$ p& @, }& F4 D
  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
    ) n9 R, h+ p% P. P( V4 s8 [0 ~% T1 a
  55.                                 / C  D8 z2 @# i0 }' p1 N
  56.   }
    7 t5 T" J+ g6 u) d6 e
  57.   /* USER CODE END 3 */& {* x3 l- q, G+ L- r7 n! d4 X
  58. }
复制代码

4 r! [: p; T+ d: s2 E" Q; o- {+ `6 f4 _, l" @
5、设置编程仿真下载模式

; F# k0 {  c4 E. F(1)选择Options for target ...>>Debug>>J-Link/J-JTRACE Cortex,点击Settings>>选择Port(SW),可以看到搜索成功SW Device,表示芯片可用,可以下载。% a) C8 }1 ], K" @# t1 y: A

: i+ R5 M) ?8 u) r- I  z
edefb6b9a2a14be3b1221ad6d5c7a8a2.png
) f$ f/ K0 ?3 I" p' \0 X1 _3 [5 v( r& h0 j
5 ]0 O9 b9 M7 p- b(2)点击Download(或者快捷键F8),即可下载程序。
" D! I5 L! C+ X: Y
  a7 H$ b4 t8 f  ^/ R0 a$ h
ba221842d5db40808aa129dd83c593d0.png 9 P9 q& X1 _; i3 s
6 {9 p9 \/ r) q' Q! _
(3) 如果下载程序后,没有看到LED1灯闪烁,可以按下述方式设置一下(Reset and run表示下载后自动复位和重启运行)。或者重新彻底断电再次上电(或按开发板的Reset按键复位MCU即可)。* D, L- T- y# n4 F3 l8 T4 r

  @7 V# @, V9 A4 k
9f8aa1a4e8f04041bcf5cb183facd100.png ) u3 H# n' O. |. x8 _0 Y
4 k! w3 w7 }, _& E( }7 J# o
6、查看串口printf函数打印log效果
( S5 P! X' j+ _! l$ J2 D- y0 _(1)设置串口助手参数为:115200、NONE、8、 1(和代码中串口初始化参数一致)。6 C+ n2 T0 v+ ^  o7 v! p
(2)设置成功后,就可以看到串口打印的效果。每隔500ms闪烁LED1指示灯一次,且串口输出一个log。# U+ @, }$ ?! P1 y- m; v. m# A

" j8 J4 A( }3 a4 D" u  e
d829b0e14309464391254bf65851aca2.png 2 A- H8 k2 J% p( O$ @$ h' N7 @

; g0 O: t2 y0 D- N5 L+ Q————————————————
1 h+ ?5 q1 w) x+ g: {2 R版权声明:智能小屋ZYXC3 g; v* K$ g* X. E9 _

  F- F. G  K! ?6 R
( C( y& k. z! e9 e
赞 收藏 评论0 发布时间:2023-1-14 18:12

举报

0个回答

所属标签

相似技术帖

官网相关资源

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