SPI详解,以STM32F4为例

通用SPI有4根线:

①时钟线SCK。
②主机输出从机输入MOSI (master output slave in)。
③主机输入从机输出MISO。
④片选CS(chip select)。建议推挽上拉。

 

由以上四根线定义可见,SPI是区分主机、从机的。片选线的作用:主机通过拉低某个从设备的CS,来选中这个从设备。

时钟SCK只能由主机发出,从机被这个SCK驱动。根据SCK的极性(CPOL,Clock POLarity),和接收方采样的相位(CPHA,Clock PHAse)),SPI可以分为4种模式:

----------CPOL ---CPHA
模式0     0             0      高脉冲(SCK空闲时为低),第1个边沿(上升沿)采样
模式1     0             1      高脉冲(SCK空闲时为低),第2个边沿(下降沿)采样
模式2    1              0      低脉冲(SCK空闲时为高),第1个边沿(下降沿)采样
模式3    1              1      低脉冲(SCK空闲时为高),第2个边沿(上升沿)采样

所谓SCK的极性,极性=0时,意即:SCK空闲时为低电平,发出的脉冲均为高脉冲(低-高-低)。

所谓MISO/MOSI的相位,相位=0,意即:发送方在脉冲的第1个边沿保持数据稳定,供接收方采样。发送方在脉冲的第2个边沿改变数据。

 

 

 

STM32F407的一段例程

/*SPI接口定义-开头****************************/
#define ADIS_SPI                           SPI1
#define ADIS_SPI_CLK                       RCC_APB2Periph_SPI1
#define ADIS_SPI_CLK_INIT                  RCC_APB2PeriphClockCmd

//SPI-CS A4
#define ADIS_CS_PIN                        GPIO_Pin_4              
#define ADIS_CS_GPIO_PORT                  GPIOA                     
#define ADIS_CS_GPIO_CLK                   RCC_AHB1Periph_GPIOA
//SPI-SCK A5
#define ADIS_SPI_SCK_PIN                   GPIO_Pin_5                 
#define ADIS_SPI_SCK_GPIO_PORT             GPIOA                       
#define ADIS_SPI_SCK_GPIO_CLK              RCC_AHB1Periph_GPIOA
#define ADIS_SPI_SCK_PINSOURCE             GPIO_PinSource5
#define ADIS_SPI_SCK_AF                    GPIO_AF_SPI1
//SPI-MISO A6
#define ADIS_SPI_MISO_PIN                  GPIO_Pin_6                
#define ADIS_SPI_MISO_GPIO_PORT            GPIOA                   
#define ADIS_SPI_MISO_GPIO_CLK             RCC_AHB1Periph_GPIOA
#define ADIS_SPI_MISO_PINSOURCE            GPIO_PinSource6
#define ADIS_SPI_MISO_AF                   GPIO_AF_SPI1
//SPI-MOSI A7
#define ADIS_SPI_MOSI_PIN                  GPIO_Pin_7               
#define ADIS_SPI_MOSI_GPIO_PORT            GPIOA                     
#define ADIS_SPI_MOSI_GPIO_CLK             RCC_AHB1Periph_GPIOA
#define ADIS_SPI_MOSI_PINSOURCE            GPIO_PinSource7
#define ADIS_SPI_MOSI_AF                   GPIO_AF_SPI1

