系列文章目录


文章目录

  • 系列文章目录
  • 前言
  • 一、SPI.h
  • 二、SPI.c
    • 1.SPI配置
    • 2.DMA配置
  • 3.w25q64.c
  • 4.w25q64.h
  • 五.main.c
  • 六.串口打印代码
  • 七、输出结果

前言

框架:自己新建库文件夹 取名lib,并按顺序新建spi.c、w25q64.c(根据自己芯片型号)
使用开发板为正点原子mini板演示,开发板上芯片为W25Q64。


一、SPI.h

#ifndef _SPI_H
#define _SPI_H#include "stm32f10x.h"
#include "system.h"/*如果不使用SPI_DMA,屏蔽下面define*/
#define SPI1_DMA#ifdef  SPI1_DMA
extern u8 SPI_RX_BUFFER[4096];
extern u8 SPI_TX_BUFFER[4096];
#endifvoid SPI1_Config(void);            //初始化SPI1口
void SPI1_SetSpeed(u8 SpeedSet); //设置SPI1速度
u8 SPI1_ReadWriteByte(u8 TxData);//SPI1总线读写一个字节void SPI1_DMA_Config(void);
void SPI_transmission(u8 *rx_buf,u8 *tx_buf,u16 NumByte);
void SPI_DMA_Read(u8 *rx_buf,u8 *tx_data,u16 NumByte);
void SPI_DMA_Write(u8 *rx_data,u8 *tx_buf,u16 NumByte);
#endif

二、SPI.c

1.SPI配置

#include "SPI.h"
#include "stdio.h"#define Rx_BFSize  (u8)20
#define Tx_BFSize  (u8)20
#define SPI1_DR_Addr ( (u32)0x4001300C )
u8 Rx_Addr[Rx_BFSize];
u8 Tx_Addr[Tx_BFSize];/*长度一定要>=数据接收发送大小*/
u8 SPI_RX_BUFFER[4096];
u8 SPI_TX_BUFFER[4096];void SPI1_Config(void)
{    u8 count=0;GPIO_InitTypeDef   GPIO_InitStructure;SPI_InitTypeDef      SPI_InitStructure;RCC_APB2PeriphClockCmd( RCC_APB2Periph_SPI1 , ENABLE);RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA , ENABLE);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;  //SCK,MOSIGPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);    //GPIO_Mode_IN_FLOATINGGPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;   //MISOGPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;  //NSS 由软件控制 设置为普通推挽输出GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);        //初始化GPIOAGPIO_SetBits(GPIOA,GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工SPI_InitStructure.SPI_Mode = SPI_Mode_Master;       //设置SPI工作模式:设置为主SPISPI_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;     //定义波特率预分频的值:波特率预分频值为256SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始SPI_InitStructure.SPI_CRCPolynomial = 7;  //CRC值计算的多项式                //NSS由  软件控制SPI_Init(SPI1, &SPI_InitStructure);                 //初始化SPI1
#ifdef  SPI1_DMASPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Tx,ENABLE);  //使能DMA Tx通道SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Rx,ENABLE);  //使能DMA Rx通道
#endifSPI_Cmd(SPI1, ENABLE);                            //使能SPISPI_TX_BUFFER[count++]=0xFF;SPI_transmission(SPI_RX_BUFFER, SPI_TX_BUFFER, count);    }   //SPI1速度设置函数
//SPI速度=fAPB2/分频系数
//@ref SPI_BaudRate_Prescaler:SPI_BaudRatePrescaler_2~SPI_BaudRatePrescaler_256
//fAPB2时钟一般为84Mhz:
void SPI1_SetSpeed(u8 SPI_BaudRatePrescaler)
{assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));//判断有效性SPI1->CR1&=0XFFC7;//位3-5清零,用来设置波特率SPI1->CR1|=SPI_BaudRatePrescaler;   //设置SPI1速度 SPI_Cmd(SPI1,ENABLE); //使能SPI1
} 

2.DMA配置

