STM32学习笔记--SPI初始化与数据收发(02 | 3.16)

18 阅读6分钟

1、W25Q64的存储结构

编程接口:

写数据顺序:

1.写使能

2.扇区擦除

3.等待空闲

4.页编程

2、W25Q64存储数据代码

void App_W25Q64_SaveByte(uint8_t Byte)
{
	uint8_t buffer[10];

	//1.写使能
	GPIO_WriteBit(GPIOA,GPIO_Pin_15,Bit_RESET);//选中
	APP_SPI_MasterTransmitReceive(SPI1,buffer,buffer,1);
	GPIO_WriteBit(GPIOA,GPIO_Pin_15,Bit_SET);//取消选中
	//2.扇区擦除

	buffer[0] = 0x20;
	buffer[1] = 0x00;
	buffer[2] = 0x00;
	buffer[3] = 0x00;

	GPIO_WriteBit(GPIOA,GPIO_Pin_15,Bit_RESET);//选中
	APP_SPI_MasterTransmitReceive(SPI1,buffer,buffer,4);
	GPIO_WriteBit(GPIOA,GPIO_Pin_15,Bit_SET);//取消选中
	//3.等待空闲

	while(1)
	{
		GPIO_WriteBit(GPIOA,GPIO_Pin_15,Bit_RESET);//选中
		buffer[0] = 0x05;
		APP_SPI_MasterTransmitReceive(SPI1,buffer,buffer,1);

		//读状态寄存器
		buffer[0] = 0xff;
		APP_SPI_MasterTransmitReceive(SPI1,buffer,buffer,1);

		GPIO_WriteBit(GPIOA,GPIO_Pin_15,Bit_SET);//取消选中

		if((buffer[0] & 0x01) == 0) break;
	}
	//4.写使能
	GPIO_WriteBit(GPIOA,GPIO_Pin_15,Bit_RESET);//选中
	APP_SPI_MasterTransmitReceive(SPI1,buffer,buffer,1);
	GPIO_WriteBit(GPIOA,GPIO_Pin_15,Bit_SET);//取消选中

	//5.页编程
	GPIO_WriteBit(GPIOA,GPIO_Pin_15,Bit_RESET);//选中

	buffer[0] = 0x02;
	buffer[1] = 0x00;
	buffer[2] = 0x00;
	buffer[3] = 0x00;
	buffer[4] = Byte;
	
	APP_SPI_MasterTransmitReceive(SPI1,buffer,buffer,5);
	GPIO_WriteBit(GPIOA,GPIO_Pin_15,Bit_SET);//取消选中

	//6.等待空闲
	while(1)
	{
		GPIO_WriteBit(GPIOA,GPIO_Pin_15,Bit_RESET);//选中
		buffer[0] = 0x05;
		APP_SPI_MasterTransmitReceive(SPI1,buffer,buffer,1);

		//读状态寄存器
		buffer[0] = 0xff;
		APP_SPI_MasterTransmitReceive(SPI1,buffer,buffer,1);

		GPIO_WriteBit(GPIOA,GPIO_Pin_15,Bit_SET);//取消选中

		if((buffer[0] & 0x01) == 0) break;
	}	
}

3、W25Q64读取数据

uint8_t App_W25Q64_LodeByte(void)
{
	uint8_t buffer[10];
	GPIO_WriteBit(GPIOA,GPIO_Pin_15,Bit_RESET);//选中

	buffer[0] = 0x03;
	buffer[1] = 0x00;
	buffer[2] = 0x00;
	buffer[3] = 0x00;

	APP_SPI_MasterTransmitReceive(SPI1,buffer,buffer,4);
	buffer[0] = 0xff;
	APP_SPI_MasterTransmitReceive(SPI1,buffer,buffer,1);
	GPIO_WriteBit(GPIOA,GPIO_Pin_15,Bit_SET);//取消选中
	return buffer[0];

}

实验接线图

4、初始化板载LED

void App_OnBoardLED(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);

	GPIO_TypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
	GPIO_Init(GPIOC,&GPIO_InitStructure);
}

5、使用按钮控制板载LED当前状态并且保存状态

6、数据持久化

将LED断电前的状态保存到FLASH,断电后再次通电LED仍然保存上一次的状态

完整代码

#include "stm32f10x.h"
#include "button.h"

Button_TypeDef button;

void App_SPI1_Init(void);
void App_SPI_MasterTransmitReceive(SPI_TypeDef *SPIx, const uint8_t *pDataTx, uint8_t *pDataRx, uint16_t Size);
void App_W25Q64_SaveByte(uint8_t Byte);
uint8_t App_W25Q64_LoadByte(void);
void App_OnBoardLED_Init(void);
void App_Button_Init(void);
void button_clicked_cb(uint8_t clicks);

int main(void)
{
	App_SPI1_Init();
	App_OnBoardLED_Init();
	App_Button_Init();
	
	uint8_t byte = App_W25Q64_LoadByte();
	
	if(byte == 0)
	{
		GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_SET);
	}
	else
	{
		GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_RESET);
	}
	
	while(1)
	{
		My_Button_Proc(&button);
	}
}

void button_clicked_cb(uint8_t clicks)
{
	if(clicks == 1)
	{
		if(GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_13) == Bit_SET)
		{
			GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_RESET);
			App_W25Q64_SaveByte(0x01);
		}
		else
		{
			GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_SET);
			App_W25Q64_SaveByte(0x00);
		}
	}
}

