esp32开发与应用(和stm32f103用spi通信)
发布时间:2026/7/17 1:01:48
分类:文化教育
浏览:1234
)
【 声明版权所有欢迎转载请勿用于商业用途。 联系信箱feixiaoxing 163.com】现在esp32和mcu一起出现的场合很多前者适合网络传输和屏幕显示后者则多出现在工业场景。所以两者一起出现就可以发挥各自的优势。但是两个一起合作也有通信的需求。虽然用ttl可以解决通信的问题但是速率比较低不太方便我们一般还是用spi会感觉比较简单一点。1、mcu做spi hostesp32做spi slave之所以会这样是因为很多时候都是采集数据的要求这个时候用mcu做master方便一点。2、gnd务必对接不管是测试的时候还是部署的时候两个模块的gnd需要互联。3、pin连接目前esp32的pin是5/18/19/23而mcu这边的pin是pa4/pa5/pa6/pa7。两者的连接方式是这样的5连接pa418连接pa519连接pa623连接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/641.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, // 对应CPOL0, CPHA0要和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这边看到源源不断的信息打印了。