【GD32】从0开始学GD32单片机(9)—— SPI外设详解+主机从机发送和接收例程

这篇具有很好参考价值的文章主要介绍了【GD32】从0开始学GD32单片机(9)—— SPI外设详解+主机从机发送和接收例程。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

简介

SPI是串行外设接口(Serial Peripheral Interface)的缩写,是一种高速的,全双工,同步的通信总线。
SPI总共需要4根线来实现通信,NSS:片选线,用于选择需要通信的从机;CLK:同步时钟线,用于提供同步时钟信号;MISO:主机读从机写线;MOSI:主机写从机读线
GD32F103系列的SPI最高速度为18MHz

【GD32】从0开始学GD32单片机(9)—— SPI外设详解+主机从机发送和接收例程

片选线

SPI的片选逻辑要比I2C的简单得多,通常一个SPI外设会有多条片选线,如下图。

【GD32】从0开始学GD32单片机(9)—— SPI外设详解+主机从机发送和接收例程
所以我们想要与哪个从机进行通信,那么只需要拉低对应从机的片选线即可,无需像I2C那样要通过传送从机地址来片选对应的从机。

不过GD32的SPI外设好像只有一条片选线,目前我还没有见过有多条片选线的SPI外设,可能高级一点的型号会有吧

时序

因为SPI为同步通信协议,因此通信要配合同步时钟信号,时序如下图。

【GD32】从0开始学GD32单片机(9)—— SPI外设详解+主机从机发送和接收例程
值得注意的是时钟线有4种不同的时序,通过CKPH和CKPL两个配置位进行配置,CKPH配置的是第一或第二个时钟边沿为有效采样边沿,CKPL配置的是空闲状态时时钟线的电平

运行模式

SPI外设有好几种运行模式,分别有——全双工主机模式、单向线连接主机发送模式、单向线连接主机接收模式、双向线连接主机发送模式、双向线连接主机接收模式、全双工从机模式、单向线连接从机发送模式、单向线连接从机接收模式、双向线连接从机发送模式、双向线连接从机接收模式
其实简单点说就是,虽然SPI是一个全双工的通信协议,但通过配置可以使它工作在全双工、半双工和单工的状态,配置十分灵活。
全双工的接线示意图

【GD32】从0开始学GD32单片机(9)—— SPI外设详解+主机从机发送和接收例程

半双工接线示意图
【GD32】从0开始学GD32单片机(9)—— SPI外设详解+主机从机发送和接收例程

单工接线示意图
【GD32】从0开始学GD32单片机(9)—— SPI外设详解+主机从机发送和接收例程

基本发送和技术流程

主机发送

简要流程:

  1. 配置SPI外设的时序,使能SPI外设
  2. 拉低对应从机NSS线电平
  3. 软件写一个数据到发送缓冲区
  4. 数据帧从数据缓冲区加载到移位寄存器中,开始发送加载的数据
  5. 数据帧的第一位发送之后,TBE位置1
  6. 如果有更多数据则重复第3-5步
  7. 等待TRANS置0,关闭时钟信号输出,释放片选线,数据传输结束

说明:
TBE全称Transmit Buffer Empty,“发送缓冲区空”标志位。
TRANS,“通信进行中”标志位。

主机接收

简要流程:

  1. 配置SPI外设的时序,使能SPI外设
  2. 拉低对应从机NSS线电平
  3. 输出SCK时钟信号
  4. 接收到的数据将从移位寄存器存入到接收缓冲区,且RBNE位置1
  5. 软件读取接收缓冲区,RBNE位置0
  6. 如果有更多数据则重复第4-5步
  7. 等待TRANS置0,关闭时钟信号输出,释放片选线,数据传输结束

说明:
RBNE全称Read Buffer Not Empty,"接收缓冲区非空"标志位。

从机发送

简要流程:

  1. 配置SPI外设的时序,使能SPI外设
  2. 软件写第一个数据到发送缓冲区
  3. 等待NSS线电平为低,SCK线开始翻转
  4. 数据帧从数据缓冲区加载到移位寄存器中,开始发送加载的数据
  5. 数据帧的第一位发送之后,TBE位置1
  6. 如果有更多数据,在每一次TBE置1时都可将数据写入发送缓冲区
  7. 等待TRANS置0,数据传输结束

从机接收

简要流程:

  1. 配置SPI外设的时序,使能SPI外设
  2. 等待NSS线电平为低,SCK线开始翻转
  3. 接收到的数据将从移位寄存器存入到接收缓冲区,且RBNE位置1
  4. 软件读取接收缓冲区,RBNE位置0
  5. 如果有更多数据则重复第4-5步
  6. 等待TRANS置0,数据传输结束

例程

STM32F103C8T6有两个SPI外设,对应管脚映射如下:

外设 NSS SCK MISO MOSI
SPI0 PA4 PA5 PA6 PA7
SPI1 PB12 PB13 PB14 PB15

主机和从机全双工通信

现象:主机从机每2秒同时发送一组数据,同时接收一组数据

spi.c文件

#include "spi.h"

