GD32E230 SPI 不使用 DMA 模式实例代码(含 GPIO 复用配置)

[复制链接]
695|0
lxs0026 发表于 2025-8-28 08:58 | 显示全部楼层 |阅读模式
#include "gd32e23x.h"

// 引脚定义:SPI0(PB13=SCK,PB14=MISO,PB15=MOSI),NSS=PA15(软件控制)
#define SPI_NSS_GPIO_PORT    GPIOA
#define SPI_NSS_GPIO_PIN     GPIO_PIN_15
#define SPI_NSS_GPIO_CLK     RCU_GPIOA

#define SPI0_GPIO_PORT       GPIOB
#define SPI0_SCK_PIN         GPIO_PIN_13
#define SPI0_MISO_PIN        GPIO_PIN_14
#define SPI0_MOSI_PIN        GPIO_PIN_15
#define SPI0_GPIO_CLK        RCU_GPIOB
#define SPI0_CLK             RCU_SPI0

// SPI0 初始化函数:全双工主模式,8位帧,预分频8
void spi0_init(void) {
    // 1. 使能时钟(GPIOA、GPIOB、SPI0)
    rcu_periph_clock_enable(SPI_NSS_GPIO_CLK);
    rcu_periph_clock_enable(SPI0_GPIO_CLK);
    rcu_periph_clock_enable(SPI0_CLK);

    // 2. 配置SPI引脚复用(AF0)
    gpio_af_set(SPI0_GPIO_PORT, GPIO_AF_0, SPI0_SCK_PIN | SPI0_MISO_PIN | SPI0_MOSI_PIN);
    gpio_mode_set(SPI0_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, SPI0_SCK_PIN | SPI0_MISO_PIN | SPI0_MOSI_PIN);
    gpio_output_options_set(SPI0_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, SPI0_SCK_PIN | SPI0_MISO_PIN | SPI0_MOSI_PIN);

    // 3. 配置NSS引脚(推挽输出,上拉)
    gpio_mode_set(SPI_NSS_GPIO_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, SPI_NSS_GPIO_PIN);
    gpio_output_options_set(SPI_NSS_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, SPI_NSS_GPIO_PIN);
    gpio_bit_set(SPI_NSS_GPIO_PORT, SPI_NSS_GPIO_PIN); // 初始拉高NSS

    // 4. 配置SPI核心参数
    spi_parameter_struct spi_init_struct;
    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_SOFT; // 软件控制NSS
    spi_init_struct.prescale             = SPI_PSC_8; // 预分频8(假设APB1时钟48MHz,SPI时钟=6MHz)
    spi_init_struct.endian               = SPI_ENDIAN_MSB; // 大端模式
    spi_init(SPI0, &spi_init_struct);

    // 5. 使能SPI
    spi_enable(SPI0);
}

// SPI单字节收发函数(返回从机接收数据)
uint8_t spi0_send_recv_byte(uint8_t send_data) {
    uint8_t recv_data = 0;

    // 拉低NSS,选中从机
    gpio_bit_reset(SPI_NSS_GPIO_PORT, SPI_NSS_GPIO_PIN);

    // 等待发送缓冲区空,发送数据(8位操作:通过指针定位DR低8位,避免16位误操作)
    while(spi_i2s_flag_get(SPI0, SPI_FLAG_TBE) == RESET);
    *(volatile uint8_t *)&SPI_DATA(SPI0) = send_data; // 关键:8位指针操作,防止时钟异常

    // 等待接收缓冲区非空,读取数据
    while(spi_i2s_flag_get(SPI0, SPI_FLAG_RBNE) == RESET);
    recv_data = *(volatile uint8_t *)&SPI_DATA(SPI0);

    // 等待发送完成,拉高NSS
    while(spi_i2s_flag_get(SPI0, SPI_FLAG_TC) == RESET);
    gpio_bit_set(SPI_NSS_GPIO_PORT, SPI_NSS_GPIO_PIN);

    return recv_data;
}

// SPI多字节连续发送(保持时钟连续,不中途拉高NSS)
void spi0_send_multi_byte(uint8_t *data_buf, uint16_t len) {
    if(data_buf == NULL || len == 0) return;

    gpio_bit_reset(SPI_NSS_GPIO_PORT, SPI_NSS_GPIO_PIN); // 拉低NSS

    for(uint16_t i = 0; i < len; i++) {
        while(spi_i2s_flag_get(SPI0, SPI_FLAG_TBE) == RESET);
        *(volatile uint8_t *)&SPI_DATA(SPI0) = data_buf[i];
        while(spi_i2s_flag_get(SPI0, SPI_FLAG_TC) == RESET); // 确保当前字节发送完成
    }

    gpio_bit_set(SPI_NSS_GPIO_PORT, SPI_NSS_GPIO_PIN); // 所有字节发完后拉高NSS
}

您需要登录后才可以回帖 登录 | 注册

本版积分规则

103

主题

1290

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部