谁能看看为什么这个程序写入总是不成功
#ifndef _SPIFLASH_H
#define _SPIFLASH_H
#include "stm32f10x.h"
#define SPIx SPI2
#define SPI2_GPIO_CLK_PORT RCC_APB2Periph_GPIOB
#define SPI2_CLK_PORT RCC_APB1Periph_SPI2
#define SPI2_CS_GPIO_PIN GPIO_Pin_12
#define SPI2_CS_GPIO_PORT GPIOB
#define SPI2_SCK_GPIO_PIN GPIO_Pin_13
#define SPI2_SCK_GPIO_PORT GPIOB
#define SPI2_MISO_GPIO_PIN GPIO_Pin_14
#define SPI2_MISO_GPIO_PORT GPIOB
#define SPI2_MOSI_GPIO_PIN GPIO_Pin_15
#define SPI2_MOSI_GPIO_PORT GPIOB
//CS与PB12直连
#define SPI_CS_HIGH() GPIO_SetBits(SPI2_CS_GPIO_PORT,SPI2_CS_GPIO_PIN)
#define SPI_CS_LOW() GPIO_ResetBits(SPI2_CS_GPIO_PORT,SPI2_CS_GPIO_PIN)
//AT45DB161E设备ID
#define AT45DB161E_ID 0X1F260001
//AT45DB161E命令
#define READ_ID 0X9F
#define SECTOR_ERASE 0X7C
#define READ_STATUS 0XD7
#define READ_DATA 0XD2
#define PAGE_ERASE 0X81
#define BUFFER1_TO_MM 0X85
#define DUMMY 0XA5
void Spi_Flash_GPIO_Config(void);
void Spi_Flash_Config(void);
uint8_t SPI_FLASH_SendByte(uint8_t data);
uint8_t SPI_FLASH_ReadByte(void);
uint32_t SPI_FLASH_ReadID(void);
void SPI_WaitForWriteEnd(void);
void SPI_Read_Data(uint32_t pageaddr,uint8_t *buff,uint32_t NumByteToRead);
void SPI_PageErase(uint32_t addr);
void SPI_Write_Bufferf1ToPage(uint32_t pageaddr,uint32_t bufaddr,uint8_t* pBuffer, uint32_t NumByteToWrite);
uint8_t SPI_WriteSuccess(void);
#endif
#include "SpiFlash.h"
void Spi_Flash_GPIO_Config(void)
{
//GPIOB初始化结构体
GPIO_InitTypeDef GPIO_InitStructure;
//开启SPI2的GPIOB时钟和SPI2时钟
RCC_APB2PeriphClockCmd(SPI2_GPIO_CLK_PORT,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
RCC_APB1PeriphClockCmd(SPI2_CLK_PORT,ENABLE);
//PB13和PB15设置复用推挽输出
GPIO_InitStructure.GPIO_Pin = SPI2_SCK_GPIO_PIN | SPI2_MOSI_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(SPI2_SCK_GPIO_PORT,&GPIO_InitStructure);
//设置CS片选引脚为推挽输出
GPIO_InitStructure.GPIO_Pin = SPI2_CS_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(SPI2_CS_GPIO_PORT,&GPIO_InitStructure);
//设置MISO引脚为浮空输入
GPIO_InitStructure.GPIO_Pin = SPI2_MISO_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(SPI2_MISO_GPIO_PORT,&GPIO_InitStructure);
}
void Spi_Flash_Config(void)
{
//SPI2初始化结构体
SPI_InitTypeDef SPI_InitStructure;
Spi_Flash_GPIO_Config();
//片选CS引脚高电平,停止信号
SPI_CS_HIGH();
//设置SPI2通信时钟速度
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
//时钟相位,可选奇和偶
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
//时钟极性,可选高和低
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
//设置CRC校验
SPI_InitStructure.SPI_CRCPolynomial = 7;
//设置数据帧长度
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
//设置全双工模式
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
//设置高位先行
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
//设置为主机
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
//设置为软件控制使能引脚
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_Init(SPIx,&SPI_InitStructure);
//SPI2使能
SPI_Cmd(SPIx,ENABLE);
}
/**
* 函数名称:SPI_FLASH_SendByte
* 函数功能:向AT45DB161E发送一个字节的数据并返回从AT45DB161E收到的数据
* 使用范围:AT45DB161E
* 传入参数:data
* 传出参数:AT45DB161E发回的数据
**/
uint8_t SPI_FLASH_SendByte(uint8_t data)
{
//检查等待TX缓冲区为空
while(SPI_I2S_GetFlagStatus(SPIx,SPI_I2S_FLAG_TXE) == RESET);
//发送数据data
SPI_I2S_SendData(SPIx,data);
//检查并等待RX缓冲区非空
while(SPI_I2S_GetFlagStatus(SPIx,SPI_I2S_FLAG_RXNE) == RESET);
//返回由Flash发回的数据
return SPI_I2S_ReceiveData(SPIx);
}
/**
* 函数名称:SPI_FLASH_ReadByte
* 函数功能:主机读取一个字节
* 使用范围:AT45DB161E
* 传入参数:无
* 传出参数:从AT45DB161E读取的数据
**/
uint8_t SPI_FLASH_ReadByte(void)
{
return SPI_FLASH_SendByte(DUMMY);
}
/**
* 函数名称:SPI_FLASH_ReadID
* 函数功能:读取AT45DB161E的ID
* 使用范围:AT45DB161E
* 传入参数:无
* 传出参数:AT45DB161E的4个字节的ID
**/
uint32_t SPI_FLASH_ReadID(void)
{
uint32_t Temp = 0, Temp0 = 0, Temp1 = 0,Temp2 = 0, Temp3 = 0;
//片选使能
SPI_CS_LOW();
//发送读取设备ID命令
SPI_FLASH_SendByte(READ_ID);
//保存第一个字节
Temp0 = SPI_FLASH_SendByte(DUMMY);
//保存第二个字节
Temp1 = SPI_FLASH_SendByte(DUMMY);
//保存第三个字节
Temp2 = SPI_FLASH_SendByte(DUMMY);
//保存第四个字节
Temp3 = SPI_FLASH_SendByte(DUMMY);
//将四个字节ID存在一起
Temp = (Temp0 << 24) | (Temp1 << 16) | (Temp2 << 8) | (Temp3);
//停止信号
SPI_CS_HIGH();
return Temp;
}
/**
* 函数名称:SPI_WaitForWriteEnd
* 函数功能:等待写结束
* 使用范围:AT45DB161E
* 传入参数:无
* 传出参数:无
**/
void SPI_WaitForWriteEnd(void)
{
uint8_t flashstatus = 0;
//片选使能
SPI_CS_LOW();
//发送读取状态寄存器命令
SPI_FLASH_SendByte(READ_STATUS);
//一直读取状态寄存器的BUSY位,直到BUSY位为0
do
{
flashstatus = SPI_FLASH_SendByte(DUMMY);
}while(flashstatus & 0X01 == 1);
//停止信号
SPI_CS_HIGH();
}
/**
* 函数名称:SPI_Read_Data
* 函数功能:读取指定地址的指定长度数据
* 使用范围:AT45DB161E
* 传入参数:读取地址,存放数据的数组,读取数据的长度
* 传出参数:无
**/
void SPI_Read_Data(uint32_t pageaddr,uint8_t *buff,uint32_t NumByteToRead)
{
uint8_t i;
//片选使能
SPI_CS_LOW();
//发送扇区擦除命令
SPI_FLASH_SendByte(READ_DATA);
//发送高位地址
SPI_FLASH_SendByte(pageaddr >> 6);
//发送第二个字节的地址
SPI_FLASH_SendByte((pageaddr & 0X3F) << 2);
SPI_FLASH_SendByte(pageaddr >> 0);
for(i=0;i<4;i++)
{
SPI_FLASH_SendByte(0xff);
}
//将读取的DATA放到buff里
while(NumByteToRead--)
{
*buff = SPI_FLASH_SendByte(DUMMY);
buff++;
}
//停止信号
SPI_CS_HIGH();
SPI_WaitForWriteEnd();
}
/**
* 函数名称:SPI_PageErase
* 函数功能:页擦除
* 使用范围:AT45DB161E
* 传入参数:擦除地址
* 传出参数:无
**/
void SPI_PageErase(uint32_t addr)
{
SPI_CS_LOW();
SPI_FLASH_SendByte(PAGE_ERASE);
//发送高位地址
SPI_FLASH_SendByte(addr >> 6);
//发送第二个字节的地址
SPI_FLASH_SendByte((addr & 0X3F) << 2);
//发送低位地址,但是低8位无用,所以全置零
SPI_FLASH_SendByte(addr & 0x00);
SPI_CS_HIGH();
SPI_WaitForWriteEnd();
}
/**
* 函数名称:SPI_Write_Bufferf1ToPage
* 函数功能:页写入
* 使用范围:AT45DB161E
* 传入参数:写入地址,写入数据,写入数量
* 传出参数:无
**/
void SPI_Write_Bufferf1ToPage(uint32_t pageaddr,uint32_t bufaddr,uint8_t* pBuffer, uint32_t NumByteToWrite)
{
SPI_CS_LOW();
SPI_FLASH_SendByte(BUFFER1_TO_MM);
//发送高位地址
SPI_FLASH_SendByte((uint32_t)(pageaddr >> 6));
//发送第二个字节的地址
SPI_FLASH_SendByte((uint32_t)(((pageaddr & 0X3F) << 2) | (bufaddr >>8)));
SPI_FLASH_SendByte((uint32_t)(bufaddr >> 0));
while (NumByteToWrite--)
{
SPI_FLASH_SendByte(*pBuffer);
pBuffer++;
}
SPI_CS_HIGH();
SPI_WaitForWriteEnd();
}
uint8_t SPI_WriteSuccess(void)
{
uint8_t flashstatus = 0;
//片选使能
SPI_CS_LOW();
//发送读取状态寄存器命令
SPI_FLASH_SendByte(READ_STATUS);
//一直读取状态寄存器的BUSY位,直到BUSY位为0
flashstatus = SPI_FLASH_SendByte(DUMMY);
//停止信号
SPI_CS_HIGH();
if(flashstatus & 0X40 == 1)
{
return 1;
}
else
{
return 0;
}
}