void App_Button_Init(void)
{
	Button_InitTypeDef Button_InitStruct = {0};
	
	Button_InitStruct.GPIOx = GPIOA;
	Button_InitStruct.GPIO_Pin = GPIO_Pin_0;
	Button_InitStruct.button_clicked_cb = button_clicked_cb;
	
	My_Button_Init(&button, &Button_InitStruct);
}


void App_OnBoardLED_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStruct;
	
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_Init(GPIOC, &GPIO_InitStruct);
}

void App_SPI1_Init(void)
{
	// #1. 初始化IO引脚
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
	GPIO_PinRemapConfig(GPIO_Remap_SPI1, ENABLE);
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStruct;
	
	// PB3 SCK AF_PP 2MHz
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_Init(GPIOB, &GPIO_InitStruct);
	
	// PB4 MISO IPU
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_Init(GPIOB, &GPIO_InitStruct);
	
	// PB5 MOSI AF_PP 2MHz
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_Init(GPIOB, &GPIO_InitStruct);
	
	// PA15 普通IO Out_PP 2MHz
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_15;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_Init(GPIOA, &GPIO_InitStruct);
	GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_SET);
	
	// #2. 对SPI本身进行初始化
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
	
	SPI_NSSInternalSoftwareConfig(SPI1, SPI_NSSInternalSoft_Set);
	
	SPI_InitTypeDef SPI_InitStruct;
	
	SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
	SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
	SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
	SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;
	SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;
	SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
	SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;
	SPI_InitStruct.SPI_NSS = SPI_NSS_Soft; 
	
	SPI_Init(SPI1, &SPI_InitStruct);
}

void App_SPI_MasterTransmitReceive(SPI_TypeDef *SPIx, const uint8_t *pDataTx, uint8_t *pDataRx, uint16_t Size)
{
	// #1. 闭合总开关
	SPI_Cmd(SPIx, ENABLE);
	
	// #2. 写入第一个字节
	SPI_I2S_SendData(SPIx, pDataTx[0]);
	
	// #3. 
	for(uint16_t i=0; i<Size-1; i++)
	{
		// 向TDR写数据
		while(SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);
		
		SPI_I2S_SendData(SPIx, pDataTx[i+1]);
		
		// 从RDR读数据
		while(SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_RXNE) == RESET);
		
		pDataRx[i] = SPI_I2S_ReceiveData(SPIx);
	}
	
	// #4. 读取最后一个字节的数据
	while(SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_RXNE) == RESET);
	
	pDataRx[Size-1] = SPI_I2S_ReceiveData(SPIx);
	
	// #5. 断开总开关
	SPI_Cmd(SPIx, DISABLE);
}

void App_W25Q64_SaveByte(uint8_t Byte)
{
	uint8_t buffer[10];
	
	// #1. 写使能
	buffer[0] = 0x06;
	
	GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_RESET); // 选中
	
	App_SPI_MasterTransmitReceive(SPI1, buffer, buffer, 1);
	
	GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_SET); // 取消选中
	
	// #2. 扇区擦除
	
	buffer[0] = 0x20;
	buffer[1] = 0x00;
	buffer[2] = 0x00;
	buffer[3] = 0x00;
	
	GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_RESET); // 选中
	
	App_SPI_MasterTransmitReceive(SPI1, buffer, buffer, 4);
	
	GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_SET); // 取消选中
	
	// #3. 等待空闲
	while(1)
	{
		GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_RESET); // 选中
		
		// 写0x05
		
		buffer[0] = 0x05;
		App_SPI_MasterTransmitReceive(SPI1, buffer, buffer, 1);
		
		// 读状态寄存器1
		buffer[0] = 0xff;
		App_SPI_MasterTransmitReceive(SPI1, buffer, buffer, 1);
		
		GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_SET); // 取消选中
		
		if((buffer[0] & 0x01) == 0) break; 
	}
	
	// #4. 写使能
	buffer[0] = 0x06;
	
	GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_RESET); // 选中
	
	App_SPI_MasterTransmitReceive(SPI1, buffer, buffer, 1);
	
	GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_SET); // 取消选中
	
	// #5. 页编程
	GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_RESET); // 选中
	
	buffer[0] = 0x02;
	buffer[1] = 0x00;
	buffer[2] = 0x00;
	buffer[3] = 0x00;
	buffer[4] = Byte;
	
	App_SPI_MasterTransmitReceive(SPI1, buffer, buffer, 5);
	
	GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_SET); // 取消选中
	
	// #6. 等待空闲
	while(1)
	{
		GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_RESET); // 选中
		
		// 写0x05
		
		buffer[0] = 0x05;
		App_SPI_MasterTransmitReceive(SPI1, buffer, buffer, 1);
		
		// 读状态寄存器1
		buffer[0] = 0xff;
		App_SPI_MasterTransmitReceive(SPI1, buffer, buffer, 1);
		
		GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_SET); // 取消选中
		
		if((buffer[0] & 0x01) == 0) break; 
	}
	
}

uint8_t App_W25Q64_LoadByte(void)
{
	uint8_t buffer[10];
	
	GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_RESET); // 选中
	
	buffer[0] = 0x03;
	buffer[1] = 0x00;
	buffer[2] = 0x00;
	buffer[3] = 0x00;
	
	App_SPI_MasterTransmitReceive(SPI1, buffer, buffer, 4);
	
	buffer[0] = 0xff;
	
	App_SPI_MasterTransmitReceive(SPI1, buffer, buffer, 1);
	
	GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_SET); // 取消选中
	
	return buffer[0];
}