【实验】ESP32S3的SPI通信

ESP32-S3 通讯口资源简介

本次实验我们选用的是图灵哥TRGESP32S3拓展板,板子上搭载的是乐鑫科技ESP32-S3-N16R8这颗SOC,同时还用到图灵哥科技的2.4寸屏模块,接口方便接插。

ESP32-S3-N16R8是乐鑫信息科技(Espressif Systems)推出的一款高性能、低功耗的Wi-Fi和蓝牙双模芯片。它继承了ESP32系列的传统,并引入了更为强大的处理能力和丰富的外设资源。

以下是ESP32-S3-N16R8芯片的主要通讯口资源:

  1. Wi-Fi接口:
    • 支持802.11b/g/n协议
    • 支持WPA3安全协议
    • 支持Station、SoftAP、Station+SoftAP三种模式
  2. 蓝牙接口:
    • 支持蓝牙5.0,包括经典蓝牙和BLE(蓝牙低功耗)
    • 支持多种蓝牙Profile,例如SPP、A2DP、HID等
  3. USB OTG接口:支持USB 2.0 OTG(On-The-Go)功能,可以作为USB设备或USB主机使用;
  4. SPI接口:2个SPI控制器,可用于连接外部Flash存储器、显示屏、传感器等设备
  5. I2C接口:2个I2C控制器,用于连接各种I2C设备,如传感器、EEPROM等
  6. UART接口:3个UART接口,可用于与外部设备进行串行通信,或者用于调试目的
  7. I2S接口:2个I2S接口,用于音频信号传输,可以连接外部DAC或ADC,支持I2S或PCM格式
  8. SD/SDIO/MMC接口:支持SD卡、SDIO和MMC协议,可用于扩展存储
  9. PWM接口:8个PWM控制器,可用于电机控制、调光等应用
  10. GPIO接口:丰富的通用输入输出接口48个,可以配置为数字输入/输出,或者复用为上述提到的各种通讯接口
  11. Ethernet接口:支持通过外接以太网物理层(PHY)芯片实现以太网连接虽然ESP32-S3-N16R8没有内置以太网MAC/PHY,但它可以通过外部PHY芯片和RMII接口来支持以太网连接

SPI通讯的基本原理

SPI通讯涉及以下几个主要信号线

  1. SCLK(时钟线):由主设备(通常是ESP32)提供,用于同步数据的传输
  2. MOSI(主设备输出从设备输入):用于主设备向从设备发送数据
  3. MISO(主设备输入从设备输出):用于从设备向主设备发送数据
  4. SS/CS(从设备选择/片选线):由主设备控制,用于选择要通信的从设备

ESP32S3的SPI通讯特点:

  1. 支持多个SPI接口:ESP32提供了多个SPI控制器,可以同时支持多个SPI设备
  2. 可配置的时钟频率:ESP32的SPI时钟频率可调,最高可达80MHz
  3. 全双工通信:可以同时进行数据的发送和接收
  4. 支持DMA(直接内存访问):可以减少CPU的负担,提高数据传输效率
  5. 可配置的数据位宽:支持8位、16位、32位等不同的数据位宽

SPI通讯配置步骤

  1. 初始化SPI主机:配置SPI总线的模式、时钟频率、数据位宽等参数
  2. 设置片选线:配置SS/CS线,用于选择从设备
  3. 数据传输:通过MOSI和MISO线进行数据的发送和接收
  4. 关闭SPI主机:在数据传输完成后,关闭SPI主机以节省资源

主要程序源码

demo_show.cpp

/**
 ****************************************************************************************************
 * @file      demo_show.cpp
 * @author    Turinger Software
 * @version   V1.0
 * @date      2024-09-20
 * @brief     SPILCD展示代码
 * 实验平台    图灵哥 TRGESP32S3探索板
 *
 ****************************************************************************************************
 */

#include "demo_show.h" 
#include "spilcd.h"
#include <math.h>

#define PI (float)(3.1415926)

static float cube[8][3] = {
    {-16, -16, -16},
    {-16, +16, -16},
    {+16, +16, -16},
    {+16, -16, -16},
    {-16, -16, +16},
    {-16, +16, +16},
    {+16, +16, +16},
    {+16, -16, +16}
};

static uint8_t line_id[24] = {
    1, 2, 2, 3,
    3, 4, 4, 1,
    5, 6, 6, 7,
    7, 8, 8, 5,
    8, 4, 7, 3,
    6, 2, 5, 1
};

/**
 * @brief     计算矩阵乘法
 * @param       a      : 矩阵a
 *              b[3][3]: 矩阵b
 * @retval      计算结果
 */
static float *demo_matconv(float *a, float b[3][3])
{
    float res[3];
    uint8_t res_index;
    uint8_t a_index;
    
    for (res_index = 0; res_index < 3; res_index++)
    {
        res[res_index] = b[res_index][0] * a[0] + b[res_index][1] * a[1] + b[res_index][2] * a[2];
    }
    
    for (a_index = 0; a_index < 3; a_index++)
    {
        a[a_index] = res[a_index];
    }
    
    return a;
}

