欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > 能源 > ESP32S3(主模式) 与 STM32(从模式) 进行SPI全双工通信

ESP32S3(主模式) 与 STM32(从模式) 进行SPI全双工通信

2025/2/12 0:04:57 来源:https://blog.csdn.net/weixin_64094522/article/details/145555836  浏览:    关键词:ESP32S3(主模式) 与 STM32(从模式) 进行SPI全双工通信

开发环境:
ESP-IDF: ESP32S3
Keil5:STM32F103C8T6
通信方式:SPI 全双工通信
两天从0摸索的,大部分时间被卡是因为STM32 引脚模式配置错误
效果:
在这里插入图片描述
主设备收到上次的数据,是因为全双工原理,可以理解为一个U形管道,通过挤压,配置收发缓冲区进行收发数据
在这里插入图片描述

STM32 SPI 从模式配置表:
在这里插入图片描述

STM32:
使用SPI2,配置流程:

  1. 时钟配置
  2. 引脚配置
  3. SPI 参数配置
#ifndef __SPI_COM_H
#define __SPI_COM_H#include "stm32f10x.h"#define SPI_NAME  SPI2
#define SPI_MOSI  GPIO_Pin_15// 发送端 SDA    
#define SPI_MISO  GPIO_Pin_14 // 接收端 SDI     
#define SPI_CLK   GPIO_Pin_13 // 时钟 SCL      
#define SPI_CS    GPIO_Pin_12 // 片选 CS       void SPI_COM_Init(void);void send_data(void);
#endif
#include "spi_com.h"// 定义全局变量
static uint8_t rx_data = 0x00;// 处理接收数据,并准备发送数据(全双工)
static uint8_t tx_data = 0x00;// 初始化 SPI 从机
void SPI_COM_Init(void) {SPI_InitTypeDef SPI_InitStructure;GPIO_InitTypeDef GPIO_InitStructure;// 使能 SPI_NAME 和 GPIOA 时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);// 配置 SPI_NAME 的引脚GPIO_InitStructure.GPIO_Pin = SPI_MOSI; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin =  SPI_CLK;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = SPI_MISO;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = SPI_CS; // SS 引脚GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; GPIO_Init(GPIOB, &GPIO_InitStructure);// 配置 SPI_NAME 为从机模式SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;   // 72M / 4 = 18MHZ SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;SPI_InitStructure.SPI_CRCPolynomial = 0; //CRC冗余位数SPI_Init(SPI_NAME, &SPI_InitStructure);// 使能 SPI_NAMESPI_Cmd(SPI_NAME, ENABLE);
//	  // 使能 SPI 接收中断
//    SPI_I2S_ITConfig(SPI_NAME, SPI_I2S_FLAG_RXNE, ENABLE);	 
//	 // 使能 NVIC 中断
//    NVIC_InitTypeDef NVIC_InitStructure;
//    NVIC_InitStructure.NVIC_IRQChannel = SPI2_IRQn;
//    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
//    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
//    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
//    NVIC_Init(&NVIC_InitStructure);}// 中断服务函数
void SPI2_IRQHandler(void) {
    if (SPI_I2S_GetITStatus(SPI_NAME, SPI_I2S_IT_RXNE) == SET) {
        rx_data = SPI_I2S_ReceiveData(SPI_NAME);
        // 处理接收数据,并准备发送数据(全双工)
        tx_data = rx_data;  // 填充要发送的数据
        SPI_I2S_SendData(SPI_NAME, rx_data);
		 
    }
}// 软件接收法,可优化为中断控制
void send_data(void){while (SPI_I2S_GetFlagStatus(SPI_NAME, SPI_I2S_FLAG_TXE) == RESET);SPI_I2S_SendData(SPI_NAME, rx_data); while (SPI_I2S_GetFlagStatus(SPI_NAME, SPI_I2S_FLAG_RXNE) == RESET); rx_data = SPI_I2S_ReceiveData(SPI_NAME);tx_data = rx_data;printf("ReciveData:%d\r\n",rx_data);printf("SendData:%d\r\n",tx_data);}

ESP32S3:
使用SPI3,配置流程:

  1. 总线配置
  2. 设备配置
#ifndef _SPI_COM_H_
#define _SPI_COM_H_#include <stdio.h>
#include <string.h>
#include "driver/spi_master.h"
#include "driver/gpio.h"
#include "esp_log.h" // 定义 SPI 主机编号
#define SPI_HOST_NUM  SPI3_HOST // 定义 SPI 最大传输大小
#define SPI_MAX_TRANSFER_SIZE  1024 #define SPI_SEND_RECIVE_LEN  8*1
// 定义 SPI 引脚编号
#define PIN_NUM_MOSI  GPIO_NUM_1// 发送端 SDA 14
#define PIN_NUM_MISO  GPIO_NUM_14 // 接收端 SDI
#define PIN_NUM_CLK   GPIO_NUM_21 // 时钟 SCL
#define PIN_NUM_CS    GPIO_NUM_47 // 片选 CSvoid spi_com_init(void);
esp_err_t spi3_send_data(uint8_t *data);
#endif
#include "SPI_COM.h"// 定义日志标签
static const char *TAG = "SPI_COM_TEST";// SPI句柄
spi_device_handle_t spi;// SPI2初始化函数
void spi_com_init(void)
{spi_bus_config_t buscfg;buscfg.miso_io_num = PIN_NUM_MISO;buscfg.mosi_io_num = PIN_NUM_MOSI;buscfg.sclk_io_num = PIN_NUM_CLK;buscfg.quadwp_io_num = -1;buscfg.quadhd_io_num = -1;buscfg.max_transfer_sz = SPI_MAX_TRANSFER_SIZE;buscfg.flags = SPICOMMON_BUSFLAG_MASTER;buscfg.isr_cpu_id = ESP_INTR_CPU_AFFINITY_1;buscfg.intr_flags = 0;// 初始化SPI总线esp_err_t ret = spi_bus_initialize(SPI_HOST_NUM, &buscfg, SPI_DMA_CH_AUTO);if (ret != ESP_OK){ESP_LOGE(TAG, "SPI bus 初始化失败: %s", esp_err_to_name(ret));return;}spi_device_interface_config_t devcfg;devcfg.command_bits = 0;devcfg.address_bits = 0;devcfg.dummy_bits = 0;devcfg.mode = 0;devcfg.clock_source = SPI_CLK_SRC_APB;devcfg.clock_speed_hz = 1 * 1000 * 1000; // 1MHzdevcfg.spics_io_num = PIN_NUM_CS;devcfg.queue_size = 10;devcfg.flags = 0; // 全双工// 将设备添加到SPI总线ret = spi_bus_add_device(SPI_HOST_NUM, &devcfg, &spi);if (ret != ESP_OK){ESP_LOGE(TAG, "SPI device 初始化失败: %s", esp_err_to_name(ret));spi_bus_free(SPI_HOST_NUM);return;}ESP_LOGI(TAG, "SPI3 初始化成功!");
}
esp_err_t spi3_send_data(uint8_t *data)
{if (!spi){return ESP_FAIL;}uint8_t rx_buffer[1];spi_transaction_t t;t.length = SPI_SEND_RECIVE_LEN; t.rxlength = SPI_SEND_RECIVE_LEN;t.tx_buffer = data;t.rx_buffer = rx_buffer;t.flags = 0;// 启动传输esp_err_t er = spi_device_transmit(spi, &t);ESP_LOGI(TAG, "发送数据:%d",  data[0]);ESP_LOGI(TAG, "接收数据:%d",  rx_buffer[0]);return er;
}

测试代码
STM32:

#include "FreeRTOS.h"
#include "task.h"
#include "delay.h"
#include "usart.h"
#include "spi_com.h"// 任务句柄
TaskHandle_t app_start_handle = NULL;
TaskHandle_t app_task1_handle = NULL;
TaskHandle_t app_task2_handle = NULL;// 任务函数声明
void App_Start(void* pvParamenters);
void App_Task1(void* pvParamenters);
void App_Task2(void* pvParamenters);// 主函数
int main(void)
{//将全部优先级设为抢占优先级 0-15 级NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//创建任务xTaskCreate((TaskFunction_t)App_Start,          //任务入口函数(const char *)"App_Start",          //任务名字(uint16_t)configMINIMAL_STACK_SIZE*2, //任务栈大小(void*)NULL,                        //任务入口函数参数(UBaseType_t)1,                     //任务优先级  提高优先级(TaskHandle_t*)&app_start_handle);  //任务句柄//开启任务调度器                        vTaskStartScheduler();
}void App_Start(void *pvParameters)
{ taskENTER_CRITICAL(); //进入临界区usart1_init(115200); // 初始化串口,波特率为 115200SPI_COM_Init();taskEXIT_CRITICAL();//退出临界区xTaskCreate((TaskFunction_t)App_Task1,          //任务入口函数(const char *)"App_Task1",          //任务名字(uint16_t)configMINIMAL_STACK_SIZE*2, //任务栈大小(void*)NULL,                        //任务入口函数参数(UBaseType_t)1,                     //任务优先级  提高优先级(TaskHandle_t*)&app_task1_handle);  //任务句柄//创建任务xTaskCreate((TaskFunction_t)App_Task2,          //任务入口函数(const char *)"App_Task2",          //任务名字(uint16_t)configMINIMAL_STACK_SIZE*2, //任务栈大小(void*)NULL,                        //任务入口函数参数(UBaseType_t)1,                     //任务优先级(TaskHandle_t*)&app_task2_handle);  //任务句柄vTaskDelete(NULL);	 
}void App_Task1(void *pvParameters)
{ while(1){delay_ms(2000);printf("App_Task1 is running...\r\n");}}void App_Task2(void *pvParameters)
{	while(1){delay_ms(10);printf("Hello, this is a test message!\r\n");send_data();}
}

ESP32S3:

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "SPI_COM.h"
static const char *TAG = "MAIN_TEST";// 任务句柄
TaskHandle_t task1_handle = NULL;
TaskHandle_t task2_handle = NULL;// 函数声明
void task_1(void *pvParameters);
void task_2(void *pvParameters);// 入口函数导出
extern "C" void app_main()
{// 创建 task_1 任务,指定运行在核心 0BaseType_t result1 = xTaskCreatePinnedToCore(task_1, "task_1", 1024 * 10, NULL, 1, &task1_handle, 0);// 创建 task_2 任务,指定运行在核心 0BaseType_t result2 = xTaskCreatePinnedToCore(task_2, "task_2", 1024 * 10, NULL, 1, &task2_handle, 0);
}// task_1 任务函数
void task_1(void *pvParameters)
{while (1){vTaskDelay(pdMS_TO_TICKS(1000)); // 延迟 1 秒ESP_LOGI(TAG, "这是 task_1 在运行");}
}// task_2 任务函数
void task_2(void *pvParameters)
{spi_com_init();vTaskDelay(pdMS_TO_TICKS(500));uint8_t test_data[] = {0x12};while (1){ESP_LOGI(TAG, "这是 task_2 在运行");vTaskDelay(pdMS_TO_TICKS(500));test_data[0]++;test_data[0] = test_data[0] % 15;spi3_send_data(test_data);}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com