STM32的SPI学习(SPI芯片为SST25VF016B)

学习板芯片为STM32F103VE

先简单介绍下SPI(全称:Serial Peripheral interface,串行外围设备接口):SPI接口主要应用在 EEPROM,FLASH,实时时钟,AD转换器,是一种高速的,全双工,同步的通信总线。一般SPI芯片与MCU通信,只会使用4个管脚:MOSI(主输出),MISO(主输入),CS(片选低电平有效),SCK(时钟)


STM32的SPI学习(SPI芯片为SST25VF016B)_第1张图片


从图中可以看出,
主机和从机都有一个串行移位寄存器,主机通过向它的串行寄存器写入一个字节来发起一次传输。
寄存器通过MOSI信号线将字节传送给从机,从机也将自己的移位寄存器中的内容通过MISO信号线返回给主机。
这样,两个移位寄存器中的内容就被交换。
外设的写操作和读操作是同步完成的。
如果只进行写操作,主机只需忽略接收到的字节;
反之,若主机要读取从机的一个字节,就必须发送一个空字节来引发从机的传输。


STM32内的SPI的特点:

1 8或16位传输帧格式选择

2 可编程的时钟极性(CPOL)和相位(CPHA)

3 可编程的数据顺序,MSB在前或LSB在前

4 8个主模式波特率预分频系数(最大为fPCLK/2)

5 支持DMA功能的1字节发送和接收缓冲器:产生发送和接受请求

6 可触发中断的专用发送和接收标志


SPI较重要的寄存器:

STM32的SPI学习(SPI芯片为SST25VF016B)_第2张图片


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

状态寄存器:STM32的SPI学习(SPI芯片为SST25VF016B)_第3张图片


更多信息参考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个函数的调用顺序不能调换*/
    
    SPI_CS_L;    
    SPI_SendData(0x20);
    SPI_SendData((addr&0xFFFFFF)>>16);    
    SPI_SendData((addr&0xFFFF)>>8);
    SPI_SendData(addr&0xFF); 
    
    SPI_CS_H;    
    while(Is_Busy());    
    
}



//写数据存储器使能
void WREN(void){    
    SPI_CS_L;    
    SPI_SendData(0x06);
    SPI_CS_H;
}

//写数据存储器禁止
void WRDI(void){    
    SPI_CS_L;    
    SPI_SendData(0x04);
    SPI_CS_H;    
    while(Is_Busy());
}

//使能写状态寄存器,打开写保护
void WRSR(void){
    SPI_CS_L;    
    SPI_SendData(0x50);
    SPI_CS_H;    
    SPI_CS_L;    
    SPI_SendData(0x01);        //    BP3 BP2 BP1 BP0 置0,取消写保护
    SPI_SendData(0);
    SPI_CS_H;    
    while(Is_Busy());
}

//读取器件ID,用于判断SPI通信是否成功
u16 RDID(void){
    u16 id;
    
    SPI_CS_L;    
    SPI_SendData(0x90);
    SPI_SendData(0x00);
    SPI_SendData(0x00);
    SPI_SendData(0x00);
    id = SPI_ReadData();
    id<<=8;
    id += SPI_ReadData();
    SPI_CS_H;
    
    return id;
}


//主函数
int main(void){
    u8 readBuf[100];
    u8 str[]="hello world 你好";
    u16 size=sizeof(str)/sizeof(str[0]);
    RCC_Configuration();
    GPIO_Configuration();
    USART_Configuration();
    SPI_Configuration();
    
    /*data = RDID();
    printf("%X\r\n",data);*/
    
    SST_SPI_WRITE(0,str,size); //写入hello world 你好
    delay_ms(100);
    SST_SPI_Read(0,readBuf,size);//读出hello world 你好
    printf("%s\r\n",readBuf);
    delay_ms(5000);
    
    while(1){
    }
}
 
  





你可能感兴趣的:(STM32基础)