STM32F401RET6 LQFP64 (Nucleo-F401RE) SPI通信(主从双机SPI通信)

STM32F401RET6 LQFP64 (Nucleo-F401RE) SPI通信(主从双机SPI通信)

1.1 SPI总线介绍

SPI 通讯使用 3 条总线及片选线,3 条总线分别为 SCK、MOSI、MISO,片选线为NSS(CS)

请添加图片描述

NSS 信号线由高变低 ,是 SPI 通讯的起始信号 。 NSS 是每个从机各自独占的信号线,当从机在自己的 NSS 线检测到起始信号后,就知道自己被主机选 中了,开始准备与主机通讯。在图中的标号处, NSS 信号由低变高 ,是 SPI 通讯的停止 信号 ,表示本次通讯结束,从机的选中状态被取消。

SPI 使用 MOSI 及 MISO 信号线来传输数据,使用 SCK 信号线进行数据同步。 MOSI 及 MISO 数据线在 SCK 的每个时钟周期传输一位数据,且数据输入输出是同时进行的。

SPI 一共有四种通讯模 式,它们的主要区别是总线空闲时 SCK 的时钟状态以及数据采样时刻。为方便说明,在此 引入“时钟极性 CPOL”和“时钟相位 CPHA”的概念。

时钟极性 CPOL 是指 SPI 通讯设备处于空闲状态时, SCK 信号线的电平信号(即 SPI 通 讯开始前、 NSS 线为高电平时 SCK 的状态)。 CPOL=0 时, SCK 在空闲状态时为低电平,CPOL=1 时,则相反。

时钟相位 CPHA 是指数据的采样的时刻,当 CPHA=0 时, MOSI 或 MISO 数据线上的信号将会在 SCK 时钟线的“奇数边沿” 被采样。当 CPHA=1 时,数据线在 SCK 的“偶数边沿” 采样。

1.1.1 CPHA=0 时的 SPI 通讯模式

在这里插入图片描述
在这里插入图片描述

1.1.2 CPHA=1 时的 SPI 通讯模式

在这里插入图片描述

1.2 注意事项

  • SCLK信号线只由主设备控制,从设备不能控制信号线。同样,在一个基于SPI的设备中,至少有一个主控设备;

  • 部分MCU SPI模块一旦使能。SCK一直输出。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mWZBDnNf-1684574929468)(D:\tool_install\st mcu\STM32F401RET6 LQFP64 (Nucleo-F401RE)] SPI通信(主从双机SPI通信).assets\v2-2fdc62a4f8d7ae6038ca4678c6241b5c_1440w.webp)

1.3 SPI模式编号

SPI的时钟极性和相位的配置通常称为 SPI模式,所有可能的模式都遵循以下约定;具体如下表所示;

SPI Mode CPOL CPHA
0 [00] 0 0
1 [01] 0 1
2 [10] 1 0
3 [11] 1 1

1.4 MCU 与MCU 之间主从通信连接

连线是一一对应的,不能将MOSI接上MISO,且两个设备的配置参数速率、相位、极性、CRC和传输方向及位数要相同,切记,一定要共地

1.4.1 SPI 初始化CLK以及PIN 复用

void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	if(spiHandle->Instance==SPI1)
	{
	    /* SPI2 clock enable */
	    __HAL_RCC_SPI1_CLK_ENABLE();
	  
	    __HAL_RCC_GPIOA_CLK_ENABLE();
	    /**SPI1 GPIO Configuration    
D13 SCK PA5

D12 MISO PA6

D11 MOSI PA7

D10 CS  PB6
	    */


	    GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
	    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
	    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
			GPIO_InitStruct.Pull=GPIO_PULLUP ;//GPIO_NOPULL; 
			GPIO_InitStruct.Alternate=GPIO_AF5_SPI1; 
	    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
	
		printf("spi pin init\r\n");
//	    GPIO_InitStruct.Pin = ADC_MISO_Pin;
//	    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
//	    GPIO_InitStruct.Pull = GPIO_NOPULL;
//	    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
	}
}

1.4.2 SPI控制器初始化

  /*##-1- Configure the SPI peripheral #######################################*/
  /* Set the SPI parameters */
  SpiHandle.Instance               = SPIx;
  
  SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
  SpiHandle.Init.Direction         = SPI_DIRECTION_2LINES;
//  SpiHandle.Init.CLKPhase          = SPI_PHASE_1EDGE;
//  SpiHandle.Init.CLKPolarity       = SPI_POLARITY_HIGH;
	
//#ifdef MASTER_BOARD
	SpiHandle.Init.CLKPhase = SPI_PHASE_2EDGE;
//#else
	//SpiHandle.Init.CLKPhase          = SPI_PHASE_1EDGE;
//#endif
	SpiHandle.Init.CLKPolarity       = SPI_POLARITY_HIGH;
	
  SpiHandle.Init.CRCCalculation    = SPI_CRCCALCULATION_DISABLE;
  SpiHandle.Init.CRCPolynomial     = 7;
  SpiHandle.Init.DataSize          = SPI_DATASIZE_8BIT;
  SpiHandle.Init.FirstBit          = SPI_FIRSTBIT_MSB;
	#ifdef MASTER_BOARD
  SpiHandle.Init.NSS               = SPI_NSS_SOFT;
	#else
  SpiHandle.Init.NSS               = SPI_NSS_HARD_INPUT;
	#endif
  SpiHandle.Init.TIMode            = SPI_TIMODE_DISABLE;
  
#ifdef MASTER_BOARD
  SpiHandle.Init.Mode = SPI_MODE_MASTER;
	printf("SPI MASTER_BOARD\r\n");
#else
  SpiHandle.Init.Mode = SPI_MODE_SLAVE;
	printf("SPI slaver_BOARD\r\n");
#endif /* MASTER_BOARD */
	printf("HAL_SPI_Init start \r\n");
  if(HAL_SPI_Init(&SpiHandle) != HAL_OK)
  {
    /* Initialization Error */
    //Error_Handler();
		printf("Initialization Error \r\n");
		while(1);
  }

dle) != HAL_OK)
{
/* Initialization Error */
//Error_Handler();
printf(“Initialization Error \r\n”);
while(1);
}


猜你喜欢

转载自blog.csdn.net/xushx_bigbear/article/details/130783884