树莓派(主)与STM32(从)使用SPI通信(持续更新中)

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

1.实验目的

使用树莓派向 STM32 发送数据,STM32 收到数据后通过串口的方式将数据打印到电脑上,同时返回给树莓派数据。树莓派接收到数据后打印在控制台上。
SPI 的配置为

树莓派主机
STM32 从机
全双工
8 bit 传输
工作模式 0 :CPOL|CPHA = 00
MSB 优先
禁止 CRC 校验

2.SPI 简介

SPI(Serial Peripheral Interface,串行外设接口)是 Motorola 公司提出的一种同步串行数据传输标准

2.1 接口

SPI 接口经常被称为 4 线串行总线,以主/从方式工作,数据传输过程由主机初始化,其使用的 4 条信号线分别为:

  1. SCLK:串行时钟,用来同步数据传输,由主机输出,从机不用配置时钟
  2. MOSI:主机输出从机输入数据线,通常先传输 MSB ;
  3. MISO:主机输入从机输出数据线,通常先传输 LSB ;
  4. CS:片选线,低电平有效,由主机输出。
    在 SPI 总线上,某一时刻可以出现多个从机,但只能存在一个主机,主机通过片选线来确定要通信的从机。连接是对应相连,如下所示
    SCLK-----SCLK
    MOSI-----MOSI
    MISO-----MISO
    CS-----CS

2.2 数据传输

在一个 SPI 时钟周期内,会完成如下操作:

  • 主机通过 MOSI 线发送 1 位数据,从机通过该线读取这 1 位数据;
  • 从机通过 MISO 线发送 1 位数据,主机通过该线读取这 1 位数据。
    这是通过移位寄存器来实现的。如下图所示,主机和从机各有一个移位寄存器,且二者连接成环。随着时钟脉冲,数据按照从高位到低位的方式依次移出主机寄存器和从机寄存器,并且依次移入从机寄存器和主机寄存器。当寄存器中的内容全部移出时,相当于完成了两个寄存器内容的交换。
    stm32和树莓派通信,stm32,单片机,嵌入式硬件,树莓派

2.3 时钟极性和时钟相位

在 SPI 操作中,最重要的两项设置就是时钟极性( CPOL 或 UCCKPL )和时钟相位( CPHA 或 UCCKPH )。

  • CPOL 表示时钟信号的初始电平的状态(就是空闲状态),CPOL 为 0 表示时钟信号初始状态为低电平,为 1 表示时钟信号的初始电平是高电平。
  • CPHA 表示在哪个时钟沿采样数据,CPHA 为 0 表示在首个时钟变化沿采样数据,而 CPHA 为 1 则表示在第二个时钟变化沿采样数据。
    主机和从机的发送数据是同时完成的,两者的接收数据也是同时完成的。所以为了保证主从机正确通信,应使得它们的SPI具有相同的时钟极性和时钟相位。

2.4 SPI的4种工作模式

由于 CPOL 和 CPHA 都有两种不同状态,所以 SPI 分成了 4 种模式。我们在开发的时候,使用比较多的是模式 0 和模式 3 ,如下表所示

SPI工作模式 CPOL CPHA SCL空闲状态 采样边沿 采样时刻
0 0 0 低电平 上升沿 奇数边沿
1 0 1 低电平 下降沿 偶数边沿
2 1 0 高电平 下降沿 奇数边沿
3 1 1 高电平 上升沿 偶数边沿

2.5 优缺点

优点:

  • 支持全双工操作
  • 操作简单
  • 数据传输速率较高

缺点:

  • 需要占用主机较多的口线(每个从机都需要一根片选线)
  • 只支持单个主机

3.树莓派部分

3.1 开启SPI

树莓派默认是没有开启 SPI 的功能的,我们需要手动去开启一下
在终端输入

raspi-config

然后跟着下面的图进行操作(小键盘上下左右是选择,回车是确定)
stm32和树莓派通信,stm32,单片机,嵌入式硬件,树莓派
stm32和树莓派通信,stm32,单片机,嵌入式硬件,树莓派
stm32和树莓派通信,stm32,单片机,嵌入式硬件,树莓派
stm32和树莓派通信,stm32,单片机,嵌入式硬件,树莓派

stm32和树莓派通信,stm32,单片机,嵌入式硬件,树莓派
stm32和树莓派通信,stm32,单片机,嵌入式硬件,树莓派
输入命令

ls /dev/spi*

出现如下图的样子,就是成功打开了
stm32和树莓派通信,stm32,单片机,嵌入式硬件,树莓派

3.2 安装vscode(可选)

标题是超链接,点击跳转

3.3 下载bcm支持包

