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


    STM32F103标准库开发—目录


    一、实验前期准备

    本次实验的 MCU 是 STM32F103C8T6 芯片,通过 SPI 通信实现 W25Q128 的读写操作。

    1. 原理图

    在这里插入图片描述

    2. 引脚连接

    SPI接口GPIO端口
    CS(片选)PA4
    SCLK(时钟)PA5
    MISO(数据输入)PA6
    MOSI(数据输出)PA7

    二、SPI 底层驱动

    SPI.c

    #include "SPI.h"
    
    /*
    	SPI引脚初始化配置
    	**PA4------CS
    	**PA5------SCLK
    	**PA6------MISO
    	**PA7------MOSI
    */
    
    static void SPI1_GPIO_Config(void)	
    {
    	GPIO_InitTypeDef GPIO_InitStructure;
    	
    	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOA, ENABLE );//PORTA时钟使能 
    
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5| GPIO_Pin_6|GPIO_Pin_7;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //PA5/6/7复用推挽输出 
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA, &GPIO_InitStructure);						//初始化GPIOA
    	
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  //PA4推挽输出
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA, &GPIO_InitStructure);						//初始化GPIOA
    
    	GPIO_SetBits(GPIOA,GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7); //初始上拉输出
    
    }
    
    //SPI1初始化函数
    void SPI1_Init(void)
    {
    	SPI1_GPIO_Config();//SPI引脚初始化配置	
      
    	SPI_InitTypeDef  SPI_InitStructure;
    	
    	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_SPI1,  ENABLE );//SPI1时钟使能 	
    	
    	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  	//设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
    	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;													//设置SPI工作模式:设置为主SPI
    	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;											//设置SPI的数据大小:SPI发送接收8位帧结构
    	SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;														//串行同步时钟的空闲状态为高电平
    	SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;													//串行同步时钟的第二个跳变沿(上升或下降)数据被采样
    	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;															//NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
    	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;	//定义波特率预分频的值:波特率预分频值为256
    	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;										//指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
      SPI_InitStructure.SPI_CRCPolynomial = 7;	//CRC值计算的多项式
    	SPI_Init(SPI1, &SPI_InitStructure);  			//根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
    	
    	SPI_Cmd(SPI1, ENABLE); //使能SPI外设
    	SPI1_ReadWriteByte(0xFF);//启动传输
    } 
    
    /*
    	SPI的读写操作
    	**TxData:要写入的字节
    	**返回值:读取到的字节
    */
    uint8_t SPI1_ReadWriteByte(uint8_t TxData)
    {			 	
    	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) //检查指定的SPI标志位设置与否:发送缓存空标志位
    	{
    		//等待发送完成
    	}			  
    	SPI_I2S_SendData(SPI1, TxData); //通过外设SPIx发送一个数据
    	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET) //检查指定的SPI标志位设置与否:接受缓存非空标志位
    	{
    		//等待接收完成
    	}	  						    
    	return SPI_I2S_ReceiveData(SPI1); //返回通过SPIx最近接收的数据					    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72

    SPI.h

    #ifndef __SPI_H
    #define	__SPI_H
    
    #include "stm32f10x.h"
    
    #define SPI_CS(a)		if (a)	\
    						GPIO_SetBits(GPIOA,GPIO_Pin_4);\
    						else		\
    					    GPIO_ResetBits(GPIOA,GPIO_Pin_4)
    
    void SPI1_Init(void);//SPI1初始化函数
    uint8_t SPI1_ReadWriteByte(uint8_t TxData);//SPI1读写函数
    
    #endif 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    三、读取 W25Q128 设备 ID

    本次实验是:读取 W25Q128 设备 ID,然后通过串口1打印出来。
    通过简单的实验来调试,有利于发现问题。
    通过W25Q128的数据手册可知其设备ID如下图所示:
    在这里插入图片描述

    W25Q128.c

    #include "W25Q128.h"
    #include "SPI.h"
    
    
    uint8_t W25Q128_ReadWriteByte(uint8_t TxData)//函数包装一下
    {     
     	  return SPI1_ReadWriteByte(TxData); 		
    }
    
    uint16_t W25Q128_ReadID(void)//读取芯片ID
    {
    	uint16_t Temp = 0;	  
    	W25Q128_CS(0);				    
    	W25Q128_ReadWriteByte(W25X_ManufactDeviceID);//发送读取ID命令	    
    	W25Q128_ReadWriteByte(0x00); 	    
    	W25Q128_ReadWriteByte(0x00); 	    
    	W25Q128_ReadWriteByte(0x00); 	 			   
    	Temp|=W25Q128_ReadWriteByte(0xFF)<<8;  
    	Temp|=W25Q128_ReadWriteByte(0xFF);	 
    	W25Q128_CS(1);				    
    	return Temp;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    W25Q128.h

    #ifndef __W25Q128_H
    #define	__W25Q128_H
    
    #include "stm32f10x.h"
    
    //操作指令表
    #define W25X_ManufactDeviceID	 0x90       //制造商+设备ID
    
    #define W25Q128_CS(a) SPI_CS(a)	
    
    uint8_t W25Q128_ReadWriteByte(uint8_t TxData);//函数包装一下
    uint16_t W25Q128_ReadID(void);//读取芯片ID
    
    #endif 
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    main.c

    #include 
    #include "Uart1.h"
    #include "delay.h"
    #include "SPI.h"
    #include "W25Q128.h"
    
    uint16_t W25Q128_ID=0;
    
    int main (void)
    {
    	Uart1_init();
    	SPI1_Init();
    	
    	W25Q128_ID = W25Q128_ReadID();
    	while(1)
    	{
    		printf("\nW25Q128_ID=0x%X\n",W25Q128_ID);
    		delay_ms(500);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    实验结果

    在这里插入图片描述
    接收到 W25Q128 设备ID 为0xEF17


    不了解串口通信的朋友,可以看下面这几篇文章
    STM32F103标准库开发----Uart串口通信实验----初始化配置
    STM32F103标准库开发----Uart串口通信实验----安装串口驱动和串口调试
    STM32F103标准库开发----Uart串口通信实验----函数发送和中断接收
    STM32F103标准库开发----Uart串口通信实验----printf()函数重定向
    STM32F103标准库开发----Uart串口通信实验----程序源码 点击下载


    四、读写 W25Q128 外部 Flash

    W25Q128.c

    #include "W25Q128.h"
    #include "SPI.h"
    
    
    uint8_t W25Q128_ReadWriteByte(uint8_t TxData)//函数包装一下
    {     
     	return SPI1_ReadWriteByte(TxData); 		
    }
    
    
    uint16_t W25Q128_ReadID(void)//读取芯片ID
    {
    	uint16_t Temp = 0;	  
    	W25Q128_CS(0);				    
    	W25Q128_ReadWriteByte(W25X_ManufactDeviceID);//发送读取ID命令	    
    	W25Q128_ReadWriteByte(0x00); 	    
    	W25Q128_ReadWriteByte(0x00); 	    
    	W25Q128_ReadWriteByte(0x00); 	 			   
    	Temp|=W25Q128_ReadWriteByte(0xFF)<<8;  
    	Temp|=W25Q128_ReadWriteByte(0xFF);	 
    	W25Q128_CS(1);				    
    	return Temp;
    }
    
    //读取W25Q128的状态寄存器
    //BIT7  6   5   4   3   2   1   0
    //SPR   RV  TB BP2 BP1 BP0 WEL BUSY
    //SPR:默认0,状态寄存器保护位,配合WP使用
    //TB,BP2,BP1,BP0:FLASH区域写保护设置
    //WEL:写使能锁定
    //BUSY:忙标记位(1,忙;0,空闲)
    //默认:0x00
    uint8_t W25Q128_ReadSR(void)//读取状态寄存器
    {
        uint8_t byte=0;
        W25Q128_CS(0);                               //使能器件
        W25Q128_ReadWriteByte(W25X_ReadStatusReg1);  //发送读取状态寄存器命令
        byte=W25Q128_ReadWriteByte(0Xff);            //读取一个字节
        W25Q128_CS(1);                               //取消片选
        return byte;
    }
    
    //写W25Q128状态寄存器
    //只有SPR,TB,BP2,BP1,BP0(bit 7,5,4,3,2)可以写!!!
    void W25Q128_WriteSR(uint8_t sr)//写状态寄存器
    {
        W25Q128_CS(0);                           		//使能器件
        W25Q128_ReadWriteByte(W25X_WriteStatusReg1);	//发送写取状态寄存器命令
        W25Q128_ReadWriteByte(sr);               		//写入一个字节
        W25Q128_CS(1);                            		//取消片选
    }
    
    void W25Q128_Write_Enable(void) //写使能 
    {
       	W25Q128_CS(0);	
    	W25Q128_ReadWriteByte(W25X_WriteEnable);
    	W25Q128_CS(1);	
    }
    
    void W25Q128_Write_Disable(void) //禁止写入	
    {
       	W25Q128_CS(0);	
    	W25Q128_ReadWriteByte(W25X_WriteDisable);
    	W25Q128_CS(1);	
    }
    
    void W25Q128_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead)   
    { 						    
    	W25Q128_CS(0);	                          //使能器件   
        W25Q128_ReadWriteByte(W25X_ReadData);      //发送读取命令  
        W25Q128_ReadWriteByte((uint8_t)((ReadAddr)>>16));   //发送24bit地址    
        W25Q128_ReadWriteByte((uint8_t)((ReadAddr)>>8));   
        W25Q128_ReadWriteByte((uint8_t)ReadAddr);   
        for(uint16_t i=0;i<NumByteToRead;i++)
    	{ 
           pBuffer[i]=W25Q128_ReadWriteByte(0XFF);    //循环读数  
        }
    	W25Q128_CS(1);				    	      
    }  
    
    
    void W25Q128_Write_Page(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
    {
      
        W25Q128_Write_Enable();                  //SET WEL 
    	W25Q128_CS(0);                            //使能器件   
        W25Q128_ReadWriteByte(W25X_PageProgram);   //发送写页命令   
    
        W25Q128_ReadWriteByte((uint8_t)((WriteAddr)>>16)); //发送24bit地址    
        W25Q128_ReadWriteByte((uint8_t)((WriteAddr)>>8));   
        W25Q128_ReadWriteByte((uint8_t)WriteAddr);   
        for(uint16_t i=0;i<NumByteToWrite;i++)
    	{
    		W25Q128_ReadWriteByte(pBuffer[i]);//循环写数  
    	}
    	W25Q128_CS(1);                            //取消片选 
    	W25Q128_Wait_Busy();					   //等待写入结束
    } 
    
    //无检验写SPI FLASH 
    //必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
    //具有自动换页功能 
    void W25Q128_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)   
    { 			 		 
    	uint16_t pageremain=256-WriteAddr%256; //单页剩余的字节数		 	    
    	if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256个字节
    	while(1)
    	{	   
    		W25Q128_Write_Page(pBuffer,WriteAddr,pageremain);
    		if(NumByteToWrite==pageremain)	break;//写入结束了
    	 	else 
    		{
    			pBuffer+=pageremain;
    			WriteAddr+=pageremain;	
    			NumByteToWrite-=pageremain;			  //减去已经写入了的字节数
    			if(NumByteToWrite>256)pageremain=256; //一次可以写入256个字节
    			else pageremain=NumByteToWrite; 	  //不够256个字节了
    		}
    	}	    
    } 
    
    //写SPI FLASH  
    //在指定地址开始写入指定长度的数据
    //该函数带擦除操作!
    //pBuffer:数据存储区
    //WriteAddr:开始写入的地址(24bit)						
    //NumByteToWrite:要写入的字节数(最大65535)   
    uint8_t W25Q128_BUFFER[4096];		 
    void W25Q128_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)   
    { 
     	uint16_t i;    
    	uint8_t * W25Q128_BUF;	  
        W25Q128_BUF=W25Q128_BUFFER;	     
     	uint32_t secpos = WriteAddr/4096;//扇区地址  
    	uint16_t secoff = WriteAddr%4096;//在扇区内的偏移
    	uint16_t secremain = 4096-secoff;//扇区剩余空间大小   
    
     	if(NumByteToWrite<=secremain)		secremain=NumByteToWrite;//不大于4096个字节
    	while(1) 
    	{	
    		W25Q128_Read(W25Q128_BUF,secpos*4096,4096);//读出整个扇区的内容
    		for(i=0;i<secremain;i++)//校验数据
    		{
    			if(W25Q128_BUF[secoff+i]!=0XFF)	break;//需要擦除  	  
    		}
    		if(i<secremain)//需要擦除
    		{
    			W25Q128_Erase_Sector(secpos*4096);//擦除这个扇区
    			for(i=0;i<secremain;i++)	   //复制
    			{
    				W25Q128_BUF[i+secoff]=pBuffer[i];	  
    			}
    			W25Q128_Write_NoCheck(W25Q128_BUF,secpos*4096,4096);//写入整个扇区  
    
    		}else W25Q128_Write_NoCheck(pBuffer,WriteAddr,secremain);//写已经擦除了的,直接写入扇区剩余区间. 				   
    		if(NumByteToWrite==secremain)	break;//写入结束了
    		else//写入未结束
    		{
    			secpos++;//扇区地址增1
    			secoff=0;//偏移位置为0 	 
    
    		    pBuffer+=secremain;  //指针偏移
    			WriteAddr+=secremain;//写地址偏移	   
    		    NumByteToWrite-=secremain;				//字节数递减
    			if(NumByteToWrite>4096)	secremain=4096;	//下一个扇区还是写不完
    			else 	secremain=NumByteToWrite;		//下一个扇区可以写完了
    		}	 
    	}	 
    }
    
    //擦除一个扇区
    //Dst_Addr:扇区地址 根据实际容量设置
    //擦除一个扇区的最少时间:150ms
    
    void W25Q128_Erase_Sector(uint32_t Dst_Addr)   
    {  
        W25Q128_Write_Enable();                  //SET WEL 	 
        W25Q128_Wait_Busy();   
      	W25Q128_CS(0);                            //使能器件   
        W25Q128_ReadWriteByte(W25X_SectorErase);   //发送扇区擦除指令 
        W25Q128_ReadWriteByte((uint8_t)((Dst_Addr)>>16));  //发送24bit地址    
        W25Q128_ReadWriteByte((uint8_t)((Dst_Addr)>>8));   
        W25Q128_ReadWriteByte((uint8_t)Dst_Addr);  
    	W25Q128_CS(1);                            	//取消片选     	      
        W25Q128_Wait_Busy();   				    	//等待擦除完成
    }  
    
    //擦除整个芯片		  
    //等待时间超长...
    void W25Q128_Erase_Chip(void)   
    {                                   
        W25Q128_Write_Enable();                  //SET WEL 
        W25Q128_Wait_Busy();   
      	W25Q128_CS(0);                           //使能器件   
        W25Q128_ReadWriteByte(W25X_ChipErase);   //发送片擦除命令  
    	W25Q128_CS(1);                           //取消片选     	      
    	W25Q128_Wait_Busy();   				   	//等待芯片擦除结束
    }
    
    
    //等待空闲
    void W25Q128_Wait_Busy(void)   
    {   
    	while((W25Q128_ReadSR()&0x01)==0x01);   // 等待BUSY位清空
    }  
    
    //进入掉电模式
    void W25Q128_PowerDown(void)   
    { 
      	W25Q128_CS(0);                            //使能器件   
        W25Q128_ReadWriteByte(W25X_PowerDown);    //发送掉电命令  
    	W25Q128_CS(1);                            //取消片选     	      
    }   
    //掉电唤醒
    void W25Q128_WAKEUP(void)   
    {  
      	W25Q128_CS(0);                                //使能器件   
        W25Q128_ReadWriteByte(W25X_ReleasePowerDown);    
    	W25Q128_CS(1);                                //取消片选     	      
    }   
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220

    W25Q128.h

    #ifndef __W25Q128_H
    #define	__W25Q128_H
    
    #include "stm32f10x.h"
    
    //操作指令表
    #define W25X_WriteEnable		   	0x06 	//写使能
    #define W25X_WriteDisable		   	0x04 	//写禁止
    #define W25X_ReadStatusReg1		 	0x05 	//读状态寄存器1
    #define W25X_ReadStatusReg2		 	0x35 	//读状态寄存器2
    #define W25X_ReadStatusReg3		 	0x15 	//读状态寄存器3
    #define W25X_WriteStatusReg1   		0x01 	//写状态寄存器1
    #define W25X_WriteStatusReg2   		0x31 	//写状态寄存器2
    #define W25X_WriteStatusReg3   		0x11 	//写状态寄存器3
    #define W25X_ReadData				0x03 	//读数据
    #define W25X_FastReadData		   	0x0B 	//快读
    #define W25X_FastReadDual		   	0x3B    //双输出快读
    #define W25X_PageProgram		   	0x02 	//页编程
    #define W25X_BlockErase			   	0xD8 	//块擦除(64K)
    #define W25X_SectorErase		   	0x20    //扇区擦除(4K)
    #define W25X_ChipErase			   	0xC7    //芯片擦除
    #define W25X_PowerDown			   	0xB9    //掉电
    #define W25X_ReleasePowerDown	 	0xAB    //释放掉电
    #define W25X_DeviceID			    0xAB    //器件ID
    #define W25X_ManufactDeviceID	 	0x90    //制造商+设备ID
    #define W25X_JedecDeviceID		 	0x9F 	//电子元件ID
    
    
    #define W25Q128_CS(a) SPI_CS(a)	
    
    
    uint8_t W25Q128_ReadWriteByte(uint8_t TxData);//函数包装一下
    
    uint16_t W25Q128_ReadID(void);//读取芯片ID
    
    uint8_t W25Q128_ReadSR(void);//读取状态寄存器
    void W25Q128_WriteSR(uint8_t sr);//写状态寄存器
    
    void W25Q128_Write_Enable(void);//写使能
    void W25Q128_Write_Disable(void);//禁止写入	
    
    void W25Q128_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead); //读取数据
    void W25Q128_Write_Page(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);//页写
    void W25Q128_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);//无检验写数据,可自动翻页
    void W25Q128_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);//写入数据,带擦写功能
    
    void W25Q128_Erase_Sector(uint32_t Dst_Addr);//擦除扇区
    void W25Q128_Erase_Chip(void);//擦除整个芯片	
    
    void W25Q128_Wait_Busy(void);//等待空闲
    void W25Q128_PowerDown(void); //进入掉电模式
    void W25Q128_WAKEUP(void);//掉电唤醒
    
    #endif 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    main.c

    #include 
    #include "Uart1.h"
    #include "delay.h"
    #include "SPI.h"
    #include "W25Q128.h"
    
    uint16_t W25Q128_ID=0;
    uint8_t Write_data[20]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
    uint8_t Read_data[100];
    
    int main (void)
    {
    	Uart1_init();
    	SPI1_Init();
    	
    	W25Q128_ID=W25Q128_ReadID();
    	W25Q128_Write_Page(Write_data,0x01,20);
    	
    	while(1)
    	{
    		W25Q128_Read(Read_data,0x00,100);
    		for(int i=0;i<100;i++)
    		{
    			printf(" 0x%X ",Read_data[i]);
    		}
    		printf("\nW25Q128_ID=0x%X\n",W25Q128_ID);
    		delay_ms(500);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    实验结果

    在这里插入图片描述


    STM32F103标准库开发----SPI实验----基本原理
    STM32F103标准库开发----SPI实验----底层驱动程序
    STM32F103标准库开发----SPI实验----W25Qxx系列外部Flash芯片

  • 相关阅读:
    java计算机毕业设计物流信息管理系统录像演示源码+系统+数据库+lw文档+mybatis+运行部署
    Nextcloud fpm 版在 Dokcer 下安装踩坑
    Install nodejs 18.x to Linux mint 20.3
    解决方案 | VS2022 + AutoCAD2024 + ObjectARX2024环境搭建过程
    SpringMVC:RESTful案例
    leetcode:805. 数组的均值分割【meet in middle + 选or不选 + 折半搜索】
    2023年蓝帽杯取证复现
    做外贸用以下邮箱比较好
    项目进展跟踪的5个基本原则
    振弦采集模块传感器接口
  • 原文地址:https://blog.csdn.net/MQ0522/article/details/126337400