当前位置: 首页 > news >正文

ESP32外设学习部分--SPI篇

SPI学习

前言

我个人以为开始学习一个新的单片机最好的方法就是先把他各个外设给跑一遍,整体了解一下他的功能,由此记录一下我学习ESP32外设的过程,防止以后忘记。

SPI 配置步骤

SPI总线初始化

    spi_bus_config_t buscfg = {.miso_io_num = PIN_NUM_MISO,.mosi_io_num = PIN_NUM_MOSI,.sclk_io_num = PIN_NUM_CLK,.quadwp_io_num = -1,.quadhd_io_num = -1,.max_transfer_sz = PARALLEL_LINES * 320 * 2 + 8};

点击进入可以查看结构体中的内容如下

typedef struct {union {int mosi_io_num;    ///< GPIO pin for Master Out Slave In (=spi_d) signal, or -1 if not used.int data0_io_num;   ///< GPIO pin for spi data0 signal in quad/octal mode, or -1 if not used.};union {int miso_io_num;    ///< GPIO pin for Master In Slave Out (=spi_q) signal, or -1 if not used.int data1_io_num;   ///< GPIO pin for spi data1 signal in quad/octal mode, or -1 if not used.};int sclk_io_num;      ///< GPIO pin for SPI Clock signal, or -1 if not used.union {int quadwp_io_num;  ///< GPIO pin for WP (Write Protect) signal, or -1 if not used.int data2_io_num;   ///< GPIO pin for spi data2 signal in quad/octal mode, or -1 if not used.};union {int quadhd_io_num;  ///< GPIO pin for HD (Hold) signal, or -1 if not used.int data3_io_num;   ///< GPIO pin for spi data3 signal in quad/octal mode, or -1 if not used.};int data4_io_num;     ///< GPIO pin for spi data4 signal in octal mode, or -1 if not used.int data5_io_num;     ///< GPIO pin for spi data5 signal in octal mode, or -1 if not used.int data6_io_num;     ///< GPIO pin for spi data6 signal in octal mode, or -1 if not used.int data7_io_num;     ///< GPIO pin for spi data7 signal in octal mode, or -1 if not used.int max_transfer_sz;  ///< Maximum transfer size, in bytes. Defaults to 4092 if 0 when DMA enabled, or to `SOC_SPI_MAXIMUM_BUFFER_SIZE` if DMA is disabled.uint32_t flags;       ///< Abilities of bus to be checked by the driver. Or-ed value of ``SPICOMMON_BUSFLAG_*`` flags.esp_intr_cpu_affinity_t  isr_cpu_id;    ///< Select cpu core to register SPI ISR.int intr_flags;       /**< Interrupt flag for the bus to set the priority, and IRAM attribute, see*  ``esp_intr_alloc.h``. Note that the EDGE, INTRDISABLED attribute are ignored*  by the driver. Note that if ESP_INTR_FLAG_IRAM is set, ALL the callbacks of*  the driver, and their callee functions, should be put in the IRAM.*/} spi_bus_config_t;

可以看到上面可以配置的内容非常多,可以配置三线四线SPI,但是我们本次主要学习两线的就可以了,用不到的管脚直接配置-1就OK了。

添加SPI设备

    spi_device_interface_config_t devcfg = {#ifdef CONFIG_LCD_OVERCLOCK.clock_speed_hz = 26 * 1000 * 1000,     //Clock out at 26 MHz#else.clock_speed_hz = 10 * 1000 * 1000,     //Clock out at 10 MHz#endif.mode = 0,                              //SPI mode 0.spics_io_num = PIN_NUM_CS,             //CS pin.queue_size = 7,                        //We want to be able to queue 7 transactions at a time.pre_cb = lcd_spi_pre_transfer_callback, //Specify pre-transfer callback to handle D/C line};

然后配置spi_device_interface_config_t 这个结构体,老规矩继续看一下这个结构体中的内容

typedef struct {uint8_t command_bits;           ///< Default amount of bits in command phase (0-16), used when ``SPI_TRANS_VARIABLE_CMD`` is not used, otherwise ignored.uint8_t address_bits;           ///< Default amount of bits in address phase (0-64), used when ``SPI_TRANS_VARIABLE_ADDR`` is not used, otherwise ignored.uint8_t dummy_bits;             ///< Amount of dummy bits to insert between address and data phaseuint8_t mode;                   /**< SPI mode, representing a pair of (CPOL, CPHA) configuration:- 0: (0, 0)- 1: (0, 1)- 2: (1, 0)- 3: (1, 1)*/spi_clock_source_t clock_source;///< Select SPI clock source, `SPI_CLK_SRC_DEFAULT` by default.uint16_t duty_cycle_pos;        ///< Duty cycle of positive clock, in 1/256th increments (128 = 50%/50% duty). Setting this to 0 (=not setting it) is equivalent to setting this to 128.uint16_t cs_ena_pretrans;       ///< Amount of SPI bit-cycles the cs should be activated before the transmission (0-16). This only works on half-duplex transactions.uint8_t cs_ena_posttrans;       ///< Amount of SPI bit-cycles the cs should stay active after the transmission (0-16)int clock_speed_hz;             ///< SPI clock speed in Hz. Derived from `clock_source`.int input_delay_ns;             /**< Maximum data valid time of slave. The time required between SCLK and MISOvalid, including the possible clock delay from slave to master. The driver uses this value to give an extradelay before the MISO is ready on the line. Leave at 0 unless you know you need a delay. For better timingperformance at high frequency (over 8MHz), it's suggest to have the right value.*/int spics_io_num;               ///< CS GPIO pin for this device, or -1 if not useduint32_t flags;                 ///< Bitwise OR of SPI_DEVICE_* flagsint queue_size;                 ///< Transaction queue size. This sets how many transactions can be 'in the air' (queued using spi_device_queue_trans but not yet finished using spi_device_get_trans_result) at the same timetransaction_cb_t pre_cb;   /**< Callback to be called before a transmission is started.**  This callback is called within interrupt*  context should be in IRAM for best*  performance, see "Transferring Speed"*  section in the SPI Master documentation for*  full details. If not, the callback may crash*  during flash operation when the driver is*  initialized with ESP_INTR_FLAG_IRAM.*/transaction_cb_t post_cb;  /**< Callback to be called after a transmission has completed.**  This callback is called within interrupt*  context should be in IRAM for best*  performance, see "Transferring Speed"*  section in the SPI Master documentation for*  full details. If not, the callback may crash*  during flash operation when the driver is*  initialized with ESP_INTR_FLAG_IRAM.*/} spi_device_interface_config_t;

可以看到这个结构体里面的参数也是比较多的,但是我们主要关注的其实就是clock_speed_hz,mode,spics_io_num,这几个参数,这几个也是我们在STM32上最熟悉的;当然如果需要驱动LCD我们可能还需要控制一个DC脚,这时候也可以关注一下pre_cb这个参数,这个是在启用SPI传输前的回调,我们可以用它来控制下个发的是command还是data。

初始化总线

    //Initialize the SPI busret = spi_bus_initialize(LCD_HOST, &buscfg, SPI_DMA_CH_AUTO);

用上面的函数就可以初始化我们配置好的SPI总线。

入参的选择

typedef enum {SPI_DMA_DISABLED = 0,     ///< Do not enable DMA for SPI#if CONFIG_IDF_TARGET_ESP32SPI_DMA_CH1      = 1,     ///< Enable DMA, select DMA Channel 1SPI_DMA_CH2      = 2,     ///< Enable DMA, select DMA Channel 2#endifSPI_DMA_CH_AUTO  = 3,     ///< Enable DMA, channel is automatically selected by driver} spi_common_dma_t;

前两个其实都不用讲,都是我们配置好的。最后一个要看下如果选择了DMA通道,发送的数据就要需要是被存储在DMA可以访问的内存中,不然容易出现问题。
添加设备

    //Attach the LCD to the SPI busret = spi_bus_add_device(SPI2_HOST, &devcfg, &spi);

用上面的函数就可以添加我们的SPI设备了

数据发送

数据发送的时候我们可以使用两个函数来发送我们的数据

spi_device_queue_trans 函数和spi_device_polling_transmit函数的区别

spi_device_queue_transspi_device_polling_transmit 都是ESP32 SPI主机驱动程序中用于发送SPI事务的函数,但它们在传输方式和使用场景上有所不同:

esp_err_t SPI_MASTER_ATTR spi_device_queue_trans(spi_device_handle_t handle, spi_transaction_t *trans_desc, TickType_t ticks_to_wait)esp_err_t SPI_MASTER_ISR_ATTR spi_device_polling_transmit(spi_device_handle_t handle, spi_transaction_t* trans_desc)
  1. spi_device_queue_trans

    • 这个函数用于将SPI事务添加到中断传输队列中。
    • 调用这个函数后,当前线程可以继续执行其他任务,而SPI传输将在后台通过中断服务程序异步处理。
    • 它允许多个事务排队,适合于需要连续发送多个SPI事务的场景,或者当需要在传输之间插入其他代码时。
    • 事务完成后,需要使用spi_device_get_trans_result函数来获取事务的结果。
    • 这种方式适用于非阻塞传输,可以提高CPU的利用率。
  2. spi_device_polling_transmit

    • 这个函数用于发送轮询模式下的SPI事务,调用后会等待事务完成并返回结果。
    • 在轮询模式下,CPU会一直等待直到SPI事务完成,期间不能执行其他任务,这可能会导致CPU资源的浪费。
    • 它适合于对实时性要求较高的场合,或者当需要在事务之间精确控制时序时。
    • 如果需要在传输中间插入其他代码,可以使用spi_device_polling_startspi_device_polling_end两个函数来实现。

总结来说,spi_device_queue_trans提供了一种非阻塞的、异步的SPI传输方式,适合于多任务环境和需要高CPU利用率的场景;而spi_device_polling_transmit提供了一种同步的、阻塞的传输方式,适合于对时序要求严格的场合。开发者可以根据具体的应用需求选择合适的函数。

struct spi_transaction_t {uint32_t flags;                 ///< Bitwise OR of SPI_TRANS_* flagsuint16_t cmd;                   /**< Command data, of which the length is set in the ``command_bits`` of spi_device_interface_config_t.**  <b>NOTE: this field, used to be "command" in ESP-IDF 2.1 and before, is re-written to be used in a new way in ESP-IDF 3.0.</b>**  Example: write 0x0123 and command_bits=12 to send command 0x12, 0x3_ (in previous version, you may have to write 0x3_12).*/uint64_t addr;                  /**< Address data, of which the length is set in the ``address_bits`` of spi_device_interface_config_t.**  <b>NOTE: this field, used to be "address" in ESP-IDF 2.1 and before, is re-written to be used in a new way in ESP-IDF3.0.</b>**  Example: write 0x123400 and address_bits=24 to send address of 0x12, 0x34, 0x00 (in previous version, you may have to write 0x12340000).*/size_t length;                  ///< Total data length, in bitssize_t rxlength;                ///< Total data length received, should be not greater than ``length`` in full-duplex mode (0 defaults this to the value of ``length``).void *user;                     ///< User-defined variable. Can be used to store eg transaction ID.union {const void *tx_buffer;      ///< Pointer to transmit buffer, or NULL for no MOSI phaseuint8_t tx_data[4];         ///< If SPI_TRANS_USE_TXDATA is set, data set here is sent directly from this variable.};union {void *rx_buffer;            ///< Pointer to receive buffer, or NULL for no MISO phase. Written by 4 bytes-unit if DMA is used.uint8_t rx_data[4];         ///< If SPI_TRANS_USE_RXDATA is set, data is received directly to this variable};} ;        //the rx data should start from a 32-bit aligned address to get around dma issue.

同样的使用上面两个函数我们都需要传递这个结构体来指示一些东西

flags:SPI 事务标志位,可以使用 SPI_TRANS_* 宏定义进行设置。这些标志位用于控制事务的行为,例如是否使用 DMA、是否在事务结束后保持 CS 信号等

length:本次发送的总数据长度,以位为单位。SPI 最多一次可传输 64 字节(65536 位)数据,如果需要传输更多数据,建议使用 DMA

user:用户定义的变量,可以用于存储事务 ID 等信息

tx_buffer:发送数据缓冲区指针,如果不需要发送数据,则设置为 NULL

rx_buffer:接收数据缓冲区指针,如果不需要接收数据,则设置为 NULL,在 DMA 使用时,每次读取 4 字节

最终代码


void lcd_spi_pre_transfer_callback(spi_transaction_t *t){int dc=(int)t->user;gpio_set_level(PIN_NUM_DC, dc);//  printf("DC get 1\n");}void send_non_blocking(spi_device_handle_t spi,uint8_t *data,uint16_t len){esp_err_t ret;static spi_transaction_t trans;memset(&trans, 0, sizeof(trans));       //Zero out the transactiontrans.length=8*len;trans.flags = 0; //undo SPI_TRANS_USE_TXDATA flagtrans.tx_buffer = data;ret=spi_device_queue_trans(spi, &trans, portMAX_DELAY);}spi_device_handle_t spi;uint8_t spi_send[5] DMA_ATTR = {0x23,0x12,0x37,0x44,0x55};void tx_spi_init(void){esp_err_t ret;spi_bus_config_t buscfg = {.miso_io_num = PIN_NUM_MISO,.mosi_io_num = PIN_NUM_MOSI,.sclk_io_num = PIN_NUM_CLK,.quadwp_io_num = -1,.quadhd_io_num = -1,.max_transfer_sz = 16 * 320 * 2 + 8};spi_device_interface_config_t devcfg = {#ifdef CONFIG_LCD_OVERCLOCK.clock_speed_hz = 26 * 1000 * 1000,     //Clock out at 26 MHz#else.clock_speed_hz = 1 * 1000 * 1000,     //Clock out at 10 MHz#endif.mode = 3,                              //SPI mode 0.spics_io_num = PIN_NUM_CS,             //CS pin.queue_size = 7,                        //We want to be able to queue 7 transactions at a time.pre_cb = lcd_spi_pre_transfer_callback, //Specify pre-transfer callback to handle D/C line};//Initialize the SPI busret = spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO);ESP_ERROR_CHECK(ret);//Attach the LCD to the SPI busret = spi_bus_add_device(SPI2_HOST, &devcfg, &spi);ESP_ERROR_CHECK(ret);}void spi_test(void)
{send_non_blocking(spi,spi_send,5);
}

在这里插入图片描述

相关文章:

ESP32外设学习部分--SPI篇

SPI学习 前言 我个人以为开始学习一个新的单片机最好的方法就是先把他各个外设给跑一遍&#xff0c;整体了解一下他的功能&#xff0c;由此记录一下我学习ESP32外设的过程&#xff0c;防止以后忘记。 SPI 配置步骤 SPI总线初始化 spi_bus_config_t buscfg {.miso_io_num …...

Tomcat的下载和使用,配置控制台输出中文日志

目录 1. 简介2. 下载3. 使用3.1 文件夹展示3.1.1 控制台输出乱码 3.2 访问localhost:80803.3 访问静态资源 4. 总结 1. 简介 Tomcat&#xff0c;全称为Apache Tomcat&#xff0c;是一个开源的Web应用服务器和Servlet容器&#xff0c;由Apache软件基金会的Jakarta项目开发。它实…...

MySQL不能被其他地址访问,授权问题解决(8.x,,5.x)

首先强调的是两个版本&#xff0c;5版本和8版本问题反馈不一样 Linux系统部署mysql8.4版本 MySQL官网地址写的很清楚了&#xff0c;不多介绍 直接进入主题&#xff0c;恶心了我三个多小时的问题&#xff0c;翻阅大量国内外资料&#xff0c;结果并不是个多么难得问题&#xff0…...

四、个人项目系统搭建

文章目录 一、python写的后端代码二、html代码三、index.css四、js代码 效果图&#xff1a; 一、python写的后端代码 后端代码使用Flask编写&#xff0c;如下所示&#xff1a; # app.py from flask import Flask, render_template, request, jsonify, g import sqlite3 import…...

CV(4)--边缘提取和相机模型

前言 仅记录学习过程&#xff0c;有问题欢迎讨论 边缘提取&#xff08;涉及语义分割&#xff09;&#xff1a; 图象的边缘是指图象局部区域亮度变化显著的部分,也有正负之分&#xff0c;暗到亮为正 求边缘的幅度&#xff1a;sobel&#xff0c;Canny算子 图像分高频分量和低…...

SORT算法详解及Python实现

目录 SORT算法详解及Python实现第一部分:SORT算法概述与原理1.1 SORT算法简介1.2 应用场景1.3 算法流程第二部分:数学公式与主要模块2.1 卡尔曼滤波模型2.2 目标关联与匈牙利算法2.3 新建与移除机制第三部分:Python实现:SORT算法基础代码3.1 安装依赖3.2 基础代码实现第四部…...

图计算之科普:BSP计算模型、Pregel计算模型、

一、BSP计算模型 BSP计算模型&#xff0c;即整体同步并行计算模型&#xff08;Bulk Synchronous Parallel Computing Model&#xff09;&#xff0c;又名大同步模型或BSP模型&#xff0c;是由哈佛大学L.G. Valiant教授&#xff08;2010年图灵奖得主&#xff09;在1992年提出的…...

pytest入门一:用例的执行范围

从一个或多个目录开始查找&#xff0c;可以在命令行指定文件名或目录名。如果未指定&#xff0c;则使用当前目录。 测试文件以 test_ 开头或以 _test 结尾 测试类以 Test 开头 &#xff0c;并且不能带有 init 方法 测试函数以 test_ 开头 断言使用基本的 assert 即可 所有的…...

22. 正则表达式

一、概述 正则表达式&#xff08;regular expression&#xff09;又称 规则表达式&#xff0c;是一种文本模式&#xff08;pattern&#xff09;。正则表达式使用一个字符串来描述、匹配具有相同规格的字符串&#xff0c;通常被用来检索、替换那些符合某个模式&#xff08;规则&…...

Flink Python作业快速入门

Flink Python快速入门_实时计算 Flink版(Flink)-阿里云帮助中心 import argparse # 用于处理命令行参数和选项&#xff0c;使程序能够接收用户通过命令行传递的参数 import logging import sysfrom pyflink.common import WatermarkStrategy, Encoder, Types from pyflink.data…...

自定义函数库

求两点距离 double dis(double x1, double y1, double x2, double y2){return sqrt(pow(x2-x1, 2)pow(y2-y1, 2)); }判断闰年 bool isLeapYear(int year){return year%40 && year%100!0 || year%4000; }判断素数 bool isPrime(int num){if(num<2) return false;f…...

FreeRTOS例程2-任务挂起恢复与使用中断遇到的坑!

任务挂起简单点理解就是现在不需要执行这个任务&#xff0c;让它先暂停&#xff0c;就是挂起。恢复就是从刚才挂起的状态下继续运行。 API函数 任务挂起vTaskSuspend() 函数原型(tasks.c中): void vTaskSuspend( TaskHandle_t xTaskToSuspend ) 1. 参数&#xff1a; xTaskTo…...

L23.【LeetCode笔记】验证回文串(剖析几种解法)

目录 1.题目 2.自解 提交结果 反思 大小写之间的位运算 提交结果 3.代码优化 提交结果 ​编辑 4.LeetCode网友提供的解法 1.题目 https://leetcode.cn/problems/XltzEq/description/ 给定一个字符串 s &#xff0c;验证 s 是否是 回文串 &#xff0c;只考虑字母和数…...

FPGA 17 ,FPGA 与 SR-IOV虚拟化技术,高性能计算与虚拟化技术的结合(FPGA 与 SR-IOV 和 PCI,高性能计算与虚拟化的完美融合)

目录 前言 一. SR-IOV 的起源与发展 1. SR-IOV 的起源与时间线 2. SR-IOV 的诞生原因 3. SR-IOV 的详细介绍 二. SR-IOV 和 PCI 之间的关系 三. PCI 的起源与演进 1. PCI 的起源与时间线 2. PCI 的关键特性 四. FPGA 的独特魅力 1. FPGA 的定义与特性 2. FPGA 的内…...

解决navicat 导出excel数字为科学计数法问题

一、原因分析 用程序导出的csv文件&#xff0c;当字段中有比较长的数字字段存在时&#xff0c;在用excel软件查看csv文件时就会变成科学技术法的表现形式。 其实这个问题跟用什么语言导出csv文件没有关系。Excel显示数字时&#xff0c;如果数字大于12位&#xff0c;它会自动转化…...

[Unity] AppLovin Max接入Native 广告 Android篇

把下载下来的maxnativelibrary-release-文件放在Plugins/Android下 将这一行加入到mainTemplate.gradle文件中 implementation androidx.constraintlayout:constraintlayout:2.1.4添加下面的两个脚本 using System; using System.Collections; using System.Collections.Gener…...

Source Insight 4.0的安装

一、安装与破解 1、下载Source Insight 4.0安装包 https://pan.baidu.com/s/1t0u1RM19am0lyzhlNTqK9Q?pwdnvmk 2、下载程序破解补丁包 https://pan.baidu.com/s/1irvH-Kfwjf4zCCtWJByqJQ 其中包含文件si4.pediy.lic 和 sourceinsight4.exe。 3、安装下载的Source Insight …...

远程调试软件对比与使用推荐

远程调试软件对比与使用推荐 远程调试是现代软件开发中不可或缺的一部分&#xff0c;尤其是在处理分布式系统、云端服务或远程服务器上的问题时。以下是对几种常见远程调试工具的详细对比和推荐使用场景。 1. GDB (GNU Debugger) 特点 开源&#xff1a;完全免费且开源&…...

鸿蒙项目云捐助第二讲鸿蒙图文互动基本程序实现

鸿蒙项目云捐助第二讲鸿蒙图文互动基本程序实现 结合第一讲建立的“Hello World”程序&#xff0c;得到如下图所示的界面。 这里的“Hello World”是通过“Priview”显示出来的。在这个界面中进行开发的前奏曲&#xff0c;可以通过点击更换图片的案例来体会一下鸿蒙Next的开发…...

求解球面的一组正交标架

目录 求解球面的一组正交标架 求解球面的一组正交标架 球面 r ( u , v ) ( a cos ⁡ u cos ⁡ v , a cos ⁡ u sin ⁡ v , a sin ⁡ u ) \mathbf{r}(u,v)\left(a\cos u\cos v,a\cos u\sin v,a\sin u\right) r(u,v)(acosucosv,acosusinv,asinu), 求得 r u ( − a sin ⁡ u c…...

C++初阶-list的底层

目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...

智慧医疗能源事业线深度画像分析(上)

引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...

从WWDC看苹果产品发展的规律

WWDC 是苹果公司一年一度面向全球开发者的盛会&#xff0c;其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具&#xff0c;对过去十年 WWDC 主题演讲内容进行了系统化分析&#xff0c;形成了这份…...

抖音增长新引擎:品融电商,一站式全案代运营领跑者

抖音增长新引擎&#xff1a;品融电商&#xff0c;一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中&#xff0c;品牌如何破浪前行&#xff1f;自建团队成本高、效果难控&#xff1b;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...

全球首个30米分辨率湿地数据集(2000—2022)

数据简介 今天我们分享的数据是全球30米分辨率湿地数据集&#xff0c;包含8种湿地亚类&#xff0c;该数据以0.5X0.5的瓦片存储&#xff0c;我们整理了所有属于中国的瓦片名称与其对应省份&#xff0c;方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具

文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...

基于数字孪生的水厂可视化平台建设:架构与实践

分享大纲&#xff1a; 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年&#xff0c;数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段&#xff0c;基于数字孪生的水厂可视化平台的…...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成

厌倦手动写WordPress文章&#xff1f;AI自动生成&#xff0c;效率提升10倍&#xff01; 支持多语言、自动配图、定时发布&#xff0c;让内容创作更轻松&#xff01; AI内容生成 → 不想每天写文章&#xff1f;AI一键生成高质量内容&#xff01;多语言支持 → 跨境电商必备&am…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...