【idf ESP32】SPI的使用

文章目录

  • 前言
    • 通信流程图
    • SPI总线初始化
      • `spi_bus_config_t` 结构体声明及成员含义
      • `spi_bus_initialize` 函数的作用、原型及参数和返回值的含义
        • 函数原型:
        • 参数含义:
        • 返回值:
      • 示例:
    • 添加SPI设备
      • `spi_bus_add_device` 函数介绍
        • 函数原型:
        • 参数说明:
        • 返回值:
      • `spi_device_interface_config_t` 结构体
        • 成员含义:
      • 示例代码:
        • 参数含义:
        • 返回值:
      • `spi_transaction_t` 结构体声明及成员含义
      • 示例:
    • spi_device_release_bus
        • 函数原型:
        • 参数含义:
        • 返回值:
      • 示例:
    • spi_bus_remove_device
        • 函数原型:
        • 参数含义:
        • 返回值:
      • 示例:
    • 示例
  • 总结


前言

ESP32 是一款功能强大的微控制器,广泛应用于物联网(IoT)设备和嵌入式系统中。SPI(Serial Peripheral Interface)是 ESP32 常用的一种通信协议,用于在微控制器和外部设备之间进行高速数据传输。SPI 通信具有简单、高效和可靠的特点,非常适合需要快速响应的应用场景。在本文中,我们将探讨如何在 ESP32 上使用 SPI 总线,实现与外部传感器、存储设备和其他外设的通信。


通信流程图

+---------------------------+
|  开始                      |
+---------------------------+|v
+---------------------------+
| 初始化 SPI 总线            |
|  - 配置引脚                 |
|  - 设置参数                 |
+---------------------------+|v
+---------------------------+
| 添加 SPI 设备              |
|  - 配置设备参数            |
|  - 设置 CS 引脚            |
+---------------------------+|v
+---------------------------+
| 配置 SPI 传输              |
|  - 设置 TX 缓冲区          |
|  - 设置 RX 缓冲区          |
+---------------------------+|v
+---------------------------+
| 执行 SPI 传输              |
|  - 发送数据                |
|  - 接收数据                |
+---------------------------+|v
+---------------------------+
| 移除 SPI 设备              |
|  - 释放资源                |
+---------------------------+|v
+---------------------------+
| 释放 SPI 总线              |
|  - 释放引脚                |
|  - 清理资源                |
+---------------------------+|v
+---------------------------+
| 结束                      |
+---------------------------+

SPI总线初始化

spi_bus_config_t 结构体声明及成员含义

在 ESP32 中,spi_bus_config_t 结构体用于配置 SPI 总线的参数。下面是该结构体的声明及其成员的含义:

typedef struct {int mosi_io_num;      // MOSI(主设备输出,从设备输入)引脚编号int miso_io_num;      // MISO(主设备输入,从设备输出)引脚编号int sclk_io_num;      // SCLK(时钟信号)引脚编号int quadwp_io_num;    // WP(写保护)引脚编号,用于四线制 SPI,如果不使用则设置为 -1int quadhd_io_num;    // HD(保持数据)引脚编号,用于四线制 SPI,如果不使用则设置为 -1int max_transfer_sz;  // 最大传输数据大小,以字节为单位uint32_t flags;       // 标志位,用于设置 SPI 总线的特定属性(通常设置为 0)int intr_flags;       // 中断标志,用于配置中断的优先级
} spi_bus_config_t;

spi_bus_initialize 函数的作用、原型及参数和返回值的含义

spi_bus_initialize 函数用于初始化 SPI 总线。它配置 SPI 总线的引脚和其他参数,以便 SPI 设备可以在总线上通信。

函数原型:
esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus_config, spi_dma_chan_t dma_chan);
参数含义:
  • host:指定要将设备添加到的 SPI 主机(总线)。可以是 SPI1_HOSTSPI2_HOSTSPI3_HOST(在 ESP32 上),以及适用于其他 ESP32 变体的主机接口。
  • bus_config:指向 spi_bus_config_t 结构体的指针,该结构体包含了 SPI 总线的配置信息。
  • dma_chan:指定要使用的 DMA 通道(通常是 1 或 2,你可以使用自动SPI_DMA_CH_AUTO,如果不使用 DMA,则设置为 0)。