#ifdef SPI1_DMA
void SPI1_DMA_Config(void)
{   DMA_InitTypeDef DMA_InitStructure;RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);/*********************  DMA_Rx  *********************/DMA_DeInit(DMA1_Channel2); //DMA1 通道2 SPI1_RX DMA_InitStructure.DMA_BufferSize=Rx_BFSize; //传输数据量的大小DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;     //DMA传输方向,SRC 外设为数据源DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;          //非存储器到存储器传输模式DMA_InitStructure.DMA_MemoryBaseAddr=(u32)Rx_Addr;   //数据缓冲区地址DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte; //内存数据宽度 数据宽度 8位DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;          //传输数据时候内存地址递增DMA_InitStructure.DMA_Mode=DMA_Mode_Normal;      //内存不循环采集数据DMA_InitStructure.DMA_PeripheralBaseAddr=SPI1_DR_Addr;  //SPI1 外设基地址DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;  //外设数据宽度 数据宽度 8位DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;     //传输地址固定不变  ENABLE时下次发送数据地址递增+1DMA_InitStructure.DMA_Priority=DMA_Priority_Medium;        //通道优先级DMA_Init(DMA1_Channel2,&DMA_InitStructure);      //DMA1 通道2 SPI1_RX /*********************  DMA_Tx  *********************/DMA_DeInit(DMA1_Channel3); //DMA1 通道3 SPI1_TX DMA_InitStructure.DMA_BufferSize=Tx_BFSize; //传输数据量的大小DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralDST;     //DMA传输方向,DST 内存作为数据源DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;         //非存储器到存储器传输模式DMA_InitStructure.DMA_MemoryBaseAddr=(u32)Tx_Addr;   //数据缓冲区地址DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte; //内存数据宽度 数据宽度 8位DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;          //传输数据时候内存地址递增DMA_InitStructure.DMA_Mode=DMA_Mode_Normal;      //内存不循环采集数据DMA_InitStructure.DMA_PeripheralBaseAddr=SPI1_DR_Addr;  //SPI1 外设基地址DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;  //外设数据宽度 数据宽度 8位DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;     //传输地址固定不变  ENABLE时下次发送数据地址递增+1DMA_InitStructure.DMA_Priority=DMA_Priority_Medium;        //通道优先级DMA_Init(DMA1_Channel3,&DMA_InitStructure);      //DMA1 通道2 SPI1_RX
}void SPI_transmission(u8 *rx_buf,u8 *tx_buf,u16 NumByte)
{//  DMA_Cmd(DMA1_Channel2,DISABLE);     //关闭DMA
//  DMA_Cmd(DMA1_Channel3,DISABLE);DMA_SetCurrDataCounter(DMA1_Channel2,NumByte);       //设定通道内存宽度DMA_SetCurrDataCounter(DMA1_Channel3,NumByte);DMA1_Channel2->CCR |= (1<<7);         //打开地址自增DMA1_Channel3->CCR |= (1<<7);DMA1_Channel2->CMAR =(u32)rx_buf;DMA1_Channel3->CMAR =(u32)tx_buf;SPI1->DR;       //清空SPI DR寄存器while((SPI1->SR&1<<1)==0);  //等待清除DMA_Cmd(DMA1_Channel2,ENABLE);    //开启DMADMA_Cmd(DMA1_Channel3,ENABLE);while( DMA_GetFlagStatus(DMA1_FLAG_TC3) == RESET);   //等待传输完成while( DMA_GetFlagStatus(DMA1_FLAG_TC2) == RESET);DMA_Cmd(DMA1_Channel2,DISABLE);     //关闭DMADMA_Cmd(DMA1_Channel3,DISABLE);DMA_ClearFlag(DMA1_FLAG_TC3);     //清空传输完成flagDMA_ClearFlag(DMA1_FLAG_TC2);
}void SPI_DMA_Read(u8 *rx_buf,u8 *tx_data,u16 NumByte)
{//  DMA_Cmd(DMA1_Channel2,DISABLE);
//  DMA_Cmd(DMA1_Channel3,DISABLE);DMA_SetCurrDataCounter(DMA1_Channel2,NumByte);DMA_SetCurrDataCounter(DMA1_Channel3,NumByte);DMA1_Channel3->CCR &= ~(1<<7);DMA1_Channel2->CMAR =(u32)rx_buf;DMA1_Channel3->CMAR =(u32)tx_data;SPI1->DR;while((SPI1->SR&1<<1)==0);DMA_Cmd(DMA1_Channel2,ENABLE);DMA_Cmd(DMA1_Channel3,ENABLE);while( DMA_GetFlagStatus(DMA1_FLAG_TC3) == RESET);while( DMA_GetFlagStatus(DMA1_FLAG_TC2) == RESET);DMA_Cmd(DMA1_Channel2,DISABLE);DMA_Cmd(DMA1_Channel3,DISABLE);DMA_ClearFlag(DMA1_FLAG_TC3);DMA_ClearFlag(DMA1_FLAG_TC2);
}void SPI_DMA_Write(u8 *rx_data,u8 *tx_buf,u16 NumByte)
{//  DMA_Cmd(DMA1_Channel2,DISABLE);
//  DMA_Cmd(DMA1_Channel3,DISABLE);DMA_SetCurrDataCounter(DMA1_Channel2,NumByte);DMA_SetCurrDataCounter(DMA1_Channel3,NumByte);DMA1_Channel2->CCR &= ~(1<<7); DMA1_Channel2->CMAR =(u32)rx_data;DMA1_Channel3->CMAR =(u32)tx_buf;SPI1->DR;while((SPI1->SR&1<<1)==0);DMA_Cmd(DMA1_Channel2,ENABLE);DMA_Cmd(DMA1_Channel3,ENABLE);while( DMA_GetFlagStatus(DMA1_FLAG_TC3) == RESET);while( DMA_GetFlagStatus(DMA1_FLAG_TC2) == RESET);DMA_Cmd(DMA1_Channel2,DISABLE);DMA_Cmd(DMA1_Channel3,DISABLE);DMA_ClearFlag(DMA1_FLAG_TC3);DMA_ClearFlag(DMA1_FLAG_TC2);
}
#elseu8 SPI1_ReadWriteByte(u8 TxData){while((SPI1->SR&1<<1)==0);SPI1->DR=TxData;while((SPI1->SR&1<<0)==0);return SPI1->DR;}
#endif

