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

STM32G0+EMW3080+阿里云飞燕平台实现单片机WiFi智能联网功能(三)STM32G0控制EMW3080实现IoT功能

  • 项目描述:该系列记录了STM32G0+EMW3080实现单片机智能联网功能项目的从零开始一步步的实现过程;
  • 硬件环境:单片机为STM32G030C8T6;物联网模块为EMW3080V2-P;网联网模块的开发板为MXKit开发套件,具体型号为XCHIP
    MXKit-Base V2.2;
  • 软件环境:STM32需要的软件有STM32CubeMX和STM32CubeIDE;开发IDE为eclipse;MXKit的串口调试工具使用的是putty.exe;
  • 串口指令:串口指令使用的是AT指令; 通信方式使用的是UART
  • 项目过程:本项目采用模块化的形式一步步的实现STM32G0+EMW3080+阿里云实现单片机智能联网功能;第一步先使用MXKit开发板和PC进行通信;第二步是配置阿里云飞燕平台;第三步是MXKit开发板实现配网功能,MXKit和阿里云之间成功通讯;第四步是STM32G0单片机实现和EMW3080的串口通讯;第五步是测试整体的功能;

本节为该项目的第四节,主要任务是实现STM32G030C8T6控制EMW3080实现IoT功能,即STM32G030C8T6控制EMW3080实现配网、断网重连、以及数据的下发、app控制设备等;最终的结果是,单片机上电后,向EMW3080发送配网指令,配网成功后,在云智能app端下发指令能够控制单片机上的LED等开和关;当然也支持wifi断开重连等功能;

经过上一篇文章,STM32G0+EMW3080+阿里云飞燕平台实现单片机WiFi智能联网功能(三)EMW3080完成配网,EMW3080连接到阿里云飞平台,通过串口调试EMW3080已经能成功的进行配网了,所以我们现在要做的就是,让STM32G030C8T6来发送配网指令,完成EMW3080的配网过程,并且在完成配网后,可以向STM32G030C8T6发送和接收数据用于控制设备;

文章目录

  • 一、硬件连接
  • 二、代码实现
  • 笔记

一、硬件连接

STM32G030C8T6和EMW3080的连接原理图如下图所示:
在这里插入图片描述

其中,使用STM32G030C8T6的UART1串口,接到EMW3080的UART串口上,接线如上图所示;然后STM32G030C8T6通过STLINK或JLINK连接到电脑上,便于调试和烧写程序;EMW3080开发板通过自带电源线也连接到电脑的USB端口上用于供电;这样接线部分就接好了;
需要注意的是,STM32G030C8T6我是用的是USART1;EMW3080开发板上有“UART”和“DEBUG”两个区域都由RX和TX,
在这里插入图片描述

我们需要使用UART区域中的RX和TX,而不是DEBUG中的,如果不小心使用了DEBUG中的RX和TX,指令虽然也能发送到EMW3080,但是无法识别;

接线完成后,实物图如下所示:

在这里插入图片描述

二、代码实现

接下来就是在STM32G030C8T6中编写代码实现向EMW3080发送AT指令进行配网,并根据返回的信息判断是否配网成功;待配网成功后,STM32G030C8T6接收云端发下来的指令,并进行响应的控制;本代码示例中通过下发LED等开和关的指令,控制STM32上的灯亮和灭;

