学习板芯片为STM32F103VE
先简单介绍下SPI(全称:Serial Peripheral interface,串行外围设备接口):SPI接口主要应用在 EEPROM,FLASH,实时时钟,AD转换器,是一种高速的,全双工,同步的通信总线。一般SPI芯片与MCU通信,只会使用4个管脚:MOSI(主输出),MISO(主输入),CS(片选低电平有效),SCK(时钟)
STM32内的SPI的特点:
1 8或16位传输帧格式选择
2 可编程的时钟极性(CPOL)和相位(CPHA)
3 可编程的数据顺序,MSB在前或LSB在前
4 8个主模式波特率预分频系数(最大为fPCLK/2)
5 支持DMA功能的1字节发送和接收缓冲器:产生发送和接受请求
6 可触发中断的专用发送和接收标志
SPI较重要的寄存器:
8或16位传输帧格式选择 由SPI_CR1寄存器上的DFF位确定,0:8位
时钟极性和相位由SPI_CR1寄存器上的CPOL,CPHA 位确定
模式0:CPOL=0,CPHA=0:SCK在空闲时保持低电平,在第一个变化沿传递数据 (本次使用的SPI芯片SST25VF016B只能使用在模式0和3)
模式1:CPOL=0,CPHA=1:SCK在空闲时保持低电平,在第二个变化沿传递数据
模式2:CPOL=1,CPHA=0:SCK在空闲时保持高电平,在第一个变化沿传递数据
模式3:CPOL=1,CPHA=1:SCK在空闲时保持高电平,在第二个变化沿传递数据
可编程的数据顺序 ,MSB在前或LSB在前 由SPI_CR1寄存器中的LSBFIRST位确定,0:MSB在前
8个主模式波特率预分频系数(最大为fPCLK/2) 由SPI_CR1寄存器上的BR[2:0]确定
应用程序通过3个状态标志可以完全监控SPI总线的状态:
1.发送缓冲器空闲标志(TXE),此标志为’1’时表明发送缓冲器为空,要等到该位为0,进行下一次发送
2.接收缓冲器非空(RXNE),同理
3.忙(Busy)标志
SPI芯片SST25VF016B
8个管脚,一般只有4个管脚与MCU连接,SI,SO,CE,SCK
更多信息参考SST25VF016B数据手册
STM32y与SST25VF016B进行SPI通信代码实现:
//时钟配置
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//用于打印读取到的数据
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);
//管脚配置 SPI PA5:SCK PA6:MOSI PA7:MISO PE6:CS
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7; //
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; //
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOE,&GPIO_InitStructure);
GPIO_SetBits(GPIOE,GPIO_Pin_6);
//SPI配置
SPI_InitTypeDef SPI_InitStructure;
SPI_InitStructure.SPI_Direction=SPI_Direction_2Lines_FullDuplex;//双向全双工
SPI_InitStructure.SPI_Mode=SPI_Mode_Master; //主机模式
SPI_InitStructure.SPI_DataSize=SPI_DataSize_8b; //每次发生8位
SPI_InitStructure.SPI_CPOL=SPI_CPOL_High; //时钟空闲时为高
SPI_InitStructure.SPI_CPHA=SPI_CPHA_2Edge; //第2个变化沿传递数据 模式3
SPI_InitStructure.SPI_NSS=SPI_NSS_Soft; //NSS软件模式
SPI_InitStructure.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_8;//时钟8分频 SPI 在APB2上,则为9M
SPI_InitStructure.SPI_FirstBit=SPI_FirstBit_MSB; //高位在前
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI1,&SPI_InitStructure);
SPI_Cmd(SPI1,ENABLE);
//SPI发送数据
u8 SPI_SendData(u8 data){
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)==RESET);
SPI_I2S_SendData(SPI1,data);
}
//SPI接收数据
u8 SPI_ReadData(void){
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE)==RESET);
SPI_I2S_SendData(SPI1, 0);
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE)==RESET);
return SPI_I2S_ReceiveData(SPI1);
}
//根据芯片SST25VF016B的数据手册,编写对该芯片操作的函数
//读取状态寄存器
u8 RDSR(void){
u8 data;
SPI_CS_L;
SPI_SendData(0x05);
data = SPI_ReadData();
SPI_CS_H;
return data;
}
//根据状态寄存器最低位BUSY判断芯片是否处于忙状态
u8 Is_Busy(void){
if((RDSR()&0x01)==1)
return 1; //1 : 忙
else
return 0; //0 :空闲
}
void SST_SPI_Read(u32 addr,u8* buf,u16 size){
int i =0;
SPI_CS_L;
SPI_SendData(0x0B);
SPI_SendData((addr&0xFFFFFF)>>16); //È¡24λµÄ¸ß8λ
SPI_SendData((addr&0xFFFF)>>8); //È¡24λµÄÖÐ8λ
SPI_SendData(addr&0xFF); //È¡24λµÄµÍ8λ
SPI_SendData(0);
while(i>16); //先发送地址高8位
SPI_SendData((addr&0xFFFF)>>8); //发送地址中8位
SPI_SendData(addr&0xFF); //发送地址低8位 因为该芯片是一共24位
SPI_SendData(buf[0]);
SPI_SendData(buf[1]);
SPI_CS_H;
i=2;
while(i
WRSR(); //使能写状态寄存器,打开写保护
WREN(); //使能写数据存储器
/*上面2个函数的调用顺序不能调换*/