一、简介
最近因为项目需求,需要在一块板子内实现一个主机和五个从机的通信;
主机平台选用的是STM32F407VGT6,从机平台选用的是STM32F103C8T6;通信总线选用的是SPI总线。在构想是觉得采用SPI进行主从通信会很简单,但在实际开发的过程中,各种坑,通信时而正常时而混乱。不过在不断探究中,也逐渐发现了,各种问题所在,借此记录下来,希望能帮助一些兄弟在开发中避免一些坑。
本次实现的平台如下:
通信主机:
- 芯片:STM32F103RCT6
- 硬件平台:野火mini开发板
通信从机:
- 芯片:STM32F103C8T6
- 硬件平台:淘宝STM32F103C8T6最小系统开发板
软件:
- HAL库
- MDK
- STM32CubeMx
二、开发过程中遇到的问题
以下是我在开发中遇到问题:
1. 相同的数据,每次发送,主从接收到都是不同的乱码
开发板之间没共地,或者供地接触不够好;更换质量较好的杜邦线,线材很影响信号质量。
2. 通信不正常,很没规律的不正常
检查主从机的SPI外设配置,接线等。
3. 数据出现移位
SPI总线的时钟质量不好,出现不该出现的高低电平,让从机认为这是一bit数据,出现移位寄存器移位,例如原本是8bit数据,现在由于干扰从机接收到的可能是9bit或者10bit数据,而从机实际接收到的数据只是最先传入的8bit数据。
要保证良好的时钟信号,同时也可以将SPI的数据采集触发改成时钟下降沿触发(好像是下降沿的信号质量要比上升沿的信号质量要更好),降低SPI通信速度。
在保证时钟的稳定的情况下,可通过复位从机的SPI外设来解决偶然发生的数据移位问题。
4.从机spi启动比主机慢
在主机发出片选信号都需要加一段延时,以确保从机的SPI外设比主机先启动。
三、硬件电路接线
NSS片选我们使用软件控制方式:
所以我们主从机的SPI通信接线就直接按照手册对接就行。
片选信号根据自己需求设置GPIO口,通过软件控制,有效电平和标准SPI协议保持一样就好,空闲高,有效低。
四、主从机SPI外设配置
4.1、主机配置
其中只有PA4、PA5、PA6、PA7是我们需要关注的,PA4是片选脚
4.2、从机配置
其中只有PA15、PB3、PB4、PB5是我们需要关注的,PA15是片选管脚。
4.3、接线
PA4 -> PA15(片选Nss)
PA5 -> PB3(SCK)
PA6 -> PB4(MISO)
PA7 -> PB5(MOSI)
五、如何清除移位寄存器
通过RCC寄存器复位SPI1外设,在从新初始化SPI1外设完成移位寄存器清除
if(SPI1->SR != 0x02) //当BSY为1时,表示SPI正在忙于通信,但在通信还未开始的时候BSY为1就可以表示移位寄存器存在干扰数据
{
//只用通过RCC复位整个SPI外设后重新初始化,才能清除spi移位寄存器中的残留数据
__HAL_RCC_SPI1_FORCE_RESET();
__HAL_RCC_SPI1_RELEASE_RESET();
MX_SPI1_Init();
printf("SPI复位,清空移位寄存器残留数据\n");
HAL_Delay(10);
}
六、代码
6.1、主机代码
uint8_t rx_buffer[22]={'1','2','3',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
uint8_t tx_buffer[22]={0x00,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16};
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_SPI1_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
printf("主从测试开始\n");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
//SPI通信
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);
HAL_Delay(2); //通过延时保证从机SPI外设比主机先启动
HAL_SPI_TransmitReceive(&hspi1,tx_buffer,rx_buffer,8,100);
HAL_Delay(10);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);
printf("接收到的数据:");
for(num = 0;num < 8;num++)
{
printf("%#x ",rx_buffer[num]);
}
memset(rx_buffer,0,8);
printf("\n");
HAL_Delay(5000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
//重映射printf函数
int fputc(int ch,FILE*stream)
{
uint8_t c =ch;
HAL_UART_Transmit(&huart1,&c,1,50);
return ch;
}
6.2、从机代码
uint8_t Tx_data[8]={0x87,0xa2,0x41,0x02,0x93,0x04,0x05,0x06};
uint8_t Rx_data[8]={0};
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_ADC1_Init();
MX_SPI1_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
bsp_spi_eeror(&hspi1); //通信错误判断
if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_15) == 0) //识别NSS线(低电平有效)
{
HAL_SPI_TransmitReceive(&hspi1,Tx_data,Rx_data,8,100);
while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_15) == 0){}; //等待 主机 释放 片选
printf("spi从机Rx_dete:");
for(int i=0 ; i < 8;i++)
{
printf("%#x ",Rx_data[i]);
}
memset(Rx_data,0,8);
printf("\n主机以释放nss线\n");
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
七、效果展示
左侧为主机串口显示,右侧为从机串口显示;与程序中的数据对比可发现收发数据传输均正确
文章来源:https://www.toymoban.com/news/detail-797121.html
逻辑分析仪显示数据:由于中间片选出现了一次高电平干扰,导致后部分的数据分析异常,但实际传输的数据是正常的。
文章来源地址https://www.toymoban.com/news/detail-797121.html
到了这里,关于STM32 HAL库 SPI主从双机通信的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!