返回值:
  • ESP_OK:表示初始化成功。
  • 其他错误代码(如 ESP_ERR_INVALID_ARGESP_ERR_INVALID_STATE 等):表示初始化过程中发生了错误。

示例:

spi_bus_config_t bus_config = {.mosi_io_num = 23,.miso_io_num = 19,.sclk_io_num = 18,.quadwp_io_num = -1,.quadhd_io_num = -1,.max_transfer_sz = 4096,.flags = 0,.intr_flags = 0
};esp_err_t ret = spi_bus_initialize(HSPI_HOST, &bus_config, 1);
if (ret == ESP_OK) {printf("SPI bus initialized successfully.\n");
} else {printf("Failed to initialize SPI bus: %s\n", esp_err_to_name(ret));
}

以上示例演示了如何使用 spi_bus_initialize 函数初始化一个 SPI 总线。通过配置 spi_bus_config_t 结构体并调用 spi_bus_initialize 函数,我们可以轻松地设置 SPI 总线,以便与外部设备进行通信。

添加SPI设备

spi_bus_add_device 函数介绍

spi_bus_add_device 函数用于将一个 SPI 设备添加到已经初始化的 SPI 总线上。它会创建一个 SPI 设备句柄,用于后续的 SPI 通信操作。

函数原型:
esp_err_t spi_bus_add_device(spi_host_device_t host, const spi_device_interface_config_t *dev_config, spi_device_handle_t *handle);
参数说明:
  • host:指定要将设备添加到的 SPI 主机(总线)。可以是 SPI1_HOSTSPI2_HOSTSPI3_HOST(在 ESP32 上),以及适用于其他 ESP32 变体的主机接口。

  • dev_config:指向 spi_device_interface_config_t 结构体的指针,该结构体包含了 SPI 设备的配置参数,如时钟频率、SPI 模式、片选引脚等。

  • handle:指向 spi_device_handle_t 类型的指针,用于接收设备句柄。这个句柄用于后续的 SPI 传输操作。

返回值:
  • ESP_OK:表示成功将设备添加到 SPI 总线上。
  • 其他错误代码(如 ESP_ERR_INVALID_ARGESP_ERR_NO_MEM 等):表示添加设备过程中发生了错误。

spi_device_interface_config_t 结构体

spi_device_interface_config_t 结构体用于配置 SPI 设备的参数。以下是结构体的定义及其成员的含义:

typedef struct {uint32_t clock_speed_hz;       // SPI 时钟频率,以赫兹为单位uint8_t mode;                  // SPI 模式(0、1、2 或 3)int spics_io_num;              // 片选引脚的编号uint8_t queue_size;            // 事务队列的大小spi_device_pre_cb_t pre_cb;    // 传输前的回调函数(可以设置为 NULL)spi_device_post_cb_t post_cb;  // 传输后的回调函数(可以设置为 NULL)void* user;                    // 用户定义的数据uint8_t flags;                 // 设备标志,指定设备的一些特殊特性(如 DMA 支持)int address_bits;              // 设备地址位数(用于某些设备的地址模式)int dummy_bits;                // 假数据位数(用于 SPI 设备的空闲周期)spi_device_handle_t handle;    // 设备句柄(自动设置,无需用户配置)
} spi_device_interface_config_t;
成员含义:
  • clock_speed_hz:设置 SPI 时钟频率,以赫兹(Hz)为单位。该值决定了 SPI 总线的速度。

  • mode:指定 SPI 模式,取值为 0、1、2 或 3。SPI 模式决定了数据传输的极性和相位。

  • spics_io_num:指定 SPI 设备的片选(CS)引脚的编号。片选引脚用于选择具体的 SPI 设备进行通信。

  • queue_size:指定事务队列的大小。事务队列用于存储待处理的 SPI 传输事务,确保数据传输的顺序和可靠性。

  • pre_cb:传输前的回调函数。可以在传输前执行一些特定的操作,比如设置设备状态。可以设置为 NULL 表示不使用回调函数。

  • post_cb:传输后的回调函数。可以在传输完成后执行一些特定的操作,比如处理传输结果。可以设置为 NULL 表示不使用回调函数.

  • user:用户定义的数据,可以在回调函数中使用。用于存储与设备相关的额外信息。

  • flags:设备标志,指定设备的一些特殊特性。例如,是否启用 DMA 支持等。

  • address_bits:设备地址位数(用于某些设备的地址模式)。设置设备地址的位数。

  • dummy_bits:假数据位数,设置在 SPI 传输中需要插入的假数据位数,用于某些 SPI 设备的空闲周期。

  • handle:SPI 设备句柄,自动设置,用于后续的 SPI 传输操作。用户无需手动配置。

