#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
}
|