目录

  • 1、SPI简介
    • 1. SPI协议简介
  • 2.SPI物理层的特点
    • 2.1.SPI 的内部简明图
    • 2.2.物理层
  • 3.SPI的协议层
    • 3.1.SPI基本通讯过程
    • 3.2. 通讯的起始和停止信号
  • 3.3.数据有效性
  • 3.4.CPOL/CPHA及通讯模式
  • 4.STM32 的 SPI 特性及架构
    • 4.1.通讯引脚:
    • 4.2. 时钟控制逻辑(波特率发生器)
    • 4.3.数据控制逻辑
    • 4.4.整体控制逻辑
    • 4.5.通讯过程
  • 5.SPI 初始化结构体详解
  • 6.SPI-读写串行FLASH
    • 6.1.[FLASH简介](https://editor.csdn.net/md/?articleId=118969718)
    • 6.2.硬件设计
    • 6.3.软件设计
    • 6.4.代码详解
  • 7.代码
  • 工程文件

1、SPI简介

1. SPI协议简介

SPI协议是由摩托罗拉公司提出的通讯协议(Serial PeripheralInterface),即串行外围设备接口,是一种高速全双工同步的通信总线。并且在芯片的管脚上只占用四根线,节约了芯片的管脚,它被广泛地使用在ADC、LCD等设备与MCU间,要求通讯速率较高的场合。

2.SPI物理层的特点

2.1.SPI 的内部简明图

MISO 主设备数据输入,从设备数据输出。
MOSI 主设备数据输出,从设备数据输入。
SCLK 时钟信号,由主设备产生。
CS 从设备片选信号,由主设备控制。

2.2.物理层


SS:从每个从设备都有独立的这一条SS信号线,常称为片选信号线,也称为NSS、CS。
本信号线独占主机的一个引脚,即有多少个从设备,就有多少条片选信号线。I2C协议中通过设备地址来寻址、选中总线上的某个设备并与其进行通讯;而SPI协议中没有设备地址,它使用SS信号线来寻址,当主机要选择从设备时,把该从设备的SS信号线设置为低电平,该从设备即被选中,即片选有效,接着主机开始与被选中的从设备进行SPI通讯。所以SPI通讯以SS线置低电平为开始信号,以SS线被拉高作为结束信号。

SCK (Serial Clock):时钟信号线,用于通讯数据同步。
它由通讯主机产生,决定了通讯的速率,不同的设备支持的最高时钟频率不一样,如STM32的SPI时钟频率最大为fpclk/2,两个设备之间通讯时,通讯速率受限于低速设备。

MOSI (Master Output, Slave Input):主设备输出/从设备输入引脚。
主机的数据从这条信号线输出,从机由这条信号线读入主机发送的数据,即这条线上数据的方向为主机到从机。

MISO(Master Input,,Slave Output):主设备输入/从设备输出引脚。
主机从这条信号线读入数据,从机的数据由这条信号线输出到主机,即在这条线上数据的方向为从机到主机。

3.SPI的协议层

SPI协议定义了通讯的起始和停止信号、数据有效性、时钟同步等环节。

3.1.SPI基本通讯过程

3.2. 通讯的起始和停止信号


NSS信号线由高变低,是SPI通讯的起始信号。NSS是每个从机各
自独占的信号线,当从机检在自己的NSS线检测到起始信号后,就知道自己被主机选中了,开始准备与主机通讯。
NSS信号由低变高,是SPI通讯的停止信号,表示本次通
讯结束,从机的选中状态被取消。

3.3.数据有效性


SPI使用MOSI及MISO信号线来传输数据,使用SCK信号线进行数据同步。MOSI及MISO数据线在SCK的每个时钟周期传输一位数据,且数据输入输出是同时进行的。

3.4.CPOL/CPHA及通讯模式

由CPOL及CPHA的不同状态,SPI分成了四种模式,主机与从机需要工作在相同的模式下才可以正常通讯,实际中采用较多的是“模式0”与“式3”。

时钟极性CPOL是指SPI通讯设备处于空闲状态时,SCK信号线的电平信号(即SPI通讯开始前、 NSS线为高电平时SCK的状态)。
CPOL=0时, SCK在空闲状态时为低电平,CPOL=1时,则为高电平。

时钟相位CPHA是指数据的采样的时刻,当CPHA=0时,MOSI或MISO数据线上的信号将会在SCK时钟线的“奇数边沿”被采样。当CPHA=1时,数据线在SCK的“偶数边沿”采样。

总结:

4.STM32 的 SPI 特性及架构

4.1.通讯引脚:

● MISO:主设备输入/从设备输出引脚。该引脚在从模式下发送数据,在主模式下接收数据。
● MOSI:主设备输出/从设备输入引脚。该引脚在主模式下发送数据,在从模式下接收数据。
● SCK:串口时钟,作为主设备的输出,从设备的输入
● NSS:从设备选择。这是一个可选的引脚,用来选择主/从设备。

4.2. 时钟控制逻辑(波特率发生器)

SCK线的时钟信号,由波特率发生器根据“控制寄存器CR1”中的BR[0:2]位控制,该位是对fpclk时钟的分频因子,对fpclk的分频结果就是SCK引脚的输出时钟频率。

其中的fpclk频率是指SPI所在的APB总线频率,APB1为fpclk1(36MHZ),APB2为fpckl2(72MHZ)。

4.3.数据控制逻辑

SPI的MOSI及MISO都连接到数据移位寄存器上,数据移位寄存器的数据来源来源于接收缓冲区及发送缓冲区。
• 通过写SPI的“数据寄存器DR”把数据填充到发送缓冲区中。
• 通过读“数据寄存器DR”,可以获取接收缓冲区中的内容。
• 其中数据帧长度可以通过“控制寄存器CR1”的“DFF位”配置成8位及16位模式;配置“LSBFIRST位”可选择MSB先行还是LSB先行。

4.4.整体控制逻辑

• 整体控制逻辑负责协调整个SPI外设,控制逻辑的工作模式根据“控制寄存器(CR1/CR2)”的参数而改变,基本的控制参数包括前面提到的SPI模式、波特率、LSB先行、主从模式、单双向模式等等。

• 在外设工作时,控制逻辑会根据外设的工作状态修改“状态寄存器(SR)”,只要读取状态寄存器相关的寄存器位,就可以了解SPI的工作状态了。除此之外,控制逻辑还根据要求,负责控制产生SPI中断信号、DMA请求及控制NSS信号线。

• 实际应用中,一般不使用STM32 SPI外设的标准NSS信号线,而是更简单地使用普通的GPIO,软件控制它的电平输出,从而产生通讯起始和停止信号。

4.5.通讯过程

• 控制NSS信号线,产生起始信号(图中没有画出);
• 把要发送的数据写入到“数据寄存器DR”中,该数据会被存储到发
送缓冲区;
• 通讯开始,SCK时钟开始运行。MOSI把发送缓冲区中的数据一位
一位地传输出去;MISO则把数据一位一位地存储进接收缓冲区中;
• 当发送完一帧数据的时候,“状态寄存器SR”中的“TXE标志位”
会被置1,表示传输完一帧,发送缓冲区已空;类似地,当接收完
一帧数据的时候,“RXNE标志位”会被置1,表示传输完一帧,接
收缓冲区非空;
• 等待到“TXE标志位”为1时,若还要继续发送数据,则再次往
“数据寄存器DR”写入数据即可;等待到“RXNE标志位”为1时,通过读取“数据寄存器DR”可以获取接收缓冲区中的内容。

5.SPI 初始化结构体详解

typedef struct
{
uint16_t SPI_Direction; // 设置 SPI 的单双向模式
uint16_t SPI_Mode; // 设置 SPI 的主/从机端模式
uint16_t SPI_DataSize;// 设置 SPI 的数据帧长度,可选 8/16 位
uint16_t SPI_CPOL;// 设置时钟极性 CPOL,可选高/低电平
uint16_t SPI_CPHA; // 设置时钟相位,可选奇/偶数边沿采样
uint16_t SPI_NSS; // 设置 NSS 引脚由 SPI 硬件控制还是软件控制

uint16_t SPI_BaudRatePrescaler;//设置时钟分频因子,fpclk/分频数 =fSCK
uint16_t SPI_FirstBit; // 设置 MSB/LSB 先行
uint16_t SPI_CRCPolynomial; //设置 CRC 校验的表达式
} SPI_InitTypeDef;

SPI_Direction

本成员设置SPI的通讯方向,可设置为双线全双工

(SPI_Direction_2Lines_FullDuplex),双线只接收
(SPI_Direction_2Lines_RxOnly),单线只接收(SPI_Direction_1Line_Rx)、单线
(SPI_Direction_1Line_Tx)只发送模式。

SPI_Mode

本成员设置SPI工作在主机模式(SPI_Mode_Master)或从机模式(SPI_Mode_Slave),这两个模式的最大区别为SPI的SCK信号线的时序,SCK 的时序是由通讯中的主机产生的。若被配置为从机模式,STM32的SPI外设将接 受外来的SCK信号。

SPI_DataSize

本成员可以选择SPI通讯的数据帧大小是为8位(SPI_DataSize_8b)还是16位(SPI_DataSize_16b)。

SPI_CPOL

时钟极性CPOL成员,可设置为高电平(SPI_CPOL_High)或低电平 (SPI_CPOL_Low )。

SPI_CPHA

时钟相位CPHA 则可以设置为SPI_CPHA_1Edge(在SCK的奇数边沿采集数据) 或SPI_CPHA_2Edge
(在SCK的偶数边沿采集数据) 。

SPI_NSS

本成员配置NSS引脚的使用模式,可以选择为硬件模(SPI_NSS_Hard )与软件模式(SPI_NSS_Soft ),在硬件模式中的SPI片选信号由SPI硬件自动产生,而软件模式则需要亲自把相应的GPIO端口拉高或置低产生非片选和片选信号。

SPI_BaudRatePrescaler

本成员设置波特率分频因子,分频后的时钟即为SPI的SCK信号线的时钟频率。这个成员参数可设置为fpclk的2、4、6、8、16、32、64、128、256分频

SPI_FirstBit

所有串行的通讯协议都会有MSB先行(高位数据在前)还是LSB先行(低位数据在前)的问题,而STM32的SPI模块可以通过这个结构体成员,对该特性编程控制

•SPI_CRCPolynomial

这是SPI的CRC校验中的多项式,若我们使用CRC校验时,就使用这个成员的参数(多项式),来计算CRC的值。

6.SPI-读写串行FLASH

6.1.FLASH简介

FLSAH 存储器又称闪存,它与 EEPROM 都是掉电后数据不丢失的存储器,但 FLASH 存储器容量普遍大于 EEPROM,现在基本取代了它的地位。我们生活中常用的 U 盘、SD 卡、SSD 固态硬盘以及我们 STM32 芯片内部用于存储程序的设备,都是 FLASH 类型的存储器。在存储控制上,最主要的区别是 FLASH 芯片只能一大片一大片地写。

6.2.硬件设计

6.3.软件设计

编程要点
(1) 初始化通讯使用的目标引脚及端口时钟;
(2) 使能 SPI 外设的时钟;
(3) 配置 SPI 外设的模式、地址、速率等参数并使能 SPI 外设;
(4) 编写基本 SPI 按字节收发的函数;
(5) 编写对 FLASH 擦除及读写操作的的函数;
(6) 编写测试程序,对读写数据进行校验。

6.4.代码详解

初始化对应的GPIO

static void GPIO_Config(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,  ENABLE);GPIO_InitTypeDef   GPIO_InitStruct;GPIO_InitStruct.GPIO_Pin = SPI_SCK_PIN|SPI_MOSI_PIN;  //MOSI SCKGPIO_InitStruct.GPIO_Mode = SPI_SCK_Mode ;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB , &GPIO_InitStruct);GPIO_InitStruct.GPIO_Pin = SPI_MISO_PIN;   //MISOGPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING ;GPIO_Init(GPIOB , &GPIO_InitStruct);GPIO_InitStruct.GPIO_Pin = SPI_CS_PIN;   //CSGPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP ;GPIO_Init(GPIOx , &GPIO_InitStruct);}

初始化SPI

static void SPI_Config(void)
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);SPI_I2S_DeInit(SPI_x);SPI_InitTypeDef SPI_InitStructure; SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//全双工通信 SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置主SPISPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //数据大小为8bitSPI_InitStructure.SPI_CPOL = SPI_CPOL_High;   SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;    //模式3,(空闲时高电平,和偶数边采样)SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;   //软件触发SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;   //波特率设置SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB ;   //高位有效SPI_InitStructure.SPI_CRCPolynomial = 0; //数据不校验SPI_Init(SPI_x, &SPI_InitStructure); SPI_Cmd(SPI_x,ENABLE);
}

