STM32 3个硬件SPI的使用

本文详细介绍了STM32微控制器中SPI1、SPI2和SPI3的硬件初始化过程,包括时钟配置、引脚配置及SPI模式设置等关键步骤,并提供了模拟SPI时序的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

硬件平台:STM32F103

SPI1初始化过程

static OS_EVENT *spi1_sem_event;
static void SPI1SemInit(void)
{
    spi1_sem_event = OSSemCreate(1);
}

extern void SPI1SemGet(void)
{
    uint8_t err;

    OSSemPend(spi1_sem_event, 0, &err);
}

extern void SPI1SemPut(void)
{
    OSSemPost(spi1_sem_event);
}
static void Spi1_Init(void)
{
    SPI_InitTypeDef  SPI_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;

    /* Enable SPI1 and GPIO clocks */
    /*!< SPI_FLASH_SPI_CS_GPIO, SPI_FLASH_SPI_MOSI_GPIO,
       SPI_FLASH_SPI_MISO_GPIO, SPI_FLASH_SPI_DETECT_GPIO
       and SPI_FLASH_SPI_SCK_GPIO Periph clock enable */

    /*!< SPI_FLASH_SPI Periph clock enable */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
    /*!< AFIO Periph clock enable */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);


    /*!< Configure SPI_FLASH_SPI pins: SCK */
    GPIO_InitStructure.GPIO_Pin = PIN_SPI1_SCLK;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(PORT_SPI1_SCLK, &GPIO_InitStructure);

    /*!< Configure SPI_FLASH_SPI pins: MISO */
    GPIO_InitStructure.GPIO_Pin = PIN_SPI1_MISO;
    GPIO_Init(PORT_SPI1_MISO, &GPIO_InitStructure);

    /*!< Configure SPI_FLASH_SPI pins: MOSI */
    GPIO_InitStructure.GPIO_Pin = PIN_SPI1_MOSI;
    GPIO_Init(PORT_SPI1_MOSI, &GPIO_InitStructure);

    /* SPI1 configuration */
    // W25X16: data input on the DIO pin is sampled on the rising edge of the CLK.
    // Data on the DO and DIO pins are clocked out on the falling edge of CLK.
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//设置SPI工作模式:设置为主SPI
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;//设置SPI的数据大小:SPI发送接收8位帧结构
#if 0
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //串行同步时钟的空闲状态为高电平
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //串行同步时钟的第二个跳变沿(上升或下降)数据被采样
#else
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;      //时钟悬空低
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;    //数据捕获于第1个时钟沿
#endif
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;   //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;//定义波特率预分频的值:波特率预分频值为2
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
    SPI_InitStructure.SPI_CRCPolynomial = 7;//CRC值计算的多项式
    SPI_Init(SPI1, &SPI_InitStructure);

    /* Enable SPI1  */
    SPI_Cmd(SPI1, ENABLE);
    SPI1SemInit();
}
extern void SPI1_SetSpeed(u8 SpeedSet)
{
    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;
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
    //如果速度设置输入0,则低速模式,非0则高速模式
    if(SpeedSet == 1)
    {
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32;
    }
    else
    {
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
    }
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_InitStructure.SPI_CRCPolynomial = 7;
    SPI_Init(SPI1, &SPI_InitStructure);
}

extern void spi1WriteData(Uchar *buf,Uint len)
{
    for (; len ; len--,buf++)
    {
        while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
        SPI_I2S_SendData(SPI1, *buf);
        while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
        SPI_I2S_ReceiveData(SPI1);
    }
}

extern u8 SPI1_Swap_DataMSB(u8 byte)
{
    u8 retry=0;
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) //检查指定的SPI标志位设置与否:发送缓存空标志位
    {
        retry++;
        if(retry>200)return 0;
    }
    SPI_I2S_SendData(SPI1, byte); //通过外设SPIx发送一个数据
    retry=0;

    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET) //检查指定的SPI标志位设置与否:接受缓存非空标志位
    {
        retry++;
        if(retry>200)return 0;
    }
    return SPI_I2S_ReceiveData(SPI1); //返回通过SPIx最近接收的数据
}

