【ESP32S3 Sense接入语音识别+MiniMax模型+TTS模块语音播报】

【ESP32S3 Sense接入语音识别+MiniMax模型+TTS模块语音播报】

  • 1. 前言
  • 2. 功能模块概述
    • 2.1 语音接入
    • 2.2 大模型接入
    • 2.3 TTS模块接入
  • 3. 先决条件
    • 3.1 环境配置
    • 3.2 所需零件
    • 3.3 硬件连接步骤
  • 4. 核心代码
    • 4.1 源码分享
    • 4.2 代码解析
  • 5. 上传验证
    • 5.1 对话测试
    • 5.2 报错
  • 6. 总结

1. 前言

大家好,今天的教程将围绕如何实现精准的语音播报功能展开,我们用到了ESP32S3 Sense接入语音识别+MiniMax模型对话+SNR9816TTS模块。
在这里插入图片描述

在后续的测试过程中,我们用到了一款极致实用的AI工具——海螺AI!(有问题,找海螺AI)它是MiniMax旗下的一款自研AI平台,专注于解决实际问题,可以让你的工作更高效、更便捷!
在这里插入图片描述
本博客文本作为输入海螺AI,生成了以下视频文案,还是非常不错哒!👍👍👍
在这里插入图片描述

海螺AI提供了多种实用功能,能够满足多种场景下的需求。比如,你可以用它来处理图片和文件、进行知识搜索和问答、生成代码和文案,让你的工作流更畅通无阻!
在这里插入图片描述

MiniMax是海螺的母公司,MiniMax最近推出了大法师计划,为全球大模型初创公司和开发者免费提供2000亿tokens,以促进通用人工智能设计开发行业的发展。(MiniMax大法师计划)

在这里插入图片描述

2. 功能模块概述

首先串口输入“1”字符,随后麦克风采集2s声音数据,对接百度在线语音识别,将返回文本结果丢入MiniMax模型,进而返回第二次结果文本,实现语言对话文本效果。经过以上两次调用后,载入TTS模块就可完整对话,实现精准的语音播报功能。

讲解视频:

2.1 语音接入

百度在线语音接入教程:
【ESP32S3 Sense接入百度在线语音识别】
在这里插入图片描述

使用Seeed XIAO ESP32S3 Sense开发板接入百度智能云实现在线语音识别。自带麦克风模块用做语音输入,通过串口发送字符“1”来控制数据的采集和上传。

2.2 大模型接入

国产大模型接入分享如下:
【ESP32接入国产大模型之MiniMax】
【ESP32接入语言大模型之智谱清言】
【ESP32接入国产大模型之文心一言】
【ESP32接入语言大模型之通义千问】

下面是不标准测评,强烈推荐使用MiniMax大模型
在这里插入图片描述

MiniMax是一家中国科技公司,一直致力于进行大模型相关的研究。近期提出了MINIMAX大法师计划,获取更多的2000亿token,为全球 AI大模型领域创业公司以及优秀的个人开发者提供了丰富的资源。
在这里插入图片描述

模型响应时间内容质量免费token次数地址
MiniMax3s8分500万+2000亿tokenhttps://www.minimaxi.com/
智谱清言7s8分300万https://open.bigmodel.cn/
文心一言10s9分500万https://cloud.baidu.com/doc/WENXINWORKSHOP/s/Nlks5zkzu
通义千问8s8分800万https://tongyi.aliyun.com/qianwen/

结合以上图表对比,无能是回复文本的质量与速度方面,MiniMax是海螺的母公司,是MiniMax开展的大法师计划领先!!!😘😘😘

STT语音接入+大模型Chat接入整合教程见:【ESP32S3 Sense接入语音识别+MiniMax模型对话】

在这里插入图片描述

2.3 TTS模块接入

在这里插入图片描述