整个工程的代码可以从以下链接中下载(https://download.csdn.net/download/AnChenliang_1002/88511568)

下载后的资源可以直接用STM32CubeIDE运行;

下面大致讲解一下代码结构:
在这里插入图片描述
主要的源文件如上图所示,其中我们IoT的功能主要在wilo_wifiMoudule.c中实现;

附上wilo_wifiMoudule.c的完整代码:

#include "wilo_wifiModule.h"#include "wilo_uart.h"#define DISCONNECT_TRUE 1
#define DISCONNECT_FALSE 0extern UART_HandleTypeDef huart1;
extern uint8_t rxBuffer[128];
extern __IO uint8_t receivedIndex;//跟踪接收到的字符的索引
extern uint8_t stringMatched ;//是否接收到完整的字符串
extern uint8_t receivedData[128]; // 全局数组用于存储完整接收到的内容
extern __IO uint8_t receivedLength; // 当前接收到的数据长度,为0时表示未收到数据,大于0时表示收到了数据
extern uint8_t preReceivedLength;//前一次接收到的数据长度
extern const char* atCommands[] ;// 声明一个设备参数变量
DeviceParameters deviceParams;void reset_receive()
{// 重置接收索引,准备接收下一段内容receivedIndex = 0;stringMatched = 0;receivedLength = 0;preReceivedLength = 0;memset(receivedData,0,sizeof(receivedData));
}// 发送指令并等待回复函数
HAL_StatusTypeDef sendCommandAndWait(const char* command, const char* expectedReply)
{// 发送指令HAL_UART_Transmit_IT(&huart1, (uint8_t*)command, strlen(command));// 接收回复HAL_UART_Receive_IT(&huart1, &rxBuffer[receivedIndex], 1); while((0 == receivedLength))//如果还未接收到数据,一直等待;直到收到数据{OLED_ShowString(0,4,"wait response");}//HAL_UART_Transmit_IT(&huart1, (uint8_t*)"wait!!!!\r\n", 10);//OLED_Clear();//OLED清零while(0 == stringMatched )//如果还没有接收完所有数据,一直等待,直到接收完所有数据{ReceivedAll();//判断是否接收完所有字符串了}//HAL_UART_Transmit_IT(&huart1, (uint8_t*)"111\r\n", 5);//HAL_Delay(1000);//HAL_UART_Transmit_IT(&huart1, (uint8_t*)"received\r\n", 10);OLED_Clear();//OLED清零OLED_ShowString(0,4,"received:");OLED_ShowString(80,4,(u8 *)receivedData);// 延时3秒//HAL_Delay(3000);//replyBuffer = receivedData;if (strstr((const char *)receivedData, expectedReply) != NULL){// 重置接收,准备接收下一段内容reset_receive();// 收到期望的回复return HAL_OK;}// 重置接收,准备接收下一段内容reset_receive();		return HAL_ERROR;
}
#if 0
//等待wifi配网成功
HAL_StatusTypeDef WaitConnected()
{//uint32_t startTime = HAL_GetTick();//uint32_t elapsedTime = 0;int Connected = 0;//是否配网完成// 持续等待回复,直到收到配网成功的回复;当TimeOut_flag为2时说明超时了while ( 1 != Connected){HAL_UART_Receive_IT(&huart1, &rxBuffer[receivedIndex], 1);if(0 == stringMatched)//还未接收到数据,一直等待{OLED_Clear();//OLED清零OLED_ShowString(0,4,"000 wait Connect");// 延时3秒//HAL_Delay(3000);while( stringMatched == 0){ReceivedAll();//判断是否接收完所有字符串了}}if(1 == stringMatched){OLED_Clear();//OLED清零OLED_ShowString(0,0,"received:");OLED_ShowString(80,0,(u8 *)receivedData);// 延时3秒HAL_Delay(3000);if (strstr(receivedData, "ILOPEVENT:ILOP,CONNECTED") != NULL){OLED_Clear();//OLED清零OLED_ShowString(0,4,"Connect OK");// 延时3秒//HAL_Delay(3000);// 重置接收,准备接收下一段内容reset_receive();Connected = 1;return HAL_OK;//配网成功}// 重置接收,准备接收下一段内容reset_receive();}// 更新经过的时间//elapsedTime = HAL_GetTick() - startTime;}return HAL_TIMEOUT;
}
#endif//等待wifi配网成功
HAL_StatusTypeDef WaitConnected()
{//uint32_t startTime = HAL_GetTick();//uint32_t elapsedTime = 0;OLED_Clear();//OLED清零OLED_ShowString(0,4," waiting Connect");int Connected = 0;//是否配网完成// 持续等待回复,直到收到配网成功的回复;当TimeOut_flag为2时说明超时了while ( 1 != Connected){HAL_UART_Receive_IT(&huart1, &rxBuffer[receivedIndex], 1);if(0 != receivedLength)//收到数据了{//OLED_Clear();//OLED清零//OLED_ShowString(0,4,"000 wait Connect");// 延时3秒//HAL_Delay(3000);while( stringMatched == 0)//判断是否接收完数据,如果未接收完,则一直循环,直到接收完{ReceivedAll();//判断是否接收完所有字符串了}OLED_Clear();//OLED清零OLED_ShowString(0,0,"received:");OLED_ShowString(80,0,(u8 *)receivedData);// 延时3秒//HAL_Delay(3000);if (strstr((const char *)receivedData, "ILOPEVENT:ILOP,CONNECTED") != NULL){OLED_Clear();//OLED清零OLED_ShowString(0,4,"Connect OK");// 延时3秒//HAL_Delay(3000);// 重置接收,准备接收下一段内容reset_receive();Connected = 1;return HAL_OK;//配网成功}// 重置接收,准备接收下一段内容reset_receive();}}return HAL_TIMEOUT;
}// 进入WiFi配网过程的函数
HAL_StatusTypeDef WiFiConfigInit()
{HAL_StatusTypeDef status;// 发送指令 "AT",直到收到的回复是OKstatus = sendCommandAndWait(atCommands[0], "OK");while (status != HAL_OK){OLED_Clear();//OLED清零OLED_ShowString(0,4,"AT Not OK");status = sendCommandAndWait("AT\r\n", "OK");}OLED_Clear();//OLED清零OLED_ShowString(0,4,"AT  OK");// 延时10秒//HAL_Delay(10000);// 发送指令 "AT+ILOPAWSAP\r\n"status = sendCommandAndWait("AT+ILOPAWSAP\r\n", "OK");while (status != HAL_OK){OLED_Clear();//OLED清零OLED_ShowString(0,4,"SWAP  Not OK");status = sendCommandAndWait("AT+ILOPAWSAP\r\n", "OK");}OLED_Clear();//OLED清零OLED_ShowString(0,4,"SWAP OK");// 延时10秒//HAL_Delay(10000);if(HAL_OK ==  WaitConnected()){OLED_Clear();//OLED清零OLED_ShowString(0,4,"Connect OK");}else{OLED_Clear();//OLED清零OLED_ShowString(0,4,"Connect TimeOut");return HAL_TIMEOUT;}// 配网成功return HAL_OK;
}void DeviceInit()
{deviceParams.powerState = 0;
}
/*判断wifi是否断开,返回DISCONNECT 表示wifi断开;返回CONNECT表示wifi处于连接状态*/
uint8_t wifi_isDisconnected()
{uint8_t disConnected = DISCONNECT_FALSE;//默认没有断开if (strstr((const char *)receivedData, "ILOPEVENT:ILOP,CONNECTING") != NULL){OLED_Clear();//OLED清零OLED_ShowString(0,4,"wifi disconnect ");// 延时3秒//HAL_Delay(3000);// 重置接收,准备接收下一段内容reset_receive();disConnected = DISCONNECT_TRUE;//wifi断开}	return disConnected;
}void wifi_task()
{HAL_UART_Receive_IT(&huart1, &rxBuffer[receivedIndex], 1);//if(0 == stringMatched)//还未接收到数据,一直等待if(0 != receivedIndex)//说明接收到消息了{//OLED_ShowString(0,4,"Recive date begin");// 延时3秒//HAL_Delay(3000);while( 0 == stringMatched){ReceivedAll();//判断是否接收完所有字符串了}OLED_Clear();//OLED清零OLED_ShowString(0,0,"received:");OLED_ShowString(80,0,(u8 *)receivedData);// 延时3秒//HAL_Delay(3000);if(DISCONNECT_TRUE == wifi_isDisconnected())//如果wifi断开了{OLED_Clear();//OLED清零OLED_ShowString(0,4,"wifi DisConnect ");// 延时3秒//HAL_Delay(3000);				//while(HAL_OK != WaitConnected());WaitConnected();//等待wifi重连成功OLED_Clear();//OLED清零OLED_ShowString(0,4,"wifi recover ");// 延时3秒//HAL_Delay(3000);		}else{OLED_Clear();//OLED清零OLED_ShowString(0,4,"wifi parse Task ");//HAL_Delay(3000);parseWiFiCommand((char *)receivedData);deviceControl();reset_receive();	}}{OLED_Clear();//OLED清零OLED_ShowString(0,4,"wifi connect ");		}	}void parseWiFiCommand(const char* command)
{const char* keyword = "+ILOPEVENT:SETJSON,property,";const char* powerstateKeyword = "\"powerstate\":";const char* powerstateValue = NULL;// 检查指令是否以关键字开头if (strncmp(command, keyword, strlen(keyword)) != 0) {while(1){OLED_Clear();//OLED清零OLED_ShowString(0,4,"error 1");}//return;}// 定位到powerstate关键字的位置powerstateValue = strstr(command, powerstateKeyword);if (powerstateValue == NULL) {while(1){OLED_Clear();//OLED清零OLED_ShowString(0,4,"error 2");}//return;}// 解析powerstate的值powerstateValue += strlen(powerstateKeyword);int powerstate = *powerstateValue - '0';//将powerstateValue指针所指向的字符转换为整数,并将结果存储在powerstate变量中。*powerstateValue表示取指针所指向的字符,然后通过减去字符'0'的ASCII值,实现将字符转换为对应的整数值。// 根据powerstate设置state的值if (powerstate == 0) {deviceParams.powerState = 0;} else if (powerstate == 1) {deviceParams.powerState = 1;} else {while(1){OLED_Clear();//OLED清零OLED_ShowString(0,4,"error 3");}}
}void deviceControl()
{if(0 == deviceParams.powerState)HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_SET);//灯灭elseHAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_RESET);//灯亮		
}// 发送数据
void sendWiFiData(const char* paramName, const char* paramValue) {// 构建发送数据的格式//sprintf(txBuffer, "+ILOPEVENT:SETJSON,%s,%d,{\"%s\":%s}\r\n", paramName, strlen(paramValue), paramName, paramValue);// 在这里实现串口发送功能,将txBuffer中的数据发送出去// 例如:HAL_UART_Transmit(&huart1, (uint8_t*)txBuffer, strlen(txBuffer), HAL_MAX_DELAY);
}

笔记

记录几个开发中的细节:

1、单片机向wifi模块发送指令 AT+ILOPAWSAP\r\n进行配网
2、当单片机收到wifi模块返回的信息中,包含ILOPEVENT:ILOP,CONNECTED时,说明配网成功
3、当单片机收到wifi模块返回的信息中,包含ILOPEVENT:ILOP,CONNECTING时,说明wifi已经断开,正在重连
4、云端向EMW3080发送的控制指令,也就是单片机需要解析的指令,格式如下(以参数“开关状态”为例):

+ILOPEVENT:SETJSON,property,16,{"powerstate":0}
+ILOPEVENT:SETJSON,property,16,{"powerstate":1}

相关文章:

STM32G0+EMW3080+阿里云飞燕平台实现单片机WiFi智能联网功能(三)STM32G0控制EMW3080实现IoT功能

项目描述:该系列记录了STM32G0EMW3080实现单片机智能联网功能项目的从零开始一步步的实现过程;硬件环境:单片机为STM32G030C8T6;物联网模块为EMW3080V2-P;网联网模块的开发板为MXKit开发套件,具体型号为XCH…...

IntelliJ IDEA - Git Commit 后 Commit 窗口不消失解决方案

这个现象是在 2023 年版本后开始的,一开始以为是 Mac 系统的原因,后来发现原来 Windows 也这样,所以应该只跟 IDEA 版本有关 可以看到左侧 commit 后,这个侧边栏还在,按理讲在以前的版本是之前消失,这样使…...

Vue 组件化编程 和 生命周期

目录 一、组件化编程 1.基本介绍 : 2.原理示意图 : 3.全局组件示例 : 4.局部组件示例 : 5.全局组件和局部组件的区别 : 二、生命周期 1.基本介绍 : 2.生命周期示意图 : 3.实例测试 : 一、组件化编程 1.基本介绍 : (1) 开发大型应用的时候,页面往往划分成…...

《数字图像处理-OpenCV/Python》连载(41)图像的旋转

《数字图像处理-OpenCV/Python》连载(41)图像的旋转 本书京东优惠购书链接:https://item.jd.com/14098452.html 本书CSDN独家连载专栏:https://blog.csdn.net/youcans/category_12418787.html 第 6 章 图像的几何变换 几何变换分…...

案例 - 拖拽上传文件,生成缩略图

直接看效果 实现代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>拖拽上传文件</title>&l…...

PHP 使用递归方式 将其二维数组整合为层级树 其中层级id 为一个uuid的格式 造成的诡异问题 已解决

不啰嗦 直接上源代码 <?php function findChildren($list, $p_id){$r array();foreach ($list as $k > $item) {if ($item[fid] $p_id) {unset($list[$k]);$length count($r);$r[$length] $item;if ($t findChildren($list, $item[id])) {$r[$length][children] …...

rv1126-rv1109-添加分区,定制固件,开机挂载功能

===================================================================== 修改分区: 这里是分区的txt文件选择; 这里是分区的划分,我这里回车了,方便看 FIRMWARE_VER: 8.1 MACHINE_MODEL: RV1126 MACHINE_ID: 007 MANUFACTURER: RV1126 MAGIC: 0x5041524B ATAG: 0x00200…...

一台电脑使用多个gitee账号,以及提交忽略部分文件

目录 ​编辑 一&#xff1a;前言 二&#xff1a;解决方法 三&#xff1a;提交gitee时忽略文件 一&#xff1a;前言 在开发中&#xff0c;我们拥有不止一个 gitee 账号&#xff0c;通常而言一个是公司的&#xff0c;一个是私人的。有时候我们在公司写了一些自己的东西&#…...

解析邮件文本内容; Mime文本解析; MimeStreamParser; multipart解析

原始文本 ------_Part_46705_715015081.1699589700255 Content-Type: text/html;charsetUTF-8 Content-Transfer-Encoding: base64PGh0bWwCiAgICA8aGVhZD4KICAgICAgICA8bWV0YSBodHRwLW VxdWl2PSJDb250ZW50LVR5cGUiIGNvbnRlbnQ9InRleHQvaHRt bDsgY2hhcnNldD1VVEYtOCICiAgICAgIC…...

获取请求IP以及IP解析成省份

某些业务需要获取请求IP以及将IP解析成省份之类的&#xff0c;于是我写了一个工具类&#xff0c;可以直接COPY /*** IP工具类* author xxl* since 2023/11/9*/ Slf4j public class IPUtils {/*** 过滤本地地址*/public static final String LOCAL_ADDRESS "127.0.0.1&quo…...

YOLOv8-seg改进:复现HIC-YOLOv5,HIC-YOLOv8-seg助力小目标分割

🚀🚀🚀本文改进:HIC-YOLOv8-seg:1)添加一个针对小物体的额外预测头,以提供更高分辨率的特征图2)在backbone和neck之间采用involution block来增加特征图的通道信息;3)在主干网末端加入 CBAM 的注意力机制; 🚀🚀🚀HIC-YOLOv8-seg小目标分割检测&复杂场景…...

vscode 终端进程启动失败: shell 可执行文件“C:\Windows\System32\WindowsPower

vscode 终端进程启动失败: shell 可执行文件“C:\Windows\System32\WindowsPower 第一次用vscode&#xff0c;然后遇到这个问题&#xff0c;在设置里搜索 terminal.integrated.defaultProfile.windows 将这里的null改成"Command Prompt" 重启就可以了...

【中间件篇-Redis缓存数据库02】Redis高级特性和应用(慢查询、Pipeline、事务、Lua)

Redis高级特性和应用(慢查询、Pipeline、事务、Lua) Redis的慢查询 许多存储系统&#xff08;例如 MySQL)提供慢查询日志帮助开发和运维人员定位系统存在的慢操作。所谓慢查询日志就是系统在命令执行前后计算每条命令的执行时间&#xff0c;当超过预设阀值,就将这条命令的相关…...

栈 和 队列

什么是栈? 一种特殊的线性表&#xff0c;只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出&#xff08;LIFO - Last In First Out&#xff09;的原则。   从数据结构的角度来看&…...

【推荐】一款AI写作大师、问答、绘画工具-「智元兔 AI」

在当今技术飞速发展的时代&#xff0c;越来越多的领域开始应用人工智能&#xff08;Artificial Intelligence&#xff0c;简称AI&#xff09;。其中&#xff0c;AI写作工具备受瞩目&#xff0c;备受推崇。在众多的选择中&#xff0c;智元兔AI是一款在笔者使用过程中非常有帮助的…...

阿里云付费用户破100万 用户规模亚洲最大

导读阿里巴巴集团公布2018财年第一季度财报&#xff0c;阿里云达到一个重要里程碑&#xff0c;云计算付费用户数量首次超过100万&#xff0c;成为亚洲首家达到百万级用户规模的云计算公司。同时&#xff0c;企业级市场被云计算人工智能等新技术全面激活&#xff0c;推动该季度营…...

人工智能基础——Python:Matplotlib与绘图设计

人工智能的学习之路非常漫长&#xff0c;不少人因为学习路线不对或者学习内容不够专业而举步难行。不过别担心&#xff0c;我为大家整理了一份600多G的学习资源&#xff0c;基本上涵盖了人工智能学习的所有内容。点击下方链接,0元进群领取学习资源,让你的学习之路更加顺畅!记得…...

Ubuntu 配置 Github 的 SSH keys

先进入已有的 Git 目录或使用新建的一个 Git 仓库下。 设置 Github 用户名和邮箱&#xff1a; $ git config --global user.name [Github用户名] $ git config --global user.email [Github认证邮箱]生成 SSH 密钥文件&#xff1a; $ ssh-keygen -t rsa -C [Github认证邮箱]…...

Flink—— Flink Data transformation(转换)

Flink数据算子转换有很多类型&#xff0c;各位看官看好&#xff0c;接下来&#xff0c;演示其中的十八种类型。 1.Map&#xff08;映射转换&#xff09; DataStream → DataStream 将函数作用在集合中的每一个元素上,并返回作用后的结果&#xff0c;其中输入是一个数据流&…...

前端读取文件当文件选择相同文件名的文件,内容不会变化

前端读取文件当文件选择相同文件名的文件&#xff0c;内容不会变化 今天遇到个奇怪的bug&#xff0c;使用打开文件&#xff0c;并选择文件时&#xff0c;正常情况会读取文件信息。 但是如果先选择相同的文件名&#xff0c;则内容不会发生变化。 先说结论 只要不使用事件中e…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

el-switch文字内置

el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

苍穹外卖--缓存菜品

1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; ①每个分类下的菜品保持一份缓存数据…...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...

JAVA后端开发——多租户

数据隔离是多租户系统中的核心概念&#xff0c;确保一个租户&#xff08;在这个系统中可能是一个公司或一个独立的客户&#xff09;的数据对其他租户是不可见的。在 RuoYi 框架&#xff08;您当前项目所使用的基础框架&#xff09;中&#xff0c;这通常是通过在数据表中增加一个…...

用机器学习破解新能源领域的“弃风”难题

音乐发烧友深有体会&#xff0c;玩音乐的本质就是玩电网。火电声音偏暖&#xff0c;水电偏冷&#xff0c;风电偏空旷。至于太阳能发的电&#xff0c;则略显朦胧和单薄。 不知你是否有感觉&#xff0c;近两年家里的音响声音越来越冷&#xff0c;听起来越来越单薄&#xff1f; —…...

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

Yolov8 目标检测蒸馏学习记录

yolov8系列模型蒸馏基本流程&#xff0c;代码下载&#xff1a;这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中&#xff0c;**知识蒸馏&#xff08;Knowledge Distillation&#xff09;**被广泛应用&#xff0c;作为提升模型…...

redis和redission的区别

Redis 和 Redisson 是两个密切相关但又本质不同的技术&#xff0c;它们扮演着完全不同的角色&#xff1a; Redis: 内存数据库/数据结构存储 本质&#xff1a; 它是一个开源的、高性能的、基于内存的 键值存储数据库。它也可以将数据持久化到磁盘。 核心功能&#xff1a; 提供丰…...

6️⃣Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙

Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙 一、前言:离区块链还有多远? 区块链听起来可能遥不可及,似乎是只有密码学专家和资深工程师才能涉足的领域。但事实上,构建一个区块链的核心并不复杂,尤其当你已经掌握了一门系统编程语言,比如 Go。 要真正理解区…...