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

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

[复制链接]
STMCU小助手 发布时间:2023-1-14 18:12
一、开发板平台简介:  g1 X" G; ?+ \2 V2 h0 W
1、开发板资源简介& c, _0 H$ t. ]$ x; X
(1)开发板主芯片型号:STM32L431RCT6! g) T: v7 ~" @
(2)开发板主芯片封装:LQFP-64_10x10x05P
+ t' X& _; S5 U3 _5 H* c(3)开发板主芯片内核:ARM® Cortex®-M4! q, I4 ?0 w1 {6 `
(4)开发板主芯片主频:80MHz# {1 F  B$ k; c2 z) v9 i3 h( C9 ?
(5)开发板主芯片Flash大小:256KB( n! X! `- i* f0 ~! u
(6)开发板主芯片RAM大小:64KB
1 B1 T, K0 {3 P0 h; r (7)其他外设:请参考芯片手册. }; {  J. a0 v% L! s

0 `( ^5 l, M: p  R$ `2 W$ Q
bb91345227434ee7a43a34bf3fe366e6.png
1 N0 o$ b  i8 a/ W
. `; C+ e/ l& }8 p0 S$ H
929c0cce04aa4115a8623703982bf3e1.png ( E% g4 {: T2 @6 H" b3 j
6 b; {) S/ N: ^3 r8 W
2、串口简介
7 _  b" X( ^( p4 H
         串口全称为串行通讯接口,即数据在通信线上一次传输一位,按先后一定顺序传输。我们通常所说的单片机串口准确来说应该是串行异步收发传输器(Universal Asynchronous Receiver/Transmitter,UART),使用TTL电平,串口需要RXD、TXD、GND三根线进行通信。
2 R- Y6 _, H* Z  ~& g$ z        (1)我们选用的STM32L431RCT6开发板串口1已通过USB转TLL串口芯片CH340G引出,使用时,只需要用公对公USB线连接电脑即可(注意也得需要安装CH340G驱动),后期验证试验也试验该串口1进行。0 F* S2 @* p/ y- y2 j3 D
        (2)开发板上的其他串口已通过排针引出,为TTL电平,通信的时候需要注意选择对应的电平模块,如USB转TTL串口模块等。
& C6 E% J$ L, x% T( g
/ \+ ?7 n! a4 W  二、新建工程3 [: b( Z4 i4 n
1、新建STM32CubeMX基础工程
+ ?2 v4 a7 r/ a8 l: i+ T5 q4 N" k
(1)打开STM32CubeMX,点击“File”-->"New Project"; t; g6 Z' R. _. [6 x

* s4 k8 a7 q; z9 @- w  ]* j% ?1 J$ A
2399170347904e959c855fefd5877f84.png , A+ A8 \! E) l' F5 x/ T% Z  D" N: y  {
+ h" x; ]3 S5 W& r9 z) s
(2)等待打开主芯片选项界面(大约1分钟时间)。7 i# M) F* m3 R; z: h+ J* t
" X$ e, x- \0 X6 ^' k
d74d2fdc60c9440483e2b7cf8d928e7f.png 9 b6 H' J# W& S1 U1 N; L

# ]7 [# U# g! J  z- S: v) U! b- c: z0 d(3)昨天搜索框中输入(或选择)所需的主芯片型号(因为我们用的是STM32L431RCT6开发板,所以此处现在STM32L431RC),然后在右下角选择STM32L431RCTx(因为开发板主芯片是STM32L431RCT6),左键双击即可打开新建的项目。
7 z6 U5 |5 J% r) t
" n) x8 d% b3 D
7b80345238d74bea82ce70e1a348f7b4.png : g2 S0 e- k8 z/ {
; r" D) a% p- h

0 \% n, O( k% {7 J' z5 r8 t; d(4)选择时钟源。; v# l! D  J- _4 V) p1 {
(1)因为开发板上有8M外部时钟,此处选择外部高速时钟(HSE)。
) K( o: M3 _0 C3 y( c& |(2)因为我们没有用到外部低速时钟(LSE),此处不做处理。
. \+ ^9 u9 ?, a  }; e1 D  U' {9 R) k+ h
72119b971f62410fa8344f7f9fb9f389.png
, ?  x6 m/ u! T( ~/ a
5 {+ c$ K' B' m- z; j  A2、配置GPIO控制LED
& N$ ?+ i8 G$ k7 T2 J$ O, K/ q* r备注:LED灯用来指示系统是否正常工作。
+ \5 G0 Y* p7 m- D, E* X(1)查STM32L431RCT6开发板原理图得LED1控制引脚为PC0,则配置GPIO的引脚PC0。2 S. Z! ^. A$ C. F
鼠标左键点击PC0,选择“GPIO_Output”,表示设置该引脚为输出模式。* `( ]+ F$ i$ m) c: k  p1 ^! G
+ H, A( m2 ^1 J' ?0 a: q; o2 s* b3 s
492907c1e71149819adbaee4516a2af4.png   H' N8 a+ `* [0 {

: ^$ h% }: J/ X% P2 v! n5 K! i6 h(2)根据自己的需求配置GPIO的参数,如输出方式、输出频率、上拉下拉等。因为GPIO控制LED的要求比较低,此处采用默认参数即可,不用修改。, J( W) t4 F" k" u) b
8 Q+ u+ `8 p: z& K" Q( B: B
38ff4b80e1c5495ba3076a5158fd91fa.png
9 Z6 h5 O8 M2 e: w
* @& z" Z1 N+ H2 M6 v4 C
3、设置串口1参数/ f; v1 f$ H1 l
1、查原理图得知,串口0使用STM32L431RCT6引脚为PA9-USART1_TX,PA10-USART1_RX,引脚设置如下:
: b8 J3 a& }# s, f7 u6 m* T
% T. M) \% a$ Z, P1 y: @
497b8ee0243e446784e64a3c31e8a26f.png 5 k( R4 [: r$ Z, n+ i4 k

9 v1 G6 F  ]4 T4 J (1)序号1用来设置串口收发引脚的选择。" v" G2 M: q" X  U6 A
(2)序号2-3-4-5-6设置串口参数,如波特率115200、8位、NONE无奇偶校验等。
+ d0 a2 R+ Y  a6 F, \3 s0 e9 E% A9 z4 B4 f1 b
4、配置SPI Flash接口& w/ P8 j) w6 B3 y4 O' M
(1)查看STM32L431RCT6开发板原理图得知,芯片原理图如下:. ^) }. N/ N' T4 L/ I& s
5 ]" H& ?5 f* m6 J9 I
11aaba64f3d34f9ea1e4cbbfc0fdc102.png
. u" W6 E; D- ~* P  I
: L8 C% L: Y( c0 {' M) ^4 o (2)SPI Flash接口对应芯片的PB12、 PB13、 PB14  PB15,芯片引脚配置如下:
- m% O2 b. R1 g* ~2 MPB12:SPI2_NSS,此处设置普通输出IO即可。不能配置成NSS。
; Z5 t' k7 ]" p$ ?: @. p/ XPB13:SPI2_SCK
8 y! }) {& x; WPB14:SPI2_MISO
0 m/ Q% y; k2 Q  aPB15:SPI_MOSI/ e+ j/ @8 j# `8 `9 l

: X8 P4 S) v4 Q* x0 \, _' ~- @
ade62d1658174af99a93e3928b62849c.png
+ V# R0 p1 S. H5 [' k- U

) L' I5 z. [( z, j8 W: O8 d, U (3)设置SPI引脚参数,并选择 Full-Duplex Master 全双工主模式,此处不开启 NSS 即不使用硬件片选信号。( t! L( k4 [# l7 \2 H
5 ^0 \  r. C% z! p. U7 q
c932367c299e46979e55a3e1a05d2c7e.png
2 U) r! \& I1 u3 J( U3 N
, X4 W) ^8 L6 [: v(4)设置SPI基础参数以及时钟。
9 m2 o+ l2 `  C  q1 X9 v# s
* [1 H: V  M' G6 n; ^
e5af1c8c0b0b4ac9a07d740b955028c0.png
5 v. B$ ?1 `- l, e4 r: a0 f5 k) U: X0 O7 o! t. d
dcc8d73ddcbe4082a09165905ac71cf1.png
3 w4 E1 M  I$ W. m! Q! T8 _3 G5 H& [  `) Y* z8 O
4、配置项目工程参数7 `# W9 F# X% R! F) C: ^9 r0 ~
(1)配置时钟树,用于系统内部时钟,以及各个外设时钟等。此处选择外部8M晶振作为主时钟频率,内部最大倍频80MHz。9 p+ l3 g0 `8 U- {  S) K, \
- U) F; u: o! }* b  u* k  c
7818db74b3594231bb1923c5425155c1.png , X; Z- e7 q% L2 H

" s$ I) y& n5 ^) P(2)完成配置工程。
5 o5 Z; a% S* O( A: q+ [  L* k备注:需要注意代码生成过程中的继承关系,如图所示:需要保留开发者自己编写的代码时,请根据配置设置,不然生成代码后会删除自己编写的代码(从这个方面也可以看出开发者备份自己的代码是多么的重要。)
6 j  \, {  S. _. \. P% \. n! {) Y, X4 Z
efdb616174f54925b6eac31109f227b5.png . r+ y- D+ m" C) W/ v) z! Z7 {

  S) V/ s% H& v4 y& j3 O. h
41c3f2716e4e4eda8f62fa3a1d871322.png
4 D) i0 S5 {$ y; k5 W, S& J3 B

" X  I* y6 O. g2 z8 b(3)生成代码。8 ?3 l$ {& v, F
3 C5 `% S/ ]6 Q/ ~! o$ K$ a$ i
8eaa7d0babea40ee93f158481a6ee471.png 6 y" j) B: h9 U' x2 L# l' U
7 y0 y6 }+ o( I; i! ~% v
三、在KEIL 5中编写代码5 M7 j) G0 b. W6 J
1、使用KEIL 5(MDK)打开项目工程文件
3 Y8 T3 N& P4 {# r/ I
(1)找到刚才新建工程的存储路径,安装项目名称,打开项目工程。% b9 D8 w# d$ g

+ X* ^8 B5 C: j3 V
089f22b1faf8419f8f1fb3830cea3e8b.png
8 _+ q1 ~: s/ ^. V2 A4 G/ z6 [0 e% H3 T# D6 G
(2)添加每隔500ms,LED1闪烁一次的系统提示,用于提示程序运行正常。
; W$ D5 [' j, J! y2 V0 }' Q2 ^8 Y8 N2 x9 @
6ab72ceaeb7a41af833842fe5ba6f34d.png : A7 j' {$ i% b: g% ~$ F; e
3 C5 R1 i* O7 Z8 _# I
2、添加使用printf函数打印log的代码! T' @7 I7 ?/ y7 d- z6 I" K9 V( j
(1)在项目选项中勾选Use Micro LIB选项,勾选该项目后,可以正常使用基本的C语言库。
- p# z7 B2 @$ ~2 J) Z
& n' u* o6 F& m3 Y& U! S' J" b
3db54bee7a3e4fb78ecb85f0c26ece57.png 1 X) x# t5 [# z* y5 }1 N
& k1 @1 l8 q* V5 _+ }" u
(2)printf函数会调用fputs函数,fputs函数为弱定义函数,即使用__weak修饰符修饰的函数,可通过自己编写函数定义覆盖原定义,我们在此处重写fputs函数。在usart.c中添加如下代码。) e, Z& Q( c5 f$ f7 W; k6 Q
备注:开发者自己的代码需要注意添加位置,一定要放置到一对《USER CODE BEGIN和USER CODE END》之间,避免重新生成工程后被覆盖。1 X0 d/ j; b9 J+ K( q! h; {

8 W0 s- m8 F2 e2 E
607544c9bb2b4ca995be69d71d763526.png
3 N6 U/ i5 a6 N; N

) r& ?1 u. Q5 V; K; c 代码段如下:可直接复制使用。5 x  q& B4 U$ }- B+ _: m" L* @
  1. /* USER CODE BEGIN 1 */' l0 H; c! K6 V: z. u
  2. + a, o9 O% X3 Q" |! L* C, s
  3. #include <stdio.h>
    * W' O2 ?# i+ e
  4. #ifdef __GNUC__* a) s1 E1 i- I) `% C1 ]% Y
  5.         #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
    0 Q$ Q* L. S2 T. a9 r
  6. #else( T3 C0 S/ H. l- B/ ~7 M( k1 Q6 t
  7.         #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f): R( v9 W, V2 I" M" q+ s7 o
  8. #endif2 [4 B) I5 d7 M" X) B
  9. PUTCHAR_PROTOTYPE6 Y& Y8 X( I5 b
  10. {, h2 q7 L0 q7 f5 u* F  P: ^
  11.                 HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
    $ R4 j0 o" s2 u; ?$ @
  12.                 return ch;' Q# L- r1 }6 U* j3 L5 Z
  13. }8 F0 x' Z" b4 @1 F
  14. . i0 e/ V& F; F" {; |. v

  15. 4 s# ^. I% }  s/ r
  16. /* USER CODE END 1 */
复制代码

; h6 R% ~4 B2 ]* r$ X9 `
. i# W. C; }8 x
(3)使用printf打印log数据。需要注意main.c位置添加"stdio.h"头文件(printf的函数声明头文件)。

6 b$ V% x! ]) ]" A: X! q4 T# H- }2 ~+ L9 \
ad684ef90b44425198d2cd6b046d6d5b.png 4 A. e3 Q* S( V2 U# D
" r- D1 v% k  |  l3 C7 W% W( u) z
  1. printf("hello world,this is printf function!\r\n");   //printf 打印函数
    0 {/ C- t: [8 i! {5 q
复制代码

: m& i; O4 |) g1 X+ y& M' K 3、在w25qxx.c文件中添加SPI底层驱动函数
" T2 u. j/ o( I- l7 I0 p
  1. #include "main.h"
    8 S1 \' o) f: s, ]
  2. #include "spi.h"2 @% d$ E, f3 @
  3. #include "w25qxx.h"
    7 z/ ^; N" j( w- |
  4. /**
    3 ?6 U" {# d( @4 U3 M
  5.   * @brief SPI1 读一个字节
      _+ y$ a0 S5 n: M& e' ?! `
  6.   * @param None) L% m% K* ~! f: O+ N
  7.   * @retval None3 L  ]* n! H/ ^
  8.   */
    / Q1 v8 q. J* b+ y
  9. static uint8_t spi2_flash_read_byte(void)
    8 _; S- A+ Y* b/ y
  10. {5 k1 P2 o# M9 k1 E+ K. ^8 ?7 c
  11.     uint8_t t_data, r_data;
      F4 K9 |2 v$ @! h+ F! ^
  12. $ p1 n" Z" s  \! G8 g, [) }
  13.     if(HAL_SPI_TransmitReceive(&hspi2, &t_data, &r_data, 1, 0xFFFFFF) != HAL_OK)
    ' }5 a& x# d& Y2 Z
  14.     {
    - G# N- b" ?/ {+ P, J7 x/ v# b
  15.         r_data = 0xff;
    % d  K2 x3 S* M0 b+ y
  16.     }
    ' L6 O. Y0 W/ t, c
  17.     return r_data;  R$ V8 E% R6 e* Z
  18. }
    : I; m& p. P/ G
  19. /**1 H) [6 x: a4 I' s' h( h9 ?2 x
  20.   * @brief SPI1 写一个字节
    / x- W- S* G& e" [  a
  21.   * @param byte 写入的字节% x" W2 S! n; o8 L' m' ~; t+ G) h2 u
  22.   * @retval 写状态 0成功 1失败) z% W2 D' Q3 ^" f6 k1 g
  23.   */( U8 P  E1 x. S) B$ |
  24. static uint8_t spi2_flash_send_byte(uint8_t byte)* Z5 r, R% V7 ^/ k4 M
  25. {
    7 {- o" z4 ~6 O: j9 O0 }% T
  26.     uint8_t r_data;
    * I' i9 q' r4 [/ C, V+ ~

  27. 4 o% x2 z. k: t# d; A
  28.     if(HAL_SPI_TransmitReceive(&hspi2, &byte, &r_data, 1, 0xFFFFFF) != HAL_OK)
    : Y, Q6 Q9 }2 r5 r
  29.     {
    ' f  r$ T" D" k
  30.       return 1;
      H7 k. \9 P( f% }
  31.     }! O; P' A( ~- y- }: e
  32.     return 0;
    % A4 G; U7 l( [5 d
  33. }2 i  C+ \/ s* Z
  34. /**. y/ T# b9 x* w6 A
  35.   * @brief FLASH 写使能
    / L% C+ R, Z/ H8 u/ c" l
  36.   * @param None3 e5 u' A# l8 B1 V5 e( ]3 `
  37.   * @retval None# t! k9 ~2 S$ G8 `& b
  38.   */7 D; V! N8 |! v9 O" I# H6 \
  39. static void spi2_flash_write_enable(void)& ]9 P% ]4 e4 c4 z+ A2 k, z
  40. {' u8 l1 B! ?$ Y+ e
  41.     SPI_FLASH_CS_LOW();, x5 c8 S0 q% x3 N& d
  42.     spi2_flash_send_byte(W25X_WriteEnable);
    ! P4 e  p6 y" z: }) e1 K. L( r7 c4 s" f
  43.     SPI_FLASH_CS_HIGH();
    " x& M' c0 K8 J; ?
  44. }) i3 y' }. b" `; ^
  45. /**
    $ p6 [1 e/ c  r5 P) O" x" ^- b
  46.   * @brief FLASH 等待写结束: s6 c. `8 B( }2 A7 n; y  j
  47.   * @param None
    % \+ ^' P, D/ y3 B; h  Z$ P4 B
  48.   * @retval None9 R) ?& Q/ E8 u# Z
  49.   */" k! r% r$ t, H0 Q& y) l
  50. static void spi2_flash_wait_for_write_end(void)4 t( }( M' ?! k2 R+ d* t5 o% m4 ?6 r
  51. {8 W2 z0 K0 ~# n  S
  52.   uint8_t state = 0;
    4 N9 W* L0 `1 q

  53. & d5 `% ?' s) Y
  54.    SPI_FLASH_CS_LOW();! O9 D$ o* k, G. d; n, J0 E# m
  55. , v3 x# z1 `; e
  56.                 spi2_flash_send_byte(W25X_ReadStatusReg);
    1 y/ W# \$ ^0 s- H: t
  57. 8 K+ @' n, K4 v4 p* Q
  58.   do
    " S$ h4 }0 H" t( u1 U. R* P
  59.   {
    * ]) h1 ~9 V* ^
  60.       state = spi2_flash_read_byte();
    , l6 i; G, ~% |7 P- k# m; {
  61.   }
    ; J5 j: d) V0 @  u& _" u; Y
  62.   while((state & 0x01) == SET);
    6 S( V9 q! }5 I2 a1 e  z% G

  63. 7 ^; r# L+ J3 z& E6 k1 @% @" Y7 J
  64.   SPI_FLASH_CS_HIGH();' b0 k  c# ~# U" h
  65. }8 M0 p, T9 _! p
  66. /**
    , R( x1 @. q" ?! h* R% a$ I# f5 g
  67.   * @brief FLASH 读ID
    & q) q: j. E- e& B
  68.   * @param None
    ) k1 ~6 a' ~. A" O5 H1 ?
  69.   * @retval None. w* B- y! d0 N! q/ H9 j
  70.   */
    , s9 P9 h: C- J4 H& j. K" _
  71. uint32_t spi_flash_read_ID(void)! v+ d4 }" L+ f- `. N4 k% r0 F" y& M
  72. {# |) \) r- f- L
  73.   uint32_t temp, temp0, temp1, temp2;6 U" e" |% i' A) o

  74. ! u6 z$ _+ g7 _, E4 m
  75.   SPI_FLASH_CS_LOW();
    5 n  ^4 k) h8 _) |, O
  76.   spi2_flash_send_byte(W25X_JedecDeviceID);
    0 v  `# [/ ^( w# l5 I
  77. # }2 u3 Q4 o  i0 b% I% Y
  78.   temp0 = spi2_flash_read_byte();' t# Q# D9 K- e9 X
  79.   temp1 = spi2_flash_read_byte();" p" l* }# {, x- `" y
  80.   temp2 = spi2_flash_read_byte();
    2 `" \; B/ w# V* A5 v; b5 ^8 \

  81. : ?4 B, a9 R  ?8 r7 D4 Q
  82.         SPI_FLASH_CS_HIGH();3 A0 f! S' Q' O
  83. & ?3 _; R+ v% R. p
  84.   temp = (temp0 << 16) | (temp1 << 8) | temp2;; ^' p6 U4 y9 ~4 M8 I$ b

  85. 7 o$ P6 s! B% b
  86.   return temp;
      B+ E- V$ Y& c! O, C5 ]9 E
  87. }8 |4 j6 x; i: @  _! S8 }  E
  88. /**; I# s5 H+ v% h
  89.   * @brief 读FLASH9 h0 L4 v" k8 [/ v
  90.   * @param addr 读flash的起始地址
    $ R9 y. X5 |9 n8 o6 P
  91.   * @param pdata 读到的数据存放起始地址( _1 ^% l( U( m+ w3 T. F
  92.   * pdata size 读数据大小
    ) p) [) c1 l$ q4 b5 \8 q
  93.   * @retval None, p& i5 M) D& O
  94.   */
    ; X% A& q) _+ s- A: o
  95. void spi2_flash_read(uint32_t addr,uint8_t *pdata, uint16_t size)
    % o6 _6 A+ r/ D6 q* ^
  96. {
    5 S5 b) z: x" e
  97.    SPI_FLASH_CS_LOW();9 t4 w7 i1 f9 E4 S) I$ K# K2 v1 D
  98. : z& r/ c& t% G( w5 w! F
  99.   spi2_flash_send_byte(W25X_ReadData);
    # e4 G( q& G% P. K: L% H

  100. $ ?& ~! m) Z* M% l* A5 C! f8 D
  101.   spi2_flash_send_byte((addr & 0xFF0000) >> 16);' P: R: Y; F( q. y# t! A9 G
  102.   spi2_flash_send_byte((addr & 0xFF00) >> 8);6 O) J# E& {' u6 X  T
  103.   spi2_flash_send_byte(addr  & 0xFF);
    , v. X6 t' t6 l/ W) N! m! H! q; @* |
  104. . Q' f/ L* D% b( G: z. K
  105.   while (size--)% O7 Z/ V& B3 @! x6 l$ c' G. I
  106.   {5 H- F& w, p/ R7 `: Q/ u
  107.     *pdata = spi2_flash_read_byte();* p- f* _6 ]! D
  108.     pdata++;
    . f% U4 j7 t* s
  109.   }
    5 k" r" E( B6 t; q2 L
  110. * I: p  v3 b: Q9 \& v; g3 E
  111.         SPI_FLASH_CS_HIGH();
    0 [9 n' P8 |7 j2 {8 ~# U( R
  112. }
    ) p) t9 m' B$ L  s+ |" m' o
  113. /**
    9 \& g! R3 i  F( `
  114.   * @brief 按页写FLASH
    5 N8 F! z3 r1 C- W) ]' a
  115.   * @param addr 写入flash的起始地址: m* w/ S! b' V# `. ^
  116.   * @param pdata 写入数据的起始地址; I4 r8 D' B) }3 ?# G2 |: I! i
  117.   * pdata size 写数据大小
    . h8 ]: ?( d% ]# g' r
  118.   * @retval None; @3 u9 u. {- |
  119.   */* P, s( w1 v: r% f' {( t3 e
  120. void spi2_flash_page_write(uint32_t addr, uint8_t *pdata, uint16_t size)8 h) Y3 }* P8 L5 r7 \: c0 C$ m/ [7 m
  121. {
    * |6 \' H* z! X) u
  122.     uint16_t i;( x' a' T+ i- k, V  }) h

  123. # h+ G5 y' q2 b! P0 ?8 R6 e: k$ Q; }
  124.      spi2_flash_write_enable();9 z2 f+ }, _4 C( ?* n+ F
  125. 1 s9 i! w& m: c; o" {
  126.      SPI_FLASH_CS_LOW();
    " ~% l# \! i7 L1 X
  127. 2 R  H9 t" G4 o, h
  128.     spi2_flash_send_byte(W25X_PageProgram);+ h* \. G, G; X+ K" i2 N& l
  129.     spi2_flash_send_byte((uint8_t)((addr)>>16));, g" ]! X. f3 O1 P9 f% [
  130.     spi2_flash_send_byte((uint8_t)((addr)>>8));
    0 t) g8 i. o9 Z4 Z1 P$ a+ W" Y% ^
  131.     spi2_flash_send_byte((uint8_t)addr);
    9 `6 |: B# X5 `% ]1 k

  132. 8 u' v0 ~2 H7 |( q, ?$ s  W2 S
  133.     for(i = 0; i < size; i++)
    8 E6 t1 M% H7 \. W- W' E/ n' a8 h
  134.     {  }9 K1 O- j7 V+ Q4 C
  135.         spi2_flash_send_byte(pdata[i]);5 ]  }2 ~  V) n. m
  136.     }8 f- `8 _8 i7 }; v9 C2 _
  137. ! I* q4 D0 n# Q' z9 g* L3 Y  Y
  138.     SPI_FLASH_CS_HIGH();: v) T7 e, O4 r6 Y; V7 y
  139.     spi2_flash_wait_for_write_end();
      m9 U, Q3 B: s, X
  140. }
    ' `7 s  t2 }+ q
  141. /**
    4 S; q/ y$ f/ `
  142.   * @brief 写FLASH2 [; M' E% S  k% S
  143.   * @param addr 写入flash的起始地址6 ~. ^& `" w- W
  144.   * @param pdata 写入数据的起始地址' O6 O: P$ ]7 ~# T, ]3 \
  145.   * pdata size 写数据大小& n) `2 P8 w8 ]  ?
  146.   * @retval None1 d- g8 ?" y/ v/ Y) _" f
  147.   */( G" [" }. Y* B0 r1 O6 i# `
  148. void spi2_flash_write(uint32_t addr, uint8_t *pdata, uint32_t size)
    " M% ?0 U4 v6 l  z1 D/ ~
  149. {
    # g! ?2 Z, f3 ~* U! X
  150.     uint32_t page_remain;5 L  |* _( Z( ^

  151. 6 x% a6 P8 b- W
  152.     page_remain = 256 - addr%256;' X, j9 e% G& L9 R( t6 m4 g
  153. 5 ^. k  p1 s6 a9 s, K
  154.     if(size <= page_remain)
    ; o4 t1 Y' Z  A$ c& Y
  155.     {
    ) C, x% F, V1 o
  156.         page_remain = size;& }  ^! y6 \1 Z* E  m
  157.     }, ~1 B& C* ?* h  E4 G! |- U* a0 z
  158.     while(1)- J' r* f; f3 y$ _2 }
  159.     {
    - D  a6 p' k$ T) M& |
  160.         spi2_flash_page_write(addr, pdata, page_remain);
    7 y& `) w! j& m, p/ o! n7 g8 V
  161. 6 o: |" o) l& F! C$ l9 A$ ~
  162.         if(size == page_remain); Q8 D6 G. S( o* P( F9 D4 i
  163.             break;; M; I& A2 U4 d% r7 I( H
  164.          else" D4 w) \1 f/ q. T; C; Z' O# m
  165.         {
    & B* e# E; h* I- c: a1 P: O$ g
  166.              pdata += page_remain;% w: x+ h3 l2 I
  167.              addr += page_remain;" u# j" E2 z$ R6 t3 O

  168. 8 k5 I) e( E" {! Y- m7 `$ V' Y! l
  169.              size -= page_remain;
    7 V2 l9 g& j. j$ _( G6 j8 n
  170.             if(size > 256): U9 Z# Z( f( Z3 T3 x, q8 {
  171.                 page_remain = 256;
    ) P# Z6 V% e! i+ ]" w
  172.             else1 _6 ^% i3 d* F& }2 a  h( a( K$ a
  173.                 page_remain = size;" j: W* ~- {( B8 u5 [  c2 D
  174.         }
    8 @' R, k# y; N. _+ E
  175.     }
    8 I, P! e5 Q1 h8 m- I
  176. }) x# y' l8 [3 X/ R) ?9 w; `
  177. /**
    2 Z1 @: M; U' Q- P  f7 X
  178.   * @brief 擦除FLASH扇区
    2 [& y$ Q: N0 _5 ?) W  P6 W
  179.   * @param sector_addr 扇区的起始地址
    & f* c$ |/ }8 v6 K# ^. b  }
  180.   * @retval None1 v$ p' q' ]3 Z, v
  181.   */
    # l+ I  _* q3 f. O: m
  182. void spi2_flash_sector_erase(uint32_t sector_addr)% O( [: x: K$ [- b* C
  183. {
    $ Q" k& \1 ?* ]1 Z
  184.     spi2_flash_write_enable();( ?* e6 W1 e/ n
  185.     spi2_flash_wait_for_write_end();7 \! z& ~7 P1 u) K; n4 k- ~2 r$ g

  186. % F, m8 C& a+ T
  187.     SPI_FLASH_CS_LOW();( F8 K" b) l, g5 w7 P( }
  188.     spi2_flash_send_byte(W25X_SectorErase);, E0 w' _8 R  D* X/ R: q7 J4 U; K
  189.     spi2_flash_send_byte((sector_addr & 0xFF0000) >> 16);8 M: @5 B! G9 u; `4 Q
  190.     spi2_flash_send_byte((sector_addr & 0xFF00) >> 8);
    $ @0 l2 ^9 C, }* }# @" [1 k
  191.     spi2_flash_send_byte(sector_addr & 0xFF);- X/ {" W- r1 K3 ~5 m/ V

  192. 4 n6 [7 m; l5 @/ B
  193.     SPI_FLASH_CS_HIGH();
    : a9 `* ~7 d1 S4 W5 r

  194. 2 Z, F9 c5 r* t6 N
  195.     spi2_flash_wait_for_write_end();
    2 H0 W; G; o- W: h& h7 L; f
  196. }
    , y/ x% g) Z1 V3 V

  197. - {: q+ @/ I1 T+ \- T
  198. /**
    " w8 k- `: a5 Z( a, z1 k3 P8 S
  199.   * @brief 擦除FLASH块
    * [' m: j9 b/ r
  200.   * @param None/ e- C6 L5 C; e
  201.   * @retval None
    ' ?2 _- S- D/ r
  202.   */
    5 b9 z) l: K' }/ s# \" z7 z$ M
  203. void spi2_flash_block_erase(void)
    % x4 K: K1 H/ y0 U. E, \8 f, a
  204. {/ R! s" ], H+ X1 B; c
  205.     spi2_flash_write_enable();, X4 x/ N* ?7 s( F" s
  206. 7 |+ O* G" f9 u) M. d- e6 x$ r9 d: D
  207.     SPI_FLASH_CS_LOW();$ W$ Z5 E5 Z" G! O
  208.     spi2_flash_send_byte(W25X_ChipErase);1 z1 `+ |" w2 R
  209.     SPI_FLASH_CS_HIGH();# q3 S  i. B/ y& C- d8 ]! `5 w) q

  210. ! E5 p( t; V3 Y, n
  211.     spi2_flash_wait_for_write_end();5 Y2 M0 J; R' x# B& C2 G, h  J( d$ K
  212. }
    0 `' @* N( r9 J# d
复制代码
" ^$ h; z. s$ l2 B0 e7 e
0 P- ~0 O9 J9 e$ }% F
4、在main.c中添加功能函数* M) J/ l/ f1 f3 j- z9 B
  1. /**
    ! J5 b/ B9 x7 ^
  2.   * @brief  The application entry point.
    6 \* [( R% a9 r$ j
  3.   * @retval int
    : X6 C/ \' r# V/ o1 O5 h& n. \8 c
  4.   */
    5 _" @5 H- g, O; Z0 b; G. J
  5. int main(void)5 c4 N7 z) a+ j8 \/ B
  6. {7 R' e% {+ O( x
  7.   /* USER CODE BEGIN 1 */1 Q3 F) s8 u- t
  8.         uint32_t w25q_chip_id=0;                                                                                        //读取芯片ID/ s; M6 O  G* l  J. z6 o
  9.         uint8_t  onebyte_read[8]={0};                                                                                    //读取的数据) J: S6 [8 u0 w0 i0 T
  10.         uint8_t  onebyte_write[8]={0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80};                                //写入的数据
    / ^, @1 f1 X5 v8 u
  11.   /* USER CODE END 1 */* B; w6 {& Z- V, |/ t
  12.   
    . J) Y6 Y5 B% J

  13. ( Q, R% q' s7 G7 \$ ~$ V
  14.   /* MCU Configuration--------------------------------------------------------*/0 j+ `6 u4 R: c& |9 X" P
  15. $ i0 {% a$ c' ^+ l  W
  16.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */1 ?9 h) x, W# d1 P6 _& C
  17.   HAL_Init();
    7 k" s7 b# P, c. Q8 B; ~: d/ U
  18. 2 P* z6 H. g! }0 A. @
  19.   /* USER CODE BEGIN Init */
    " i. ~8 u: e9 _. x5 [( D& r

  20. ) ^; [9 \% N3 B* W! d4 A
  21.   /* USER CODE END Init */- o( I7 g+ w- M/ S
  22. . i/ F. P, R. ]3 N; ^" t5 h
  23.   /* Configure the system clock */
    7 v" x# h) \2 v+ }
  24.   SystemClock_Config();
    : I) \$ f: f6 A- b
  25. - \! k8 X) _3 @
  26.   /* USER CODE BEGIN SysInit */9 I* z- j* o; t* x
  27. 4 V6 @. }( I) O$ r( b- r0 e
  28.   /* USER CODE END SysInit *// X- `! [# w/ Q0 a2 f' K. ^
  29. ( |# q5 p4 R3 Z
  30.   /* Initialize all configured peripherals */
    . n) y7 W9 |: n
  31.   MX_GPIO_Init();2 E, d3 w. _7 x( k( x0 {3 _; Z
  32.   MX_DMA_Init();
    ' C$ N' L. r6 I) a9 J
  33.   MX_USART1_UART_Init();+ v% I* V# y2 _
  34.   MX_SPI2_Init();  W: M* j6 F  r9 `
  35.   /* USER CODE BEGIN 2 */! J9 N7 H& B& A2 ]0 j% B
  36.         HAL_GPIO_WritePin(GPIOC,GPIO_PIN_0,GPIO_PIN_SET);                                                                //初始化LED13 n  s! E& Y8 q+ P8 B6 T: O. i
  37.         w25q_chip_id=spi_flash_read_ID();                                                                                                                                //读取flash芯片ID
    3 c6 S7 B, Q( k9 z& {" x% \
  38.         HAL_Delay(100);3 p2 u7 @9 w; j
  39.         printf("hello world,spi_flash_read_ID==0x%0x!\r\n",w25q_chip_id); //printf 芯片ID
    8 ]8 [# ~, [8 r  o
  40.         spi2_flash_sector_erase(0x0);                                                                                                                                                        //写之前需要先擦除扇区                                                                                                                                       
    : K4 ]' \7 p4 c8 a% V) z3 u
  41.         spi2_flash_write(0x0,onebyte_write,8);                                                                                                                //写八个字节7 [# k: ]1 I  F: x
  42.         spi2_flash_read(0x00,onebyte_read,8);                                                                                                                        //读取写入的字节4 J* G7 U' b2 V# L* L5 a( {9 `
  43.   /* USER CODE END 2 */
    : c6 C7 i, p4 Y, ?+ f0 m8 T. M# y% ^

  44. $ M! }) @" u( d: _+ e. s6 B9 d* }2 k
  45.   /* Infinite loop *// K6 V! ?  _; m' J  y8 J# f6 o
  46.   /* USER CODE BEGIN WHILE */
    / R2 }3 Q! o- b0 }
  47.   while (1)
      K3 j" I6 _* s0 u" Z9 o( y
  48.   {: H( v: b# c# S8 s
  49.     /* USER CODE END WHILE */
    ) k5 r  l" t, d( k
  50. 9 Z, b8 }% z5 B' @; a
  51.     /* USER CODE BEGIN 3 */3 ]3 n" G$ Q9 v' u  [" \
  52.                                 HAL_Delay(500);
      \& F, k0 W* U+ D4 g0 T
  53.                                 HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);                                                                        //每隔500ms闪烁一次LED1& ?0 q' ]% n. P5 \
  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 . n- z6 B7 v( ]% `4 c6 s* t
  55.                                 
    / a) H  @" \  z$ I- E( Q' s! G$ Z
  56.   }
    1 B: ]+ ?% E9 X( H- d2 }) d- w. [+ y
  57.   /* USER CODE END 3 */
    : n: ~7 H  T3 s1 e, D/ R2 I' ?. G
  58. }
复制代码

7 j( c+ w* f: N# j/ Q5 J. P
4 d. j- Q5 D" y& z2 U 5、设置编程仿真下载模式
" ^$ P. X6 e8 u$ n
(1)选择Options for target ...>>Debug>>J-Link/J-JTRACE Cortex,点击Settings>>选择Port(SW),可以看到搜索成功SW Device,表示芯片可用,可以下载。
( F- S/ c2 _$ z7 X8 E9 {4 V$ U7 c
  h: b/ x! I4 }
edefb6b9a2a14be3b1221ad6d5c7a8a2.png 5 a# [5 |4 `) @! d% g7 p" U. C