SPI2初始化过程

static OS_EVENT *spi2_sem_event;
static void SPI2SemInit(void)
{
    spi2_sem_event = OSSemCreate(1);
}

extern void SPI2SemGet(void)
{
    uint8_t err;

    OSSemPend(spi2_sem_event, 0, &err);
}

extern void SPI2SemPut(void)
{
    OSSemPost(spi2_sem_event);
}

extern void Spi2_Init(void)
{
    SPI_InitTypeDef  SPI_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
    /*!< AFIO Periph clock enable */
    //RCC_APB2PeriphClockCmd(RCC_APB1Periph_AFIO, ENABLE);


    GPIO_InitStructure.GPIO_Pin = PIN_SPI2_SCLK;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(PORT_SPI2_SCLK, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = PIN_SPI2_MISO;
    GPIO_Init(PORT_SPI2_MISO, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = PIN_SPI2_MOSI;
    GPIO_Init(PORT_SPI2_MOSI, &GPIO_InitStructure);

    /* SPI2 configuration */
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
#if 1
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
#else
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;      //时钟悬空低
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;        //数据捕获于第1个时钟沿
#endif
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_InitStructure.SPI_CRCPolynomial = 7;
    SPI_Init(SPI2, &SPI_InitStructure);

    /* Enable SPI2  */
    SPI_Cmd(SPI2, ENABLE);
    SPI2SemInit();
}

/*******************************************************************************
* Function Name  : SPI_SetSpeed
* Description    : SPI设置速度为高速
* Input          : u8 SpeedSet
*                  如果速度设置输入0,则低速模式,非0则高速模式
*                  SPI_SPEED_HIGH   1
*                  SPI_SPEED_LOW    0
* Output         : None
* Return         : None
*******************************************************************************/
void SPI2_SetSpeed(u8 SpeedSet)
{
    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;
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
    //如果速度设置输入0,则低速模式,非0则高速模式
    if(SpeedSet == 1)
    {
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32;
    }
    else
    {
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
    }
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_InitStructure.SPI_CRCPolynomial = 7;
    SPI_Init(SPI2, &SPI_InitStructure);
}

extern void spi2WriteData(Uchar *buf,Uint len)
{
    for (; len ; len--,buf++)
    {
        while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);
        SPI_I2S_SendData(SPI2, *buf);
        while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);
        SPI_I2S_ReceiveData(SPI2);
    }
}

extern u8 SPI2_Swap_DataMSB(u8 byte)
{
  /* Loop while DR register in not emplty */
  while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);

  /* Send byte through the SPI1 peripheral */
  SPI_I2S_SendData(SPI2, byte);

  /* Wait to receive a byte */
  while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);

  /* Return the byte read from the SPI bus */
  return SPI_I2S_ReceiveData(SPI2);
}

SPI3初始化过程

static OS_EVENT *spi3_sem_event;

static void SPI3SemInit(void)
{
    spi3_sem_event = OSSemCreate(1);
}

extern void SPI3SemGet(void)
{
    uint8_t err;

    OSSemPend(spi3_sem_event, 0, &err);
}

extern void SPI3SemPut(void)
{
    OSSemPost(spi3_sem_event);
}