3.w25q64.c

#include "W25QXX.h"void W25QXX_Config(void)
{   W25QXX_CS=1;           //SPI FLASH不选中SPI1_DMA_Config();SPI1_Config();                  //初始化SPISPI1_SetSpeed(SPI_BaudRatePrescaler_2);     //设置为42M时钟,高速模式
#ifdef W25Q256  u8 count=0;W25QXX_CS=0; SPI_TX_BUFFER[count++]=W25X_Entry4ByteMode;SPI_transmission(SPI_RX_BUFFER, SPI_TX_BUFFER, count);W25QXX_CS=1;
#endif
}  u8 W25QXX_ReadSR(void)
{  u8 byte=0;  u8 count=0;W25QXX_CS=0;                            //使能器件 SPI_TX_BUFFER[count++]=W25X_ReadStatusReg;SPI_TX_BUFFER[count++]=0xFF;SPI_DMA_Write(&byte,SPI_TX_BUFFER,count);   W25QXX_CS=1;   //取消片选  return byte;
} u8 W25QXX_ReadSR_2(void)
{  u8 byte=0;  u8 count=0;W25QXX_CS=0;                            //使能器件 SPI_TX_BUFFER[count++]=W25X_ReadStatusReg_2;SPI_TX_BUFFER[count++]=0xFF;SPI_DMA_Write(&byte,SPI_TX_BUFFER,count); W25QXX_CS=1;   //取消片选  return byte;
} u8 W25QXX_ReadSR_3(void)
{  u8 byte=0;  u8 count=0;W25QXX_CS=0;                            //使能器件 SPI_TX_BUFFER[count++]=W25X_ReadStatusReg_3;SPI_TX_BUFFER[count++]=0xFF;SPI_DMA_Write(&byte,SPI_TX_BUFFER,count); W25QXX_CS=1;   //取消片选  return byte;
} //写W25QXX状态寄存器
//只有SPR,TB,BP2,BP1,BP0(bit 7,5,4,3,2)可以写!!!
void W25QXX_Write_SR(u8 sr)
{   u8 count=0;W25QXX_CS=0;                            //使能器件   SPI_TX_BUFFER[count++]=W25X_WriteStatusReg;SPI_TX_BUFFER[count++]=sr;SPI_transmission(SPI_RX_BUFFER, SPI_TX_BUFFER, count); W25QXX_CS=1;                            //取消片选
}   //W25QXX写使能
//将WEL置位
void W25QXX_Write_Enable(void)
{u8 count=0;W25QXX_CS=0;                            //使能器件 SPI_TX_BUFFER[count++]=W25X_WriteEnable;SPI_transmission(SPI_RX_BUFFER, SPI_TX_BUFFER, count);W25QXX_CS=1;                            //取消片选
}
//W25QXX写禁止
//将WEL清零
void W25QXX_Write_Disable(void)
{  u8 count=0;W25QXX_CS=0;                            //使能器件   SPI_TX_BUFFER[count++]=W25X_WriteDisable;SPI_transmission(SPI_RX_BUFFER, SPI_TX_BUFFER, count);   W25QXX_CS=1;                            //取消片选
}
//读取芯片ID
//返回值如下:
//0XEF13,表示芯片型号为W25Q80
//0XEF14,表示芯片型号为W25Q16
//0XEF15,表示芯片型号为W25Q32
//0XEF16,表示芯片型号为W25Q64
//0XEF17,表示芯片型号为W25Q128
u16 W25QXX_ReadID(void)
{u8 count = 0;u16 Temp = 0;W25QXX_CS=0;                  SPI_TX_BUFFER[count++]=W25X_ManufactDeviceID;SPI_TX_BUFFER[count++]=0x00;SPI_TX_BUFFER[count++]=0x00;SPI_TX_BUFFER[count++]=0x00;SPI_TX_BUFFER[count++]=0xFF;SPI_TX_BUFFER[count++]=0xFF;SPI_transmission(SPI_RX_BUFFER, SPI_TX_BUFFER, count);Temp = SPI_RX_BUFFER[4]<<8 | SPI_RX_BUFFER[5];       W25QXX_CS=1;                  return Temp;
} //读取SPI FLASH
//在指定地址开始读取指定长度的数据
//pBuffer:数据存储区
//ReadAddr:开始读取的地址(24bit)
//NumByteToRead:要读取的字节数(最大65535)
void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)
{ u8 count=0;u8 temp=0xFF; W25QXX_CS=0;                            //使能器件 SPI_TX_BUFFER[count++]=W25X_ReadData;
#ifdef W25Q256SPI_TX_BUFFER[count++]=(u8)((ReadAddr)>>24);
#endifSPI_TX_BUFFER[count++]=(u8)((ReadAddr)>>16);SPI_TX_BUFFER[count++]=(u8)((ReadAddr)>>8);SPI_TX_BUFFER[count++]=(u8)ReadAddr;    SPI_transmission(SPI_RX_BUFFER, SPI_TX_BUFFER, count);SPI_DMA_Read(pBuffer,&temp,NumByteToRead);W25QXX_CS=1;
} //SPI在一页(0~65535)内写入少于256个字节的数据
//在指定地址开始写入最大256字节的数据
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!!
void W25QXX_Write_Page(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{u8 count=0;u8 temp=0; W25QXX_Write_Enable();                  //SET WEL W25QXX_CS=0;                            //使能器件 SPI_TX_BUFFER[count++]=W25X_PageProgram;
#ifdef W25Q256SPI_TX_BUFFER[count++]=(u8)((WriteAddr)>>24);
#endifSPI_TX_BUFFER[count++]=(u8)((WriteAddr)>>16);SPI_TX_BUFFER[count++]=(u8)((WriteAddr)>>8);SPI_TX_BUFFER[count++]=(u8)WriteAddr;SPI_transmission(SPI_RX_BUFFER, SPI_TX_BUFFER, count);SPI_DMA_Write(&temp,pBuffer,NumByteToWrite); W25QXX_CS=1;                            //取消片选 W25QXX_Wait_Busy();                    //等待写入结束
} //无检验写SPI FLASH
//必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
//具有自动换页功能
//在指定地址开始写入指定长度的数据,但是要确保地址不越界!
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大65535)
//CHECK OK
void W25QXX_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{                    u16 pageremain;pageremain=256-WriteAddr%256; //单页剩余的字节数               if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256个字节while(1){      W25QXX_Write_Page(pBuffer,WriteAddr,pageremain);if(NumByteToWrite==pageremain)break;//写入结束了else //NumByteToWrite>pageremain{pBuffer+=pageremain;WriteAddr+=pageremain;  NumByteToWrite-=pageremain;              //减去已经写入了的字节数if(NumByteToWrite>256)pageremain=256; //一次可以写入256个字节else pageremain=NumByteToWrite;       //不够256个字节了}};
} //写SPI FLASH
//在指定地址开始写入指定长度的数据
//该函数带擦除操作!
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大65535)
u8 W25QXX_BUFFER[4096];
void W25QXX_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{ u32 secpos;u16 secoff;u16 secremain;     u16 i;    u8 * W25QXX_BUF;   W25QXX_BUF=W25QXX_BUFFER;       secpos=WriteAddr/4096;//扇区地址  secoff=WriteAddr%4096;//在扇区内的偏移secremain=4096-secoff;//扇区剩余空间大小   if(NumByteToWrite<=secremain)secremain=NumByteToWrite; //不大于剩余空间while(1) { W25QXX_Read(W25QXX_BUF,secpos*4096,4096);//读出整个扇区的内容for(i=0;i<secremain;i++)//校验数据{if(W25QXX_BUF[secoff+i]!=0XFF)break;//需要擦除     }if(i<secremain)//需要擦除{W25QXX_Erase_Sector(secpos);//擦除这个扇区for(i=0;i<secremain;i++)     //复制{W25QXX_BUF[i+secoff]=pBuffer[i];    }W25QXX_Write_NoCheck(W25QXX_BUF,secpos*4096,4096);//写入整个扇区  }else W25QXX_Write_NoCheck(pBuffer,WriteAddr,secremain);//写已经擦除了的,直接写入扇区剩余区间.                   if(NumByteToWrite==secremain)break;//写入结束了else//写入未结束{secpos++;//扇区地址增1secoff=0;//偏移位置为0     pBuffer+=secremain;  //指针偏移WriteAddr+=secremain;//写地址偏移       NumByteToWrite-=secremain;              //字节数递减if(NumByteToWrite>4096)secremain=4096;   //下一个扇区还是写不完else secremain=NumByteToWrite;         //下一个扇区可以写完了}    };
}//擦除整个芯片
//等待时间超长...
void W25QXX_Erase_Chip(void)
{          u8 count=0;u8 temp=0; W25QXX_Write_Enable();                  //SET WEL W25QXX_Wait_Busy();   W25QXX_CS=0;    //使能器件   SPI_TX_BUFFER[count++]=W25X_ChipErase;SPI_DMA_Write(&temp,SPI_TX_BUFFER,count);W25QXX_CS=1;                            //取消片选            W25QXX_Wait_Busy();                      //等待芯片擦除结束
}  //擦除一个扇区
//Dst_Addr:扇区地址 根据实际容量设置
//擦除一个山区的最少时间:150ms
void W25QXX_Erase_Sector(u32 Dst_Addr)
{  u8 count=0;u8 temp=0;Dst_Addr*=4096;W25QXX_Write_Enable();                  //SET WEL      W25QXX_Wait_Busy();   W25QXX_CS=0;    //使能器件      SPI_TX_BUFFER[count++]=W25X_SectorErase;
#ifdef W25Q256SPI_TX_BUFFER[count++]=(u8)((Dst_Addr)>>24);
#endifSPI_TX_BUFFER[count++]=(u8)((Dst_Addr)>>16);SPI_TX_BUFFER[count++]=(u8)((Dst_Addr)>>8);SPI_TX_BUFFER[count++]=(u8)Dst_Addr;SPI_DMA_Write(&temp,SPI_TX_BUFFER,count);W25QXX_CS=1;                            //取消片选            W25QXX_Wait_Busy();                      //等待擦除完成
} //等待空闲
void W25QXX_Wait_Busy(void)
{   while((W25QXX_ReadSR()&0x01)==0x01);  // 等待BUSY位清空
}//进入掉电模式
void W25QXX_PowerDown(void)
{ u8 count=0;u8 temp=0;W25QXX_CS=0;                            //使能器件SPI_TX_BUFFER[count++]=W25X_PowerDown;SPI_DMA_Write(&temp,SPI_TX_BUFFER,count);  W25QXX_CS=1;                            //取消片选               delay_us(3);                               //等待TPD
} 唤醒
void W25QXX_WAKEUP(void)
{  u8 count=0;u8 temp=0;W25QXX_CS=0;                            //使能器件  SPI_TX_BUFFER[count++]=W25X_ReleasePowerDown;SPI_DMA_Write(&temp,SPI_TX_BUFFER,count); W25QXX_CS=1;                            //取消片选              delay_us(3);                               //等待TRES1
}   