" ^, a) L/ y; n- x5 I' v3 E+ |(2)点击Download(或者快捷键F8),即可下载程序。
; E; m8 X6 Q9 J( ^  e/ |& }* Q* n! L, \$ `; r$ t
ba221842d5db40808aa129dd83c593d0.png
) Y! D4 B, g! j& q
8 ?2 c' R/ u9 b# O8 |& F# {7 A
(3) 如果下载程序后,没有看到LED1灯闪烁,可以按下述方式设置一下(Reset and run表示下载后自动复位和重启运行)。或者重新彻底断电再次上电(或按开发板的Reset按键复位MCU即可)。
- y8 B+ b% J: J1 G
; N" |3 m8 D- F6 R/ m0 n
9f8aa1a4e8f04041bcf5cb183facd100.png 3 R; H; }  d" L2 L7 `3 ^2 C
% C7 w/ r2 ?3 B: U: T
6、查看串口printf函数打印log效果
1 R+ `0 e" E8 n/ F/ u4 o(1)设置串口助手参数为:115200、NONE、8、 1(和代码中串口初始化参数一致)。
2 f+ O' }4 l) O. j% K/ s9 N6 U(2)设置成功后,就可以看到串口打印的效果。每隔500ms闪烁LED1指示灯一次,且串口输出一个log。" S- T4 q% ?0 J4 a! u9 _: D1 o/ `$ p
' W/ \# b' E/ N
d829b0e14309464391254bf65851aca2.png
" o9 B$ T; P9 C6 ~
3 v. p$ J0 k( G3 i0 ~, C————————————————
0 D' ?' ]- y9 C版权声明:智能小屋ZYXC
" V6 j! i0 m1 W6 Z) f) ~' b2 ]7 N# m

# Z7 M! k* c' B% w& }$ d; A( Q
收藏 评论0 发布时间:2023-1-14 18:12

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版