发送和接收一个字节数据(发送和接收同步进行)

u8 SPI_FLASH_SendByte(u8 byte)
{while (SPI_I2S_GetFlagStatus(SPI2 , SPI_I2S_FLAG_TXE) == RESET);  //判断发送缓存空标志位是否为空SPI_I2S_SendData(SPI_x , byte);while (SPI_I2S_GetFlagStatus(SPI2 , SPI_I2S_FLAG_RXNE) == RESET); //判断接收缓存空标志位是否为空return SPI_I2S_ReceiveData(SPI2 );
}

写入FLASH使能

void SPI_Write_Enable(void)  //写入FLASH使能
{CS_L;SPI_FLASH_SendByte(WriteEnable);  //0x06CS_H;
}

读设备ID

u32 SPI_FLASH_ReadID(void)
{u32 Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0;CS_L;  // 开始通讯:CS低电平 SPI_FLASH_SendByte(JEDEC_byte); //发送JEDEC(0x9f)指令,读取ID Temp0 = SPI_FLASH_SendByte(Dummy); // 读取一个字节数据 Temp1 = SPI_FLASH_SendByte(Dummy); // 读取一个字节数据 Temp2 = SPI_FLASH_SendByte(Dummy); // 读取一个字节数据 CS_H; // 停止通讯:CS高电平Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2;  //把数据组合起来,作为函数的返回值return Temp;
}