4.STM32部分(只讲解SPI和主函数部分)

4.1 spi.c 中 spi 的初始化代码

/* SPI1 引脚初始化,会在HAL_SPI_Init的时候调用*/
void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    if(spiHandle->Instance==SPI1)
    {
        __HAL_RCC_SPI1_CLK_ENABLE();
        __HAL_RCC_GPIOA_CLK_ENABLE();
        /**SPI1 引脚配置
        PA4     ------> SPI1_NSS
        PA5     ------> SPI1_SCK
        PA6     ------> SPI1_MISO
        PA7     ------> SPI1_MOSI
        */
        GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    }
}

/* SPI1 配置初始化 */
void MX_SPI1_Init(void)
{
    hspi1.Instance = SPI1;
    hspi1.Init.Mode = SPI_MODE_SLAVE;// 从机
    hspi1.Init.Direction = SPI_DIRECTION_2LINES;// 全双工
    hspi1.Init.DataSize = SPI_DATASIZE_8BIT;//8 bit 传输
    hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;//CPOL = 0
    hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;//CPHA = 0
    hspi1.Init.NSS = SPI_NSS_HARD_INPUT;//片选硬件输入
    hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;//MSB 优先
    hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
    hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;//禁止 CRC 校验
    hspi1.Init.CRCPolynomial = 10;
    if (HAL_SPI_Init(&hspi1) != HAL_OK)//判断是否初始化成功
    {
        Error_Handler();
    }
}

4.2 main.c

#include "main.h"
#include "spi.h"
#include "usart.h"
#include "gpio.h"
#include "stdio.h"

void SystemClock_Config(void);//函数声明,实现在下面

/* 输出和输入重定向,主要用于 printf 串口输出 */
int fputc(int ch, FILE *f)
{
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
    return ch;
}
int fgetc(FILE *f)
{
    uint8_t ch = 0;
    HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
    return ch;
}

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_USART1_UART_Init();//串口初始化
    MX_SPI1_Init();//SPI1初始化
    HAL_Delay(1000);

    uint8_t data2[10]={0};//接收数据
    uint8_t send_data2[10]={0xff,0xfe,0xfd,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7,0xf6};//发送数据
    HAL_SPI_TransmitReceive(&hspi1, (uint8_t *)send_data2, (uint8_t *)data2,10,0xff);//提前将数据放进发送缓存区
    while (1)
    {		
        HAL_GPIO_WritePin(Start_GPIO_Port,Start_Pin,GPIO_PIN_RESET);
        HAL_Delay(100);
        HAL_GPIO_WritePin(Start_GPIO_Port,Start_Pin,GPIO_PIN_SET);
        
        /* 接收10个字节的同时,发送10个字节出去,等待时间为 65535ms ,超时则不继续等待 */
        HAL_SPI_TransmitReceive(&hspi1, (uint8_t *)send_data2, (uint8_t *)data2,10,65535);
        /* 通过串口发送给电脑 */
        for(int i=0;i<10;i++)
        {
            printf("0x%02X\n",data2[i]);//指定为以16进制的形式格式化输出
        }				
        HAL_Delay(2000);//延时2s
    }
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    __HAL_RCC_PWR_CLK_ENABLE();
    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLM = 4;
    RCC_OscInitStruct.PLL.PLLN = 168;
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
    RCC_OscInitStruct.PLL.PLLQ = 4;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    {
        Error_Handler();
    }
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
    {
        Error_Handler();
    }
}

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
    __disable_irq();
    while (1)
    {
    }
}

源码见本文末尾

5.验证结果

下面是树莓派的引脚图
stm32和树莓派通信,stm32,单片机,嵌入式硬件,树莓派

按照下面的方式连接树莓派与 STM32 的引脚
树莓派--------STM32
MOSI/#10--------PA7
MISO/#9----------PA6
SCLK/#11--------PA5
GND---------------GND

cd “/home/pi/SPI_test/bcm2835-1.71/examples/spi/” && gcc *.c -o spi && "/home/pi/SPI_test/bcm2835-1.71/examples/spi/"spi

stm32和树莓派通信,stm32,单片机,嵌入式硬件,树莓派
stm32和树莓派通信,stm32,单片机,嵌入式硬件,树莓派

6.源码

树莓派bcm2835-1.71(带本实验所需程序)
STM32F407从机SPI使用HAL库轮询方式文章来源地址https://www.toymoban.com/news/detail-633441.html

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

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

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

