当前位置:   article > 正文

学习STM32(5)--STM32单片机串口通信的应用_stm32 usart fasong

stm32 usart fasong

引 言 

        在嵌入式系统开发中,掌握各种外设接口的使用是关键技能之一。UART(通用异步收发传输器)和SPI(串行外围接口)是常见的通信接口,通过它们可以实现微控制器与外部设备之间的数据交换。本实验的目的是通过实际操作,熟悉STM32F103微控制器上UART1和SPI接口的配置与使用方法。

实验目的

1.掌握STM32F103的UART1的使用

2.掌握STM32F103的SPI读写的使用

实验内容

3.1通信概念及分类

        单片机为了拓展硬件资源需要和各种外设通信,有的传输距离远、有的需要传输速度快,有的需要抗干扰强,这就需要不同的通信方式。UART(通用异步收发传输器)和SPI(串行外围接口)是两种常用的通信接口。

        UART接口因其简单易用和稳定性高,被广泛应用于短距离、低速的通信场合。

        而SPI接口则因其高速和全双工通信特点,常用于需要快速数据传输的场合,如存储器读写、传感器数据采集等。

3.2数据传送的方式-串行通讯与并行通讯

串行通讯 USART /SPI:

1.设备之间通过少量数据信号线(一般是 8 根以下),地线以及控制信号线

2.按数据位形式一位一位地传输数据的通讯方式

并行通讯:

1.使用多个数据线进行传输

2.像多个车道的公路,可以同时传输多个数据位的数据

                                                图1 特性分析

3.3 数据通讯方向-全双工、半双工及单工通讯

根据数据通讯的方向,通讯又分为全双工、半双工及单工通讯:

1.全双工的通讯就是一个双向车道,两个方向上的车流互不相干;

2.半双工则像乡间小道那样,同一时刻只能让一辆小车通过,另一方向的来车只能等待道路 空出来时才能经过;

 3.单工则像单行道,另一方向的车辆完全禁止通行。

3.4数据同步方式-同步通讯与异步通讯

        同步通讯:收发设备双方会使用一根信号线表示时钟信号,在时钟信号的驱动下 双方进行协调,同步数据

        异步通讯:不使用时钟信号进行数据同步,它们直接在数据信号中穿插一些同步用的信号位,或者把主体数据进行打包,以数据帧的格式传输数据

3.5串口通讯硬件

串口通讯(Serial Communication)是一种设备间非常有用的串行通讯方式

1.简单双向串口通信有两根通信线(发送端TX和接收端RX)

2.TX与RX要交叉连接

3.当只需单向的数据传输时,可以只接一根通信线

4.当电平标准不一致时,需要加电平转换芯片

                                        图2 串口通讯接线图

3.6通信接口及协议

                                                      图3 各通信接口的通信协议

3.7串口协议层参数及时序

波特率:串口通信的速率, 如4800、9600、115200

起始位:标志一个数据帧的开始,固定为低电平

数据位:数据帧的有效载荷,1为高电平,0为低电平,低位先行

校验位:用于数据验证,根据数据位计算得来

停止位:用于数据帧间隔,固定为高电平

                                                        图4 串口协议时序

传输一帧数据示例

假设传输一帧包含8个数据位、1个校验位和1个停止位的数据帧,总长度为11位。

起始位:固定为0。

数据位:假设数据为 0b10101010(即十进制的170)。

校验位:根据奇偶校验规则计算(假设为偶校验)。

停止位:固定为1。

3.8 USART

USART:通用同步异步收发器 (Universal Synchronous Asynchronous Receiver and Transmitter)

串行通信设备,可以灵活地与外部设备进行全双工数据交换。

UART(Universal Asynchronous Receiver and Transmitter)它是在 USART 基础上裁剪掉了同步通信功能,只有异步通信。

简单区分同步和异步就是看通信时需不需要对外提供时钟输出,我们平时用的串口通信基本都是UART。

3.8.1 USART-功能引脚

TX发送数据输出引脚。

RX接收数据输入引脚。

nRTS: 将被设置为高电平。该引脚只适用于硬件流控制。

nCTS清除以发送(Clear To Send),n 表示低电平有效。如果使能CTS流控制,发送器在发送下一帧数据之前会检测nCTS引脚,如果为低电平,表示可以发送数据,如果为高电平则在发送完当前数据帧之后停止发送。该引脚只适用于硬件流控制。

SCLK发送器时钟输出引脚。这个引脚仅适用于同步模式。

                                                        图5 配置引脚图

3.8.2 USART-发送和接收控制器-标志位介绍

                                                图6 USART-发送和接收控制器

3.8.3 编程要点

(1) 使能 RX 和 TX 引脚 GPIO 时钟和 USART 时钟;

(2) 初始化 GPIO,并将 GPIO 复用到 USART 上;

(3) 配置 USART 参数;

(4) 配置中断控制器并使能 USART 接收中断;

(5) 使能 USART;

(6) 在 USART 接收中断服务函数实现数据接收和发送。

3.8.4 USART 实验步骤

硬件准备

开发板:确保开发板具有USART接口,并连接好所需的电缆。

电脑:配置好终端软件,如Tera Term、PuTTY或其他串行终端软件。

串口线:用于连接开发板和电脑的串口线。

通过USART进行串行通信,开发板发送字符串到电脑,并进入中断接收等待状态。电脑发送数据后,开发板产生中断并将接收到的数据返回发送给电脑

3.9 SPI

SPI(Serial Peripheral Interface)是一种同步,全双工支持总线挂载多设备(一主多从)的串行通信协议,通常用于短距离通信。它包含四条主要信号线:

NSS(Slave Select):选择从设备。

SCK(Serial Clock):时钟信号。

MOSI(Master Out Slave In):主机输出从机输入。

MISO(Master In Slave Out):主机输入从机输出。

在 SPI 通信中,NSS、SCK、MOSI 信号都由主机控制产生,而 MISO 信号由从机产生,主机通过该信号线读取从机的数据。MOSI 与 MISO 的信号只在 NSS 为低电平的时候才有效,在SCK 的每个时钟周期 MOSI 和 MISO 传输一位数据。

                                                                图7 SPI时序图