示例代码:

以下是如何使用 spi_bus_add_device 函数将一个 SPI 设备添加到 SPI 总线的示例代码:

#include "driver/spi_master.h"// 定义 SPI 总线配置
spi_bus_config_t bus_config = {.mosi_io_num = 23,.miso_io_num = 19,.sclk_io_num = 18,.quadwp_io_num = -1,.quadhd_io_num = -1,.max_transfer_sz = 4096,
};// 初始化 SPI 总线
esp_err_t ret = spi_bus_initialize(SPI2_HOST, &bus_config, 1);
if (ret != ESP_OK) {// 处理初始化失败的情况
}// 定义 SPI 设备配置
spi_device_interface_config_t dev_config = {.clock_speed_hz = 1*1000*1000,    // 时钟频率 1 MHz.mode = 0,                        // SPI 模式 0.spics_io_num = 5,                // CS 引脚.queue_size = 7,                  // 事务队列大小.pre_cb = NULL,                   // 传输前的回调函数.post_cb = NULL,                  // 传输后的回调函数
};// 设备句柄
spi_device_handle_t handle;// 添加 SPI 设备
ret = spi_bus_add_device(SPI2_HOST, &dev_config, &handle);
if (ret == ESP_OK) {printf("SPI 设备成功添加。\n");
} else {printf("添加 SPI 设备失败: %s\n", esp_err_to_name(ret));
}

通过 spi_bus_add_device 函数,你可以将 SPI 设备成功地添加到 SPI 总线上,并配置其操作参数,为后续的 SPI 数据传输做好准备。


## spi_device_polling_transmit`spi_device_polling_transmit` 函数用于通过 SPI 总线发送和接收数据,并在完成传输前阻塞。该函数适用于需要确保数据立即传输且无延迟的场景,因为它在数据传输完成前不会返回。#### 函数原型:```c
esp_err_t spi_device_polling_transmit(spi_device_handle_t handle, spi_transaction_t *trans_desc);
参数含义:
  • handle:SPI 设备的句柄,用于标识哪个 SPI 设备进行传输。该句柄在调用 spi_bus_add_device 函数时获得。
  • trans_desc:指向 spi_transaction_t 结构体的指针,该结构体包含了 SPI 传输的信息,如发送和接收缓冲区、数据长度等。
返回值:
  • ESP_OK:表示传输成功。
  • 其他错误代码(如 ESP_ERR_INVALID_ARGESP_ERR_INVALID_STATE 等):表示传输过程中发生了错误。

spi_transaction_t 结构体声明及成员含义

在调用 spi_device_polling_transmit 函数时,需要提供 spi_transaction_t 结构体,该结构体包含了 SPI 传输的具体信息。下面是该结构体的声明及其成员的含义:

