STM32F103C8T6--SPI通信协议及代码示例

一、SPI电路结构及通信协议

1.1.1SPI电路总线的电路结构

MOSI:主机给从机发送地址

MISO:从机给主机发送地址

SCK:时钟线

NSS:低电压代表选中,高电压代表没有选中

2.1.1通信流程及波形

NSS1低电压代表从机被选中;

SCK控制运行速度,高电平代表高速度

MOSI向MISO发送数据,MISO向MOSI返回数据

3.1.1参数1时钟信号的极性

低极性:空闲的时候默认为低电压,与高极性的时候相反

3.2.1参数1时钟信号的相位

第一边沿采集:在数字为1的边缘进行采集(低极性)

第二边沿采集:在数字为2的边缘进行采集(高极性)

4.1.1SPI的四种采集模式

5.1.1比特位的传输顺序

两种模,第一种LSB First:先传最低有效位(0~7)

              第二种MSB First:先传最高有效位(7~0)

6.1.1数据宽度

就有是每次传输比特位的个数,例如一次传输8个bit,一次传输16个bit

二、SPI IO模块引脚初始化

1.1.1W25Q64模块简介

2.1.1定位SPI引脚内部结构

3.1.1查询参考手册第8.3.10

SPI2没有重映射

4.1.1接线

5.1.1选择SPI工作模式

6.1.1选择W25Q64 IO引脚的最大输出速度

选择符合要求的最低频率

7.1.1选择SPI IO引脚输入输出模式及速率

8.1.1SPI引脚初始化代码(main.c)

#include "stm32f10x.h"
#include "delay.h"

void APP_SPI_Init(void);
int main(void)
{
	APP_SPI_Init();
	while(1)
	{
 	}
}


void APP_SPI_Init(void)
{
//#1初始化IO引脚
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	GPIO_PinRemapConfig(GPIO_Remap_SPI1,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);	
}

三、IO模块初始化

1.1.1SPI模块的基本工作原理

TXE:发送数据寄存器为空

RxNE:接收数据寄存器非空

NSS:作为从机的时候使用   
先闭合总开关,写入第一个字,标志位TXE=1,读取第字节宽度-1个数据位,开始向TDR(发送数据寄存器)写数据,标志位TXE=0,然后读数据标志位RxNE=0,再断开总开关。

2.1.1选择数据通信方向

这里我们选择全双工模式

3.1.1数据宽度、极性、相位和比特位的传输顺序

相位:什么时候对信号进行采集

根据图示,以发送0x04(0000  0100)为例

相位:1/2

数据位:8b(0~7)

极性:高/低(Model3/Model0)

比特位传输顺序:MSB(先传最高位)

4.1.1设置波特率

时钟的频率是72MHZ,假设我们想得到18MZ,我们可以在分频器中选择4分频,72/4=18MHZ

5.1.1NSS引脚配置方式

软件NSS:向内部NSS输入1,相当于外接了电源

硬件NSS:

对从机外接一个3.3v电压的方式

6.1.1代码部分(main.c部分)

#include "stm32f10x.h"
#include "delay.h"

void APP_SPI_Init(void);
int main(void)
{
	APP_SPI_Init();
	while(1)
	{
		
 	}
}


void APP_SPI_Init(void)
{
//#1初始化IO引脚
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	GPIO_PinRemapConfig(GPIO_Remap_SPI1,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);	
	
	//#2对SPI本身进行初始化
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);
	SPI_InitTypeDef SPI_InitStruct;
	
	SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
	SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex ;//2线全双工模式
	SPI_InitStruct.SPI_DataSize =SPI_DataSize_8b;//字节宽度
	SPI_InitStruct.SPI_CPOL = SPI_CPOL_High;//高极性
	SPI_InitStruct.SPI_CPHA = SPI_CPHA_2Edge;//第2边沿采集
	SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;//先传最高位
	SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;//设置波特率
	SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;//选择软NSS
	
	
	SPI_Init(SPI1,&SPI_InitStruct);
	SPI_NSSInternalSoftwareConfig(SPI1,SPI_NSSInternalSoft_Set);//向内部NSS写1
	
	
}

四、数据收发

1.1.1SPI数据收发的特点

2.1.1SPI数据收发的过程简介

TDR:发送数据寄存器

RDR:接收数据寄存器

TXE:发送数据寄存器为空

RxNE:接收数据寄存器不为空

3.1.1代码示例

void My_SPI_MasterTransmitReceive(SPI_TypeDef *SPIx, const uint8_t *pDataTx, uint8_t *pDataRx, uint16_t Size)
{
	if(Size == 0) return;
	
	// #1. 闭合总开关
	SPI_Cmd(SPIx, ENABLE);
	
	// #2. 写入第一个字节
	SPI_I2S_SendData(SPIx, pDataTx[0]);
	
	// #3. 读写Size-1个字节
	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);
}

五、W25Q64实验