/**
 * @brief     旋转向量
 * @param       point: 需要旋转的向量
 *              x    : X轴旋转量
 *              y    : Y轴旋转量
 *              z    : Z轴旋转量
 * @retval      计算结果
 */
static void demo_rotate(float *point, float x, float y, float z)
{
    float rx[3][3];
    float ry[3][3];
    float rz[3][3];
    
    x /= PI;
    y /= PI;
    z /= PI;
    
    rx[0][0] = cos(x);
    rx[0][1] = 0;
    rx[0][2] = sin(x);
    rx[1][0] = 0;
    rx[1][1] = 1;
    rx[1][2] = 0;
    rx[2][0] = -sin(x);
    rx[2][1] = 0;
    rx[2][2] = cos(x);
    
    ry[0][0] = 1;
    ry[0][1] = 0;
    ry[0][2] = 0;
    ry[1][0] = 0;
    ry[1][1] = cos(y);
    ry[1][2] = -sin(y);
    ry[2][0] = 0;
    ry[2][1] = sin(y);
    ry[2][2] = cos(y);
    
    rz[0][0] = cos(z);
    rz[0][1] = -sin(z);
    rz[0][2] = 0;
    rz[1][0] = sin(z);
    rz[1][1] = cos(z);
    rz[1][2] = 0;
    rz[2][0] = 0;
    rz[2][1] = 0;
    rz[2][2] = 1;
    
    demo_matconv(demo_matconv(demo_matconv(point, rz), ry), rx);
}

/**
 * @brief     演示立方体3D旋转
 * @param       无
 * @retval      无
 */
void demo_show_cube(void)
{
    uint8_t point_index;
    uint8_t line_index;
    
    for (point_index = 0; point_index < 8; point_index++)
    {
        demo_rotate(cube[point_index], 0.5f, 0.3f, 0.2f);
    }
    
    for (line_index = 0; line_index < 24; line_index += 2)
    {
        /* LCD画线段 */
        lcd_draw_line(120 + cube[line_id[line_index] - 1][0],
                      210 + cube[line_id[line_index] - 1][1],
                      120 + cube[line_id[line_index + 1] - 1][0],
                      210 + cube[line_id[line_index + 1] - 1][1],
                      BLUE);
    }
    
    delay(100);
    
    lcd_fill(92, 182, 148, 238, WHITE);   /* 填充立方体活动区域 */
}

实验效果

实验到此结束,感谢观看。

### ESP32-S3 SPI配置及使用教程 #### 1. 硬件准备 为了实现SPI通信,硬件上需准备好ESP32-S3开发板以及支持SPI协议的外设。对于ESP32-S3而言,该芯片内置有四个SPI控制器:SPI0、SPI1、GP-SPI2和GP-SPI3[^2]。 #### 2. 开发环境搭建 确保已安装适用于ESP32-S3的Arduino IDE或其他IDE,并正确设置了开发板管理器中的选项来匹配所使用的具体型号。 #### 3. 配置SPI参数 在代码中初始化SPI总线前,先定义好要使用的引脚编号和其他必要的设置: ```cpp #include <SPI.h> // 定义用于连接到外部设备的数据传输引脚 #define MOSI_PIN 35 // 主输出/从输入 #define MISO_PIN 37 // 主输入/从输出 #define SCLK_PIN 36 // 时钟信号 #define SS_PIN 34 // 片选(Chip Select) SPIClass spi; void setup() { pinMode(SS_PIN, OUTPUT); digitalWrite(SS_PIN, HIGH); // 默认情况下不选择任何器件 // 初始化SPI对象并指定数据位宽与时序模式 spi.begin(SCLK_PIN, MISO_PIN, MOSI_PIN); // 设置最大频率(单位Hz) spi.setFrequency(1000000); } ``` 这段程序展示了如何通过`SPIClass`类实例化一个名为`spi`的对象来进行标准SPI操作。这里选择了GPIO35作为MOSI(Master Out Slave In),GPIO37作为MISO(Master In Slave Out),GPIO36作为SCLK(Clock Line),而GPIO34则被用来充当SS(Select Signal)。 #### 4. 数据交换过程 一旦完成了上述准备工作之后就可以开始发送接收命令了: ```cpp byte dataToTransmit[] = {0xAA}; // 准备待传送给从机的信息包 int bytesSent; int receivedData; void loop(){ delay(1000); // 每隔一秒执行一次 digitalWrite(SS_PIN, LOW); // 选取目标外围装置 // 发送指令给选定的目标 bytesSent = spi.transfer(dataToTransmit,sizeof(dataToTransmit)); // 接收来自对方回应的数据 receivedData = spi.transfer(0x00); Serial.println(receivedData,BIN); digitalWrite(SS_PIN,HIGH); // 结束当前会话 } ``` 此部分实现了简单的读写流程——当主控端想要向某个特定地址发起请求时就拉低对应的CS引脚电平;完成交互后再将其恢复高阻态表示结束对话。同时利用`transfer()`函数可以方便地完成单字节或多字节数组形式的消息传递工作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值