esp32开发与应用(和stm32f103用spi通信)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

现在esp32和mcu一起出现的场合很多,前者适合网络传输和屏幕显示,后者则多出现在工业场景。所以两者一起出现就可以发挥各自的优势。但是两个一起合作,也有通信的需求。虽然用ttl可以解决通信的问题,但是速率比较低不太方便,我们一般还是用spi,会感觉比较简单一点。

1、mcu做spi host,esp32做spi slave

之所以会这样,是因为很多时候都是采集数据的要求,这个时候用mcu做master方便一点。

2、gnd务必对接

不管是测试的时候,还是部署的时候,两个模块的gnd需要互联。

3、pin连接

目前esp32的pin是5/18/19/23,而mcu这边的pin是pa4/pa5/pa6/pa7。两者的连接方式是这样的,5连接pa4,18连接pa5,19连接pa6,23连接pa7。

4、esp32需要主动发起通信怎么办

一般是通过gpio,让mcu触发一个中断。

5、代码部分

这部分代码可以让ai写也可以。首先写mcu的代码,

复制代码
#include "stm32f10x.h"

#define SPI_CS_LOW()   GPIO_ResetBits(GPIOA, GPIO_Pin_4)
#define SPI_CS_HIGH()  GPIO_SetBits(GPIOA, GPIO_Pin_4)

void SPI1_Master_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    SPI_InitTypeDef  SPI_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE);

    // SCK(PA5), MOSI(PA7) 复用推挽输出
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_5 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // MISO(PA6) 浮空输入
    GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // NSS(PA4) 用普通GPIO推挽输出,软件控制片选
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_4;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    SPI_CS_HIGH(); // 默认不选中

    SPI_InitStructure.SPI_Direction         = SPI_Direction_2Lines_FullDuplex;
    SPI_InitStructure.SPI_Mode              = SPI_Mode_Master;
    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_Soft;  // 软件NSS,用GPIO4手动拉
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64; // 72MHz/64=1.125MHz,先低速验证
    SPI_InitStructure.SPI_FirstBit          = SPI_FirstBit_MSB;
    SPI_InitStructure.SPI_CRCPolynomial     = 7;
    SPI_Init(SPI1, &SPI_InitStructure);

    SPI_Cmd(SPI1, ENABLE);
}

uint8_t SPI1_TransferByte(uint8_t data)
{
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
    SPI_I2S_SendData(SPI1, data);
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
    return SPI_I2S_ReceiveData(SPI1);
}

// 简单延时(根据你的系统时钟自行调整或换成systick延时)
void delay_us(uint32_t us)
{
    for (uint32_t i = 0; i < us * 8; i++) __NOP();
}

void SPI1_TransferBuffer(uint8_t *tx, uint8_t *rx, uint16_t len)
{
    SPI_CS_LOW();
    delay_us(10); // 给ESP32 slave一点反应时间,非常关键!
    for (uint16_t i = 0; i < len; i++)
    {
        rx[i] = SPI1_TransferByte(tx[i]);
    }
    SPI_CS_HIGH();
}

int main(void)
{
    SPI1_Master_Init();

    uint8_t tx_buf[4] = {0x11, 0x22, 0x33, 0x44};
    uint8_t rx_buf[4] = {0};

    while (1)
    {
        SPI1_TransferBuffer(tx_buf, rx_buf, 4);
        // rx_buf 里是 ESP32 回传的数据
        for (volatile int i = 0; i < 500000; i++); // 简单延时
    }
}

然后是esp32的代码,

复制代码
#include "driver/spi_slave.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "string.h"

#define GPIO_MOSI 23
#define GPIO_MISO 19
#define GPIO_SCLK 18
#define GPIO_CS   5

static const char *TAG = "SPI_SLAVE";

void app_main(void)
{
    esp_err_t ret;

    spi_bus_config_t buscfg = {
        .mosi_io_num = GPIO_MOSI,
        .miso_io_num = GPIO_MISO,
        .sclk_io_num = GPIO_SCLK,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
    };

    spi_slave_interface_config_t slvcfg = {
        .mode = 0,               // 对应CPOL=0, CPHA=0,要和STM32一致
        .spics_io_num = GPIO_CS,
        .queue_size = 3,
        .flags = 0,
    };

    // 初始化SPI从机,用DMA
    ret = spi_slave_initialize(SPI2_HOST, &buscfg, &slvcfg, SPI_DMA_CH_AUTO);
    ESP_ERROR_CHECK(ret);

    WORD_ALIGNED_ATTR uint8_t recvbuf[4] = {0};
    WORD_ALIGNED_ATTR uint8_t sendbuf[4] = {0xA1, 0xA2, 0xA3, 0xA4}; // 要回传给STM32的数据

    while (1)
    {
        spi_slave_transaction_t t = {0};
        t.length = 4 * 8; // 单位bit
        t.tx_buffer = sendbuf;
        t.rx_buffer = recvbuf;

        // 阻塞等待STM32发起一次传输
        ret = spi_slave_transmit(SPI2_HOST, &t, portMAX_DELAY);

        if (ret == ESP_OK) {
            ESP_LOGI(TAG, "recv: %02X %02X %02X %02X",
                     recvbuf[0], recvbuf[1], recvbuf[2], recvbuf[3]);

            // 根据收到的数据,更新下一次要回传的内容
            sendbuf[0]++; // 举例:简单自增,实际按你的协议处理
        }
    }
}

6、测试

测试的时候,一般先把esp32准备,插好之后,再接入mcu。这个时候不出意外,就可以在esp32这边看到源源不断的信息打印了。

相关推荐
简单电磁炮1 小时前
硬件基础5--arm基础
单片机·嵌入式硬件
Kuakewei8882 小时前
智能手表pogo pin充电口安全方案:PW2605R 输入反接短路保护芯片
嵌入式硬件
崇山峻岭之间3 小时前
433遥控器解码
单片机
GeekArch4 小时前
第5讲:嵌入式场景二范式决策树:什么情况快写、什么情况严写
人工智能·stm32·单片机·mcu·物联网·决策树·机器学习
炸膛坦客17 小时前
单片机开发工具篇:(九)MCU 芯片包的安装
单片机·嵌入式硬件
智者知已应修善业1 天前
【51单片机实现初始化数码管不显示按启动从0秒计时到60按暂停一次显示当前秒按2次恢复原始状态】2024-6-11
c语言·c++·经验分享·笔记·嵌入式硬件·算法·51单片机
电气_空空1 天前
基于LabVIEW的数据采集系统设计与实现
单片机·嵌入式硬件·labview
caimouse1 天前
ReactOS BootCD 光盘布局完整深度分析
单片机·reactos
zlinear数据采集卡1 天前
从万用表的6步调零到硅片级微秒自校准:硬核拆解LHAMP188的宽压轨到轨与零漂移实战
arm开发·stm32·单片机·嵌入式硬件·fpga开发