void SPI_MasterInit(void)
{
    /* 初始化GPIO */
    rcu_periph_clock_enable(RCU_GPIOA);
    /* SPI0 GPIO: NSS/PA4, SCK/PA5, MISO/PA6, MOSI/PA7 */
    gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_7);
    gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_6);

    /* 初始化SPI */
    rcu_periph_clock_enable(RCU_SPI0);
    
    spi_parameter_struct spi_init_struct = {0};
    spi_struct_para_init(&spi_init_struct);
    
    spi_init_struct.trans_mode           = SPI_TRANSMODE_FULLDUPLEX;  // 全双工模式
    spi_init_struct.device_mode          = SPI_MASTER;  // 主机模式
    spi_init_struct.frame_size           = SPI_FRAMESIZE_8BIT;  // 8位数据
    spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;  // 空闲电平为低,第一个边沿采样
    spi_init_struct.nss                  = SPI_NSS_HARD;  // 硬件片选
    spi_init_struct.prescale             = SPI_PSC_8;  // 时钟8分频,108MHz / 8 = 13.5MHz
    spi_init_struct.endian               = SPI_ENDIAN_MSB;  // 大端模式
    spi_init(SPI0, &spi_init_struct);
    
    spi_nss_output_enable(SPI0);
    spi_enable(SPI0);
}

void SPI_SlaveInit(void)
{
    /* 初始化GPIO */
    rcu_periph_clock_enable(RCU_GPIOB);
    /* SPI0 GPIO: NSS/PB12, SCK/PB13, MISO/PB14, MOSI/PB15 */
    gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_14);
    gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_15);

    /* 初始化SPI */
    rcu_periph_clock_enable(RCU_SPI1);
    
    spi_parameter_struct spi_init_struct = {0};
    spi_struct_para_init(&spi_init_struct);
    
    spi_init_struct.trans_mode           = SPI_TRANSMODE_FULLDUPLEX;  // 全双工模式
    spi_init_struct.device_mode          = SPI_SLAVE;  // 从机模式
    spi_init_struct.frame_size           = SPI_FRAMESIZE_8BIT;  // 8位数据
    spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;  // 空闲电平为低,第一个边沿采样
    spi_init_struct.nss                  = SPI_NSS_HARD;  // 硬件片选
    spi_init_struct.prescale             = SPI_PSC_8;  // 时钟8分频,108MHz / 8 = 13.5MHz
    spi_init_struct.endian               = SPI_ENDIAN_MSB;  // 大端模式
    spi_init(SPI1, &spi_init_struct);
    
    spi_enable(SPI1);
}

void SPI_MasterSlaveFullduplex(void)
{
    uint8_t master_tx_buf[16] = {0};
    uint8_t master_rx_buf[16] = {0};
    uint8_t slave_tx_buf[16] = {0};
    uint8_t slave_rx_buf[16] = {0};
    
    memset(master_tx_buf, 0x00, sizeof(master_tx_buf));
    memset(master_rx_buf, 0x00, sizeof(master_rx_buf));
    memset(slave_tx_buf, 0x00, sizeof(slave_tx_buf));
    memset(slave_rx_buf, 0x00, sizeof(slave_rx_buf));
    
    for(uint8_t i = 0; i < 16; ++i)
    {
        master_tx_buf[i] = 0x80 + i;
        slave_tx_buf[i] = 0x40 + i;
    }
    
    printf("Master send: ");
    for(uint8_t i = 0; i < 16; ++i)
    {
        printf("%x ", master_tx_buf[i]);
    }
    printf("\n");
    
    printf("Slave send: ");
    for(uint8_t i = 0; i < 16; ++i)
    {
        printf("%x ", slave_tx_buf[i]);
    }
    printf("\n");

    for(uint8_t i = 0; i < 16; ++i)
    {
        while(RESET == spi_i2s_flag_get(SPI1, SPI_FLAG_TBE));
        spi_i2s_data_transmit(SPI2, slave_tx_buf[i]);
        while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_TBE));
        spi_i2s_data_transmit(SPI0, master_tx_buf[i]);
        while(RESET == spi_i2s_flag_get(SPI1, SPI_FLAG_RBNE));
        slave_rx_buf[i] = spi_i2s_data_receive(SPI2);
        while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_RBNE));
        master_rx_buf[i] = spi_i2s_data_receive(SPI0);
    }
    
    printf("Master receive: ");
    for(uint8_t i = 0; i < 16; ++i)
    {
        printf("%x ", master_rx_buf[i]);
    }
    printf("\n");
    
    printf("Slave receive: ");
    for(uint8_t i = 0; i < 16; ++i)
    {
        printf("%x ", slave_rx_buf[i]);
    }
    printf("\n");
}

main.c文件

#include "gd32f10x.h"
#include "main.h"
#include "systick.h"
#include "usart.h"
#include "spi.h"
#include <stdio.h>
#include <string.h>

int main(void)
{	
    systick_config();
    USART_Config();
    SPI_MasterInit();
    SPI_SlaveInit();
        
    while(1)
    {
        SPI_MasterSlaveFullduplex();
        delay_ms(2000);
    }
}