4.w25q64.h

#include "system.h"
#include "SPI.h"
#include "USART.h"
#include "delay.h"/*如果不是W25Q256,屏蔽下面define*/
//#define W25Q256#define W25QXX_CS GAout(4)#define W25X_WriteEnable     0x06
#define W25X_WriteDisable       0x04
#define W25X_ReadStatusReg      0x05
#define W25X_WriteStatusReg     0x01
#define W25X_ReadData           0x03
#define W25X_FastReadData       0x0B
#define W25X_FastReadDual       0x3B
#define W25X_PageProgram        0x02
#define W25X_BlockErase         0xD8
#define W25X_SectorErase        0x20
#define W25X_ChipErase          0xC7
#define W25X_PowerDown          0xB9
#define W25X_ReleasePowerDown   0xAB
#define W25X_DeviceID           0xAB
#define W25X_ManufactDeviceID   0x90
#define W25X_JedecDeviceID      0x9F
#define W25X_Entry4ByteMode     0xB7
#define W25X_Exit4ByteMode      0xE9
#define W25X_ReadStatusReg_2    0x35
#define W25X_WriteStatusReg_2   0x31
#define W25X_ReadStatusReg_3    0x15
#define W25X_WriteStatusReg_3   0x11void W25QXX_Config(void);
u16  W25QXX_ReadID(void);               //读取FLASH ID
u8   W25QXX_ReadSR(void);               //读取状态寄存器
void W25QXX_Write_SR(u8 sr);            //写状态寄存器
void W25QXX_Write_Enable(void);         //写使能
void W25QXX_Write_Disable(void);        //写保护
void W25QXX_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite);
void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead);   //读取flash
void W25QXX_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite);//写入flash
void W25QXX_Erase_Chip(void);           //整片擦除
void W25QXX_Erase_Sector(u32 Dst_Addr); //扇区擦除
void W25QXX_Wait_Busy(void);            //等待空闲
void W25QXX_PowerDown(void);            //进入掉电模式
void W25QXX_WAKEUP(void);               //唤醒
u8 W25QXX_ReadSR_2(void);
void W25QXX_Write_SR_2(u8 sr);
u8 W25QXX_ReadSR_3(void);#endif 