1.1.1W25Q64储存结构

                                                这是一个flash存储结构

2.1.1使用W25Q64模块存储数据

3.1.1存储代码示例


void APP_W25Q64_Init(uint8_t Byte)
{
	uint8_t buffer[10];
	//#1写使能
	GPIO_WriteBit(GPIOA,GPIO_Pin_15,Bit_RESET);//选中
	My_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);//选中
	My_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;
	  My_SPI_MasterTransmitReceive(SPI1,buffer,buffer,1);
		
		//读寄存器状态
			buffer[0]=0xff;
			My_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);//选中
	My_SPI_MasterTransmitReceive(SPI1,buffer,buffer,4);
	GPIO_WriteBit(GPIOA,GPIO_Pin_15,Bit_SET);//取消选中
	
	//#5页编程
	GPIO_WriteBit(GPIOA,GPIO_Pin_15,Bit_RESET);//选中
	
	buffer[0]=0x20;
	buffer[1]=0x00;
	buffer[2]=0x00;
	buffer[3]=0x00;
  buffer[4]=Byte;
	My_SPI_MasterTransmitReceive(SPI1,buffer,buffer,5);	
	
	//#6等待空闲
		while(1)
	{
		GPIO_WriteBit(GPIOA,GPIO_Pin_15,Bit_RESET);//选中
		//写0x05
		buffer[0]=0x05;
	  My_SPI_MasterTransmitReceive(SPI1,buffer,buffer,1);
		
		//读寄存器状态
			buffer[0]=0xff;
			My_SPI_MasterTransmitReceive(SPI1,buffer,buffer,1);
		  GPIO_WriteBit(GPIOA,GPIO_Pin_15,Bit_SET);//取消选中
		if((buffer[0]&0x01)==0)break;
	}
}

4.1.1使用W25Q64读数据

查询W25Q64参考手册第11.2.8节

5.1.1代码示例(main.c部分)

#include "stm32f10x.h"
#include "delay.h"
#include "spi.h"
void APP_SPI_Init(void);
void APP_W25Q64_Init(uint8_t Byte);
uint8_t APP_W25Q64_LoadByte(void);
uint8_t a =0;
int main(void)
{
	APP_SPI_Init();
		APP_W25Q64_Init(0x12);
		a=APP_W25Q64_LoadByte();
	while(1)
	{
		APP_W25Q64_Init(0x12);
		a=APP_W25Q64_LoadByte();
 	}
}


void APP_SPI_Init(void)
{
//#1初始化IO引脚
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	
	GPIO_PinRemapConfig(GPIO_Remap_SPI1,ENABLE);
		GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable,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_InitTypeDef SPI_InitStruct;
	
	SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
	SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex ;//2线全双工模式
	SPI_InitStruct.SPI_DataSize =SPI_DataSize_8b;//字节宽度
	SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;//低极性
	SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;//第1边沿采集
	SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;//先传最高位
	SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;//设置波特率
	SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;//选择软NSS
	
	
	SPI_Init(SPI1,&SPI_InitStruct);
	SPI_NSSInternalSoftwareConfig(SPI1,SPI_NSSInternalSoft_Set);//向内部NSS写1
	
}

void APP_W25Q64_Init(uint8_t Byte)
{
	uint8_t buffer[10];
	//#1写使能
	GPIO_WriteBit(GPIOA,GPIO_Pin_15,Bit_RESET);//选中
	My_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);//选中
	My_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;
	  My_SPI_MasterTransmitReceive(SPI1,buffer,buffer,1);
		
		//读寄存器状态
			buffer[0]=0xff;
			My_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);//选中
	My_SPI_MasterTransmitReceive(SPI1,buffer,buffer,4);
	GPIO_WriteBit(GPIOA,GPIO_Pin_15,Bit_SET);//取消选中
	
	//#5页编程
	GPIO_WriteBit(GPIOA,GPIO_Pin_15,Bit_RESET);//选中
	
	buffer[0]=0x20;
	buffer[1]=0x00;
	buffer[2]=0x00;
	buffer[3]=0x00;
  buffer[4]=Byte;
	My_SPI_MasterTransmitReceive(SPI1,buffer,buffer,5);	
	
	//#6等待空闲
		while(1)
	{
		GPIO_WriteBit(GPIOA,GPIO_Pin_15,Bit_RESET);//选中
		//写0x05
		buffer[0]=0x05;
	  My_SPI_MasterTransmitReceive(SPI1,buffer,buffer,1);
		
		//读寄存器状态
			buffer[0]=0xff;
			My_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;
My_SPI_MasterTransmitReceive(SPI1,buffer,buffer,4);	
		buffer[0]=0xff;
My_SPI_MasterTransmitReceive(SPI1,buffer,buffer,1);
	  GPIO_WriteBit(GPIOA,GPIO_Pin_15,Bit_SET);//取消选中
return buffer[0];	
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值