写一个esp开发SPI的链接吗,
下面给出一个基于 ESP-IDF 的 SPI 主机(Master)示例,包含硬件连线建议和完整的 C 代码。ESP32-C3 与 ESP32-C2 的 SPI 外设基本一致,都可以按此方式配置。
1. 硬件连线示意
名称 | ESP32-Cx 引脚 | 外围设备 引脚 | 说明 |
---|---|---|---|
SCLK | GPIO_NUM_10 | SCLK | SPI 时钟 |
MOSI | GPIO_NUM_11 | MOSI | 主设备输出,向从设备输入 |
MISO | GPIO_NUM_12 | MISO | 主设备输入,从从设备输出 |
CS | GPIO_NUM_13 | CS(片选) | 拉低选中,从设备才能响应 |
GND | GND | GND | 公共地 |
3.3V | 3.3V | VCC | 供电 |
备注
- 上表仅为示例,GPIO 号可在代码中自由映射;
- 避免使用被 QSPI(闪存)占用的 6–11 引脚(ESP32-C3/C2 上这几脚预留给外部闪存)。
- 若板子上已经拉好 CS(片选),可直接对应;否则也可用任意可用 GPIO 做软件片选。
2. SPI 总线与设备接口配置
#include "driver/spi_master.h"
#include "driver/gpio.h"
#include "esp_err.h"#define SPI_HOST HSPI_HOST // 也可用 VSPI_HOST
#define PIN_NUM_MISO GPIO_NUM_12
#define PIN_NUM_MOSI GPIO_NUM_11
#define PIN_NUM_CLK GPIO_NUM_10
#define PIN_NUM_CS GPIO_NUM_13static spi_device_handle_t spi_handle;void spi_master_init(void)
{esp_err_t ret;// 1. 配置 SPI 总线引脚spi_bus_config_t buscfg = {.mosi_io_num = PIN_NUM_MOSI,.miso_io_num = PIN_NUM_MISO,.sclk_io_num = PIN_NUM_CLK,.quadwp_io_num = -1, // 不使用四线模式.quadhd_io_num = -1,.max_transfer_sz = 4096 // 最大传输字节数,根据应用调整};// 初始化 SPI 总线, DMA 通道选择 1(可选 0、1、2,DMA 1 较通用)ret = spi_bus_initialize(SPI_HOST, &buscfg, 1);assert(ret == ESP_OK);// 2. 配置 SPI 从设备(即外围设备)接口spi_device_interface_config_t devcfg = {.clock_speed_hz = 1*1000*1000, // 1 MHz.mode = 0, // SPI 模式 0 (CPOL=0, CPHA=0).spics_io_num = PIN_NUM_CS, // 片选引脚.queue_size = 3, // 同时可挂起事务数.flags = 0, // 默认,MSB 先行};// 将设备添加到总线ret = spi_bus_add_device(SPI_HOST, &devcfg, &spi_handle);assert(ret == ESP_OK);
}
3. 读写示例
// 同步发送一段数据
esp_err_t spi_send(const uint8_t* data, size_t len)
{spi_transaction_t t = {.length = len * 8, // 单位:bit.tx_buffer = data,.rx_buffer = NULL,};return spi_device_transmit(spi_handle, &t);
}// 同步接收 len 字节
esp_err_t spi_receive(uint8_t* buf, size_t len)
{spi_transaction_t t = {.length = len * 8,.tx_buffer = NULL,.rx_buffer = buf,};return spi_device_transmit(spi_handle, &t);
}// 同时发送并接收
esp_err_t spi_transfer(const uint8_t* tx, uint8_t* rx, size_t len)
{spi_transaction_t t = {.length = len * 8,.tx_buffer = tx,.rx_buffer = rx,};return spi_device_transmit(spi_handle, &t);
}
调用示例:
void app_main(void)
{spi_master_init();const uint8_t tx_data[3] = {0x9F, 0x00, 0x00}; // 例如读取 Flash IDuint8_t rx_data[3] = {0};esp_err_t ret = spi_transfer(tx_data, rx_data, sizeof(tx_data));if (ret == ESP_OK) {printf("Read ID: %02X %02X %02X\n", rx_data[0], rx_data[1], rx_data[2]);} else {printf("SPI transaction failed: %d\n", ret);}
}
4. 注意事项
- 引脚复用冲突
- 确认所选 GPIO 未被 JTAG、UART、I2C 等占用;
- 某些开发板会固定 HSPI 与 VSPI 引脚,需参考板子原理图。
- 时序与电平
- SPI 时钟速率不可超出外设承受范围;
- 不同外设对 CPOL/CPHA(mode)的要求要一致。
- DMA vs. 中断
- 使用 DMA(bus_initialize 中第三个参数设为非 0)可提高大块数据传输效率;
- 若只需少量控制命令,中断或轮询即可。
- ESP32-C2 特殊
- ESP32-C2 与 C3 在引脚映射上完全兼容,上述代码同样适用。
- ESP32-C2 与 C3 在引脚映射上完全兼容,上述代码同样适用。
以上示例即可让 ESP32-C3/C2 通过 SPI 主机接口,与外部 SPI 设备(Flash、传感器、显示器等)通信。如需更高级的 DMA 双向传输或异步调用,可在 spi_device_interface_config_t
中设置 .flags = SPI_DEVICE_NO_DUMMY
、.duty_cycle_pos
等参数,或改用 spi_device_queue_trans()
+ spi_device_get_trans_result()
异步接口。