STM32 SPI 模拟实现 W25X16读写 代码

本文主要是为了针对 SPI 通讯的深入了解,加强基本工的练习。希望对大家有用!联系方式:QQ:279894340 

想要原代码的可以到我的博客下载。谢谢

一、SPI总线协议及SPI时序图详解:

SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。
      SPI是一个环形总线结构,由ss(cs)、sck、sdi、sdo构成,其时序其实很简单,主要是在sck的控制下,两个双向移位寄存器进行数据交换。
    上升沿发送、下降沿接收、高位先发送。
    上升沿到来的时候,sdo上的电平将被发送到从设备的寄存器中。
    下降沿到来的时候,sdi上的电平将被接收到主设备的寄存器中。
    假设主机和从机初始化就绪:并且主机的sbuff=0xaa (10101010),从机的sbuff=0x55 (01010101),下面将分步对spi的8个时钟周期的数据情况演示一遍(假设上升沿发送数据)。
---------------------------------------------------
脉冲           主机sbuff    从机sbuff     sdi    sdo(到从设备)
---------------------------------------------------
0    00-0     10101010     01010101      0      0
---------------------------------------------------
1    0--1     0101010x     10101011      0      1
1    1--0     01010100     10101011      0      1
---------------------------------------------------
2    0--1     1010100x     01010110      1      0
2    1--0     10101001     01010110      1      0
---------------------------------------------------
3    0--1     0101001x     10101101      0      1
3    1--0     01010010     10101101      0      1
---------------------------------------------------
4    0--1     1010010x     01011010      1      0
4    1--0     10100101     01011010      1      0
---------------------------------------------------
5    0--1     0100101x     10110101      0      1
5    1--0     01001010     10110101      0      1
---------------------------------------------------
6    0--1     1001010x     01101010      1      0
6    1--0     10010101     01101010      1      0
---------------------------------------------------
7    0--1     0010101x     11010101      0      1
7    1--0     00101010     11010101      0      1
---------------------------------------------------
8    0--1     0101010x     10101010      1      0
8    1--0     01010101     10101010      1      0全双工通讯,一次传2个字节
---------------------------------------------------

    这样就完成了两个寄存器8位的交换,上面的0--1表示上升沿、1--0表示下降沿,sdi、 sdo相对于主机而言的。根据以上分析,一个完整的传送周期是16位,即两个字节,因为,首先主机要发送命令过去,然后从机根据主机的名准备数据,主机在下一个8位时钟周期才把数据读回来。
    SPI总线是Motorola公司推出的三线同步接口,同步串行3线方式进行通信:一条时钟线SCK,一条数据输入线MOSI,一条数据输出线MISO;用于 CPU与各种外围器件进行全双工、同步串行通讯。SPI主要特点有:可以同时发出和接收串行数据;可以当作主机或从机工作;提供频率可编程时钟;发送结束中断标志;写冲突保护;总线竞争保护等。


/*********************************************************************************************************

** 宏定义
*********************************************************************************************************/ 
#define SPI_CSHIGH  GPIO_SetBits(GPIOB,GPIO_Pin_9)  // CS----PB9
#define SPI_CSLOW   GPIO_ResetBits(GPIOB,GPIO_Pin_9)  
  
#define SPI_SCKHIGH GPIO_SetBits(GPIOA,GPIO_Pin_5)    //SCLK----PA5
#define SPI_SCKLOW  GPIO_ResetBits(GPIOA,GPIO_Pin_5)  

#define SPI_OUTHIGH GPIO_SetBits(GPIOA,GPIO_Pin_7)  
#define SPI_OUTLOW  GPIO_ResetBits(GPIOA,GPIO_Pin_7)  //MOSI----PA7

#define SPI_IN      GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_6)  //MISO----PA6

/**********************************************************************
* Function:  SPI_SendData
* Description:  
*               
* Input:      void
* Output:    
* Return:  RecevieData  :接收到的数据
* Others:  
* Modify Date:    Version:    Author:      Modification:
* -----------------------------------------------
* 2017-06-22  V1.0     Hu Weiping         
**********************************************************************/
static uint8_t SPI_SendData(uint8_t data)  
{  
    uint8_t RecevieData=0,i;  

    for(i=0;i<8;i++)  
    {  
        if(data&0x80)  
        {  
            SPI_OUTHIGH;  
        }  
        else  
        {  
            SPI_OUTLOW;  
        }  

      SPI_SCKHIGH;              //我这里是选择下降沿采集数据
       data<<=1; 
     __NOP();__NOP();__NOP();__NOP(); 
     RecevieData <<= 1;

        if(SPI_IN)
        {
            RecevieData |= 1; //Wait SDO to go Hi
        }
       SPI_SCKLOW;          
    }  
    return RecevieData;  
}