static void Spi3_Init(void)
{
    SPI_InitTypeDef  SPI_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;

    /* Enable SPI1 and GPIO clocks */
    /*!< SPI_FLASH_SPI_CS_GPIO, SPI_FLASH_SPI_MOSI_GPIO,
       SPI_FLASH_SPI_MISO_GPIO, SPI_FLASH_SPI_DETECT_GPIO
       and SPI_FLASH_SPI_SCK_GPIO Periph clock enable */

    /*!< SPI_FLASH_SPI Periph clock enable */
    //RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);
    /*!< AFIO Periph clock enable */
    //RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);


    /*!< Configure SPI_FLASH_SPI pins: SCK */
    GPIO_InitStructure.GPIO_Pin = PIN_SPI_SCLK;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(PORT_SPI_SCLK, &GPIO_InitStructure);

    /*!< Configure SPI_FLASH_SPI pins: MISO */
    GPIO_InitStructure.GPIO_Pin = PIN_SPI_MISO;
    GPIO_Init(PORT_SPI_MISO, &GPIO_InitStructure);

    /*!< Configure SPI_FLASH_SPI pins: MOSI */
    GPIO_InitStructure.GPIO_Pin = PIN_SPI_MOSI;
    GPIO_Init(PORT_SPI_MOSI, &GPIO_InitStructure);

    /* SPI1 configuration */
    // W25X16: data input on the DIO pin is sampled on the rising edge of the CLK.
    // Data on the DO and DIO pins are clocked out on the falling edge of CLK.
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
#if 1
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
#else
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;      //时钟悬空低
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;    //数据捕获于第1个时钟沿
#endif
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_InitStructure.SPI_CRCPolynomial = 7;
    SPI_Init(SPI3, &SPI_InitStructure);

    /* Enable SPI1  */
    SPI_Cmd(SPI3, ENABLE);
    SPI3SemInit();
}

/*******************************************************************************
* Function Name  : SPI_SetSpeed
* Description    : SPI设置速度为高速
* Input          : u8 SpeedSet
*                  如果速度设置输入0,则低速模式,非0则高速模式
*                  SPI_SPEED_HIGH   1
*                  SPI_SPEED_LOW    0
* Output         : None
* Return         : None
*******************************************************************************/
void SPI3SetSpeed(u8 SpeedSet)
{
    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;
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
    //如果速度设置输入0,则低速模式,非0则高速模式
    if(SpeedSet == 1)
    {
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32;
    }
    else
    {
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
    }
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_InitStructure.SPI_CRCPolynomial = 7;
    SPI_Init(SPI3, &SPI_InitStructure);
}

extern void spi3WriteData(Uchar *buf,Uint len)
{
    for (; len ; len--,buf++)
    {
        while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_TXE) == RESET);
        SPI_I2S_SendData(SPI3, *buf);
        while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_RXNE) == RESET);
        SPI_I2S_ReceiveData(SPI3);
    }
}


extern u8 SPI3_Swap_DataMSB(u8 byte)
{
  /* Loop while DR register in not emplty */
  while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_TXE) == RESET);

  /* Send byte through the SPI1 peripheral */
  SPI_I2S_SendData(SPI3, byte);

  /* Wait to receive a byte */
  while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_RXNE) == RESET);

  /* Return the byte read from the SPI bus */
  return SPI_I2S_ReceiveData(SPI3);
}

SPI用GPIO模拟注意以下四种状态的时序,转自网络~~~

#define _CPOL     1
#define _CPHA     0
#define SCK_IO    DDRA|=0X01
#define MOSI_IO   DDRA|=0X02
#define MISO_IO   DDRA&=0XFB
#define SSEL_IO   DDRA|=0X08
#define SCK_D(X)   (X?(PORTA|=0X01):(PORTA&=0XFE))
#define MOSI_D(X)  (X?(PORTA|=0X02):(PORTA&=0XFD))
#define SSEL_D(X)  (X?(PORTA|=0X08):(PORTA&=0XF7))

#define MISO_I()  (PINA&0X04)  
void delay()
{
 unsigned char m,n;
     for(n=0;n<5;n++);
    for(m=0;m<100;m++);
}
/************************************************
        端口方向配置  与输出初始化
************************************************/
void SPI_Init(void)
{
    SCK_IO   ; 
    MOSI_IO  ;
    MISO_IO  ; 
    SSEL_IO  ;
    SSEL_D(1);
    MOSI_D(1);

    #if _CPOL==0
        SCK_D(0);
    #else
        SCK_D(1);
    #endif
}