SNR9816TTS 是基于独家语音合成算法开发的一款高流畅度,高自然度的优美人声语音合成模块。该模块方案基于新一代的神经网络算法,纯中文版选取了优质的女声发音人(默认)和男声发音人(指令切换),中英文版只支持女声发音人,以满足各种应用场景的合成播报。

模块以中文为主,支持数字、英文(纯中文版:单个字母发音、中英文版:英文单词发音),文本编码支持GB2312。优异的合成效果(可懂度、清晰度、自然度、表现力、节奏/停顿、语速、语调、音质、音色、理解程度)方面有显著提升。

调试教程见:【Arduino使用SNR9816TTS模块教程】

3. 先决条件

这一次还是采用Arduino编程就会轻松许多开发。这样就可以通过stt+chat+tts把MiniMax语言大模型装进口袋啦🤣🤣🤣
在继续此项目之前,请确保检查以下先决条件。我们将使用 Arduino IDE 对 ESP32/ESP8266 开发板进行编程,因此在继续本教程之前,请确保已在 Arduino IDE 中安装这些开发板。此外,为了实现ESP32C3与SNR9816TTS模块的串口通信,请确保您已经安装了ESPSoftwareSerial和UTF8ToGB2312库。💕💕💕

3.1 环境配置

  1. Arduino IDE:下载并安装 Arduino IDE;
  2. ESP32 开发板库:在 Arduino IDE 中添加 ESP32 支持;
    参考博客:【esp32c3配置arduino IDE教程】
    为安装过程留出一些时间,具体时间可能因您的互联网连接而异。

3.2 所需零件

要学习本教程,您需要1个ESP32S3 Sense,建议使用后者,笔者发现同样的代码后者可以轻松调用,ESP32不行(可能板子坏了)

名称端口功能购买地址
ESP32S3 SenseTXGPIO01 RXGPIO02主控官方地址
中文版 SNR9816TTSTXRX RXTXTTS模块淘宝地址

3.3 硬件连接步骤

  1. 电源连接:将SNR9816TTS模块的5V电源引脚连接到ESP32S3的5V输出端,模块的GND引脚连接到ESP32C3的GND。

  2. 串口通信:将SNR9816TTS模块的RX引脚连接到ESP32S3的GPIO01的TX引脚,模块的TX引脚连接到Arduino的GPIO02的RX引脚。这里使用软件串口(SoftwareSerial)库模拟额外的串行通信端口。

  3. 音响:喇叭(第 3、4 引脚)接到对应SPKN和SPKP引脚上,官方喇叭响度有点大,我拆了四六级听力耳机喇叭好多啦😘😘😘。
    在这里插入图片描述

4. 核心代码

下面准备进行了基于ESP32S3 Sense 的硬件测试,此部分有源码分享和代码解析两部分

4.1 源码分享

Arduino代码如下