相关文章

  • STM32——SPI通信

    SPI(Serial Peripheral Interface)是由Motorola公司开发的一种通用数据总线 四根通信线: SCK(Serial Clock)【CLK或SCL或CK】、 MOSI(Master Output Slave Input)【DO(Data Output)】、 MISO(Master Input Slave Output)【DI(Data Input)】、 SS(Slave Select)【CS或NSS】 同步,全双工 支持总线挂载多设备

    2024年02月11日
    浏览(28)
  • STM32开发(十)STM32F103 通信 —— SPI通信编程详解

    👈《上一篇》  🏡《主目录》  👉《下一篇》 本实验通过STM32F103 的SPI功能,实现对W25Q64JVSSIQ (Flash芯片)芯片擦除,读数据,写数据等操作。 本实验内容知识点: 1、SPI通信协议介绍 2、

    2024年02月07日
    浏览(41)
  • 【【STM32-SPI通信协议】】

    STM32-SPI通信协议 •SPI(Serial Peripheral Interface)是由Motorola公司开发的一种通用数据总线 •四根通信线:SCK(Serial Clock)、MOSI(Master Output Slave Input)、MISO(Master Input Slave Output)、SS(Slave Select) •同步,全双工 •支持总线挂载多设备(一主多从) 既然是同步的,我们就会发

    2024年02月12日
    浏览(27)
  • 【STM32】学习笔记-SPI通信

    SPI通信(Serial Peripheral Interface)是一种同步的串行通信协议,用于在微控制器、传感器、存储器、数字信号处理器等之间进行通信。SPI通信协议需要使用4个线路进行通信:时钟线(SCLK)、主输入/主输出线(MISO)、主输出/主输入线(MOSI)和片选线(SS)。其中,SCLK由主设备提供,用于

    2024年02月09日
    浏览(32)
  • 树莓派与STM32之间串口通信

    目录 一、树莓派串口通信模块介绍 二、树莓派蓝牙、串口引脚映射对换步骤 1.启动串口 2. 禁用蓝牙(硬件串口与mini串口映射对换) 3.验证是否交换成功 三、树莓派安装mini串口调试助手 四、树莓派与电脑串口调试 五、树莓派与STM32串口调试 树莓派串口通信与蓝牙模块的基

    2024年02月16日
    浏览(65)
  • STM32硬件SPI通信详解-------附代码

    1.STM32内部集成了 硬件SPI收发电路 ,可以由 硬件自动执行时钟生成 、 数据收发 等功能, 减轻CPU的负担 2.可配置 8位/16位数据帧 、 高位先行/低位先行 3. 时钟频率 : fPCLK / (2, 4, 8, 16, 32, 64, 128, 256) 4.支持 多主机模型 、 主或从操作 5.可精简为 半双工/单工通信 6. 支持DMA 7. 兼

    2024年04月27日
    浏览(30)
  • 树莓派与STM32(rt1064)串口通信

    目录 一、树莓派通信 1、硬件连线准备 2、安装Serial和打开树莓派串口 2.1安装Serial 2.2打开树莓派串口 2.3修改串口映射关系 3、树莓派代码 4、上位机 5、运行uart.py代码进行测试 5.1 树莓派发送,上位机接收 5.2上位机发送,树莓派接收  二、STM32通信 6、配置串口 7、测试STM32通

    2024年02月01日
    浏览(74)
  • 【STM32】江科大STM32学习笔记汇总(持续更新中...)

    【STM32】STM32学习笔记-课程简介(01) 【STM32】STM32学习笔记-STM32简介(02) 【STM32】STM32学习笔记-软件安装(03) 【STM32】STM32学习笔记-新建工程(04) 【STM32】STM32学习笔记-GPIO输出(05) 【STM32】STM32学习笔记-GPIO相关API概述(06-1) 【STM32】STM32学习笔记-LED闪烁 LED流水灯 蜂鸣器(06-2) 【STM32】

    2024年02月22日
    浏览(34)
  • STM32 HAL库 SPI主从双机通信

    最近因为项目需求,需要在一块板子内实现一个主机和五个从机的通信; 主机平台选用的是STM32F407VGT6,从机平台选用的是STM32F103C8T6;通信总线选用的是SPI总线。在构想是觉得采用SPI进行主从通信会很简单,但在实际开发的过程中,各种坑,通信时而正常时而混乱。不过在不

    2024年01月17日
    浏览(29)
  • 基于SPI实现stm32与fpga通信(一)

    SPI通信协议有以下4种模式: 模式0:时钟极性为0,时钟相位为0,数据在时钟下降沿捕获,数据在时钟上升沿改变。 模式1:时钟极性为0,时钟相位为1,数据在时钟上升沿捕获,数据在时钟下降沿改变。 模式2:时钟极性为1,时钟相位为0,数据在时钟上升沿捕获,数据在时钟

    2024年04月16日
    浏览(34)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包