时序图说明

NSS 低电平:当 NSS 线为低电平时,SPI 通信开始,主机选择从机进行通信。在整个低电平期间,主机和从机之间的通信有效。

SCK 时钟信号:SCK 信号由主机产生,每一个时钟周期(即一个上升沿到下一个上升沿)代表一位数据的传输。在 SCK 的上升沿或下降沿(取决于 SPI 模式),MOSI 和 MISO 线上分别传输和接收数据位。

MOSI 数据传输:MOSI 线上,数据在 SCK 时钟信号的每个有效沿传输。

MISO 数据接收:MISO 线上,数据在 SCK 时钟信号的每个有效沿传输。

关键点

数据同步:SPI 是一种同步通信协议,数据传输和接收都由时钟信号(SCK)同步进行。

时钟极性和相位(SPI 模式):SCK 的上升沿或下降沿决定了数据的采样时间,这由 SPI 模式决定。常见的四种模式分别为:

模式0:CPOL = 0, CPHA = 0(时钟空闲状态为低电平,数据在上升沿采样)

模式1:CPOL = 0, CPHA = 1(时钟空闲状态为低电平,数据在下降沿采样)

模式2:CPOL = 1, CPHA = 0(时钟空闲状态为高电平,数据在下降沿采样)

模式3:CPOL = 1, CPHA = 1(时钟空闲状态为高电平,数据在上升沿采样)

3.9.1 SPI引脚

SPI 的所有硬件架构都从 MOSI、MISO、SCK 及 NSS 线展开的。

STM32 芯片有多个 SPI 外设,它们的 SPI 通讯信号引出到不同的 GPIO 引脚上,使用时必须配置到这些指定的引脚

                                                                图8 SPI引脚图

3.9.2 编程要点

(1) 初始化通讯使用的目标引脚及端口时钟;

(2) 使能 SPI 外设的时钟;

(3) 配置 SPI 外设的模式、地址、速率等参数并使能 SPI 外设;

(4) 编写基本 SPI 按字节收发的函数;

(5) 编写对 FLASH 擦除及读写操作的的函数;

(6) 编写测试程序,对读写数据进行校验。

3.9.3 SPI实验步骤

        本实验是一种使用 SPI 通讯的串行 FLASH 存储芯片的读写实验为大家讲解 STM32 的SPI 使用方法。 实验中 STM32 的 SPI 外设采用主模式,通过查询事件的方式来确保正常通讯。

        本实验板中的 FLASH 芯片(型号:W25Q64)是一种使用 SPI 通讯协议的 NOR FLASH 存储器,它的 CS/CLK/DIO/DO 引 脚分别连接到了STM32 对应的NSS/SCK/MOSI/MISO 的 SPI 引脚上

        SPI 的基本收发单元定义好,还需要了解如何对 FLASH 芯片进行读写。

        FLASH 芯片自定义了很多指令,我们通过控制 STM32 利用 SPI 总线向 FLASH 芯片发送指令,FLASH芯片收到后就会执行相应的操作。

4 深入解析

思考一(USART发送数据)

        实验例程提供的串口波特率是115200,数据位8,无校验位,1位停止位。设计程序,将上位机电脑端的波特率为9600实现单片机发送“Welcome to SZTU”;设计程序将上位机数据位设为7,校验位为Odd, 停止位为2,实现“THIS IS SGIM”。在单片机中通过寄存器进行初始化,改变波特率、奇偶校验、停止位等参数,如何设置串口助手参数实现信号的正确发送和接收?

                                                        图9 修改波特率

                                                      图10发送“Welcome to SZTU”

                                                        图11 usart配置修改

                                                        图12 发送“THIS IS SGIM”

                                                图13 设置串口助手参数

 main.c

  1. #include "stm32f10x.h"
  2. #include "bsp_usart.h"
  3. /**
  4. * @brief 主函数
  5. * @param 无
  6. * @retval 无
  7. */
  8. int main(void)
  9. {
  10. /*初始化USART 配置模式为 115200 8-N-1,中断接收*/
  11. USART_Config();
  12. /* 发送一个字符串 */
  13. Usart_SendString( DEBUG_USARTx,"THIS IS EAT\n");
  14. printf("吃货吃吃吃吃吃吃\n\n\n\n");
  15. while(1)
  16. {
  17. }
  18. }
  19. /*********************************************END OF FILE**********************/