typedef struct {uint32_t flags;              // 传输的标志位size_t length;               // 传输的总长度(以位为单位)size_t rxlength;             // 接收数据的长度(以位为单位),通常与 length 相同void *user;                  // 用户定义的指针,可以在回调中使用union {const uint8_t *tx_buffer; // 指向发送缓冲区的指针uint8_t *tx_data[4];      // 小于 32 位的数据传输直接通过此数组};union {uint8_t *rx_buffer;       // 指向接收缓冲区的指针uint8_t *rx_data[4];      // 小于 32 位的数据接收直接通过此数组};
} spi_transaction_t;

示例:

以下是如何使用 spi_device_polling_transmit 函数进行 SPI 数据传输的示例代码:

spi_device_handle_t handle; // 假设该句柄已通过 spi_bus_add_device 函数获取spi_transaction_t trans_desc = {.flags = 0,.length = 8 * sizeof(data_to_send),  // 传输数据长度,以位为单位.tx_buffer = data_to_send,           // 发送缓冲区.rx_buffer = data_received,          // 接收缓冲区
};esp_err_t ret = spi_device_polling_transmit(handle, &trans_desc);
if (ret == ESP_OK) {printf("SPI data transmitted successfully.\n");// 在 data_received 中处理接收到的数据
} else {printf("Failed to transmit SPI data: %s\n", esp_err_to_name(ret));
}

在这个示例中,spi_device_polling_transmit 函数用于发送和接收数据。通过配置 spi_transaction_t 结构体并调用该函数,我们可以实现高效的 SPI 数据传输。该函数会在传输完成后返回,因此适用于需要立即获取传输结果的应用场景。

spi_device_release_bus

spi_device_release_bus 函数用于释放当前 SPI 设备对 SPI 总线的控制权。在多任务环境或多设备环境中,如果某个任务或设备占用了 SPI 总线,那么其他任务或设备就无法使用该总线。通过调用 spi_device_release_bus,可以释放总线的控制权,让其他任务或设备能够使用 SPI 总线。

函数原型:
esp_err_t spi_device_release_bus(spi_device_handle_t handle);
参数含义:
  • handle:SPI 设备的句柄,用于标识哪个 SPI 设备要释放总线控制权。该句柄在调用 spi_bus_add_device 函数时获得。
返回值:
  • ESP_OK:表示成功释放总线。
  • 其他错误代码(如 ESP_ERR_INVALID_ARG 等):表示释放总线过程中发生了错误。

示例:

以下是如何使用 spi_device_release_bus 函数释放 SPI 总线控制权的示例代码:

spi_device_handle_t handle; // 假设该句柄已通过 spi_bus_add_device 函数获取// 进行一些 SPI 传输操作
// ...// 释放 SPI 总线
esp_err_t ret = spi_device_release_bus(handle);
if (ret == ESP_OK) {printf("SPI bus released successfully.\n");
} else {printf("Failed to release SPI bus: %s\n", esp_err_to_name(ret));
}

在这个示例中,spi_device_release_bus 函数用于释放 SPI 总线的控制权,使得其他任务或设备可以使用该总线。这个函数对于协调多个 SPI 设备或任务之间的总线使用非常有用。

spi_bus_remove_device

spi_bus_remove_device 函数用于从 SPI 总线上移除一个已添加的 SPI 设备。调用该函数可以释放与该设备相关的资源,从而让 SPI 总线可以被其他设备使用或进行重新配置。

函数原型:
esp_err_t spi_bus_remove_device(spi_device_handle_t handle);
参数含义:
  • handle:SPI 设备的句柄,用于标识要移除的 SPI 设备。该句柄在调用 spi_bus_add_device 函数时获得。
返回值:
  • ESP_OK:表示成功移除设备。
  • 其他错误代码(如 ESP_ERR_INVALID_ARG 等):表示移除设备过程中发生了错误。

示例:

以下是如何使用 spi_bus_remove_device 函数从 SPI 总线上移除一个设备的示例代码:

spi_device_handle_t handle; // 假设该句柄已通过 spi_bus_add_device 函数获取// 进行一些 SPI 传输操作
// ...// 移除 SPI 设备
esp_err_t ret = spi_bus_remove_device(handle);
if (ret == ESP_OK) {printf("SPI device removed successfully.\n");
} else {printf("Failed to remove SPI device: %s\n", esp_err_to_name(ret));
}