#include <Arduino.h>
#include "base64.h"
#include <WiFi.h>
#include "HTTPClient.h"
#include "cJSON.h"
#include <I2S.h>
#include <ArduinoJson.h>
#include <SoftwareSerial.h>
#include "UTF8ToGB2312.h"
#define MYPORT_TX 1
#define MYPORT_RX 2EspSoftwareSerial::UART myPort;uint8_t voicedata[] = { 0xFD, 0x00, 0x06, 0x01, 0x01, 0x5B, 0x76, 0x31, 0x5D };  //voicedata[7] =  0x31 ~ 0x39
// #define data_len 16000
// #define key 4             //端口0
// #define ADC 2             //端口39
// #define led 15            //端口2HTTPClient http_client;
// 1. Replace with your network credentials
const char *ssid = "J09 502";
const char *password = "qwertyuiop111";
// 2. Check your Aduio port
const int buttonPin = 1;  // the number of the pushbutton pin
const int ledPin = 21;    // the number of the LED pin
hw_timer_t *timer = NULL;
const int adc_data_len = 8000 * 3;
const int data_json_len = adc_data_len * 3;
uint16_t *adc_data;
char *data_json;
// uint16_t adc_data[data_len];    //16000个数据,8K采样率,即2秒,录音时间为2秒,想要实现更长时间的语音识别,就要改这个数组大小
// char data_json[json_len];          //用于储存json格式的数据,大一点,JSON编码后数据字节数变成原来的4/3,所以得计算好,避免出现越界
//和下面data_json数组的大小,改大一些。
uint8_t adc_start_flag = 0;     //开始标志
uint8_t adc_complete_flag = 0;  //完成标志// 3. Replace with your MiniMax API key
const char *apiKey = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJHcm91cE5hbWUiOiIyMzQ1dm9yIiwiVXNlck5hbWUiOiIyMzQ1dm9yIiwiQWN.WlEj8Nk0j_WOMXZE9SbIC8sHpwJ6R6Pi8Spl5mahJsW3-Jsz7Ev53sGGz3v__Bd5dDkt7o9-Y8BOW0WZq2ImaN7Rof7YNtYnYnvPNDyGx23_xRqq5co9P5UkC3ciYEcIch2SUZ5QPkXR-sMUPzhdowSYvfdu1N25kdKJ8GE_63NfCnsdDVt8mv0wQSSweJK0yf_C8a8ADdB1uF4vg_WKMDjHlvzERsoNZgX6FYtr-bee85rIyu4U-OrbUvEpR1FLPXa7lTlx65QvhVIYGbIKde7ERIT_7QLOQoVFvPz0gX-H6V7UlmSRgRy4LK_R9mvV5TqCy3v90WK_AFuwEhPXcg";
// 3. Replace with your baidu voice detect token
String token = "24.8f6143793af71.2592000.1713789066.282335-57722200";
HTTPClient http;
String token_key = String("Bearer ") + apiKey;
// Send request to MiniMax API
String inputText = "你好,minimax!";
String apiUrl = "https://api.minimax.chat/v1/text/chatcompletion_v2";
int httpResponseCode;
String response, question, answer;
DynamicJsonDocument jsonDoc(1024);uint32_t num = 0;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
void IRAM_ATTR onTimer() {// Increment the counter and set the time of ISRportENTER_CRITICAL_ISR(&timerMux);if (adc_start_flag == 1) {//Serial.println("");// adc_data[num] = analogRead(ADC);adc_data[num] = I2S.read();num++;if (num >= adc_data_len) {adc_complete_flag = 1;adc_start_flag = 0;num = 0;//Serial.println(Complete_flag);}}portEXIT_CRITICAL_ISR(&timerMux);
}String getGPTAnswer(String inputText) {http.begin(apiUrl);http.addHeader("Content-Type", "application/json");http.addHeader("Authorization", token_key);String payload = "{\"model\":\"abab5.5s-chat\",\"messages\":[{\"role\": \"system\",\"content\": \"你是鹏鹏的生活助手机器人,要求下面的回答严格控制在256字符以内。\"},{\"role\": \"user\",\"content\": \"" + inputText + "\"}]}";httpResponseCode = http.POST(payload);if (httpResponseCode == 200) {response = http.getString();http.end();Serial.println(response);// Parse JSON responsedeserializeJson(jsonDoc, response);String outputText = jsonDoc["choices"][0]["message"]["content"];return outputText;// Serial.println(outputText);} else {http.end();Serial.printf("Error %i \n", httpResponseCode);speech("语言大模型故障,请检查api是否失效");return "<error>";}
}void speech(String data) {//0--空闲  1--繁忙  2--异常// while (workstate() > 0) {//   if (workstate() == 1) Serial.println("tts busy");//   if (workstate() == 2) Serial.println("tts wrong");// }String utf8_str = data;String gb2312_str = GB.get(utf8_str);unsigned char head[gb2312_str.length() + 6];// 定义无符号字符类型数组,将 GB2312 编码的字符串复制到数组中unsigned char gb2312_data[gb2312_str.length() + 1];memset(gb2312_data, 0, sizeof(gb2312_data));strncpy((char *)gb2312_data, gb2312_str.c_str(), gb2312_str.length());// head bytehead[0] = 0xFD;// length bytesunsigned int dat_len = gb2312_str.length() + 3;head[1] = dat_len >> 8;head[2] = dat_len;// cmd bytehead[3] = 0x01;// para bytehead[4] = 0x01;// send each character individuallyfor (int i = 0; i < gb2312_str.length(); i++) {head[i + 5] = gb2312_data[i];}// 计算异或值并添加到数组,额这个是syn那个芯片的例程,这个异或计算有没有用我懒得改了。反正代码能跑。head[gb2312_str.length() + 5] = head[0];for (int i = 1; i < gb2312_str.length() + 5; i++) {head[gb2312_str.length() + 5] ^= head[i];}// 发送字符数组到串口for (int j = 0; j < gb2312_str.length() + 6; j++) {myPort.write(head[j]);}delay(gb2312_str.length() * 100);// Serial.println(data);
}
// 查询tts合成工作状态 返回1表示繁忙 0表示空闲
int workstate() {unsigned char head[4] = { 0xFD, 0x00, 0x01, 0x21 };// 发送字符数组到串口for (int j = 0; j < 4; j++) {myPort.write(head[j]);}// 等待myPort的返回while (myPort.available() < 1) {// 可以在这里加入一些延时,以防止过快地查询delay(150);}// 读取并处理返回的数据byte response = myPort.read();// 返回相应的状态值if (response == 0x4E) {// 繁忙return 1;} else if (response == 0x4F) {// 空闲return 0;} else {// 未知状态,可以根据需要进行处理return 2;}
}void setup() {//Serial.begin(921600);Serial.begin(115200);adc_data = (uint16_t *)ps_malloc(adc_data_len * sizeof(uint16_t));  //ps_malloc 指使用片外PSRAM内存if (!adc_data) {Serial.println("Failed to allocate memory for adc_data");}data_json = (char *)ps_malloc(data_json_len * sizeof(char));  // 根据需要调整大小if (!data_json) {Serial.println("Failed to allocate memory for data_json");}myPort.begin(115200, SWSERIAL_8N1, MYPORT_RX, MYPORT_TX, false);delay(1000);if (!myPort) {  // If the object did not initialize, then its configuration is invalidSerial.println("Invalid EspSoftwareSerial pin configuration, check config");while (1) {  // Don't continue with invalid configurationdelay(1000);}}speech("系统开机");delay(1500);for (int i = 0; i < sizeof(voicedata) / sizeof(voicedata[0]); i++) {myPort.write(voicedata[i]);}delay(1000);speech("系统音量以调小");// pinMode(ADC, ANALOG);// pinMode(buttonPin, INPUT_PULLUP);pinMode(ledPin, OUTPUT);// start I2S at 16 kHz with 16-bits per sampleI2S.setAllPins(-1, 42, 41, -1, -1);if (!I2S.begin(PDM_MONO_MODE, 16000, 16)) {Serial.println("Failed to initialize I2S!");while (1);  // do nothing}uint8_t count = 0;WiFi.mode(WIFI_STA);WiFi.begin(ssid, password);while (WiFi.status() != WL_CONNECTED) {Serial.print(".");count++;if (count >= 75) {Serial.printf("\r\n-- wifi connect fail! --");break;}vTaskDelay(200);}Serial.printf("\r\n-- wifi connect success! --\r\n");Serial.println(WiFi.localIP());http.setTimeout(4000);http_client.setTimeout(4000);// gain_token();timer = timerBegin(0, 80, true);    //  80M的时钟 80分频 1MtimerAlarmWrite(timer, 125, true);  //  1M  计125个数进中断  8KtimerAttachInterrupt(timer, &onTimer, true);timerAlarmEnable(timer);timerStop(timer);  //先暂停
}uint32_t time1, time2;
void loop() {if (Serial.available() > 0)  //按键按下{if (Serial.read() == '1') {Serial.printf("Start recognition\r\n");digitalWrite(ledPin, HIGH);adc_start_flag = 1;timerStart(timer);// time1=micros();while (!adc_complete_flag)  //等待采集完成{ets_delay_us(10);}// time2=micros()-time1;timerStop(timer);adc_complete_flag = 0;  //清标志digitalWrite(ledPin, LOW);// memset(data_json, '\0', strlen(data_json));  //将数组清空memset(data_json, '\0', data_json_len * sizeof(char));strcat(data_json, "{");strcat(data_json, "\"format\":\"pcm\",");strcat(data_json, "\"rate\":16000,");strcat(data_json, "\"dev_pid\":1537,");strcat(data_json, "\"channel\":1,");strcat(data_json, "\"cuid\":\"666666\",");strcat(data_json, "\"token\":\"");strcat(data_json, token.c_str());strcat(data_json, "\",");sprintf(data_json + strlen(data_json), "\"len\":%d,", adc_data_len * 2);strcat(data_json, "\"speech\":\"");strcat(data_json, base64::encode((uint8_t *)adc_data, adc_data_len * sizeof(uint16_t)).c_str());strcat(data_json, "\"");strcat(data_json, "}");// Serial.println(data_json);int httpCode;http_client.begin("http://vop.baidu.com/server_api");  //https://vop.baidu.com/pro_apihttp_client.addHeader("Content-Type", "application/json");httpCode = http_client.POST(data_json);if (httpCode == 200) {if (httpCode == HTTP_CODE_OK) {response = http_client.getString();http_client.end();Serial.print(response);// Parse JSON response// DynamicJsonDocument jsonDoc(512);deserializeJson(jsonDoc, response);String question = jsonDoc["result"][0];// 访问"result"数组,并获取其第一个元// 输出结果Serial.println("Input:" + question);answer = getGPTAnswer(question);speech(answer);Serial.println("Answer: " + answer);// Serial.println("Enter a prompt:");} else {Serial.printf("[HTTP] GET... failed, error: %s\n", http_client.errorToString(httpCode).c_str());speech("语音识别在线故障,请检查api是否失效");}}// while (!digitalRead(buttonPin))//   ;Serial.println("Recognition complete\r\n");}}vTaskDelay(1);
}

4.2 代码解析

用于实现一个通过 I2S 接口采集音频信号并将其发送到百度语音识别 API 进行语音识别,然后将识别出的文本通过 MiniMax API 获取 AI 回答的功能。以下是代码的主要结构和功能说明:

  1. 引入必要的库文件,包括
    ① Arduino.h:包含Arduino核心库,提供了基本的Arduino函数和结构
    ② base64.h:引入一个用于Base64编码和解码的库
    ③ WiFi.h:用于连接WiFi网络的库
    ④ HTTPClient.h:用于Arduino上进行HTTP请求的库
    ⑤ cJSON.h:用于处理JSON数据的库
    ⑥ I2S.h:I2S(Inter-IC Sound)库,用于在Arduino上进行音频处理
    ⑦ ArduinoJson.h:ArduinoJson库,用于解析和生成JSON数据
    ⑧ SoftwareSerial.h:软串口库,用于模拟多个串口
    ⑨ UTF8ToGB2312.h:一个自定义的UTF-8到GB2312编码的转换库
    然后,定义了一些必要的常量和变量。

  2. 定义了一些全局变量,如 Wi-Fi 的 SSID 和密码,以及与音频采集和处理相关的变量,如 ADC 数据缓冲区、录音标志位、完成标志位、JSON 格式数据缓冲区,还有 MiniMax API 的密钥(apiKey)。

修改Wi-Fi 的 SSID 和密码

// 1. Replace with your network credentials
const char* ssid = "J09 502";
const char* password = "qwertyuiop111";

修改MiniMax API 的密钥(apiKey)

// 3. Replace with your MiniMax API key
const char* apiKey = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJHcm91cE5hbWUiOiIyMzQ1dm9yIiwiVXNlck5hbWUiOiIyMzQ1d6Im1pbmltYXgifQ.WlEj8Nk0j_WOMXZE9SbIC8sHpwJ6R6Pi8Spl5mahJsW3-Jsz7Ev53sGGz3v__Bd5dDkt7o9-Y8BOW0WZq2ImaN7Rof7YNtYnYnvPNDyGx23_xRqq5co9P5UkC3ciYEcIch2SUZ5QPkXR-sMUPzhdowSYvfdu1N25kdKJ8GE_63NfCnsdDVt8mv0wQSSweJK0yf_C8a8ADdB1uF4vg_WKMDjHlvzERsoNZgX6FYtr-bee85rIyu4U-OrbUvEpR1FLPXa7lTlx65QvhVIYGbIKde7ERIT_7QLOQoVFvPz0gX-H6V7UlmSRgRy4LK_R9mvV5TqCy3v90WK_AFuwEhPXcg";

修改百度api

strcat(data_json, "\"token\":\"24.8f6143791.2592000.1713789066.282335-57722200\",");  //token	这里需要修改成自己申请到的token
  1. 定义了一个 HTTPClient 实例 http_client,用于向 API 发送请求。

  2. 构建函数 getGPTAnswer() ,用于向一个预先定义的API发送HTTP POST请求,以获取对特定输入文本的GPT模型生成的响应。

  3. 构建函数 speech() ,用于将输入的文本数据转换为语音,并通过串口与语音合成模块进行通信,实现语音合成的功能。

  4. 构建函数 workstate(),用于查询语音合成模块的工作状态,并返回相应的状态值。

  5. setup()函数,它在程序开始时被调用,用于初始化设置和准备工作。具体来说,该函数会初始化系统各个部分的设置,包括串口通信、内存分配、软件串口、语音提示、GPIO设置、I2S音频初始化、Wi-Fi连接和定时器初始化。

  6. loop()函数,它在程序运行过程中会一直执行,用于处理主要的逻辑流程。具体来说,它主要负责监听串口输入,控制语音识别的启动、停止和结果处理,与百度语音识别API的交互,以及延时等待。

5. 上传验证

如果提示Compilation error: ArduinoJson.h: No such file or directory

在这里插入图片描述

直接在库管理安装Arduinojson

在这里插入图片描述

打开串口监视器,注意右下角选择换行符,选择115200波特率,输入你想问的问题,他就可以回答你

5.1 对话测试

在这里插入图片描述

代码优化后可以减少动态内存使用:3s语言输入,2s识别,5s交互播报

在这里插入图片描述

串口发送“1”,开始录音,然后返回对话结果,进行TTS语音播报😘😘😘

5.2 报错

  1. 如果返回error ,大家对照列表查询错误代码,结合提示排查解决

在这里插入图片描述
2. 如果第一次可以二次自动重启,可以配置下载程序运行在core0

在这里插入图片描述
在这里插入图片描述

  1. 百度在线语音识别错误码自查表
    在这里插入图片描述

6. 总结

博主强烈推荐大家使用🎈🎈🎈海螺AI并且加入大法师计划,支持国产!它是一款由MiniMax自研的,没有调用其他产品的接口的大型语言模型。作为一个强有力的生产力工具,无论是大学生还是职场人,海螺AI都能成为你的得力助手。💕💕💕

  1. 对于大学生,它可以帮助你提升论文写作的效率,解放你的创作灵感;在求职面试中,它能够为你提供丰富的资料和实用的建议,让你轻松应对各种挑战。👍👍👍
  2. 而对于职场人来说,海螺AI更是一个不可或缺的生产力工具,能够帮助你高效处理工作任务,提升工作效率,节省宝贵的时间。👍👍👍

🥳🥳🥳现在,我们在本教程中,您学习了如何使用ESP32S3 Sense接入语音识别+MiniMax模型+TTS模块实现语音播报功能。🛹🛹🛹从而实现对外部世界进行感知,充分认识这个有机与无机的环境,后期会持续分享esp32跑freertos实用案列🥳🥳🥳科学地合理地进行创作和发挥效益,然后为人类社会发展贡献一点微薄之力。🤣🤣🤣

如果你有任何问题,可以通过下面的二维码加入鹏鹏小分队,期待与你思维的碰撞😘😘😘

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

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

相关文章

C语言杂谈

努力扩大自己&#xff0c;以靠近&#xff0c;以触及自身以外的世界 文章目录 什么是定义&#xff1f;什么是声明&#xff1f;什么是赋值&#xff1f;什么是初始化&#xff1f;什么是生命周期&#xff1f;什么是作用域&#xff1f;全局变量&#xff1f;局部变量&#xff1f;size…

HCIA-RS基础-VLAN路由

目录 VLAN 路由1. 什么是 VLAN 路由2. VLAN 路由的原理及配置3. VLAN 的缺点和 VLAN Trunking4. 单臂路由配置 总结 VLAN 路由 1. 什么是 VLAN 路由 VLAN 路由是指在虚拟局域网&#xff08;VLAN&#xff09;之间进行路由转发的过程。传统的 VLAN 配置只能在同一个 VLAN 内进行…

LCD1602显示屏

LCD1602显示 概述 LCD1602&#xff08;Liquid Crystal Display&#xff09;是一种工业字符型液晶&#xff0c;能够同时显示 1602 即 32 字符(16列两行) 引脚说明 //电源 VSS -- GND VDD -- 5V //对比度 VO -- GND //控制线 RS -- P1.0 RW -- P1.1 E -- P1.4 //背光灯 A -- 5…

在ChatGPT中,能用DALL·E 3编辑图片啦!

4月3日&#xff0c;OpenAI开始向部分用户&#xff0c;提供在ChatGPT中的DALLE 3图片编辑功能。 DALLE 3是OpenAI在2023年9月20日发布的一款文生图模型&#xff0c;其生成的图片效果可以与Midjourney、leonardo、ideogram等顶级产品媲美&#xff0c;随后被融合到ChatGPT中增强其…

matlab的歧视:simulink不能使用stm32f4系列的ADC?

2023b的matlab&#xff0c;stm32f407芯片&#xff0c;运行内容Using the Analog to Digital Converter Block to Support STMicroelectronics STM32 Processor Based Boards Using the Analog to Digital Converter Block to Support STMicroelectronics STM32 Processor Base…

基于SSM的社区疫情防控管理信息系统

目录 背景 技术简介 系统简介 界面预览 背景 随着时代的进步&#xff0c;计算机技术已经全方位地影响了社会的发展。随着居民生活质量的持续上升&#xff0c;人们对社区疫情防控管理信息系统的期望和要求也在同步增长。在社区疫情防控日益受到广泛关注的背景下&#xff0c…

【漏洞复现】通天星CMSV6车载主动安全监控云平台inspect_file接口处存在任意文件上传漏洞

免责声明&#xff1a;文章来源互联网收集整理&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该…

电商技术揭秘一:电商架构设计与核心技术

文章目录 引言一、电商平台架构概述1.1 架构设计原则与架构类型选择1.2 传统电商平台架构与现代化架构趋势分析 二、高并发处理与负载均衡2.1 高并发访问特点分析与挑战2.2 负载均衡原理与算法选择 三、分布式数据库与缓存技术3.1 分布式数据库设计与一致性考量3.2 缓存策略与缓…

基于SpringBoot和Vue的金融融资管理系统的设计和实现【附源码】

1、系统演示视频&#xff08;演示视频&#xff09; 2、需要交流和学习请联系

vue弹出的添加信息组件中 el-radio 单选框无法点击问题

情景描述:在弹出的添加信息的组件中的form中有一个单选框,单选框无法进行点击切换 原因如下: 单选框要求有个默认值,因为添加和更新操作复用同一个组件,所以我在初始化时对相关进行了判定,如果为空则赋初始值 结果这样虽然实现了初始值的展示,但是就是如此造成了单选框的无法切…

代码随想录算法训练营第二十九天(回溯5)|491. 非递减子序列、46. 全排列、47. 全排列 II(JAVA)

文章目录 491. 非递减子序列解题思路源码 46. 全排列解题思路源码 47. 全排列 II解题思路源码 总结 491. 非递减子序列 给你一个整数数组 nums &#xff0c;找出并返回所有该数组中不同的递增子序列&#xff0c;递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。 …

前端返回 List<Map<String, Object>>中的vaue值里面包含一个Bigdecimal类型,序列化时小数点丢失,如何解决?

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…

Linux 命令 top 详解

1 top命令介绍 Linux系统中&#xff0c;Top命令主要用于实时运行系统的监控&#xff0c;包括Linux内核管理的进程或者线程的资源占用情况。这个命令对所有正在运行的进程和系统负荷提供不断更新的概览信息&#xff0c;包括系统负载、CPU利用分布情况、内存使用、每个进程的内容…

PS从入门到精通视频各类教程整理全集,包含素材、作业等(7)

PS从入门到精通视频各类教程整理全集&#xff0c;包含素材、作业等 最新PS以及插件合集&#xff0c;可在我以往文章中找到 由于阿里云盘有分享次受限制和文件大小限制&#xff0c;今天先分享到这里&#xff0c;后续持续更新 PS敬伟01——90集等文件 https://www.alipan.com/s…

Golang | Leetcode Golang题解之第7题整数反转

题目&#xff1a; 题解&#xff1a; func reverse(x int) (rev int) {for x ! 0 {if rev < math.MinInt32/10 || rev > math.MaxInt32/10 {return 0}digit : x % 10x / 10rev rev*10 digit}return }

ETL工具-nifi干货系列 第八讲 处理器PutDatabaseRecord 写数据库(详细)

1、本节通过一个小例子来讲解下处理器PutDatabaseRecord&#xff0c;该处理器的作用是将数据写入数据库。 如下流程通过处理器GenerateFlowFile 生成数据&#xff0c;然后通过处理器JoltTransformJSON转换结构&#xff0c;最后通过处理器PutDatabaseRecord将数据写入数据库。如…

keepalived+LVS高可用部署

目录 一.两台设备&#xff08;2.130和2.133&#xff09;作为调度器&#xff0c;前主后备 1.部署keepalived 2.修改配置文件准备启动 3.配置keepalived的系统日志并启动 二.模拟调度器掉点和web服务进程丢失 1.调度器掉点 2.当类似于httpd这种网站服务掉点 三.以三种健康…

C++ 前K个高频单词的六种解法

目录 大堆 小堆 vectorsort vectorstable_sort multimap set/multiset 与GPT的对话 1.对于比较类型中 < 运算符重载的理解 2.map有稳定性的说法吗 ​编辑 3.为什么map和set类的仿函数后面要加const来修饰*this 5.关于名词的理解 6.匿名对象对类要求 7.map和set的…

新手使用GIT上传本地项目到Github(个人笔记)

亲测下面的文章很有用处。 1. 初次使用git上传代码到github远程仓库 - 知乎 (zhihu.com) 2. 使用Git时出现refusing to merge unrelated histories的解决办法 - 知乎

【大数据存储】实验五:Mapreduce

实验Mapreduce实例——排序&#xff08;补充程序&#xff09; 实验环境 Linux Ubuntu 16.04 jdk-8u191-linux-x64 hadoop-3.0.0 hadoop-eclipse-plugin-2.7.3.jar eclipse-java-juno-SR2-linux-gtk-x86_64 实验内容 在电商网站上&#xff0c;当我们进入某电商页面里浏览…