五.main.c

#include "main.h"const u8 TEXT_Buffer[]={"abcdefg1234567!"};
//const u8 TEXT_Buffer[4096];
#define SIZE sizeof(TEXT_Buffer)int main()
{ u8 datatemp[SIZE];LED_Config();USART1_Config(115200);W25QXX_Config();printf("\r\nID:%x\r\n",W25QXX_ReadID());   printf("SR1:%x\r\n",W25QXX_ReadSR());printf("SR2:%x\r\n",W25QXX_ReadSR_2());printf("SR3:%x\r\n",W25QXX_ReadSR_3());W25QXX_Write((u8*)TEXT_Buffer,0,SIZE);delay_ms(200);W25QXX_Read(datatemp,0,SIZE);printf("fe:%s",datatemp);while(1){      }
}

六.串口打印代码

#include "USART.h"int fputc(int ch, FILE *f)
{     while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   USART1->DR = (u8) ch;      return ch;
}void USART1_Config(u32 Baud)
{GPIO_InitTypeDef   GPIO_InitStructure;USART_InitTypeDef    USART_InitStructure;NVIC_InitTypeDef    NVIC_InitStructure;RCC_APB2PeriphClockCmd( RCC_APB2Periph_USART1 , ENABLE);RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA , ENABLE);GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);        //初始化GPIOANVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;        //子优先级3NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;            //IRQ通道使能NVIC_Init(&NVIC_InitStructure);    //根据指定的参数初始化VIC寄存器USART_InitStructure.USART_BaudRate = Baud;USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;USART_InitStructure.USART_Parity  = USART_Parity_No;USART_InitStructure.USART_StopBits =  USART_StopBits_1;USART_InitStructure.USART_WordLength = USART_WordLength_8b;USART_Init(USART1,&USART_InitStructure);USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);//开启串口接受中断USART_Cmd(USART1,ENABLE);             }
#ifndef _USART_H
#define _USART_H#include "stm32f10x.h"
#include "system.h"typedef struct __FILE FILE;int fputc(int ch, FILE *f);
void USART1_Config(u32 Baud);#endif