【GD32】从0开始学GD32单片机(9)—— SPI外设详解+主机从机发送和接收例程文章来源地址https://www.toymoban.com/news/detail-403450.html

到了这里,关于【GD32】从0开始学GD32单片机(9)—— SPI外设详解+主机从机发送和接收例程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 单片机(STM32,GD32,NXP等)中BootLoader的严谨实现详解

    Bootloader( 引导加载程序 )的主要任务是引导加载并运行应用程序,我们的软件升级逻辑也一般在BootLoader中实现。本文将详细介绍BootLoader在单片机中的实现,包括 STM32、GD32、NXP Kinetis 等等的所有单片机,因为无论是什么样的芯片,它实现的逻辑都是一样的。 注意,本篇文章主

    2024年02月02日
    浏览(60)
  • 【GD32单片机】GD32工程构建,快速上手GD32

    之前在学校接触最多的是STM32单片机,但出来工作后发现,GD32或MM32单片机却是经常能接触到的,虽然学习资料和生态没有STM32好,但基本芯片内外设资源却差不多,开发起来大同小异。 在开始构建工程之前需要去GD32的官网下载一些资料; 打开官网 https://www.gigadevice.com.cn/ 选

    2024年02月03日
    浏览(52)
  • GD32单片机和STM32单片机的对比分析

    GD32单片机和STM32单片机都是基于Arm Cortex-M3/M4内核的32位通用微控制器,广泛应用于各种嵌入式系统和物联网领域。两者之间有很多相似之处,但也有一些不同之处,本文将从以下几个方面对比分析两者的特点、优势和开发成本。 GD32单片机采用的是二代的M3/M4内核,而STM32单片

    2024年02月16日
    浏览(62)
  • GD32单片机串口DMA发送

    一:在使用GD32单片机进行串口DMA发送时,需要进行以下配置: 使能 DMA 时钟和 串口时钟 。 配置 DMA通道 ,包括数据 方向 、数据 宽度 、传输 模式 等参数。 配置串口发送端口 GPIO 的模式和引脚。 配置串口的 基本参数 ,如波特率、数据位、停止位、校验位等。 配置串口D

    2024年02月12日
    浏览(44)
  • GD32 单片机 硬件I2C死锁解决方法

    在I2C恢复函数下个断点(检测到I2C多次超时之后,应该能跳转到I2C恢复函数) 使用镊子,将SCL与SDA短接,很快就能看到程序停到恢复函数的断点上,此时再执行恢复函数,看能否正常走出(可在回复函数中写个死循环,只有I2C正常才跳出,检测I2C正常的办法,可以读从设备的

    2024年02月05日
    浏览(65)
  • 如果STM32/GD32一类的ARM单片机解除读写保护的方法

    有时候啊,使用ST-Link给STM32一类的ARM单片机下载程序的时候,发现怎么也下载不了,可能是由于芯片被写保护了。那怎么办呢?可以使用STM32 ST-LINK Utility工具解除芯片的写保护,本篇博文介绍操作步骤,文章最后有工具下载链接。 双击“STM32 ST-LINK Utility.exe”,打开软件。 软

    2024年02月09日
    浏览(53)
  • GD32单片机远程升级下载,手机在线升级下载程序,GD32在线固件下载升级,手机下载程序固件方法

            GD32、STM32单片机,是我们最常见的一种MCU。通常我们在使用STM32单片机都会遇到程序在线升级下载的问题。         GD32/STM32单片机的在线下载通常需要以下几种方式完成:       1、使用ST/GD提供的串口下载工具,本地完成固件的升级下载。        2、自行完成系统

    2024年02月02日
    浏览(59)
  • STM32 GD32 瑞萨 psoc 等单片机 无线wifi蓝牙最佳解决方案

    新联鑫威一系列低功耗高性价比sdio wifi/蓝牙combo的模块CYWL6208 , CYWL6312, CYW6209等可以搭配stm32 各种型号例如以下,支持sta/ap/ap+sta,双模蓝牙的应用,支持ThreadX,rt-thread, freertos, Azure RTOS, Linux, Android系统. 稳定强,功耗低,吞吐量高等优势可以应用在新能源充电桩 安防 工控 智能

    2024年01月17日
    浏览(56)
  • J-Flash J-Link解锁GD32单片机

    提示:本篇所使用的工具为J-Link V9,软件为J-Flash V6.48b 当给GD32单片机Flash上锁,即配置安全保护后,单片机无法再通过keil、J-Link工具J-Flash烧录程序, 可通过J-Link STM32 Unlock或者J-Flash两种方法都可以。 我们先来用J-Link命令行验证下是否是真的开启了安全保护的 打开J-Link Comm

    2024年02月21日
    浏览(47)
  • 【Arduino环境下驱动合宙esp32c3单片机基本外设】

    本教程是参加FastBond2活动主题4 - 测量仪器中的【Arduino环境下驱动合宙esp32c3单片机基本外设】。 围绕FastBond2阶段1——基于ESP32C3开发的简易IO调试设备项目需求开发。 设计目标: 多种数字和模拟信号的输入输出:用户可以选择不同的输入输出模式,并通过设备的操作界面进行

    2024年02月04日
    浏览(59)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包