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

从 0 到 1 掌握 ESP32 RMT(新手友好版)

对于 ESP32 新手而言,RMT(Remote Control)模块常被贴上 “进阶知识点” 的标签 —— 但实际上,只要顺着 “是什么→为什么用→怎么用→原理是什么” 的逻辑逐层拆解,就能轻松突破这个 “难点”。本文以可直接运行的 WS2812 LED 控制代码为核心,从基础概念到代码细节,再到原理串联,带新手逐步吃透 RMT 模块,最终实现 “不仅会用,还懂原理” 的目标。

一、先搞懂:RMT 到底是什么?为什么控制 WS2812 需要它?

在看代码前,必须先破除 “认知盲区”:RMT 不是 “遥控器模块”,而是 ESP32 专门用于生成 / 接收精准时序信号的硬件模块,是解决 “时序敏感型外设控制” 的核心工具。

1.1 RMT 的核心能力:精准控制 “高低电平的时长”

你可以把 RMT 理解为一个 “专职时序工程师”,它的核心能力有两个:
超高精度:最小时间单位可到 0.1us(由 “分辨率” 决定),能满足绝大多数外设的时序要求;
无 CPU 干预:配置完成后,RMT 会自动按设定输出时序,无需 CPU 持续轮询或中断,极大减轻 CPU 负担。

为什么这种能力对 WS2812 至关重要?

WS2812 是典型的 “时序敏感型外设”,它对数据信号的时序要求极其严格(差 0.1us 都可能出错):
“0 码”:高电平 0.3us + 低电平 0.9us;
“1 码”:高电平 0.9us + 低电平 0.3us;
复位信号:低电平≥50us(数据发送完后必须发送,否则 LED 不识别数据)。
如果用普通 GPIO 模拟(靠 CPU 频繁翻转引脚),会因为 CPU 被其他任务(如 WiFi、FreeRTOS 任务)打断,导致电平时长偏差,最终 LED 乱闪、不亮或颜色错乱。而 RMT 硬件能保证时序 “零偏差”,这就是它控制 WS2812 的核心价值。

1.2 RMT 的 3 个关键参数

分辨率(resolution):代码中RMT_LED_STRIP_RESOLUTION_HZ 10000000(10MHz),意味着 RMT 的 “最小时间单位” 是 1/10MHz = 0.1us(后续所有电平时长都基于这个单位计算,比如 0.3us 对应 3 个单位);
通道(channel):ESP32 有 8 个独立 RMT 通道(0~7),代码中用了一个 “发送通道”(因为要向 WS2812 输出时序);
符号(symbol):RMT 的基本操作单位是rmt_symbol_word_t结构体(代码中的ws2812_zero、ws2812_one就是符号),每个符号包含 “两段电平 + 两段时长”(比如 “高电平 3 个单位 + 低电平 9 个单位”,对应 WS2812 的 0 码)。

二、WS2812 协议基础 —— 理解 RMT 配置的 “目标”

RMT 的所有配置都是为了 “说对 WS2812 能听懂的话”,所以必须先搞懂 WS2812 的 “语言规则”(协议)。

2.1 WS2812 的 3 个核心协议规则

WS2812 是串联式 LED(多个 LED 可通过一根数据线串联),每个 LED 需要 3 字节数据(GRB 格式,不是 RGB!),数据通过特定时序传递:

信号类型行业标准时序代码中的对应实现(基于 10MHz 分辨率)作用
“0” 码高 0.3us + 低 0.9usws2812_zeroduration0=3(高)、duration1=9(低)表示二进制 “0”
“1” 码高 0.9us + 低 0.3usws2812_oneduration0=9(高)、duration1=3(低)表示二进制 “1”
复位信号低电平≥50usws2812_resetduration0=0(低)、duration1=500(低,500*0.1us=50us)告知 LED“数据发送完成,开始显示”