七、输出结果

源代码:STM32 SPI “DMA”操作W25QXX(16/32/64/128)系列芯片代码详解相关推荐

  1. html元素自己属性代码,jQuery如何操作HTML的元素和属性?(代码详解例)

    本篇文章给大家带来的内容是介绍jQuery如何操作HTML的元素和属性?(代码详解例),让大家了解jQuery操作元素和属性的方法.有一定的参考价值,有需要的朋友可以参考一下,希望对你们有所帮助. 1 ...

  2. STM32(八)W25Q(16/32/64/128)芯片学习总结

    系列文章目录 文章目录 系列文章目录 前言 一.硬件和数据手册部分翻译 1.W25Q64硬件设计 2.数据手册解读 二.指令 前言 按项目需求,近期调试了W25Q32芯片,W25Q系列芯片是华邦公司推 ...

  3. ATmega8/16/32/64/128中文参考手册

    文章目录 ATmega8中文参考手册 ATmega16中文参考手册 ATmega32中文参考手册 ATmega64中文参考手册 ATmega128中文参考手册 ATmega8中文参考手册 ATmega ...

  4. AD7606/AD7616使ZYNQ在能源电力领域如虎添翼,可实现16/32/64通道AD同步采样

    1 AD7606/AD7616介绍 AD7606是ADI公司的16位.8通道同步采样AD芯片,并行采样率高达200KSPS(AD7616是16位.16通道.1MSPS).在电力线路测量和保护系统中,需 ...

  5. ASP常用进制转化类(2,8,10,16,32,64)

    <% ' 名称:HDOBTools ' 描述:进制转化类 ' 作用:用于各种进转的转化 Class HDOBToolsPrivate hdobHackPrivate Sub Class_Init ...

  6. 8/16/32/64位单片机区别

    32位处理器 首先处理器都是8的倍数:8/16/32/64.表示一个时钟周期里,处理器处理的代码数. 8位机有8条线路,每个时钟周期有8个电信号,组成一个字节.8-32,则每个时钟周期从传输1个字节到 ...

  7. mysql回滚用法_Mysql误操作后利用binlog2sql快速回滚的方法详解

    前言 在日常工作或者学习中,操作数据库时候难免会因为"大意"而误操作,需要快速恢复的话通过备份来恢复是不太可能的,下面这篇文章主要给大家介绍关于Mysql误操作后利用binlog2 ...

  8. 【初篇】DHT11连接STM32、One wire单总线原理、GPIO代码详解

    目录 一.DHT11单总线原理 二.代码详解 三.代码 代码见文章末尾 一.DHT11单总线原理 DHT11温湿度传感器只需要一根线即可和MCU进行数据交换,无数据传输时,单线应为高电平状态,具体流程 ...

  9. 《STM32从零开始学习历程》——CAN通讯代码详解

    <STM32从零开始学习历程>@EnzoReventon CAN通讯代码详解 相关链接: <STM32从零开始学习历程>--CAN通讯协议物理层 CAN-bus规范 V2.0版 ...