在这个示例中,spi_bus_remove_device 函数用于从 SPI 总线上移除指定的设备。通过调用该函数,可以释放与该设备相关的资源,从而为其他设备的使用或重新配置 SPI 总线提供便利。这个函数在需要动态管理 SPI 设备的应用中非常有用。

示例

#include <stdio.h>
#include "driver/spi_master.h"
#include "esp_log.h"
#include "esp_system.h"#define SPI_BUS_SPEED_HZ 1000000      // SPI 时钟频率 1 MHz
#define SPI_DEVICE_MODE 0            // SPI 模式 0
#define SPI_DEVICE_CS_PIN 5           // 片选引脚
#define SPI_DEVICE_QUEUE_SIZE 7       // 事务队列大小static const char *TAG = "spi_example";// SPI 总线配置
spi_bus_config_t bus_config = {.mosi_io_num = 23,               // MOSI 引脚.miso_io_num = 19,               // MISO 引脚.sclk_io_num = 18,               // SCLK 引脚.quadwp_io_num = -1,             // 不使用 Quad WP.quadhd_io_num = -1,             // 不使用 Quad HD.max_transfer_sz = 4096,         // 最大传输大小
};// SPI 设备配置
spi_device_interface_config_t dev_config = {.clock_speed_hz = SPI_BUS_SPEED_HZ,    // 时钟频率.mode = SPI_DEVICE_MODE,              // SPI 模式.spics_io_num = SPI_DEVICE_CS_PIN,    // 片选引脚.queue_size = SPI_DEVICE_QUEUE_SIZE,  // 事务队列大小.pre_cb = NULL,                       // 传输前的回调函数.post_cb = NULL,                      // 传输后的回调函数
};void app_main(void)
{esp_err_t ret;// 初始化 SPI 总线ret = spi_bus_initialize(SPI2_HOST, &bus_config, 1);if (ret != ESP_OK) {ESP_LOGE(TAG, "Failed to initialize SPI bus: %s", esp_err_to_name(ret));return;}// 添加 SPI 设备spi_device_handle_t spi_handle;ret = spi_bus_add_device(SPI2_HOST, &dev_config, &spi_handle);if (ret != ESP_OK) {ESP_LOGE(TAG, "Failed to add SPI device: %s", esp_err_to_name(ret));spi_bus_free(SPI2_HOST);return;}// 准备要发送的数据uint8_t tx_data[] = {0xAA, 0xBB, 0xCC, 0xDD};uint8_t rx_data[sizeof(tx_data)] = {0};spi_transaction_t trans = {.length = sizeof(tx_data) * 8,   // 数据长度(以位为单位).tx_buffer = tx_data,            // 发送缓冲区.rx_buffer = rx_data,            // 接收缓冲区};// 执行 SPI 传输ret = spi_device_transmit(spi_handle, &trans);if (ret != ESP_OK) {ESP_LOGE(TAG, "Failed to transmit SPI data: %s", esp_err_to_name(ret));} else {ESP_LOGI(TAG, "SPI data transmitted successfully");// 打印接收到的数据printf("Received data: ");for (int i = 0; i < sizeof(rx_data); i++) {printf("0x%02X ", rx_data[i]);}printf("\n");}// 移除 SPI 设备ret = spi_bus_remove_device(spi_handle);if (ret != ESP_OK) {ESP_LOGE(TAG, "Failed to remove SPI device: %s", esp_err_to_name(ret));}// 释放 SPI 总线ret = spi_bus_free(SPI2_HOST);if (ret != ESP_OK) {ESP_LOGE(TAG, "Failed to free SPI bus: %s", esp_err_to_name(ret));}
}

总结