bsp_usart.c 

  1. #include "bsp_usart.h"
  2. /**
  3. * @brief 配置嵌套向量中断控制器NVIC
  4. * @param 无
  5. * @retval 无
  6. */
  7. static void NVIC_Configuration(void)
  8. {
  9. NVIC_InitTypeDef NVIC_InitStructure;
  10. /* 嵌套向量中断控制器组选择 */
  11. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  12. /* 配置USART为中断源 */
  13. NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
  14. /* 抢断优先级*/
  15. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  16. /* 子优先级 */
  17. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  18. /* 使能中断 */
  19. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  20. /* 初始化配置NVIC */
  21. NVIC_Init(&NVIC_InitStructure);
  22. }
  23. /**
  24. * @brief USART GPIO 配置,工作参数配置
  25. * @param 无
  26. * @retval 无
  27. */
  28. void USART_Config(void)
  29. {
  30. GPIO_InitTypeDef GPIO_InitStructure;
  31. USART_InitTypeDef USART_InitStructure;
  32. // 打开串口GPIO的时钟
  33. DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
  34. // 打开串口外设的时钟
  35. DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);
  36. // 将USART Tx的GPIO配置为推挽复用模式
  37. GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;
  38. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  39. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  40. GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);
  41. // 将USART Rx的GPIO配置为浮空输入模式
  42. GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
  43. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  44. GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
  45. // 配置串口的工作参数
  46. // 配置波特率
  47. USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
  48. // 配置 针数据字长
  49. USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  50. // 配置停止位
  51. USART_InitStructure.USART_StopBits = USART_StopBits_2;
  52. // 配置校验位
  53. USART_InitStructure.USART_Parity = USART_Parity_Odd;
  54. // 配置硬件流控制
  55. USART_InitStructure.USART_HardwareFlowControl =
  56. USART_HardwareFlowControl_None;
  57. // 配置工作模式,收发一起
  58. USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  59. // 完成串口的初始化配置
  60. USART_Init(DEBUG_USARTx, &USART_InitStructure);
  61. // 串口中断优先级配置
  62. NVIC_Configuration();
  63. // 使能串口接收中断
  64. USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);
  65. // 使能串口
  66. USART_Cmd(DEBUG_USARTx, ENABLE);
  67. }
  68. /***************** 发送一个字节 **********************/
  69. void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
  70. {
  71. /* 发送一个字节数据到USART */
  72. USART_SendData(pUSARTx,ch);
  73. /* 等待发送数据寄存器为空 */
  74. while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
  75. }
  76. /****************** 发送8位的数组 ************************/
  77. void Usart_SendArray( USART_TypeDef * pUSARTx, uint8_t *array, uint16_t num)
  78. {
  79. uint8_t i;
  80. for(i=0; i<num; i++)
  81. {
  82. /* 发送一个字节数据到USART */
  83. Usart_SendByte(pUSARTx,array[i]);
  84. }
  85. /* 等待发送完成 */
  86. while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET);
  87. }
  88. /***************** 发送字符串 **********************/
  89. void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
  90. {
  91. unsigned int k=0;
  92. do
  93. {
  94. Usart_SendByte( pUSARTx, *(str + k) );
  95. k++;
  96. } while(*(str + k)!='\0');
  97. /* 等待发送完成 */
  98. while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET)
  99. {}
  100. }
  101. /***************** 发送一个16位数 **********************/
  102. void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch)
  103. {
  104. uint8_t temp_h, temp_l;
  105. /* 取出高八位 */
  106. temp_h = (ch&0XFF00)>>8;
  107. /* 取出低八位 */
  108. temp_l = ch&0XFF;
  109. /* 发送高八位 */
  110. USART_SendData(pUSARTx,temp_h);
  111. while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
  112. /* 发送低八位 */
  113. USART_SendData(pUSARTx,temp_l);
  114. while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
  115. }
  116. ///重定向c库函数printf到串口,重定向后可使用printf函数
  117. int fputc(int ch, FILE *f)
  118. {
  119. /* 发送一个字节数据到串口 */
  120. USART_SendData(DEBUG_USARTx, (uint8_t) ch);
  121. /* 等待发送完毕 */
  122. while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);
  123. return (ch);
  124. }
  125. ///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
  126. int fgetc(FILE *f)
  127. {
  128. /* 等待串口输入数据 */
  129. while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET);
  130. return (int)USART_ReceiveData(DEBUG_USARTx);
  131. }

bsp_usart.h

  1. #ifndef __USART_H
  2. #define __USART_H
  3. #include "stm32f10x.h"
  4. #include <stdio.h>
  5. /**
  6. * 串口宏定义,不同的串口挂载的总线和IO不一样,移植时需要修改这几个宏
  7. * 1-修改总线时钟的宏,uart1挂载到apb2总线,其他uart挂载到apb1总线
  8. * 2-修改GPIO的宏
  9. */
  10. // 串口1-USART1
  11. #define DEBUG_USARTx USART1
  12. #define DEBUG_USART_CLK RCC_APB2Periph_USART1
  13. #define DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd
  14. #define DEBUG_USART_BAUDRATE 115200
  15. // USART GPIO 引脚宏定义
  16. #define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA)
  17. #define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
  18. #define DEBUG_USART_TX_GPIO_PORT GPIOA
  19. #define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_9
  20. #define DEBUG_USART_RX_GPIO_PORT GPIOA
  21. #define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_10
  22. #define DEBUG_USART_IRQ USART1_IRQn
  23. #define DEBUG_USART_IRQHandler USART1_IRQHandler
  24. // 串口2-USART2
  25. //#define DEBUG_USARTx USART2
  26. //#define DEBUG_USART_CLK RCC_APB1Periph_USART2
  27. //#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
  28. //#define DEBUG_USART_BAUDRATE 115200
  29. USART GPIO 引脚宏定义
  30. //#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA)
  31. //#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
  32. //
  33. //#define DEBUG_USART_TX_GPIO_PORT GPIOA
  34. //#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_2
  35. //#define DEBUG_USART_RX_GPIO_PORT GPIOA
  36. //#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_3
  37. //#define DEBUG_USART_IRQ USART2_IRQn
  38. //#define DEBUG_USART_IRQHandler USART2_IRQHandler
  39. // 串口3-USART3
  40. //#define DEBUG_USARTx USART3
  41. //#define DEBUG_USART_CLK RCC_APB1Periph_USART3
  42. //#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
  43. //#define DEBUG_USART_BAUDRATE 115200
  44. USART GPIO 引脚宏定义
  45. //#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOB)
  46. //#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
  47. //
  48. //#define DEBUG_USART_TX_GPIO_PORT GPIOB
  49. //#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_10
  50. //#define DEBUG_USART_RX_GPIO_PORT GPIOB
  51. //#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_11
  52. //#define DEBUG_USART_IRQ USART3_IRQn
  53. //#define DEBUG_USART_IRQHandler USART3_IRQHandler
  54. // 串口4-UART4
  55. //#define DEBUG_USARTx UART4
  56. //#define DEBUG_USART_CLK RCC_APB1Periph_UART4
  57. //#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
  58. //#define DEBUG_USART_BAUDRATE 115200
  59. USART GPIO 引脚宏定义
  60. //#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOC)
  61. //#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
  62. //
  63. //#define DEBUG_USART_TX_GPIO_PORT GPIOC
  64. //#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_10
  65. //#define DEBUG_USART_RX_GPIO_PORT GPIOC
  66. //#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_11
  67. //#define DEBUG_USART_IRQ UART4_IRQn
  68. //#define DEBUG_USART_IRQHandler UART4_IRQHandler
  69. // 串口5-UART5
  70. //#define DEBUG_USARTx UART5
  71. //#define DEBUG_USART_CLK RCC_APB1Periph_UART5
  72. //#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
  73. //#define DEBUG_USART_BAUDRATE 115200
  74. USART GPIO 引脚宏定义
  75. //#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD)
  76. //#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
  77. //
  78. //#define DEBUG_USART_TX_GPIO_PORT GPIOC
  79. //#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_12
  80. //#define DEBUG_USART_RX_GPIO_PORT GPIOD
  81. //#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_2
  82. //#define DEBUG_USART_IRQ UART5_IRQn
  83. //#define DEBUG_USART_IRQHandler UART5_IRQHandler
  84. void USART_Config(void);
  85. void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch);
  86. void Usart_SendString( USART_TypeDef * pUSARTx, char *str);
  87. void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch);
  88. #endif /* __USART_H */