最新文章

  1. C++中的迭代器(STL迭代器)iterator
  2. Environ. Res.:南土所梁玉婷组-低砷稻田土壤微生物抗砷功能基因的分布模式
  3. 理解Java动态代理(1)—找我还钱?我出钱要你的命
  4. 2015-03-06——正则表达式基础
  5. WPF动画之后属性值无法改变
  6. mysql 工具_MySQL压力测试工具,值得收藏
  7. 「长文」2022年企业数字化转型的八大趋势
  8. SQLServer2005出了点怪事~(应该是编码问题~)
  9. Python的第三方库xlwt
  10. @Resource kdown
  11. java中JFrame.setSize,Java JFrame .setSize(x, y) not working?
  12. 2021年美赛B题——解题参考
  13. 下载firebug网站
  14. 如何在线免费caj转word
  15. gst 测试摄像头命令
  16. 【目标检测】YOLOv1代码实现之TensorFlow
  17. SPSS MODELER笔记1----数据基本处理和整体方法概念
  18. 一款RS485电表的调试与上位机通讯过程
  19. jQuery学习笔记总结
  20. 显示器的 VGA、HDMI、DVI 和 DisplayPort

热门文章

  1. 完美破解CSDN的博客皮肤
  2. 技术培训 | 大数据分析处理与用户画像实践
  3. 深度强化学习中的泛化
  4. 2的幂,3的幂,4的幂
  5. 2008年北大文科在渝录取情况统计--------------仅一个未加分
  6. ios开发基础教程 2014传智播客iOS培训第4期 基础+就业班
  7. C/C++中的取整运算
  8. 个别软件无法联网_个别编程语言对软件开发的贡献
  9. 《张成功项目管理记》一客户说好才算好
  10. 连载03:软件体系设计新方向:数学抽象、设计模式、系统架构与方案设计(简化版)(袁晓河著)