通过本文的介绍,我们了解了如何在 ESP32 上使用 SPI 总线,实现与各种外部设备的高速数据通信。SPI 通信的简单性和高效性,使其成为物联网和嵌入式系统中常用的通信方式。掌握了 SPI 的使用方法后,开发者可以轻松地将 ESP32 与多种外设集成,为自己的项目提供更多功能和可能性。无论是读取传感器数据,还是控制显示屏,SPI 都能提供可靠的解决方案,帮助开发者实现他们的设计目标。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/877010.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Graph-RAG:知识图谱与大模型的融合

在数字化的浪潮中&#xff0c;知识的累积已非线性增长&#xff0c;以指数级的速度膨胀。我们站在一个信息过载的十字路口&#xff0c;迫切需要一种能力&#xff0c;能够穿透数据的迷雾&#xff0c;捕捉知识的精髓。本文将揭示 Graph-RAG 的神秘面纱&#xff0c;这是一种突破传统…

FBMM: Making Memory Management Extensible With Filesystems——论文泛读

ATC 2024 Paper 论文阅读笔记整理 问题 CXL这样的新内存技术实现了多种内存配置&#xff0c;如分层内存、远内存和内存处理。为了支持这些新的硬件配置&#xff0c;需要对操作系统进行大量修改。例如&#xff0c;Meta的TPP内核补丁对NUMA和页面回收策略进行了更改&#xff0c…

PMP证书含金量高吗?值得考吗?

值啊&#xff0c;我考过了&#xff0c;PMP 是项目管理岗位的敲门砖&#xff0c;很多企业都写明了持有PMP 证书的优先&#xff0c;而且学完这个知识体系&#xff0c;对我的能力提升确实有帮助&#xff0c;还是值得的。 一、为什么值得 这个证书就是基础知识&#xff0c;项目管…

LUA脚本改造redis分布式锁

在redis集群模式下&#xff0c;我们会启动多个tomcat实例&#xff0c;每个tomcat实例都有一个JVM&#xff0c;且不共享。而synchronize锁的作用范围仅仅是当前JVM&#xff0c;所以我们需要一个作用于集群下的锁&#xff0c;也就是分布式锁。&#xff08;就是不能用JVM自带的锁了…

系统架构设计师 - 知识产权与标准化

知识产权与标准化 知识产权与标准化&#xff08;3分&#xff09;保护范围与对象 ★ ★ ★ ★法律法规 保护期限 ★ ★知识产权人确定 ★ ★ ★ ★侵权判断 ★ ★ ★ ★标准化&#xff08;了解&#xff09;★标准的分类标准的编号 大家好呀&#xff01;我是小笙&#xff0c;本章…

数据库实验:数据库安全性

一、实验目的&#xff1a; 1、掌握SQL SERVER的身份验证方式。 2、掌握SQL SERVER的权限。 3、掌握给数据库的用户和角色赋予权限和从用户和角色收回权限。 4、掌握GRANT&#xff0c;REVOKE&#xff0c;DENY的用法。 二、实验内容&#xff1a; 1、将SQL SERVER服务器的安全…

爬虫-通过几个例子来说明并发以及多线程

并发 什么是并发&#xff1f;并发&#xff0c;在操作系统中&#xff0c;是指一个时间段中有几个程序都处于已启动运行到运行完毕之间&#xff0c;且这几个程序都是在同一个处理机上运行&#xff0c;但任一个时刻点上只有一个程序在处理机上运行。 嗯&#xff0c;字认识&#…

滞回比较器工作原理,应用,TINA仿真

滞回比较器 滞回比较器的主要应用是增加滞回控制&#xff0c;让其对微小的变化不那么敏感&#xff0c;增强抗干扰能力&#xff0c;避免由噪声引起的不稳定状态&#xff0c;通常用于噪声环境下的阈值检测以及信号调理。根据不同需求&#xff0c;滞回比较器还可以设计成开漏极输出…

Redis的使用场景——热点数据缓存

热点数据缓存 Redis的使用场景——热点数据的缓存 1.1 什么是缓存 为了把一些经常访问的数据&#xff0c;放入缓存中以减少对数据库的访问效率&#xff0c;从而减少数据库的压力&#xff0c;提高程序的性能。【在内存中存储】 1.2 缓存的原理 查询缓存中是否存在对应的数据如…