/**********************************************
模式零           写数据
***********************************************/
#if _CPOL==0&&_CPHA==0          //MODE   0  0   
void SPI_Send_Dat(unsigned char dat)
{
    unsigned char n;
    for(n=0;n<8;n++)
    {
        SCK_D(0);
        if(dat&0x80)MOSI_D(1);
        else MOSI_D(0);
        dat<<=1;
        SCK_D(1);
    }
    SCK_D(0);
}
/*********************************************
模式零         读数据
*********************************************/
unsigned char SPI_Receiver_Dat(void)
{
    unsigned char n ,dat,bit_t;
    for(n=0;n<8;n++)
    {
        SCK_D(0);
        dat<<=1;
        if(MISO_I())dat|=0x01;
        else dat&=0xfe;
        SCK_D(1);
    }
    SCK_D(0);
    return dat;
}
#endif
/**********************************************
模式二           写数据
***********************************************/
#if _CPOL==1&&_CPHA==0           //MODE   1  0
void SPI_Send_Dat(unsigned char dat)
{
    unsigned char n;
    for(n=0;n<8;n++)
    {
        SCK_D(1);
        if(dat&0x80)MOSI_D(1);
        else MOSI_D(0);
        dat<<=1;
        SCK_D(0);
    }
    SCK_D(1);
}
/*********************************************
模式二          读数据
*********************************************/
unsigned char SPI_Receiver_Dat(void)
{
    unsigned char n ,dat,bit_t;
    for(n=0;n<8;n++)
    {
        SCK_D(1);
        dat<<=1;
        if(MISO_I())dat|=0x01;
        else dat&=0xfe;
        SCK_D(0);
    }
    SCK_D(1);
    return dat;
}

#endif
/*********************************************
模式一        写数据
*********************************************/
#if _CPOL==0&&_CPHA==1           //MODE  0  1
void SPI_Send_Dat(unsigned char dat)
{
    unsigned char n;
    SCK_D(0);
    for(n=0;n<8;n++)
    {
        SCK_D(1);
        if(dat&0x80)MOSI_D(1);
        else MOSI_D(0);
        dat<<=1;
        SCK_D(0);
    }
}
/*********************************************
模式一       读数据
*********************************************/
unsigned char SPI_Receiver_Dat(void)
{
    unsigned char n ,dat,bit_t;
    for(n=0;n<8;n++)
    {
        SCK_D(1);
        dat<<=1;
        if(MISO_I())dat|=0x01;
        else dat&=0xfe;
        SCK_D(0);
    }
    SCK_D(0);
    return dat;
}
#endif
///
///

#if _CPOL==1&&_CPHA==1            //MODE  1  1
void SPI_Send_Dat(unsigned char dat)
{
    unsigned char n;
    SCK_D(1);
    for(n=0;n<8;n++)
    {
        SCK_D(0);
        if(dat&0x80)MOSI_D(1);
        else MOSI_D(0);
        dat<<=1;
        SCK_D(1);
    }
}
/************************************
模式三          读数据
************************************/
unsigned char SPI_Receiver_Dat(void)
{
    unsigned char n ,dat,bit_t;
    SCK_D(0);
    for(n=0;n<8;n++)
    { 
        SCK_D(0);
        dat<<=1;
        if(MISO_I())dat|=0x01;
        else dat&=0xfe;
        SCK_D(1);
    }
    SCK_D(1);
    return dat;
}
#endif
/*************************************
*************************************/
void main()
{

    SPI_Init();
    DDRB = 0XFF;
    //#if _CPOL
    //SCK_D(0);
    //#endif
    while(1)
    {
        //SSEL_D(0);
        //SPI_Send_Dat(0x01);
        //SPI_Send_Dat(0x31);
        //SSEL_D(1);
        SSEL_D(0);
        SPI_Send_Dat(0x81);
        PORTB =SPI_Receiver_Dat();
        SSEL_D(1);
        //delay();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值