思考二(USART实现“地址码 功能码 校验码”的数据发送)

        为了确保通信的正确,降低误码率,工业使用异步串口通信通常需要设计一个协议标准,比如以“AA”表示开始,增加CRC校验作为结尾。设计程序实现“地址码 功能码 校验码”的数据发送。比如“AA 33 XX”,其中AA为地址码,33为发送的数据,XX是计算的CRC校验码(CRC校验可以参考网络CRC计算程序CRC(循环冗余校验)在线计算_ip33.com)。

                                                        图14 CRC计算代码

                                图15 实现“地址码 功能码 数据 校验码”发送的函数

                                                        图16 主函数

在bsp_usart.c中添加

  1. #define POLY 0x1021
  2. uint16_t calculate_crc(uint8_t *data, uint16_t length) {
  3. uint16_t crc = 0xFFFF;
  4. for (uint16_t i = 0; i < length; i++) {
  5. crc ^= (uint16_t)data[i] << 8;
  6. for (uint8_t j = 0; j < 8; j++) {
  7. if (crc & 0x8000) {
  8. crc = (crc << 1) ^ POLY;
  9. } else {
  10. crc = crc << 1;
  11. }
  12. }
  13. }
  14. return crc;
  15. }
  16. void send_packet(uint8_t address, uint8_t function, uint8_t data) {
  17. uint8_t packet[6];
  18. packet[0] = 0xAA; // 起始符
  19. packet[1] = address;
  20. packet[2] = function;
  21. packet[3] = data;
  22. uint16_t crc = calculate_crc(packet, 4);
  23. packet[4] = crc & 0xFF; // CRC低字节
  24. packet[5] = (crc >> 8) & 0xFF; // CRC高字节
  25. // 通过串口发送数据包
  26. for (int i = 0; i < 6; i++) {
  27. USART_SendData(DEBUG_USARTx, packet[i]);
  28. while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);
  29. }
  30. }

思考三 (SPI流程)

        画出SPI_FLASH_BufferWrite和SPI_FLASH_BufferRead的流程图,具体到CS, MOSI,MISO,CLK信号值。基于例 程,设计程序实现将“SZTU”存入SPI Flash, 并通过读出值判读存入数据是否正确。

SPI_FLASH_BufferWrite 流程图

启动信号传输:拉低CS(Chip Select)使设备处于选中状态。

发送写入命令:通过MOSI(Master Out Slave In)发送写入命令。

发送地址:通过MOSI发送数据要写入的起始地址。

写入数据:通过MOSI发送数据。

停止信号传输:拉高CS结束写入过程。

SPI_FLASH_BufferRead 流程图

启动信号传输:拉低CS。

发送读取命令:通过MOSI发送读取命令。

发送地址:通过MOSI发送要读取数据的起始地址。

读取数据:通过MISO(Master In Slave Out)接收数据。

停止信号传输:拉高CS结束读取过程。

                                                图17 SPI_FLASH_BufferWrite流程图

                                        图18 SPI_FLASH_BufferRead流程图

                                                图19 读写页面流程图

                                                       图20 发送缓冲区写入SZTU

                图21 将“SZTU”存入SPI Flash, 并通过读出值判读存入数据是否正确