[240728] Wikidata 介绍 | 微软与 Lumen 合作提升人工智能算力

目录 Wikidata 介绍微软与 Lumen 合作提升人工智能算力 Wikidata 介绍 中文&#xff1a; 文言: 粤语&#xff1a; 来源&#xff1a; https://www.wikidata.org/wiki/Wikidata:Introduction/zh 微软与 Lumen 合作提升人工智能算力 为了满足人工智能工作负载不断增长的需求&am…

从零开始写 Docker(十九)---增加 cgroup v2 支持

本文为从零开始写 Docker 系列第十九篇&#xff0c;添加对 cgroup v2 的支持。 完整代码见&#xff1a;https://github.com/lixd/mydocker 欢迎 Star 推荐阅读以下文章对 docker 基本实现有一个大致认识&#xff1a; 核心原理&#xff1a;深入理解 Docker 核心原理&#xff1a…

微软蓝屏”事件暴露了网络安全哪些问题?

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文由 JohnKi 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f4e2;未来很长&#…

cadence SPB17.4 - allegro - 设置不同网络之间的距离规则

文章目录 cadence SPB17.4 - allegro - 设置不同网络之间的距离规则概述笔记END cadence SPB17.4 - allegro - 设置不同网络之间的距离规则 概述 插座进来的管脚&#xff0c;可能带来高压&#xff08;有可能用户接错&#xff0c;或者出现浪涌&#xff0c;或者做ESD静电测试&a…

SpringBoot热部署重启关闭(DevTools)

一、DevTools依赖 1、DevTools简介 在Spring Boot项目中&#xff0c;spring-boot-devtools模块提供了多种开发时的便利功能&#xff0c;其中最显著的是restart和livereload特性&#xff0c;它们分别用于应用代码的热重启和前端资源的即时重载。 devtools依赖&#xff1a; &l…

STL Map的使用和性能issue

1、高效地访问 1&#xff09;隐式插入问题 map初学者会直接用中括号访问&#xff0c;方便但是有代价&#xff1a;key不存在的时候还会隐式插入&#xff0c; 尤其对于LRU缓存设计&#xff0c;用这个就是灾难&#xff0c;会导致脏数据&#xff0c; 规避方案&#xff0c;cache的…

如何在调整节拍时间的过程中保持生产流程的稳定性?

在快节奏的工业生产领域&#xff0c;节拍时间&#xff08;Takt Time&#xff09;——即完成一个完整产品所需的标准时间&#xff0c;是维持生产效率和流程稳定性的关键指标。然而&#xff0c;市场需求的波动、技术升级或是生产线的微调&#xff0c;都可能要求我们对节拍时间进行…

Redis-主从模式

目录 前言 一.主从节点介绍 二.配置redis主从结构 二.主从复制 四.拓扑结构 五.数据同步 全量复制&#xff08;Full Sync Replication&#xff09; 局部复制&#xff08;Partial Replication&#xff09; Redis的学习专栏&#xff1a;http://t.csdnimg.cn/a8cvV 前言 …

SLAM:corners:Measuring Corner Properties-1999【方法解析-1】

paper:Measuring Corner Properties 目录 摘要1. 引言2. 测量属性2.1 对比度和夹角详细解析摘要 我们描述了测量灰度角点以下属性的方法:夹角、方向、对比度、钝度(或顶点的圆度)以及边界曲率(适用于尖点)。与大多数已发表的提取这些属性的方法不同,这些新方法相对简单…

docker安装phpMyAdmin

直接安装phpMyAdmin需要有php环境&#xff0c;比较麻烦&#xff0c;总结了使用docker安装方法&#xff0c;并提供docker镜像。 1.docker镜像 见我上传的docker镜像&#xff1a;https://download.csdn.net/download/taotao_guiwang/89595177 2.安装 1).加载镜像 docker load …