注:duration0对应level0(初始电平)的时长,duration1对应level1(后续电平)的时长。WS2812 数据信号以高电平开头,所以level0=1(高)、level1=0(低)。

2.2 为什么是 GRB 格式?(新手最易踩坑点)

普通 RGB 设备的颜色顺序是 “红(R)→绿(G)→蓝(B)”,但 WS2812 的硬件设计决定了它的颜色顺序是 “绿(G)→红(R)→蓝(B) ”。
代码中led_pixels数组的顺序(i*3+0=G、i*3+1=R、i*3+2=B)就是遵循这个规则 —— 如果记反(比如把i*3+0设为 R),LED 颜色会完全错乱(想亮红色,结果亮绿色)。

2.3 串联 LED 的数据传递逻辑

多个 WS2812 串联时,数据会 “逐灯传递”:
第一个 LED 接收前 3 字节数据,存储后,将剩余数据转发给第二个 LED;
第二个 LED 接收接下来 3 字节数据,存储后,转发剩余数据给第三个 LED;
所有 LED 接收完数据后,收到 “复位信号”,同时点亮对应的颜色。
这意味着:代码中led_pixels数组的顺序就是 LED 的物理顺序(数组第 0~2 字节对应第一个 LED,第 3~5 字节对应第二个 LED,以此类推)。

三、从 “主流程”到“细节”,逐行理解 RMT 工作逻辑

本文使用的代码基于 ESP-IDF 框架(ESP32 官方开发框架),遵循 “初始化→生成数据→发送数据” 的流程。我们按这个顺序拆解,每个部分都对应 RMT 的核心知识点。

3.1 先看整体代码框架(建立全局认知)

首先看代码的 “入口” 和 “主循环”,理解程序的运行逻辑:

#include "driver/rmt.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"// 配置参数(新手可直接修改这些宏)
#define RMT_LED_STRIP_GPIO_NUM 13    // 控制WS2812的GPIO引脚
#define RMT_LED_STRIP_RESOLUTION_HZ 10000000  // RMT分辨率:10MHz(0.1us/单位)
#define LED_NUM 8                     // WS2812的数量(8个)// 定义RMT符号(对应WS2812的0码、1码、复位信号)
const rmt_symbol_word_t ws2812_zero = {.level0 = 1, .duration0 = 3,  // 高电平3个单位(0.3us).level1 = 0, .duration1 = 9   // 低电平9个单位(0.9us)
};
const rmt_symbol_word_t ws2812_one = {.level0 = 1, .duration0 = 9,  // 高电平9个单位(0.9us).level1 = 0, .duration1 = 3   // 低电平3个单位(0.3us)
};
const rmt_symbol_word_t ws2812_reset = {.level0 = 0, .duration0 = 0,  // 初始低电平(时长0,不占时间).level1 = 0, .duration1 = 500 // 低电平500个单位(50us,满足复位要求)
};// 全局变量:存储RMT通道句柄和编码器句柄
typedef struct {rmt_channel_handle_t rmtChan;    // RMT发送通道句柄rmt_encoder_handle_t encoder;    // RMT编码器句柄
} led_strip_t;
static led_strip_t g_ledHandle = {0};// 颜色数据数组:每个LED占3字节(G/R/B),共8*3=24字节
static uint8_t led_pixels[LED_NUM * 3];// -------------------------- 核心函数声明 --------------------------
void rmt_led_init(void);                  // RMT初始化(配置硬件)
size_t encoder_callback(const void *data,  // 编码器回调(字节转符号)size_t data_size,size_t symbols_written,size_t symbols_free,rmt_symbol_word_t *symbols,bool *done,void *arg);
void rmt_led_set_pixels(const uint8_t *pixels, size_t len);  // 发送数据// -------------------------- 程序入口 --------------------------
void app_main(void) {// 创建FreeRTOS任务:在任务中控制LED(避免阻塞主程序)xTaskCreate(rgb_task, "rgb_task", 2048, NULL, 5, NULL);
}// -------------------------- LED控制任务 --------------------------
void rgb_task(void *pvParameters) {rmt_led_init();  // 第一步:初始化RMT(配置硬件)while (1) {// 第二步:生成LED颜色数据(前4个黄色,后4个熄灭)for (int i = 0; i < LED_NUM; i++) {if (i < 4) {led_pixels[i * 3 + 0] = 255;  // G分量(最大值)led_pixels[i * 3 + 1] = 255;  // R分量(最大值)led_pixels[i * 3 + 2] = 0;    // B分量(0,无蓝色)} else {led_pixels[i * 3 + 0] = 0;    // G=0led_pixels[i * 3 + 1] = 0;    // R=0led_pixels[i * 3 + 2] = 0;    // B=0(熄灭)}}// 第三步:发送数据到WS2812rmt_led_set_pixels(led_pixels, LED_NUM * 3);vTaskDelay(1000 / portTICK_PERIOD_MS);  // 休眠1秒(周期刷新)}
}

3.2 为什么用 FreeRTOS 任务?

“直接在app_main里初始化、发数据不行吗?为什么要创建任务?”原因有两个:
(1)避免阻塞主程序:如果后续添加其他功能(如 WiFi 通信、按键控制),vTaskDelay会让当前任务休眠,不影响其他任务运行;如果在app_main里用for(;;)循环 +delay,会阻塞整个程序。
(2)适配 RMT 的非阻塞特性:rmt_transmit(发送函数)是 “非阻塞” 的 —— 把数据交给 RMT 硬件后立即返回,不需要等待发送完成。用任务周期性生成数据,效率更高。

3.3 核心步骤 1:RMT 初始化(rmt_led_init)—— 配置 RMT 硬件

这是整个代码的 “地基”,负责把 RMT 模块配置成 “能和 WS2812 通信” 的状态。我们拆解每个配置项的作用:

void rmt_led_init(void) {// 1. 配置RMT发送通道rmt_tx_channel_config_t chan_config = {.clk_src = RMT_CLK_SRC_DEFAULT,         // 时钟源:用默认时钟(ESP32自动适配40MHz/80MHz).gpio_num = RMT_LED_STRIP_GPIO_NUM,     // 绑定GPIO:代码中是13(时序从这个引脚输出).mem_block_symbols = 256,               // 内存块大小:单位是“符号数”(存储RMT要发送的符号,需大于LED_NUM*3*8).resolution_hz = RMT_LED_STRIP_RESOLUTION_HZ, // 分辨率:10MHz(0.1us/单位).trans_queue_depth = 8,                 // 发送队列深度:最多缓存8个发送任务,避免拥堵};// 创建RMT发送通道(句柄存入g_ledHandle,后续操作通道用这个句柄)ESP_ERROR_CHECK(rmt_new_tx_channel(&chan_config, &g_ledHandle.rmtChan));// 2. 配置RMT编码器(字节转符号的“翻译官”)const rmt_simple_encoder_config_t encoder_cfg = {.callback = encoder_callback,  // 绑定编码器回调函数(核心:字节→符号的逻辑).user_data = NULL              // 用户自定义参数(这里没用,设为NULL)};// 创建编码器(句柄存入g_ledHandle)ESP_ERROR_CHECK(rmt_new_simple_encoder(&encoder_cfg, &g_ledHandle.encoder));// 3. 使能RMT通道(配置完成后必须使能,否则RMT硬件不工作)ESP_ERROR_CHECK(rmt_enable(g_ledHandle.rmtChan));
}

3.3.1 关键配置 1:mem_block_symbols为什么设 256?(新手必懂)

RMT 需要一块内存来存储 “符号”(rmt_symbol_word_t),mem_block_symbols的大小必须满足 “所有数据的符号数”,否则会因内存不足导致发送失败。
计算逻辑(以 8 个 LED 为例):
1 个 LED 需要 3 字节数据 → 1 字节 = 8 位 → 1 位 = 1 个符号 → 1 个 LED 需要 3*8=24 个符号;
8 个 LED 需要 8*24=192 个符号;
最后需要加 1 个 “复位符号” → 总共需要 192+1=193 个符号;
代码中设 256,比 193 大,足够存储,且留有余量(后续增加 LED 数量时可减少修改)。
若 LED 数量改为 100 个:总符号数 = 10038 +1=2401 → mem_block_symbols需设为≥2401(如 3000)。

3.3.2 关键配置 2:为什么需要 “编码器”?

编码器的核心作用是 “翻译”:
我们的输入数据是 “字节”(比如led_pixels里的 G=255、R=255,都是 8 位字节);
RMT 硬件能发送的是 “符号”(rmt_symbol_word_t,对应 WS2812 的 0/1 码);
编码器通过encoder_callback回调函数,把字节数据逐位翻译成对应的符号,相当于 “字节→符号” 的翻译官。

3.4 核心步骤 2:编码器回调(encoder_callback)—— 字节转符号的 “核心大脑”

这是 RMT 工作的 “灵魂”,负责把led_pixels的字节数据逐位翻译成 WS2812 能识别的符号。我们逐行拆解逻辑:

size_t encoder_callback(const void *data,        // 输入:要转换的原始数据(led_pixels数组)size_t data_size,        // 输入:原始数据的长度(LED_NUM*3字节,如8*3=24)size_t symbols_written,  // 输入:已经转换完成的符号数(初始为0)size_t symbols_free,     // 输入:当前内存还能存多少个符号(避免内存溢出)rmt_symbol_word_t *symbols, // 输出:转换后的RMT符号数组(存到这里)bool *done,              // 输出:是否转换完成(告诉RMT“可以发送了”)void *arg)               // 输入:用户自定义参数(这里没用)
{// 1. 计算当前处理到第几个字节(每个字节对应8个符号)size_t data_pos = symbols_written / 8;  // 例:symbols_written=0 → data_pos=0(处理第0个字节)uint8_t *data_bytes = (uint8_t*)data;    // 把输入数据转成字节指针,方便操作(如data_bytes[0]就是第一个字节)// 2. 如果还有字节没处理(核心逻辑:逐字节→逐位→逐符号)if (data_pos < data_size) {// 2.1 检查内存是否足够:处理1个字节需要8个符号,不够就返回0(等下次回调再处理)if (symbols_free < 8) {return 0;}// 2.2 逐位处理当前字节(WS2812要求“高位在前”,即先处理第7位,再第6位...第0位)for (int bit = 0; bit < 8; bit++) {// 判断当前位是1还是0:// 0x80是二进制10000000(最高位为1),右移bit位后与当前字节做“与运算”// 例:bit=0 → 0x80>>0=0x80 → 判断第7位是否为1;bit=1 → 0x40 → 判断第6位...if (data_bytes[data_pos] & (0x80 >> bit)) {symbols[bit] = ws2812_one;  // 位为1 → 用“1码”符号} else {symbols[bit] = ws2812_zero; // 位为0 → 用“0码”符号}}// 2.3 处理完1个字节,返回生成的符号数(8个)return 8;} // 3. 所有字节处理完,添加“复位符号”(告诉WS2812“数据结束”)else if (data_pos == data_size) {symbols[0] = ws2812_reset;  // 把复位符号存入符号数组*done = true;               // 标记“转换完成”,RMT可以开始发送了return 1;                   // 返回复位符号数(1个)}// 4. 所有工作完成,返回0(无新符号生成)return 0;
}

3.4.1 举个例子:1 字节数据怎么转符号?

假设data_bytes[data_pos] = 0xFF(二进制11111111,对应 G 分量最大值):
bit=0:0xFF & 0x80 = 0x80 → 位为 1 → symbols[0] = ws2812_one;
bit=1:0xFF & 0x40 = 0x40 → 位为 1 → symbols[1] = ws2812_one;
...(直到 bit=7):所有位都是 1 → symbols[0]~symbols[7]都是ws2812_one;
最终生成 8 个 “1 码” 符号,WS2812 接收后识别为 “该颜色分量为最大值”。

3.5 核心步骤 3:发送数据(rmt_led_set_pixels)—— 触发 RMT 发送

这一步很简单,核心是调用rmt_transmit函数,把数据交给 RMT 硬件,触发发送:

void rmt_led_set_pixels(const uint8_t *pixels, size_t len) {// 配置发送参数:发送1次(不循环)rmt_transmit_config_t tx_config = {.loop_count = 1  // 发送次数:1次(loop_count=0表示无限循环,不推荐)};// 触发发送:参数依次是“RMT通道句柄→编码器句柄→原始数据→数据长度→发送配置”ESP_ERROR_CHECK(rmt_transmit(g_ledHandle.rmtChan,    // 要使用的RMT通道g_ledHandle.encoder,    // 用哪个编码器翻译数据pixels,                 // 原始数据(led_pixels数组)len,                    // 数据长度(LED_NUM*3字节)&tx_config              // 发送配置));
}

3.5.1 rmt_transmit的内部流程(新手必懂)

调用rmt_transmit后,ESP32 会做这些事:
把pixels(字节数据)交给编码器;
编码器调用encoder_callback,把字节逐位转成符号,存入 RMT 的内存块(mem_block_symbols配置的那块内存);
编码器返回 “转换完成”(*done=true)后,RMT 硬件读取内存块的符号;
RMT 硬件按符号的level(高低电平)和duration(时长),在绑定的 GPIO(13)上输出时序;
发送完成后,RMT 硬件自动停止,等待下一次rmt_transmit调用。

四、原理串联:从 “代码执行” 到 “LED 亮灯” 的完整流程

学到这里,我们把所有知识点串成一条线,理解 “代码是怎么让 LED 亮起来的”:
(1)程序启动:app_main创建rgb_task任务,FreeRTOS 调度该任务运行;
(2)RMT 初始化:rmt_led_init配置 RMT 通道(GPIO13、10MHz 分辨率、256 符号内存)、创建编码器(绑定encoder_callback)、使能通道;
(3)生成颜色数据:rgb_task循环中配置led_pixels数组(前 4 个 LED 设为黄色,后 4 个熄灭);
(4)触发发送:调用rmt_led_set_pixels,rmt_transmit把led_pixels数据交给编码器;
(5)字节转符号:编码器回调encoder_callback,把每个字节(如 G=255)逐位转成 “1 码” 符号,最后加 1 个复位符号;
(6)RMT 输出时序:RMT 硬件读取符号,在 GPIO13 上输出 “1 码 / 0 码” 时序,最后输出 50us 复位信号;
(7)WS2812 识别:WS2812 接收时序,解析出 GRB 颜色数据,前 4 个 LED 点亮黄色,后 4 个熄灭;
(8)周期刷新:vTaskDelay(1000)让任务休眠 1 秒,之后重复步骤 3~7,保持 LED 状态。

五、新手常见问题与调试技巧

掌握基础后,更重要的是 “出问题了怎么修”。这里列举几个高频问题及解决方案:

5.1 问题 1:LED 完全不亮

可能原因及解决:
(1)GPIO 接线错误:代码中RMT_LED_STRIP_GPIO_NUM=13,确认硬件上 WS2812 的 DIN 引脚接的是 ESP32 的 GPIO13(不是其他引脚);
(2)RMT 分辨率计算错误:如果修改了RMT_LED_STRIP_RESOLUTION_HZ(比如改成 1MHz),ws2812_zero、ws2812_one的duration要重新计算(1MHz 对应 1us / 单位,0.3us=3 个单位,0.9us=9 个单位,和 10MHz 一样?不,1MHz 的话 0.3us 不足 1 个单位,会出错!所以不建议修改分辨率);
(3)内存块不足:如果 LED 数量增加(比如 100 个),mem_block_symbols没改(还是 256),会因符号存不下导致发送失败。需重新计算符号数(10038+1=2401),把mem_block_symbols设为≥2401(如 3000);
(4)电源问题:WS2812 工作电压是 5V,若用 3.3V 供电,可能因电压不足不亮(需确认硬件电源)。

5.2 问题 2:LED 颜色错乱

可能原因及解决:
(1)GRB 顺序写反:比如把led_pixels[i*3+0]设为 R 分量(不是 G 分量),导致颜色错乱。解决方案:严格遵循 “i*3+0=G、i*3+1=R、i*3+2=B”;
(2)颜色值设置错误:比如想亮红色,却把led_pixels[i*3+1](R 分量)设为 0,i*3+0(G 分量)设为 255,结果亮绿色。解决方案:明确颜色对应的分量(红色→R=255,G=0,B=0;绿色→G=255,R=0,B=0);
(3)内存块不足:mem_block_symbols较小,符号存不下导致颜色错乱。

5.3 问题 3:LED 闪烁不稳定

可能原因及解决:
(1)复位信号时长不足:WS2812 要求复位信号≥50us,若把ws2812_reset的duration1改成 100(10us),LED 会因没收到复位信号而错乱。解决方案:确保duration1≥500(10MHz 分辨率下,500*0.1us=50us);
(2)发送队列拥堵:如果频繁发送数据(比如每秒 100 次),trans_queue_depth=8可能不够,导致发送任务被丢弃。解决方案:增大trans_queue_depth(如 16);
(3)CPU 负载过高:如果其他任务占用大量 CPU,可能导致编码器回调延迟,符号生成不及时。解决方案:降低非关键任务的优先级(rgb_task的优先级是 5,可适当提高)。

5.4 调试工具推荐

逻辑分析仪:观察 GPIO13 的输出时序,确认 “0 码”“1 码”“复位信号” 的时长是否符合要求;
ESP-IDF 日志:在关键位置加ESP_LOGI日志,确认数据是否正确生成、发送是否成功:

// 例:在生成颜色数据后加日志
ESP_LOGI("LED", "G[%d] = %d, R[%d] = %d, B[%d] = %d", i, led_pixels[i*3+0], i, led_pixels[i*3+1], i, led_pixels[i*3+2]);

六、扩展应用:学会后还能做什么?

掌握 RMT 控制 WS2812 后,你可以轻松扩展到其他场景 —— 因为 RMT 的核心是 “精准时序”,所有需要精准时序的外设都能用 RMT 控制。

6.1 场景 1:实现更多 LED 效果

修改rgb_task中led_pixels的生成逻辑,可实现多种效果:
流水灯:每次只亮 1 个 LED,循环切换:

static int current_led = 0;
// 先清空所有LED
memset(led_pixels, 0, LED_NUM*3);
// 点亮当前LED(红色)
led_pixels[current_led*3+1] = 255;
// 切换到下一个LED
current_led = (current_led + 1) % LED_NUM;

呼吸灯:逐渐改变颜色值(如红色从 0→255→0 循环):

static int brightness = 0;
static int dir = 1; // 1=递增,-1=递减
// 所有LED设为红色,亮度随brightness变化
for (int i=0; i<LED_NUM; i++) {led_pixels[i*3+1] = brightness;
}
// 调整亮度方向
brightness += dir * 5;
if (brightness >= 255 || brightness <= 0) {dir *= -1;
}

6.2 场景 2:红外遥控发送(控制电视 / 空调)

RMT 不仅能发送,还能接收时序。用 RMT 生成红外协议时序(如 NEC 协议),可控制电视、空调:
NEC 协议时序:引导码(9ms 高 + 4.5ms 低)+ 地址码(8 位)+ 地址反码(8 位)+ 数据码(8 位)+ 数据反码(8 位);
实现方式:定义 NEC 协议的符号(引导码、0 码、1 码),用编码器把红外指令(如 “电源键”)转成符号,通过 RMT 发送。

6.3 场景 3:读取脉冲信号(超声波测距)

用 RMT 接收通道读取 HC-SR04 超声波模块的回声信号(高电平时长对应距离):
HC-SR04 原理:发送触发信号后,回声信号的高电平时长 ×340m/s÷2 = 距离;
实现方式:配置 RMT 为接收通道,接收回声信号的高电平时长,计算距离。

6.4 场景 4:控制舵机

舵机的角度由 “20ms 周期内的高电平时长” 决定(如 0.5ms→0°,2.5ms→180°):
用 RMT 生成 20ms 周期的信号,通过调整高电平时长控制舵机角度;
优势:无需定时器中断,RMT 硬件自动生成周期信号,CPU 负担小。

七、总结

通过本文的代码拆解和原理讲解,可以把 RMT 学习分成 3 个递进阶段:

阶段目标已掌握的标志
入门阶段理解 RMT 的核心作用、WS2812 协议、代码基本结构能修改 GPIO、LED 数量、颜色,让 LED 按预期亮灯
精通阶段吃透编码器回调逻辑、RMT 参数配置原理、完整工作流程能独立修改编码器回调,适配其他时序外设(如红外、舵机)
应用阶段基于 RMT 扩展到多外设,解决调试问题能实现复杂效果(如 LED 流水灯 + 红外遥控),并独立排查时序错误

最后要强调的是:RMT 的核心不是 “控制 WS2812”,而是 “精准控制时序”。掌握这个核心后,无论遇到什么时序敏感型外设,你都能通过 “分析协议→配置 RMT→编写编码器” 的思路解决问题 —— 这才是 ESP32 开发的核心能力。

http://www.dtcms.com/a/407456.html

相关文章:

  • 做设计什么网站可以兼职网站管理与建设总结
  • 少样本学习学习论文分享:多模态性帮助单模态性
  • 深入MySQL底层2-SQL优化与数据库运维管理
  • 设计站网页制作的公司选时代创信
  • 国外服装网站石岩做网站哪家好
  • 超越单边控制:介绍新一代对话智能体评测基准τ2-Bench
  • Scala • basis
  • vi设计公司深圳企业网站排名怎么优化
  • 深度学习视角下的图像分类技术体系总结
  • mysql数据库最新版下载,安装
  • 记2831.找出最长等值子数组 练习理解
  • 优秀网站作品下载免费广告设计模板网站
  • 住房和城乡建设部官方网站发布郑州发布会最新消息
  • 中国建站公司重庆装修公司网站建设
  • 怎样建网站域名公司建网站多少钱合适
  • 学习峰岹MOTORSIM(Day4)——电机磁铁变弱,转速反而飙升?
  • 网页搜索记录怎么删除神马seo服务
  • interface g0/0/0.1 概念及题目
  • 网站首页引导页 模版银行官网登录入口
  • 网站运营代理淘宝网站建设违规吗
  • 基于岗课赛证的中职物联网专业“综合布线课程”教学解决方案
  • 连接蓝牙时“无媒体信号”怎么办?
  • Java后端面经(八股——Redis)
  • 津做网站百度公司在哪里
  • 运用.net做网站做网站不知道做什么内容的
  • 4、除了常见的 services(业务微服务)和 gateway(API 网关)模块外,还必须建立一系列支撑性、平台级、基础设施类模块
  • 十堰的网站建设网站资料库建设的功能需求
  • 国家企业信用网查询系统杭州网站建设优化
  • ApplicationContext接口实现(二)
  • BMAD方法论:敏捷价值、原则映射与全生命周期技术