bsp_spi_flash.c

  1. #include "./flash/bsp_spi_flash.h"
  2. static __IO uint32_t SPITimeout = SPIT_LONG_TIMEOUT;
  3. static uint16_t SPI_TIMEOUT_UserCallback(uint8_t errorCode);
  4. /**
  5. * @brief SPI_FLASH初始化
  6. * @param 无
  7. * @retval 无
  8. */
  9. void SPI_FLASH_Init(void)
  10. {
  11. SPI_InitTypeDef SPI_InitStructure;
  12. GPIO_InitTypeDef GPIO_InitStructure;
  13. /* 使能SPI时钟 */
  14. FLASH_SPI_APBxClock_FUN ( FLASH_SPI_CLK, ENABLE );
  15. /* 使能SPI引脚相关的时钟 */
  16. FLASH_SPI_CS_APBxClock_FUN ( FLASH_SPI_CS_CLK|FLASH_SPI_SCK_CLK|
  17. FLASH_SPI_MISO_PIN|FLASH_SPI_MOSI_PIN, ENABLE );
  18. /* 配置SPI的 CS引脚,普通IO即可 */
  19. GPIO_InitStructure.GPIO_Pin = FLASH_SPI_CS_PIN;
  20. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  21. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  22. GPIO_Init(FLASH_SPI_CS_PORT, &GPIO_InitStructure);
  23. /* 配置SPI的 SCK引脚*/
  24. GPIO_InitStructure.GPIO_Pin = FLASH_SPI_SCK_PIN;
  25. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  26. GPIO_Init(FLASH_SPI_SCK_PORT, &GPIO_InitStructure);
  27. /* 配置SPI的 MISO引脚*/
  28. GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MISO_PIN;
  29. GPIO_Init(FLASH_SPI_MISO_PORT, &GPIO_InitStructure);
  30. /* 配置SPI的 MOSI引脚*/
  31. GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MOSI_PIN;
  32. GPIO_Init(FLASH_SPI_MOSI_PORT, &GPIO_InitStructure);
  33. /* 停止信号 FLASH: CS引脚高电平*/
  34. SPI_FLASH_CS_HIGH();
  35. /* SPI 模式配置 */
  36. // FLASH芯片 支持SPI模式0及模式3,据此设置CPOL CPHA
  37. SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
  38. SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
  39. SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
  40. SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
  41. SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
  42. SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
  43. SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
  44. SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
  45. SPI_InitStructure.SPI_CRCPolynomial = 7;
  46. SPI_Init(FLASH_SPIx , &SPI_InitStructure);
  47. /* 使能 SPI */
  48. SPI_Cmd(FLASH_SPIx , ENABLE);
  49. }
  50. /**
  51. * @brief 擦除FLASH扇区
  52. * @param SectorAddr:要擦除的扇区地址
  53. * @retval 无
  54. */
  55. void SPI_FLASH_SectorErase(u32 SectorAddr)
  56. {
  57. /* 发送FLASH写使能命令 */
  58. SPI_FLASH_WriteEnable();
  59. SPI_FLASH_WaitForWriteEnd();
  60. /* 擦除扇区 */
  61. /* 选择FLASH: CS低电平 */
  62. SPI_FLASH_CS_LOW();
  63. /* 发送扇区擦除指令*/
  64. SPI_FLASH_SendByte(W25X_SectorErase);
  65. /*发送擦除扇区地址的高位*/
  66. SPI_FLASH_SendByte((SectorAddr & 0xFF0000) >> 16);
  67. /* 发送擦除扇区地址的中位 */
  68. SPI_FLASH_SendByte((SectorAddr & 0xFF00) >> 8);
  69. /* 发送擦除扇区地址的低位 */
  70. SPI_FLASH_SendByte(SectorAddr & 0xFF);
  71. /* 停止信号 FLASH: CS 高电平 */
  72. SPI_FLASH_CS_HIGH();
  73. /* 等待擦除完毕*/
  74. SPI_FLASH_WaitForWriteEnd();
  75. }
  76. /**
  77. * @brief 擦除FLASH扇区,整片擦除
  78. * @param 无
  79. * @retval 无
  80. */
  81. void SPI_FLASH_BulkErase(void)
  82. {
  83. /* 发送FLASH写使能命令 */
  84. SPI_FLASH_WriteEnable();
  85. /* 整块 Erase */
  86. /* 选择FLASH: CS低电平 */
  87. SPI_FLASH_CS_LOW();
  88. /* 发送整块擦除指令*/
  89. SPI_FLASH_SendByte(W25X_ChipErase);
  90. /* 停止信号 FLASH: CS 高电平 */
  91. SPI_FLASH_CS_HIGH();
  92. /* 等待擦除完毕*/
  93. SPI_FLASH_WaitForWriteEnd();
  94. }
  95. /**
  96. * @brief 对FLASH按页写入数据,调用本函数写入数据前需要先擦除扇区
  97. * @param pBuffer,要写入数据的指针
  98. * @param WriteAddr,写入地址
  99. * @param NumByteToWrite,写入数据长度,必须小于等于SPI_FLASH_PerWritePageSize
  100. * @retval 无
  101. */
  102. void SPI_FLASH_PageWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)
  103. {
  104. /* 发送FLASH写使能命令 */
  105. SPI_FLASH_WriteEnable();
  106. /* 选择FLASH: CS低电平 */
  107. SPI_FLASH_CS_LOW();
  108. /* 写页写指令*/
  109. SPI_FLASH_SendByte(W25X_PageProgram);
  110. /*发送写地址的高位*/
  111. SPI_FLASH_SendByte((WriteAddr & 0xFF0000) >> 16);
  112. /*发送写地址的中位*/
  113. SPI_FLASH_SendByte((WriteAddr & 0xFF00) >> 8);
  114. /*发送写地址的低位*/
  115. SPI_FLASH_SendByte(WriteAddr & 0xFF);
  116. if(NumByteToWrite > SPI_FLASH_PerWritePageSize)
  117. {
  118. NumByteToWrite = SPI_FLASH_PerWritePageSize;
  119. FLASH_ERROR("SPI_FLASH_PageWrite too large!");
  120. }
  121. /* 写入数据*/
  122. while (NumByteToWrite--)
  123. {
  124. /* 发送当前要写入的字节数据 */
  125. SPI_FLASH_SendByte(*pBuffer);
  126. /* 指向下一字节数据 */
  127. pBuffer++;
  128. }
  129. /* 停止信号 FLASH: CS 高电平 */
  130. SPI_FLASH_CS_HIGH();
  131. /* 等待写入完毕*/
  132. SPI_FLASH_WaitForWriteEnd();
  133. }
  134. /**
  135. * @brief 对FLASH写入数据,调用本函数写入数据前需要先擦除扇区
  136. * @param pBuffer,要写入数据的指针
  137. * @param WriteAddr,写入地址
  138. * @param NumByteToWrite,写入数据长度
  139. * @retval 无
  140. */
  141. void SPI_FLASH_BufferWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)
  142. {
  143. u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;
  144. /*mod运算求余,若writeAddr是SPI_FLASH_PageSize整数倍,运算结果Addr值为0*/
  145. Addr = WriteAddr % SPI_FLASH_PageSize;
  146. /*count个数据值,刚好可以对齐到页地址*/
  147. count = SPI_FLASH_PageSize - Addr;
  148. /*计算出要写多少整数页*/
  149. NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
  150. /*mod运算求余,计算出剩余不满一页的字节数*/
  151. NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
  152. /* Addr=0,则WriteAddr 刚好按页对齐 aligned */
  153. if (Addr == 0)
  154. {
  155. /* NumByteToWrite < SPI_FLASH_PageSize */
  156. if (NumOfPage == 0)
  157. {
  158. SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
  159. }
  160. else /* NumByteToWrite > SPI_FLASH_PageSize */
  161. {
  162. /*先把整数页都写了*/
  163. while (NumOfPage--)
  164. {
  165. SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
  166. WriteAddr += SPI_FLASH_PageSize;
  167. pBuffer += SPI_FLASH_PageSize;
  168. }
  169. /*若有多余的不满一页的数据,把它写完*/
  170. SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
  171. }
  172. }
  173. /* 若地址与 SPI_FLASH_PageSize 不对齐 */
  174. else
  175. {
  176. /* NumByteToWrite < SPI_FLASH_PageSize */
  177. if (NumOfPage == 0)
  178. {
  179. /*当前页剩余的count个位置比NumOfSingle小,一页写不完*/
  180. if (NumOfSingle > count)
  181. {
  182. temp = NumOfSingle - count;
  183. /*先写满当前页*/
  184. SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
  185. WriteAddr += count;
  186. pBuffer += count;
  187. /*再写剩余的数据*/
  188. SPI_FLASH_PageWrite(pBuffer, WriteAddr, temp);
  189. }
  190. else /*当前页剩余的count个位置能写完NumOfSingle个数据*/
  191. {
  192. SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
  193. }
  194. }
  195. else /* NumByteToWrite > SPI_FLASH_PageSize */
  196. {
  197. /*地址不对齐多出的count分开处理,不加入这个运算*/
  198. NumByteToWrite -= count;
  199. NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
  200. NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
  201. /* 先写完count个数据,为的是让下一次要写的地址对齐 */
  202. SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
  203. /* 接下来就重复地址对齐的情况 */
  204. WriteAddr += count;
  205. pBuffer += count;
  206. /*把整数页都写了*/
  207. while (NumOfPage--)
  208. {
  209. SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
  210. WriteAddr += SPI_FLASH_PageSize;
  211. pBuffer += SPI_FLASH_PageSize;
  212. }
  213. /*若有多余的不满一页的数据,把它写完*/
  214. if (NumOfSingle != 0)
  215. {
  216. SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
  217. }
  218. }
  219. }
  220. }
  221. /**
  222. * @brief 读取FLASH数据
  223. * @param pBuffer,存储读出数据的指针
  224. * @param ReadAddr,读取地址
  225. * @param NumByteToRead,读取数据长度
  226. * @retval 无
  227. */
  228. void SPI_FLASH_BufferRead(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead)
  229. {
  230. /* 选择FLASH: CS低电平 */
  231. SPI_FLASH_CS_LOW();
  232. /* 发送 读 指令 */
  233. SPI_FLASH_SendByte(W25X_ReadData);
  234. /* 发送 读 地址高位 */
  235. SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);
  236. /* 发送 读 地址中位 */
  237. SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8);
  238. /* 发送 读 地址低位 */
  239. SPI_FLASH_SendByte(ReadAddr & 0xFF);
  240. /* 读取数据 */
  241. while (NumByteToRead--) /* while there is data to be read */
  242. {
  243. /* 读取一个字节*/
  244. *pBuffer = SPI_FLASH_SendByte(Dummy_Byte);
  245. /* 指向下一个字节缓冲区 */
  246. pBuffer++;
  247. }
  248. /* 停止信号 FLASH: CS 高电平 */
  249. SPI_FLASH_CS_HIGH();
  250. }
  251. /**
  252. * @brief 读取FLASH ID
  253. * @param 无
  254. * @retval FLASH ID
  255. */
  256. u32 SPI_FLASH_ReadID(void)
  257. {
  258. u32 Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0;
  259. /* 开始通讯:CS低电平 */
  260. SPI_FLASH_CS_LOW();
  261. /* 发送JEDEC指令,读取ID */
  262. SPI_FLASH_SendByte(W25X_JedecDeviceID);
  263. /* 读取一个字节数据 */
  264. Temp0 = SPI_FLASH_SendByte(Dummy_Byte);
  265. /* 读取一个字节数据 */
  266. Temp1 = SPI_FLASH_SendByte(Dummy_Byte);
  267. /* 读取一个字节数据 */
  268. Temp2 = SPI_FLASH_SendByte(Dummy_Byte);
  269. /* 停止通讯:CS高电平 */
  270. SPI_FLASH_CS_HIGH();
  271. /*把数据组合起来,作为函数的返回值*/
  272. Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2;
  273. return Temp;
  274. }
  275. /**
  276. * @brief 读取FLASH Device ID
  277. * @param 无
  278. * @retval FLASH Device ID
  279. */
  280. u32 SPI_FLASH_ReadDeviceID(void)
  281. {
  282. u32 Temp = 0;
  283. /* Select the FLASH: Chip Select low */
  284. SPI_FLASH_CS_LOW();
  285. /* Send "RDID " instruction */
  286. SPI_FLASH_SendByte(W25X_DeviceID);
  287. SPI_FLASH_SendByte(Dummy_Byte);
  288. SPI_FLASH_SendByte(Dummy_Byte);
  289. SPI_FLASH_SendByte(Dummy_Byte);
  290. /* Read a byte from the FLASH */
  291. Temp = SPI_FLASH_SendByte(Dummy_Byte);
  292. /* Deselect the FLASH: Chip Select high */
  293. SPI_FLASH_CS_HIGH();
  294. return Temp;
  295. }
  296. /*******************************************************************************
  297. * Function Name : SPI_FLASH_StartReadSequence
  298. * Description : Initiates a read data byte (READ) sequence from the Flash.
  299. * This is done by driving the /CS line low to select the device,
  300. * then the READ instruction is transmitted followed by 3 bytes
  301. * address. This function exit and keep the /CS line low, so the
  302. * Flash still being selected. With this technique the whole
  303. * content of the Flash is read with a single READ instruction.
  304. * Input : - ReadAddr : FLASH's internal address to read from.
  305. * Output : None
  306. * Return : None
  307. *******************************************************************************/
  308. void SPI_FLASH_StartReadSequence(u32 ReadAddr)
  309. {
  310. /* Select the FLASH: Chip Select low */
  311. SPI_FLASH_CS_LOW();
  312. /* Send "Read from Memory " instruction */
  313. SPI_FLASH_SendByte(W25X_ReadData);
  314. /* Send the 24-bit address of the address to read from -----------------------*/
  315. /* Send ReadAddr high nibble address byte */
  316. SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);
  317. /* Send ReadAddr medium nibble address byte */
  318. SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8);
  319. /* Send ReadAddr low nibble address byte */
  320. SPI_FLASH_SendByte(ReadAddr & 0xFF);
  321. }
  322. /**
  323. * @brief 使用SPI读取一个字节的数据
  324. * @param 无
  325. * @retval 返回接收到的数据
  326. */
  327. u8 SPI_FLASH_ReadByte(void)
  328. {
  329. return (SPI_FLASH_SendByte(Dummy_Byte));
  330. }
  331. /**
  332. * @brief 使用SPI发送一个字节的数据
  333. * @param byte:要发送的数据
  334. * @retval 返回接收到的数据
  335. */
  336. u8 SPI_FLASH_SendByte(u8 byte)
  337. {
  338. SPITimeout = SPIT_FLAG_TIMEOUT;
  339. /* 等待发送缓冲区为空,TXE事件 */
  340. while (SPI_I2S_GetFlagStatus(FLASH_SPIx , SPI_I2S_FLAG_TXE) == RESET)
  341. {
  342. if((SPITimeout--) == 0) return SPI_TIMEOUT_UserCallback(0);
  343. }
  344. /* 写入数据寄存器,把要写入的数据写入发送缓冲区 */
  345. SPI_I2S_SendData(FLASH_SPIx , byte);
  346. SPITimeout = SPIT_FLAG_TIMEOUT;
  347. /* 等待接收缓冲区非空,RXNE事件 */
  348. while (SPI_I2S_GetFlagStatus(FLASH_SPIx , SPI_I2S_FLAG_RXNE) == RESET)
  349. {
  350. if((SPITimeout--) == 0) return SPI_TIMEOUT_UserCallback(1);
  351. }
  352. /* 读取数据寄存器,获取接收缓冲区数据 */
  353. return SPI_I2S_ReceiveData(FLASH_SPIx );
  354. }
  355. /**
  356. * @brief 使用SPI发送两个字节的数据
  357. * @param byte:要发送的数据
  358. * @retval 返回接收到的数据
  359. */
  360. u16 SPI_FLASH_SendHalfWord(u16 HalfWord)
  361. {
  362. SPITimeout = SPIT_FLAG_TIMEOUT;
  363. /* 等待发送缓冲区为空,TXE事件 */
  364. while (SPI_I2S_GetFlagStatus(FLASH_SPIx , SPI_I2S_FLAG_TXE) == RESET)
  365. {
  366. if((SPITimeout--) == 0) return SPI_TIMEOUT_UserCallback(2);
  367. }
  368. /* 写入数据寄存器,把要写入的数据写入发送缓冲区 */
  369. SPI_I2S_SendData(FLASH_SPIx , HalfWord);
  370. SPITimeout = SPIT_FLAG_TIMEOUT;
  371. /* 等待接收缓冲区非空,RXNE事件 */
  372. while (SPI_I2S_GetFlagStatus(FLASH_SPIx , SPI_I2S_FLAG_RXNE) == RESET)
  373. {
  374. if((SPITimeout--) == 0) return SPI_TIMEOUT_UserCallback(3);
  375. }
  376. /* 读取数据寄存器,获取接收缓冲区数据 */
  377. return SPI_I2S_ReceiveData(FLASH_SPIx );
  378. }
  379. /**
  380. * @brief 向FLASH发送 写使能 命令
  381. * @param none
  382. * @retval none
  383. */
  384. void SPI_FLASH_WriteEnable(void)
  385. {
  386. /* 通讯开始:CS低 */
  387. SPI_FLASH_CS_LOW();
  388. /* 发送写使能命令*/
  389. SPI_FLASH_SendByte(W25X_WriteEnable);
  390. /*通讯结束:CS高 */
  391. SPI_FLASH_CS_HIGH();
  392. }
  393. /* WIP(busy)标志,FLASH内部正在写入 */
  394. #define WIP_Flag 0x01
  395. /**
  396. * @brief 等待WIP(BUSY)标志被置0,即等待到FLASH内部数据写入完毕
  397. * @param none
  398. * @retval none
  399. */
  400. void SPI_FLASH_WaitForWriteEnd(void)
  401. {
  402. u8 FLASH_Status = 0;
  403. /* 选择 FLASH: CS 低 */
  404. SPI_FLASH_CS_LOW();
  405. /* 发送 读状态寄存器 命令 */
  406. SPI_FLASH_SendByte(W25X_ReadStatusReg);
  407. /* 若FLASH忙碌,则等待 */
  408. do
  409. {
  410. /* 读取FLASH芯片的状态寄存器 */
  411. FLASH_Status = SPI_FLASH_SendByte(Dummy_Byte);
  412. }
  413. while ((FLASH_Status & WIP_Flag) == SET); /* 正在写入标志 */
  414. /* 停止信号 FLASH: CS 高 */
  415. SPI_FLASH_CS_HIGH();
  416. }
  417. //进入掉电模式
  418. void SPI_Flash_PowerDown(void)
  419. {
  420. /* 通讯开始:CS低 */
  421. SPI_FLASH_CS_LOW();
  422. /* 发送 掉电 命令 */
  423. SPI_FLASH_SendByte(W25X_PowerDown);
  424. /*通讯结束:CS高 */
  425. SPI_FLASH_CS_HIGH();
  426. }
  427. //唤醒
  428. void SPI_Flash_WAKEUP(void)
  429. {
  430. /*选择 FLASH: CS 低 */
  431. SPI_FLASH_CS_LOW();
  432. /* 发送 上电 命令 */
  433. SPI_FLASH_SendByte(W25X_ReleasePowerDown);
  434. /* 停止信号 FLASH: CS 高 */
  435. SPI_FLASH_CS_HIGH();
  436. }
  437. /**
  438. * @brief 等待超时回调函数
  439. * @param None.
  440. * @retval None.
  441. */
  442. static uint16_t SPI_TIMEOUT_UserCallback(uint8_t errorCode)
  443. {
  444. /* 等待超时后的处理,输出错误信息 */
  445. FLASH_ERROR("SPI 等待超时!errorCode = %d",errorCode);
  446. return 0;
  447. }
  448. /*********************************************END OF FILE**********************/

 bsp_spi_flash.h

  1. #ifndef __SPI_FLASH_H
  2. #define __SPI_FLASH_H
  3. #include "stm32f10x.h"
  4. #include <stdio.h>
  5. //#define sFLASH_ID 0xEF3015 //W25X16
  6. //#define sFLASH_ID 0xEF4015 //W25Q16
  7. //#define sFLASH_ID 0XEF4018 //W25Q128
  8. #define sFLASH_ID 0XEF4017 //W25Q64
  9. #define SPI_FLASH_PageSize 256
  10. #define SPI_FLASH_PerWritePageSize 256
  11. /*命令定义-开头*******************************/
  12. #define W25X_WriteEnable 0x06
  13. #define W25X_WriteDisable 0x04
  14. #define W25X_ReadStatusReg 0x05
  15. #define W25X_WriteStatusReg 0x01
  16. #define W25X_ReadData 0x03
  17. #define W25X_FastReadData 0x0B
  18. #define W25X_FastReadDual 0x3B
  19. #define W25X_PageProgram 0x02
  20. #define W25X_BlockErase 0xD8
  21. #define W25X_SectorErase 0x20
  22. #define W25X_ChipErase 0xC7
  23. #define W25X_PowerDown 0xB9
  24. #define W25X_ReleasePowerDown 0xAB
  25. #define W25X_DeviceID 0xAB
  26. #define W25X_ManufactDeviceID 0x90
  27. #define W25X_JedecDeviceID 0x9F
  28. /* WIP(busy)标志,FLASH内部正在写入 */
  29. #define WIP_Flag 0x01
  30. #define Dummy_Byte 0xFF
  31. /*命令定义-结尾*******************************/
  32. /*SPI接口定义-开头****************************/
  33. #define FLASH_SPIx SPI1
  34. #define FLASH_SPI_APBxClock_FUN RCC_APB2PeriphClockCmd
  35. #define FLASH_SPI_CLK RCC_APB2Periph_SPI1
  36. //CS(NSS)引脚 片选选普通GPIO即可
  37. #define FLASH_SPI_CS_APBxClock_FUN RCC_APB2PeriphClockCmd
  38. #define FLASH_SPI_CS_CLK RCC_APB2Periph_GPIOA
  39. #define FLASH_SPI_CS_PORT GPIOA
  40. #define FLASH_SPI_CS_PIN GPIO_Pin_4
  41. //SCK引脚
  42. #define FLASH_SPI_SCK_APBxClock_FUN RCC_APB2PeriphClockCmd
  43. #define FLASH_SPI_SCK_CLK RCC_APB2Periph_GPIOA
  44. #define FLASH_SPI_SCK_PORT GPIOA
  45. #define FLASH_SPI_SCK_PIN GPIO_Pin_5
  46. //MISO引脚
  47. #define FLASH_SPI_MISO_APBxClock_FUN RCC_APB2PeriphClockCmd
  48. #define FLASH_SPI_MISO_CLK RCC_APB2Periph_GPIOA
  49. #define FLASH_SPI_MISO_PORT GPIOA
  50. #define FLASH_SPI_MISO_PIN GPIO_Pin_6
  51. //MOSI引脚
  52. #define FLASH_SPI_MOSI_APBxClock_FUN RCC_APB2PeriphClockCmd
  53. #define FLASH_SPI_MOSI_CLK RCC_APB2Periph_GPIOA
  54. #define FLASH_SPI_MOSI_PORT GPIOA
  55. #define FLASH_SPI_MOSI_PIN GPIO_Pin_7
  56. #define SPI_FLASH_CS_LOW() GPIO_ResetBits( FLASH_SPI_CS_PORT, FLASH_SPI_CS_PIN )
  57. #define SPI_FLASH_CS_HIGH() GPIO_SetBits( FLASH_SPI_CS_PORT, FLASH_SPI_CS_PIN )
  58. /*SPI接口定义-结尾****************************/
  59. /*等待超时时间*/
  60. #define SPIT_FLAG_TIMEOUT ((uint32_t)0x1000)
  61. #define SPIT_LONG_TIMEOUT ((uint32_t)(10 * SPIT_FLAG_TIMEOUT))
  62. /*信息输出*/
  63. #define FLASH_DEBUG_ON 1
  64. #define FLASH_INFO(fmt,arg...) printf("<<-FLASH-INFO->> "fmt"\n",##arg)
  65. #define FLASH_ERROR(fmt,arg...) printf("<<-FLASH-ERROR->> "fmt"\n",##arg)
  66. #define FLASH_DEBUG(fmt,arg...) do{\
  67. if(FLASH_DEBUG_ON)\
  68. printf("<<-FLASH-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\
  69. }while(0)
  70. void SPI_FLASH_Init(void);
  71. void SPI_FLASH_SectorErase(u32 SectorAddr);
  72. void SPI_FLASH_BulkErase(void);
  73. void SPI_FLASH_PageWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite);
  74. void SPI_FLASH_BufferWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite);
  75. void SPI_FLASH_BufferRead(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead);
  76. u32 SPI_FLASH_ReadID(void);
  77. u32 SPI_FLASH_ReadDeviceID(void);
  78. void SPI_FLASH_StartReadSequence(u32 ReadAddr);
  79. void SPI_Flash_PowerDown(void);
  80. void SPI_Flash_WAKEUP(void);
  81. u8 SPI_FLASH_ReadByte(void);
  82. u8 SPI_FLASH_SendByte(u8 byte);
  83. u16 SPI_FLASH_SendHalfWord(u16 HalfWord);
  84. void SPI_FLASH_WriteEnable(void);
  85. void SPI_FLASH_WaitForWriteEnd(void);
  86. #endif /* __SPI_FLASH_H */

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Guff_9hys/article/detail/968515
推荐阅读
相关标签
  

闽ICP备14008679号