读取指定地址指定字节数据

void SPI_Read_data(uint32_t adder,uint8_t *pbuff,uint32_t numberbyte)
{/* 开始通讯:CS低电平 */CS_L;SPI_FLASH_SendByte(Read_Data);SPI_FLASH_SendByte((adder>>16)&0xff);SPI_FLASH_SendByte((adder>>16)&0xff);SPI_FLASH_SendByte(adder&0xff);while(numberbyte--){*pbuff = SPI_FLASH_SendByte(0x00);pbuff++;}CS_H;
}

擦除扇区

void SPI_Erase_Sector(uint32_t adder)  //擦除扇区 每次4KB
{SPI_Write_Enable();     //擦除的过程就是写1的过程,擦除前要使能SPI_WaitForWritend();CS_L;  //开始通讯:CS低电平 SPI_FLASH_SendByte(Erase_Sector); //0x20每次4kb,0x52擦除 32kb 0xD8擦除 64kbSPI_FLASH_SendByte((adder>>16)&0xff);SPI_FLASH_SendByte((adder>>16)&0xff);SPI_FLASH_SendByte(adder&0xff);CS_H; // 停止通讯:CS高电平 SPI_WaitForWritend();
}

等待FALSH内部时序操作完成

void SPI_WaitForWritend(void) //等待FALSH内部时序操作完成
{uint8_t  flag = 0;CS_L;SPI_FLASH_SendByte(0x05);do{flag = SPI_FLASH_SendByte(0x00);}while((flag&0x01 )== 1);  //读取状态寄存器 CS_H;  // 停止通讯:CS高电平 }

写入指定地址开始指定字节数的数据,每次最多256位

void SPI_Write_data(uint32_t adder,uint8_t *pbuffWrite,uint32_t numberbyte)
{SPI_Write_Enable();  //写入使能SPI_WaitForWritend();  //等待flash内部时序CS_L;  // 开始通讯:CS低电平SPI_FLASH_SendByte(Write_data);  //0x02SPI_FLASH_SendByte((adder>>16)&0xff);SPI_FLASH_SendByte((adder>>16)&0xff);SPI_FLASH_SendByte(adder&0xff);while(numberbyte--){SPI_FLASH_SendByte(*pbuffWrite);pbuffWrite++;}CS_H;SPI_WaitForWritend();}

休眠和唤醒

void SPI_Flash_PowerDown(void)    //进入掉电模式
{ CS_L;SPI_FLASH_SendByte(PowerDown);  //0xB9CS_H;
}   void SPI_Flash_WAKEUP(void)     //FLASH唤醒
{CS_L;// 开始通讯:CS低电平SPI_FLASH_SendByte(ReleasePowerDown); //0xABCS_H;
}   

7.代码

.c文件

#include "API.h"
static void GPIO_Config(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,  ENABLE);GPIO_InitTypeDef   GPIO_InitStruct;GPIO_InitStruct.GPIO_Pin = SPI_SCK_PIN|SPI_MOSI_PIN;  //MOSI SCKGPIO_InitStruct.GPIO_Mode = SPI_SCK_Mode ;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB , &GPIO_InitStruct);GPIO_InitStruct.GPIO_Pin = SPI_MISO_PIN;   //MISOGPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING ;GPIO_Init(GPIOB , &GPIO_InitStruct);GPIO_InitStruct.GPIO_Pin = SPI_CS_PIN;   //CSGPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP ;GPIO_Init(GPIOx , &GPIO_InitStruct);}
static void SPI_Config(void)
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);SPI_I2S_DeInit(SPI_x);SPI_InitTypeDef SPI_InitStructure; SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI_InitStructure.SPI_Mode = SPI_Mode_Master; SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;   SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;    //模式3SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB ;   //高位有效SPI_InitStructure.SPI_CRCPolynomial = 0; SPI_Init(SPI_x, &SPI_InitStructure); SPI_Cmd(SPI_x,ENABLE);}void SPIx_Init(void)
{GPIO_Config();SPI_Config();
}u8 SPI_FLASH_SendByte(u8 byte)
{while (SPI_I2S_GetFlagStatus(SPI2 , SPI_I2S_FLAG_TXE) == RESET);SPI_I2S_SendData(SPI_x , byte);while (SPI_I2S_GetFlagStatus(SPI2 , SPI_I2S_FLAG_RXNE) == RESET);return SPI_I2S_ReceiveData(SPI2 );
}void SPI_Write_Enable(void)  //写入FLASH使能
{CS_L;SPI_FLASH_SendByte(WriteEnable);CS_H;
}
u32 SPI_FLASH_ReadID(void)
{u32 Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0;CS_L;  // 开始通讯:CS低电平 SPI_FLASH_SendByte(JEDEC_byte); //发送JEDEC指令,读取ID Temp0 = SPI_FLASH_SendByte(Dummy); // 读取一个字节数据 Temp1 = SPI_FLASH_SendByte(Dummy); // 读取一个字节数据 Temp2 = SPI_FLASH_SendByte(Dummy); // 读取一个字节数据 CS_H; // 停止通讯:CS高电平Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2;  //把数据组合起来,作为函数的返回值return Temp;
}void SPI_Read_data(uint32_t adder,uint8_t *pbuff,uint32_t numberbyte)
{/* 开始通讯:CS低电平 */CS_L;SPI_FLASH_SendByte(Read_Data);SPI_FLASH_SendByte((adder>>16)&0xff);SPI_FLASH_SendByte((adder>>16)&0xff);SPI_FLASH_SendByte(adder&0xff);while(numberbyte--){*pbuff = SPI_FLASH_SendByte(0x00);pbuff++;}CS_H;
}void SPI_Erase_Sector(uint32_t adder)  //擦除扇区 每次4KB
{SPI_Write_Enable();     //擦除的过程就是写1的过程,擦除前要使能SPI_WaitForWritend();CS_L;  //开始通讯:CS低电平 SPI_FLASH_SendByte(Erase_Sector);SPI_FLASH_SendByte((adder>>16)&0xff);SPI_FLASH_SendByte((adder>>16)&0xff);SPI_FLASH_SendByte(adder&0xff);CS_H; // 停止通讯:CS高电平 SPI_WaitForWritend();
}void SPI_WaitForWritend(void) //等待FALSH内部时序操作完成
{uint8_t  flag = 0;CS_L;SPI_FLASH_SendByte(0x05);do{flag = SPI_FLASH_SendByte(0x00);}while((flag&0x01 )== 1);  //读取状态寄存器 CS_H;  // 停止通讯:CS高电平
}
void SPI_Write_data(uint32_t adder,uint8_t *pbuffWrite,uint32_t numberbyte)
{SPI_Write_Enable();  //写入使能SPI_WaitForWritend();  //等待flash内部时序CS_L;  // 开始通讯:CS低电平SPI_FLASH_SendByte(Write_data);SPI_FLASH_SendByte((adder>>16)&0xff);SPI_FLASH_SendByte((adder>>16)&0xff);SPI_FLASH_SendByte(adder&0xff);while(numberbyte--){SPI_FLASH_SendByte(*pbuffWrite);pbuffWrite++;  }CS_H;SPI_WaitForWritend();
}
void SPI_Flash_PowerDown(void)    //进入掉电模式
{ CS_L;SPI_FLASH_SendByte(PowerDown);CS_H;
}
void SPI_Flash_WAKEUP(void)     //FLASH唤醒
{CS_L;// 开始通讯:CS低电平SPI_FLASH_SendByte(ReleasePowerDown);CS_H;
}   

.h文件

#ifndef _API_H_
#define _API_H_
#include "stm32f10x.h"#define  SPI_SCK_PIN         GPIO_Pin_13 #define  SPI_SCK_Mode        GPIO_Mode_AF_PP#define  SPI_MISO_PIN        GPIO_Pin_14#define  SPI_MISO_Mode       GPIO_Mode_IN_FLOATING#define  SPI_MOSI_PIN        GPIO_Pin_15#define  SPI_MOSI_Mode       GPIO_Mode_AF_PP#define  SPI_CS_PIN          GPIO_Pin_12#define  SPI_CS_Mode         GPIO_Mode_Out_PP#define  GPIOx               GPIOB#define  CS_H                GPIO_SetBits( GPIOB,SPI_CS_PIN )#define  CS_L                GPIO_ResetBits( GPIOB, SPI_CS_PIN )#define  SPI_x               SPI2#define Dummy                 0xFF#define JEDEC_byte            0x9f    //这里不同的flash芯片可能值不一样,记得选择对应flash的值#define WriteEnable           0x06     //写使能#define Read_Data             0x03      //读数据#define Erase_Sector          0x20      //扇区擦除#define Write_data            0x02      //写入数据#define PowerDown             0xB9      //掉电模式#define ReleasePowerDown      0xAB       //唤醒u32 SPI_FLASH_ReadID(void);
void SPIx_Init(void);
void SPI_Read_data(uint32_t adder,uint8_t *pbuff,uint32_t numberbyte);
void SPI_Erase_Sector(uint32_t adder);
void SPI_WaitForWritend(void);
void SPI_Write_Enable(void);
void SPI_Write_data(uint32_t adder,uint8_t *pbuffWrite,uint32_t numberbyte);
void SPI_Flash_PowerDown(void);    //进入掉电模式
void SPI_Flash_WAKEUP(void);    //FLASH唤醒
#endif

main.c文件

#include "main.h"uint8_t readdata[4096];uint8_t Writedata[4096];int main()
{u32 readID;int i;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);Usart1_Init(115200);SPIx_Init();     //设备初始化readID=SPI_FLASH_ReadID();  //都设备IDprintf("设备ID为0x%x\r\n",readID);for(i=0;i<256;i++){Writedata[i]=i;}SPI_Erase_Sector(0);SPI_Write_data(0,Writedata,200);SPI_Read_data(0,readdata,4096);for(i=0;i<4096;i++){printf("0x %x   ",readdata[i]);if(i%10 ==0){printf("\r\n");}}
while(1){}}

