STM32 HAL库 SPI主从双机通信

这篇具有很好参考价值的文章主要介绍了STM32 HAL库 SPI主从双机通信。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、简介

最近因为项目需求,需要在一块板子内实现一个主机和五个从机的通信;
主机平台选用的是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外设比主机先启动。
stm32f103spi主从通,STM32 HAL库,stm32,嵌入式硬件,单片机

三、硬件电路接线

NSS片选我们使用软件控制方式:
stm32f103spi主从通,STM32 HAL库,stm32,嵌入式硬件,单片机
stm32f103spi主从通,STM32 HAL库,stm32,嵌入式硬件,单片机
所以我们主从机的SPI通信接线就直接按照手册对接就行。
片选信号根据自己需求设置GPIO口,通过软件控制,有效电平和标准SPI协议保持一样就好,空闲高,有效低。

四、主从机SPI外设配置

4.1、主机配置

stm32f103spi主从通,STM32 HAL库,stm32,嵌入式硬件,单片机
其中只有PA4、PA5、PA6、PA7是我们需要关注的,PA4是片选脚

4.2、从机配置

stm32f103spi主从通,STM32 HAL库,stm32,嵌入式硬件,单片机
其中只有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 */
}

七、效果展示

左侧为主机串口显示,右侧为从机串口显示;与程序中的数据对比可发现收发数据传输均正确
stm32f103spi主从通,STM32 HAL库,stm32,嵌入式硬件,单片机

逻辑分析仪显示数据:由于中间片选出现了一次高电平干扰,导致后部分的数据分析异常,但实际传输的数据是正常的。
stm32f103spi主从通,STM32 HAL库,stm32,嵌入式硬件,单片机文章来源地址https://www.toymoban.com/news/detail-797121.html

到了这里,关于STM32 HAL库 SPI主从双机通信的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32——STM32F103时钟解析(正点原子资料+HAL库代码分析)

    上次写系统时钟解析的时候说出一篇103的时钟解析,我就整理HAL库开发的正点的资料,给小白梳理,我也是小白,不做权威使用。 在 STM32 中,有五个时钟源,为 HSI、HSE、LSI、LSE、PLL。从时钟频率来分可以分为高速时钟源和低速时钟源,在这 5 个中 HIS,HSE 以及 PLL 是高速时钟

    2024年02月19日
    浏览(49)
  • 基于STM32F103HAL库的声音定位系统

    这是一道学校出的电赛题目,要求在100*100cm的平面上实现定位实现声音定位。由于一米太大了,我们就做了40cm的,下面的讲解我按照40厘米的写。用到的处理器是stm32f103c8t6接下来分享一下调试心得。 硬件部分需要制作发声装置和接收装置,详细可以

    2024年02月14日
    浏览(59)
  • STM32 F103C8T6学习笔记7:双机无线串口通信

    今日尝试配通俩个C8T6单片机之间的无线串口通信,文章提供原理,源码,测试效果图,测试工程下载: 目录 传输不规范问题: 串口通信资源: 单个串口资源理解: 单片机串口资源: 测试目标与测试硬件连接: 串口初始化与串口中断接收逻辑: 串口初始化: 初步测试能否

    2024年02月09日
    浏览(41)
  • HAL库(STM32CubeMX)之外部中断(STM32F103C8T6)

    HAL库(STM32CubeMX)——ADC学习总结(包含单次/连续模式下的轮询/中断/DMA)(蓝桥杯STM32G431RBT6) HAL库(STM32CubeMX)——DAC学习(STM32G431RBT6) HAL库(STM32CubeMX)——USART配置(中断接收/STM32G431RBT6) HAL库(STM32CubeMX)——基本定时器、PWM、输入捕获、输出比较、互补式PWM等综合学习(STM32

    2024年02月06日
    浏览(51)
  • 使用STM32F103的SPI+DMA驱动ws2812 LED

    目录 前言 一、WS2812协议 1.1 数据传输编码方式:  1.2 传输的数据结构 二、驱动方式:SPI+DMA 2.1 原理介绍 2.2 SPI+DMA操作  2.3 编写代码 2.4 使用 三 总结 参考文章 主要使用的STM32F103C8T6芯片的SPI+DMA方式实现WS2812的驱动协议,总体可以看作是使用SPI来实现一种通信协议来发送信号。

    2024年02月09日
    浏览(65)
  • STM32F103C8T6(HAL库)驱动舵机

    常见的舵机分为360°和180°两种,本次对180°舵机进行驱动,舵机驱动需要通过PWM信号进行驱动。本文通过定时器中的PWM信号设定使得SG90舵机进行不同角度的转动。 对于舵机的驱动,需要20ms的脉冲,高电平时间在0.5ms-2.5ms区间即可控制舵机在0-180°角度进行转动。常见角度对应

    2024年02月05日
    浏览(46)
  • stm32f103与openmv串口通信

    串口通信是指通过串行通信接口进行数据传输的一种通信方式。在串口通信中,数据被分成一个个的字节,按照一定的顺序依次发送和接收。串口通信通常使用UART(通用异步收发传输)协议进行数据传输。 串口通信在嵌入式系统中应用非常广泛,其主要用途包括: 调试和监

    2024年02月13日
    浏览(49)
  • STM32开发(六)STM32F103 通信 —— RS485 Modbus通信编程详解

    👈《上一篇》  🏡《主目录》  👉《下一篇》 了解 RS485 Modbus协议技术 。本实验是基于STM32F103开发 实现 通过RS-485实现modbus协议。 准备好了吗?开始我的show time。 1、硬件开发准备 主控:STM32F103ZET6 RS485收发器:SP3485P 2、软件开发准备 软件开发使用虚拟机 + VScode + STM32Cub

    2024年02月03日
    浏览(52)
  • 正点原子STM32F103精英版+HAL库实现4×4矩阵按键检测

    首先声明,本人小白一枚,所做的工作都是借鉴网上的大佬+自己摸索,但是都是亲测实际有效的。 因为所需要的功能开发板自带按键不够用,所以购买了4×4矩阵按键,当时购买的时候以为一个按键对应一个IO口,后来发现不是这样的,会浪费太多的IO口,4×4矩阵键盘用8个

    2024年02月06日
    浏览(59)
  • STM32F103C8T6(HAL库函数 - 内部Flash操作)

    STM32F103C8T6 内部Flash 为 64KB,本次将对他多余空间进行读写。 数据手册下载 STM32F103x8/STM32F103xB 数据手册 包含Flash Memory Page分布 STM32F设备命名 设备容量类型 中容量类型 内部空间介绍 Flash Memory 从 0x0800 0000 ~ 0x0801 FFFF 页分布1K每页, STM32F103C8T6 只有64KByte, 那就是64页 使用 controll

    2024年01月21日
    浏览(65)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包