/**********************************************************************
* Function:  MYSPI_Init
* Description:  初始化GPIO口
*               
* Input:      void
* Output:    
* Return:    void 
* Others:  
* Modify Date:    Version:    Author:      Modification:
* -----------------------------------------------
* 2017-06-22  V1.0     Hu Weiping         
**********************************************************************/
static void MYSPI_Init(void)  
{  
    GPIO_InitTypeDef GPIO_InitStructure;  
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOA ,ENABLE);                      
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;  
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_7; //SPI_CS  and SPI_SCK and SPI_OUT  
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 
    GPIO_Init(GPIOA,&GPIO_InitStructure);  

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; //SPI_IN  
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;  
    GPIO_Init(GPIOA,&GPIO_InitStructure);  

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;  
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //SPI_CS  and SPI_SCK and SPI_OUT  
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  
    GPIO_Init(GPIOB,&GPIO_InitStructure);  
    SPI_CSHIGH;  
    SPI_SCKLOW;  
    SPI_OUTLOW;  
}

/**********************************************************************
* Function:  SPI_Delay
* Description:  
*               
* Input:      void
* Output:    
* Return:    void 
* Others:  
* Modify Date:    Version:    Author:      Modification:
* -----------------------------------------------
* 2017-06-22  V1.0     Hu Weiping          
**********************************************************************/
static void SPI_Delay(void)  
{  
    uint16_t i;  

    for(i=0;i<72;i++);  

/**********************************************************************
* Function:  W25x16_WriteEnable
* Description:  
*               
* Input:      void
* Output:    
* Return:    void 
* Others:  
* Modify Date:    Version:    Author:      Modification:
* -----------------------------------------------
* 2017-06-22  V1.0     Hu Weiping          
**********************************************************************/
void W25x16_WriteEnable(void)  
{  
    SPI_CSLOW;  
    SPI_SendData(0x06);  
    SPI_CSHIGH;  
    SPI_Delay();  

/**********************************************************************
* Function:  W25x16_BlockErase
* Description:  SectorErase  64K Byte 
*               
* Input:      void
* Output:    
* Return:    void 
* Others:  
* Modify Date:    Version:    Author:      Modification:
* -----------------------------------------------
* 2017-06-22  V1.0     Hu Weiping         
**********************************************************************/
void W25x16_BlockErase(uint16_t addr)  
{  
    W25x16_WriteEnable();  
    SPI_CSLOW;  
    SPI_SendData(0xD8);  
    SPI_SendData((addr>>16)&0xFF);
    SPI_SendData((addr>>8)&0xFF);  
    SPI_SendData(addr&0xFF);  
    SPI_CSHIGH;  
}  

/**********************************************************************
* Function:  W25x16_ReadDeviceID
* Description:  读取设备ID
*               
* Input:      void
* Output:    
* Return:    void 
* Others:  
* Modify Date:    Version:    Author:      Modification:
* -----------------------------------------------
* 2017-06-22  V1.0     Hu Weiping         
**********************************************************************/
uint32_t W25x16_NewReadDeviceID(void)  
{  
    uint8_t ret;  

   u32 Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0;

    SPI_CSLOW;  
    SPI_SendData(0x9F);  
    Temp0 = SPI_SendData(0xff);  
    Temp1 = SPI_SendData(0xff);  
    Temp2 = SPI_SendData(0xff);  
    SPI_CSHIGH;  
    Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2;
    return Temp;  


uint8_t WriteBuf[10] = {0xAA, 0xBB, 0x45, 0x78, 0x34, 0x78, 0x89,0xAC, 0xBC, 0xDD};  
uint8_t RreadBuf[10] = {0};  
void W25x16_test(void)  

    W25x16_SectorErase(0x0000);
        W25x16_WritePage(0x0000, WriteBuf, 10);  
W25x16_ReadData(0x0000, RreadBuf, 10);
}

/**********************************************************************
* Function:  W25x16_Init
* Description:  初始化设备ID  
*               
* Input:      void
* Output:    
* Return:    void 
* Others:  
* Modify Date:    Version:    Author:      Modification:
* -----------------------------------------------
* 2017-06-22  V1.0     Hu Weiping         
**********************************************************************/  
__IO uint32_t numID = 0;


void W25x16_Init(void)  
{  
MYSPI_Init();  
numID = W25x16_NewReadDeviceID();   //这里可以查看到W25X16  ID 
W25x16_test();  
       while(1);
}

你可能感兴趣的:(STM32 SPI 模拟实现 W25X16读写 代码)