工程文件

点击

STM32F103_SPI读写外部FLASH相关推荐

  1. STM32H743+CubeMX-QSPI读写外部FLASH(W25Q128JVSQ)

    文章目录 一.前言 二.硬件电路 三.CubeMX 3.1.Clock Configuration 3.2.QUADSPI Parameter Settings 3.3.QSPI GPIO Setti ...

  2. 学习日记——ESP8266读写外部Flash(2020.5.26)

    一.Falsh布局 ⽬前 ESP8266EX 模组采⽤的 demo Flash 为 SPI Flash,ROM[硬盘,用来存储和保存数据] ⼤⼩:2 MB,封装为SOP8 (208 mil). (SP ...

  3. ESP-8266读写外部Flash

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一.W25Q32-Flash 1.官方说明 2.引脚排列 3.特殊引脚说明 1.串行数输入输出和IOS (DI DO和 ...

  4. STM32H743+CubeMX-QSPI+DMA读取外部FLASH(W25Q128JVSQ)

    文章目录 一.前言 二.硬件电路 三.CubeMX 3.1.Parameter Setting 3.2.GPIO Settings 3.3.MDMA Settings(重点) 3.4.CubeMX生成 ...

  5. QCC300x笔记(5) -- 外部Flash的读写操作

    哈喽大家好,这是该系列博文的第五篇~ 篇~ <<[系列博文索引]快速通道 > 1.    QCC300X 外部Flash的读写         QCC300x是使用外部Flash片子 ...

  6. STM32F103标准库开发---SPI实验---读写 W25Q128 外部 Flash

    STM32F103标准库开发----目录 W25Q128读写----程序源码----点击下载 W25Qxx全系列数据手册-点击下载 一.实验前期准备 本次实验的 MCU 是 STM32F103C8T6 ...

  7. Flash----读写外部Flash

    目录 前言 Flash相关API Flash工程 首先定义下flash扇区大小 定义下扇区操作编号及定义了将要写入flash数据的数组和用来缓存flash数据的数组 接下来我们从0x77000地址起, ...

  8. STM32CubeMX学习笔记(48)——USB接口使用(MSC基于外部Flash模拟U盘)

    一.USB简介 USB(Universal Serial BUS)通用串行总线,是一个外部总线标准,用于规范电脑与外部设备的连接和通讯.是应用在 PC 领域的接口技术.USB 接口支持设备的即插即用和 ...

  9. 第50章 读写内部FLASH—零死角玩转STM32-F429系列

    第50章     读写内部FLASH 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fire ...

最新文章

  1. linux 发行版本和 及其与linux内核之间的关系
  2. es文件浏览器自动上传ftp服务器,es文件浏览器访问ftp服务器
  3. opencv 报错:Error: Assertion failed (data) in cv::Mat::at, file ... mat.inl.hpp, line 897(访问了不存在矩阵的像素)
  4. 枚举方式的线程安全的单例
  5. C语言矩阵N*N旋转的算法(附完整源码)
  6. Mysql 中如何创建触发器
  7. 使用Keras进行深度学习:(三)使用text-CNN处理自然语言(上)
  8. pymssql mysql_Python利用pymssql访问mysql数据库
  9. grasshopper_如何使用Google的Grasshopper编码应用程序来学习手机上的编码基础知识...
  10. 关于码云的一些基本知识_一些关于 CPU 的基本知识
  11. 一个对于小数四舍五入的算法C语言版
  12. js获取谷歌浏览器版本
  13. android音乐播放器歌词乱码,手机听歌显示乱码 没歌词 教你如何一键解决
  14. 主题模型:LDA原理详解与应用
  15. 基于51单片机控制的BUCK开关电源Proteus仿真
  16. wamp如何升级php版本,wamp升级php
  17. 对于法线贴图(Normal Map) 的深入研究
  18. VC中三种常见中文内码的转换方法
  19. ubuntu中显示实时网速的方法
  20. 5G套餐资费会越来越便宜,但需注意“限速机制”

热门文章

  1. php函数中首次出现,PHP开发之子串在字符串中首次出现、最后出现、出现次数函数相关总结...
  2. python实现matlab_用matlab和python实现符号运算
  3. 特征筛选6——肯德尔相关系数筛选特征(单变量筛选)
  4. django保存表单数据到数据库中
  5. 使用winscp在从linux向windows传输文件
  6. java 线程缓存_Java 实现缓存,一个线程存,一个线程取
  7. 支持多协议多服务的服务器设计和实现的步骤,基于多协议的人工影响天气接入服务器设计与实现...
  8. 看图识物_有声绘本故事《晚安,建筑工地》看图识物,嘘,晚安
  9. mvn创建flink项目
  10. 【IDE】我的花里胡哨VS