#define SPI_ADIS_CS_LOW()      {ADIS_CS_GPIO_PORT->BSRRH=ADIS_CS_PIN;}
#define SPI_ADIS_CS_HIGH()     {ADIS_CS_GPIO_PORT->BSRRL=ADIS_CS_PIN;}
void spi1_init(void)
{

	SPI_InitTypeDef  SPI_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;

    /* 使能 ADIS_SPI 及GPIO 时钟 */
    /*!< SPI_ADIS_SPI_CS_GPIO, SPI_ADIS_SPI_MOSI_GPIO,
         SPI_ADIS_SPI_MISO_GPIO,SPI_ADIS_SPI_SCK_GPIO 时钟使能 */
    RCC_AHB1PeriphClockCmd (ADIS_SPI_SCK_GPIO_CLK | ADIS_SPI_MISO_GPIO_CLK|ADIS_SPI_MOSI_GPIO_CLK|ADIS_CS_GPIO_CLK, ENABLE);

    /*!< SPI_ADIS_SPI 时钟使能 */
    RCC_APB2PeriphClockCmd(ADIS_SPI_CLK, ENABLE);

    //设置引脚复用
    GPIO_PinAFConfig(ADIS_SPI_SCK_GPIO_PORT, ADIS_SPI_SCK_PINSOURCE,ADIS_SPI_SCK_AF);
    GPIO_PinAFConfig(ADIS_SPI_MISO_GPIO_PORT, ADIS_SPI_MISO_PINSOURCE,ADIS_SPI_MISO_AF);
    GPIO_PinAFConfig(ADIS_SPI_MOSI_GPIO_PORT, ADIS_SPI_MOSI_PINSOURCE,ADIS_SPI_MOSI_AF);

	/*!< 配置 SPI_ADIS_SPI 引脚:  CS*/
    GPIO_InitStructure.GPIO_Pin = ADIS_CS_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(ADIS_CS_GPIO_PORT, &GPIO_InitStructure);	
	
    /*!< 配置 SPI_ADIS_SPI 引脚: SCK */
    GPIO_InitStructure.GPIO_Pin = ADIS_SPI_SCK_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//GPIO_PuPd_NOPULL;//GPIO_PuPd_NOPULL; GPIO_PuPd_UP//SCK需要上拉,MI MO均不上拉也不下拉
    GPIO_Init(ADIS_SPI_SCK_GPIO_PORT, &GPIO_InitStructure);

	/*!< 配置 SPI_ADIS_SPI 引脚: MISO */
	GPIO_InitStructure.GPIO_PuPd =GPIO_PuPd_UP;// GPIO_PuPd_UP;
    GPIO_InitStructure.GPIO_Pin = ADIS_SPI_MISO_PIN;
    GPIO_Init(ADIS_SPI_MISO_GPIO_PORT, &GPIO_InitStructure);

	/*!< 配置 SPI_ADIS_SPI 引脚: MOSI */
    GPIO_InitStructure.GPIO_Pin = ADIS_SPI_MOSI_PIN;
	GPIO_InitStructure.GPIO_PuPd =GPIO_PuPd_DOWN;// GPIO_PuPd_UP;
    GPIO_Init(ADIS_SPI_MOSI_GPIO_PORT, &GPIO_InitStructure);
	
    /* 停止信号 ADIS: CS引脚高电平*/
    SPI_ADIS_CS_HIGH();
	
	//Delay_us(1000 * 500);

    /* ADIS_SPI 模式配置 */
    // ADIS芯片 支持SPI模式0及模式3,据此设置CPOL CPHA
    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;
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;//对PCLK2总线做256分频
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_InitStructure.SPI_CRCPolynomial = 10;
    SPI_Init(ADIS_SPI, &SPI_InitStructure);

    /* 使能 SPI  */
    SPI_Cmd(ADIS_SPI, ENABLE);
}

 

其中:
SPI_Direction_2Lines_FullDuplex指双线全双工,
SPI_Mode_Master指工作在主机模式,
SPI_DataSize_8b指的是,每次调用库函数void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data)发送数据时,总是只发出实参的低8位(8个SCK+8个MOSI比特),如果设置为SPI_DataSize_16b,则该函数会一下子发出16个SCK+16个MOSI的实参的16个bits。
SPI_CPOL_High设置SCK的极性,空闲时为高。
SPI_CPHA_2Edge设置MOSI和MISO的采样时机为SCK的第2个边沿。
SPI_NSS_Soft指片选信号不由STM32的硬件SPI模块来控制,也即由程序员自己写GPIO来控制。
SPI_BaudRatePrescaler_256,分频因子,决定了SCK的频率。由于SPI1工作在APB2总线上,SCK的频率就=PCLK2的频率/这个分频因子。
SPI_FirstBit_MSB,先发高bit位,(Most Significant Bit,与之相反的是 least significant bit)
SPI_CRCPolynomial 指的是使用多少阶的CRC多项式进行校验,一般的SPI设备都不具备此功能,随便填个值即可。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值