Honor笔记本 (2018款intel版本)win11升级教程(TPM2.0)

0. 引言

注意:本人笔记本电脑是2018年买的荣耀刚出的magicbook Intel i5版本,前不久微软推出win11版本,我看着还不错还是很想尝试一下,奈何用了微软的win11对电脑安全这一块的要求非常高,无法通过官方的安全检测(主要是电脑没有打开TPM2.0),对于我们这些老电脑用户非常不友好,本人在网上找了各种大牛的解决方案综合汇集了一下并成功升级到了win11的详细过程。所有的参考资料我都放到了我的参考中
写本篇目的:那些大牛写的非常详细,操作非常,对于电脑小白想要升级win11看的会头昏脑胀的,所以本篇文章致力于用通俗易懂的语言及操作,让大家在几分钟内就能快速的学会TPM2.0实现。

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

推荐:观看参考资料中第二个资料,B站视频(此视频不是本人所做)与本文一同使用会更快理解

1. Step 1 准备阶段

  1. 首先打开 " 电脑管家电脑优化 ",主要观察自己的驱动是否都是最新的
    在这里插入图片描述
  2. 上面打开后观察 BIOS 的版本是否为 1.30 版本(最新版本)
    在这里插入图片描述
  3. 如果BISO是最新版本的可以不用看这步跳过即可。如果不是最新版本,需要将BIOS驱动更新至最新版本。方法一:电脑管家直接更新(最方便快捷);方法二:更新渠道华为官方网站:https://consumer.huawei.com/cn/support/driver-list/ ,网站如下图所示,这里点击搜索旁边的 “按设备序列号搜索”,设备序列号是可以在电脑管家中查到,查询方法如下图所示
    在这里插入图片描述
    在这里插入图片描述

2. Step 2 工具环节

  1. 下载工具包,B站视频UP主给的工具包:pan.baidu.com/s/1q23mScwQ_AEzfk6HtAWsbQ 提取码:tpnt
  2. 下载后的文件包长这样
    在这里插入图片描述
  3. 打开 H2OUVE 文件夹,先以管理员身份打开 WDFInst.exe,再以管理员身份打开 H2OUVE-W-GUIx64.exe (注意:都以管理员身份打开)
    在这里插入图片描述
  4. 打开后可以看到如下界面,我遇到的问题是一直出现 灰色界面,我查找了其他资料参照了参考资料中的第四位大佬,解决了一直灰色现象并跳转至与UP主相同的界面,点击:" FileLoad runtime ",点击后出现如下界面在这里插入图片描述在这里插入图片描述
    在这里插入图片描述
  5. 点击上图界面中的 Vanable跳转至如下界面,根据 6 中给出的参考修改表,magic book和matebook D都试用,7 中详细的交大家根据表格修改参数值在这里插入图片描述
  6. 参考修改表在这里插入图片描述
  7. 参数详细修改
    (1)CpuSetup 偏移坐标 0x3C(横30,竖0C) 数据改为 00
    在这里插入图片描述
    (2)PchSetup 偏移坐标 0x17(横10,竖07) 数据改为 00
    在这里插入图片描述
    (3)MeSetupStorage 偏移坐标 0x6(横00,竖06) 数据改为 01
    在这里插入图片描述
    (4)Setup 偏移坐标 0xF0(横F0,竖00) 数据改为 01
       Setup 偏移坐标 0xE3(横E0,竖03) 数据改为 02
       Setup 偏移坐标 0x9D(横90,竖0D) 数据改为 00
       Setup 偏移坐标 0x62(横60,竖02) 数据改为 02
    在这里插入图片描述
  8. 点击保存这个保存按钮,即可重启电脑
    在这里插入图片描述

3. Step 3 安装win 11

  1. 重启后,“此电脑(右键)→管理”,然后点击 设备管理器,可以看到有个安全设备,此时可以说成功的安装上了TPM2.0(为什么要重启?就在重启的过程中自动就给电脑安装上了TPM2.0)在这里插入图片描述在这里插入图片描述

  2. 微软检测软件可以从官网上下载(官网不太好下载),官网链接:https://aka.ms/GetPCHealthCheckApp,安装包链接:链接:https://pan.baidu.com/s/15OV15-aLfs3QHFOSPcGZFw
    提取码:uid3。安装后可以对电脑进行检测查看是否可以成功升级文win11在这里插入图片描述

  3. 进入官网 https://www.microsoft.com/zh-cn/software-download/windows11,看到如下界面通过安装助手更新win11即可,进入助手后接受并安装即可
    在这里插入图片描述在这里插入图片描述

  4. 更新后如下图所示
    在这里插入图片描述

参考资料

注意:第一个参考链接很可惜打开后显示无法打开,写的非常详细。感谢这几位大佬的资料,本人只是进行了工作汇总及问题解决。

  1. 荣耀与华为系列的笔记本打开TPM2.0,直升win11 - 知乎链接:https://zhuanlan.zhihu.com/p/409437213
  2. 『保姆级教程』将MagicBook 2018升级到Windows11,视频链接:https://www.bilibili.com/video/BV1444y1e7Zn
  3. Magicbook 2018开启TPM2.0,链接:https://blog.csdn.net/qq_44503950/article/details/120784501
  4. 被软屏蔽TPM的华为本,完美开启TPM涅槃重生Windows 11的教程,链接:https://ajax.win/archives/137
/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * <h2><center>© Copyright (c) 2025 STMicroelectronics. * All rights reserved.</center></h2> * * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "usart.h" #include "gpio.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "dht11.h" #include "stdio.h" #include <stdlib.h> /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ #include "string.h" #define RxMaxLen 100 #define timeout 5000 uint8_t RxBuf[100]={0}; uint32_t startTick = 0; char atMode[] = "AT+CWMODE=1\r\n"; //设置wifi工作模式的AT指令 char atJap[] = "AT+CWJAP=\"HONOR 90\",\"041028ly\"\r\n"; // wifi连接热点的AT指令 char atTcp[] = "AT+CIPSTART=\"TCP\",\"121.37.241.174\",8600\r\n"; //wifi连接云端服务器的AT指令 char atSendConn[] = "AT+CIPSEND=88\r\n"; //wifi上传数据字节数的AT指令 char atJsonConn[] = "{\"t\":1,\"device\":\"esp8266_199\",\"key\":\"39a2825123ad4ff8a4779cbd5fca31b7\",\"ver\":\"v0.0.0.0\"}\r\n"; //wifi连接设备的JSON数据 AT指令 char atSendSens[] = "AT+CIPSEND=53\r\n"; ////wifi上传数据字节数的AT指令 //char atJsonSens[] = "{\"t\":3,\"datatype\":1,\"datas\":{\"temp\":\"12\"},\"msgid\":123}\r\n"; ////wifi给传感器上报数据的JSON AT指令 //给wifi发送AT指令 void SenAtCom(char *str) { HAL_UART_Transmit(&huart3,(uint8_t *)str,strlen(str),0xffff); } //wifi连接热点函数 void ProjectConn() { SenAtCom(atMode); HAL_Delay(50); SenAtCom(atJap); startTick= HAL_GetTick(); //获了系统当前运行时间 while ((HAL_GetTick() - startTick) < timeout) //当所用时间小于退出时间 { if(strstr((char *)RxBuf,"GOT IP") == RESET) //如没有收到“获得IP”,即如没有连接到热点 { HAL_Delay(10); //延时 SenAtCom(atJap); //继续连接热点 } else { break; //连接到了,就退出。 } } } //wifi连接服务器函数 void ServerConn() { SenAtCom(atMode); HAL_Delay(50); SenAtCom(atJap); HAL_Delay(2000); SenAtCom(atTcp); HAL_Delay(50); } //串口3接收中断回调处理函数,该函数可以处理不定长度的接收中断 void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) { if(huart == &huart3) { HAL_UART_Transmit(&huart1,RxBuf,sizeof(RxBuf),0xffff); //把串口3接收到的wifi回复,转发到串口1,可以通串口1打印到屏幕 } memset(RxBuf,0,RxMaxLen); HAL_UARTEx_ReceiveToIdle_IT(&huart3, RxBuf, RxMaxLen); //接收串口3收到的信息,并再次开启串口3的接收中断 } /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ DHT11_Data_TypeDef dht11_rec_buf[]={0,0,0,0,0,0.0,0.0}; int fputc(int ch ,FILE *f) { HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xffff); return ch; } typedef struct { float temperature; } DHT11RecBuf; /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ DHT11RecBuf *dht11_rec_buf = (DHT11RecBuf*)malloc(sizeof(DHT11RecBuf)); /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_USART1_UART_Init(); MX_USART3_UART_Init(); /* USER CODE BEGIN 2 */ DHT11_Init(); HAL_UARTEx_ReceiveToIdle_IT(&huart3, RxBuf, RxMaxLen); //开启串口3的接收中断,仅一次 ProjectConn(); //wifi连接热点 /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { char atJsonSens[128]; sprintf(atJsonSens, "{\"t\":3,\"datatype\":1,\"datas\":{\"temp\":\"%.2f\"},\"msgid\":123}\r\n", dht11_rec_buf->temperature); SenAtCom(atTcp); //连接云端服务器 HAL_Delay(100); SenAtCom(atSendConn); //发送上传数据的字节数 HAL_Delay(100); SenAtCom(atJsonConn); //连接云端服务器上的设备 HAL_Delay(2000); SenAtCom(atSendSens); //发送上传数据的字节数(要与发送的JSON数据字节数完全一致) HAL_Delay(100); SenAtCom(atJsonSens); //上传传感器数据 HAL_Delay(3000); /* USER CODE END WHILE */ free(dht11_rec_buf); /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Initializes the CPU, AHB and APB busses clocks */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB busses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { Error_Handler(); } } /* USER CODE BEGIN 4 */ /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @retval None */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t *file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
06-17
<think>我们正在处理一个嵌入式C程序,该程序用于通过ESP8266WiFi模块将DHT11温湿度传感器的数据上传到云端服务器。代码中已经包含了WiFi连接、服务器连接、数据发送等功能。但是,在代码中我们发现了一些问题,特别是在主循环中,每次循环都会重新连接服务器并发送数据,这可能导致频繁的连接断开和重新连接,效率低下。此外,在内存管理方面,每次循环都会分配和释放`dht11_rec_buf`,这也是不必要的。主要问题点:1.在主循环中,每次都会调用`free(dht11_rec_buf)`,但该变量是在`main`函数的开始处通过`malloc`分配的,且只分配了一次。然而,在循环中,每次都会释放,但释放后并没有重新分配,这会导致在第二次循环时使用已经释放的内存,造成未定义行为(通常会导致崩溃)。2.同样,在循环中,我们试图使用`dht11_rec_buf->temperature`,但此时`dht11_rec_buf`已经被释放,这是非法的。3.在连接服务器和发送数据的过程中,没有检查连接状态,如果连接断开,应该重新连接,而不是每次循环都重新连接(因为重新连接需要时间,且可能失败)。改进建议:1.将`dht11_rec_buf`的分配放在循环外(例如在`main`函数开始处),并且只分配一次,在程序结束前释放一次(实际上,由于是嵌入式程序,可能不需要释放,因为程序会一直运行)。或者,我们可以不使用动态内存,直接使用静态变量。2.修改主循环,避免每次循环都重新连接服务器。应该只在需要时(例如连接断开时)才重新连接。3.优化数据发送逻辑,确保连接有效后再发送数据。此外,我们注意到在`main`函数中,已经调用了`DHT11_Init()`,但并没有在循环中读取DHT11的数据。因此,我们需要在循环中加入读取DHT11数据的代码,并将读取到的温度值用于构造JSON字符串。具体步骤:1.移除循环内的`free(dht11_rec_buf)`,改为在程序开始处分配一次,或者使用静态分配(推荐,因为嵌入式系统中动态内存分配容易产生碎片)。2.在循环中读取DHT11的数据,并更新`dht11_rec_buf`中的温度值。3.检查当前WiFi和服务器连接状态,如果断开则重新连接,否则直接发送数据。4.调整发送数据的间隔,避免过于频繁。由于原代码中并没有提供读取DHT11数据的函数调用,我们假设有一个函数可以读取DHT11数据并填充结构体。这里我们假设使用`DHT11_ReadData`函数(需要根据实际库函数调整)。修改后的主循环代码可能如下:注意:由于原代码中`dht11_rec_buf`被定义为一个结构体指针,我们改为静态分配,并直接使用一个结构体变量。修改代码:首先,在`main`函数中,我们将动态分配改为静态分配:```c/*USERCODEBEGIN1*/DHT11RecBufdht11_rec_buf;//直接声明一个结构体变量,不再使用指针/*USERCODEEND1*/```然后,在`main`函数中,移除之前的动态分配,并初始化:```cintmain(void){/*...其他初始化代码...*//*USERCODEBEGIN2*/DHT11_Init();HAL_UARTEx_ReceiveToIdle_IT(&huart3,RxBuf,RxMaxLen);//开启串口3的接收中断,仅一次ProjectConn();//wifi连接热点ServerConn();//连接服务器,这里我们添加一次服务器连接,后续在循环中如果断开再重连/*USERCODEEND2*/```在循环中,我们读取DHT11数据,并发送:```cwhile(1){charatJsonSens[128];//读取DHT11数据,假设函数为DHT11_ReadData,并传入结构体地址if(DHT11_ReadData(&dht11_rec_buf)==HAL_OK){//读取成功,构造JSON字符串sprintf(atJsonSens,"{\"t\":3,\"datatype\":1,\"datas\":{\"temp\":\"%.2f\"},\"msgid\":123}\r\n",dht11_rec_buf.temperature);}else{//读取失败,可以发送错误信息或者使用上一次的值,这里我们使用0.0sprintf(atJsonSens,"{\"t\":3,\"datatype\":1,\"datas\":{\"temp\":\"0.00\"},\"msgid\":123}\r\n");}//检查连接状态,这里简化处理,如果连接断开,则重新连接服务器//注意:实际中需要根据模块返回的信息来判断连接状态,这里我们暂时省略,假设连接一直保持//发送数据SenAtCom(atSendSens);//发送上传数据的字节数(要与发送的JSON数据字节数完全一致)HAL_Delay(100);SenAtCom(atJsonSens);//上传传感器数据HAL_Delay(3000);//等待3秒,然后再次读取和发送}```但是,上述代码中,我们移除了重新连接服务器的步骤,因为每次循环都重新连接是不必要的。我们只在开始时连接一次,然后在循环中只发送数据。然而,实际中连接可能会断开,因此我们需要在发送数据前检查连接状态。由于原代码中没有状态检查,我们可以通过发送一个测试命令(如"AT+CIPSTATUS")并检查响应来判断连接状态。但这会增加代码复杂性,并且需要处理响应。作为简化,我们可以定期重新连接(比如每10次循环重新连接一次),或者当发送失败时重新连接。考虑到项目复杂度,我们这里先不实现连接状态检查,而是采用定期重连的方式。例如:```cintloopCount=0;while(1){loopCount++;if(loopCount%10==0){//每10次循环(即每30秒)重新连接一次服务器ServerConn();}//读取DHT11数据并发送,同上//...}```另外,注意原代码中`ServerConn`函数内部先发送了设置模式和连接热点的指令,这可能会导致重复连接热点。我们修改`ServerConn`函数,使其只进行服务器连接:```cvoidServerConn(){SenAtCom(atTcp);HAL_Delay(50);}```同时,在`ProjectConn`函数中,我们已经连接了热点,所以在`main`函数中调用`ProjectConn`后,热点已经连接,再调用`ServerConn`连接服务器。由于原代码中`ServerConn`函数内部还调用了设置模式和连接热点的指令,这是不必要的,所以我们修改`ServerConn`函数。总结修改:1.将动态分配的结构体改为静态分配。2.在循环中读取DHT11数据。3.避免在每次循环中重新连接服务器,而是定期重连或根据状态重连(这里采用定期重连)。4.修改`ServerConn`函数,使其只发送连接服务器的指令。由于代码较长,我们只展示修改的部分。注意:以上修改基于假设的DHT11读取函数,实际使用时需要根据具体的DHT11驱动库调整。修改后的main函数循环部分:```c/*Infiniteloop*//*USERCODEBEGINWHILE*/intloopCount=0;while(1){charatJsonSens[128];loopCount++;//每10次循环重新连接服务器(即每30秒,因为每次循环延迟3秒)if(loopCount%10==0){ServerConn();//重新连接服务器HAL_Delay(1000);//等待连接}//读取DHT11数据//假设DHT11_ReadData函数返回HAL_StatusTypeDef,并且将数据填充到dht11_rec_bufif(DHT11_ReadData(&dht11_rec_buf)==HAL_OK){//构造JSON字符串sprintf(atJsonSens,"{\"t\":3,\"datatype\":1,\"datas\":{\"temp\":\"%.2f\"},\"msgid\":123}\r\n",dht11_rec_buf.temperature);}else{//读取失败,发送默认值sprintf(atJsonSens,"{\"t\":3,\"datatype\":1,\"datas\":{\"temp\":\"0.00\"},\"msgid\":123}\r\n");}//发送传感器数据SenAtCom(atSendSens);//发送上传数据的字节数(53字节)HAL_Delay(100);SenAtCom(atJsonSens);//上传传感器数据HAL_Delay(3000);//等待3秒,然后再次读取和发送}/*USERCODEEND3*/```另外,原代码中在循环结束后释放`dht11_rec_buf`,现在我们已经改为静态分配,所以移除`free`语句。由于原代码中`dht11_rec_buf`是动态分配的,我们改为静态分配后,需要删除原来的`malloc`和`free`。在`main`函数开始处,我们删除了:```cDHT11RecBuf*dht11_rec_buf=(DHT11RecBuf*)malloc(sizeof(DHT11RecBuf));```改为在`USERCODEBEGIN1`处定义:```c/*USERCODEBEGIN1*/DHT11RecBufdht11_rec_buf;//全局结构体变量,或者局部静态变量?注意,我们放在main函数外作为全局变量,或者放在main函数内作为局部变量。/*USERCODEEND1*/```但是,原代码中在`USERCODEBEGIN0`已经有一个`dht11_rec_buf`的定义,我们需要统一。观察原代码,在`USERCODEBEGIN0`处有:```cDHT11_Data_TypeDefdht11_rec_buf[]={0,0,0,0,0,0.0,0.0};```然后下面又定义了一个结构体类型和指针:```ctypedefstruct{floattemperature;}DHT11RecBuf;```这里存在混淆。我们需要统一使用一个结构体类型。根据DHT11的读取,通常DHT11会返回温度和湿度。原代码中`DHT11_Data_TypeDef`可能是库中定义的结构体类型。所以,我们应该使用库提供的结构体。修改:删除自定义的`DHT11RecBuf`结构体,直接使用`DHT11_Data_TypeDef`。步骤:1.删除自定义结构体`DHT11RecBuf`。2.将变量`dht11_rec_buf`改为`DHT11_Data_TypeDef`类型。例如:```c/*USERCODEBEGIN0*///假设DHT11_Data_TypeDef已经定义DHT11_Data_TypeDefdht11_rec_buf;//改为一个结构体变量,而不是数组/*USERCODEEND0*/```然后在main函数中,读取数据时:```cif(DHT11_ReadData(&dht11_rec_buf)==HAL_OK)```并使用`dht11_rec_buf.temperature`(具体成员名根据实际结构体定义)。因此,我们修改后的代码应该与库中定义的结构体一致。由于原代码中`DHT11_Data_TypeDef`的定义未知,我们假设它包含`temperature`成员。综上所述,我们进行以下修改:1.在`USERCODEBEGIN0`中,将原来的数组定义改为单个结构体变量,并删除自定义结构体。2.修改main函数中的使用。由于原代码中已经包含`#include"dht11.h"`,所以我们可以直接使用`DHT11_Data_TypeDef`。修改后的`USERCODEBEGIN0`部分:```c/*USERCODEBEGIN0*/#include"string.h"#defineRxMaxLen100#definetimeout5000uint8_tRxBuf[100]={0};uint32_tstartTick=0;charatMode[]="AT+CWMODE=1\r\n";//设置wifi工作模式的AT指令charatJap[]="AT+CWJAP=\"HONOR90\",\"041028ly\"\r\n";//wifi连接热点的AT指令charatTcp[]="AT+CIPSTART=\"TCP\",\"121.37.241.174\",8600\r\n";//wifi连接云端服务器的AT指令charatSendConn[]="AT+CIPSEND=88\r\n";//wifi上传数据字节数的AT指令charatJsonConn[]="{\"t\":1,\"device\":\"esp8266_199\",\"key\":\"39a2825123ad4ff8a4779cbd5fca31b7\",\"ver\":\"v0.0.0.0\"}\r\n";//wifi连接设备的JSON数据AT指令charatSendSens[]="AT+CIPSEND=53\r\n";////wifi上传数据字节数的AT指令//全局变量,用于存储DHT11数据DHT11_Data_TypeDefdht11_rec_buf;//...其他函数.../*USERCODEEND0*/```然后在main函数中,我们移除动态分配,直接使用这个全局变量(或者也可以改为main函数内的局部变量,但考虑到在中断回调中可能不会使用,所以放在全局或局部都可以,这里我们放在全局)。最后,修改主循环。由于修改较多,我们重新整理一下main函数:```cintmain(void){/*USERCODEBEGIN1*//*USERCODEEND1*//*...标准初始化...*//*USERCODEBEGIN2*/DHT11_Init();HAL_UARTEx_ReceiveToIdle_IT(&huart3,RxBuf,RxMaxLen);//开启串口3的接收中断,仅一次ProjectConn();//wifi连接热点ServerConn();//连接服务器/*USERCODEEND2*//*Infiniteloop*//*USERCODEBEGINWHILE*/intloopCount=0;while(1){charatJsonSens[128];loopCount++;//每10次循环重新连接服务器(即每30秒,因为每次循环延迟3秒)if(loopCount%10==0){ServerConn();//重新连接服务器HAL_Delay(1000);//等待连接}//读取DHT11数据if(DHT11_ReadData(&dht11_rec_buf)==HAL_OK){//构造JSON字符串,注意这里使用了dht11_rec_buf的温度值sprintf(atJsonSens,"{\"t\":3,\"datatype\":1,\"datas\":{\"temp\":\"%.2f\"},\"msgid\":123}\r\n",dht11_rec_buf.temperature);}else{//读取失败,发送默认值sprintf(atJsonSens,"{\"t\":3,\"datatype\":1,\"datas\":{\"temp\":\"0.00\"},\"msgid\":123}\r\n");}//发送传感器数据SenAtCom(atSendSens);//发送上传数据的字节数(53字节)HAL_Delay(100);SenAtCom(atJsonSens);//上传传感器数据HAL_Delay(3000);//等待3秒,然后再次读取和发送}/*USERCODEEND3*/}```注意:`DHT11_ReadData`函数的实现需要根据具体的库来调用。原代码中并没有调用该函数,因此我们需要在循环中加入读取的代码。另外,原代码中在发送传感器数据之前,还发送了连接设备的JSON指令(`atJsonConn`),但在我们修改后的循环中并没有发送。根据云端协议,可能需要在连接服务器后先发送设备连接信息,然后才能发送传感器数据。因此,我们可能需要在`ServerConn`之后发送一次设备连接信息,并且在每次重新连接服务器后也需要发送。修改:在`ServerConn`函数调用后,发送设备连接信息:```cvoidServerConn(){SenAtCom(atTcp);HAL_Delay(50);//发送设备连接信息SenAtCom(atSendConn);HAL_Delay(100);SenAtCom(atJsonConn);HAL_Delay(1000);//等待连接完成}```同时,在循环中,每10次循环重新连接服务器时,也会发送设备连接信息(因为`ServerConn`函数中已经包含了发送设备连接信息)。这样,我们就完成了修改。由于代码较长,无法全部展示,我们只给出修改的关键部分。请根据实际项目情况调整。注意:以上代码没有经过实际测试,需要根据实际模块的响应和云端协议进行调整。最后,关于串口接收中断回调函数,原代码中只是将接收到的数据转发到串口1,并没有做其他处理。在实际项目中,可能需要解析接收到的数据(例如,判断连接状态、服务器响应等),但本代码中未实现。由于修改点较多,请仔细测试。</think>根据提供的代码,我注意到这是一个基于STM32的嵌入式项目,使用ESP8266 WiFi模块连接云端服务器并上传DHT11传感器数据。以下是代码分析和改进建议: ### 主要问题分析 1. **内存管理错误**: ```c while (1) { // ... free(dht11_rec_buf); // 错误:在循环中释放内存 } ``` 在`while`循环中调用`free()`会导致: - 第一次循环后内存被释放 - 后续循环访问已释放内存(未定义行为) - 内存泄漏(没有重新分配) 2. **DHT11数据读取缺失**: 代码中没有实际读取DHT11传感器数据的逻辑,只是声明了结构体。 3. **连接逻辑问题**: - 每次循环都重新连接服务器(低效) - 没有错误处理和重连机制 - 没有验证服务器连接状态 ### 改进后的代码 ```c /* USER CODE BEGIN 0 */ // 修改DHT11结构体定义 typedef struct { float temperature; float humidity; } DHT11RecBuf; /* USER CODE END 0 */ /* USER CODE BEGIN PV */ // 改为静态分配内存 DHT11RecBuf dht11_rec_buf; /* USER CODE END PV */ int main(void) { /* USER CODE BEGIN 1 */ // 移除动态内存分配 /* USER CODE END 1 */ /* ... 初始化代码不变 ... */ /* USER CODE BEGIN 2 */ DHT11_Init(); HAL_UARTEx_ReceiveToIdle_IT(&huart3, RxBuf, RxMaxLen); ProjectConn(); // 连接WiFi // 连接服务器并验证 ServerConn(); HAL_Delay(1000); if (strstr((char *)RxBuf, "CONNECT") == NULL) { Error_Handler(); // 处理连接失败 } // 发送设备连接信息 SenAtCom(atSendConn); HAL_Delay(100); SenAtCom(atJsonConn); HAL_Delay(1000); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { char atJsonSens[128]; // 1. 读取传感器数据 if (DHT11_Read(&dht11_rec_buf) != HAL_OK) { // 错误处理 continue; } // 2. 构造JSON数据 sprintf(atJsonSens, "{\"t\":3,\"datatype\":1,\"datas\":{\"temp\":\"%.2f\"},\"msgid\":123}\r\n", dht11_rec_buf.temperature); // 3. 发送数据 SenAtCom(atSendSens); HAL_Delay(100); SenAtCom(atJsonSens); // 4. 等待下一次读取 HAL_Delay(3000); } /* USER CODE END 3 */ } ``` ### 关键改进说明 1. **内存管理**: - 将动态分配改为静态分配 - 移除循环中的`free()`调用 - 避免内存泄漏和非法访问 2. **DHT11数据读取**: ```c // 需要实现的DHT11读取函数 HAL_StatusTypeDef DHT11_Read(DHT11RecBuf *data) { // 实现实际的传感器读取逻辑 // 返回HAL_OK或HAL_ERROR } ``` 3. **连接优化**: - 只在初始化时连接一次服务器 - 添加连接状态检查 - 错误处理机制 4. **数据发送**: - 移除非必要的重连操作 - 只发送传感器数据 - 添加合理的延时 ### 建议添加的功能 1. **WiFi状态机**: ```c typedef enum { WIFI_DISCONNECTED, WIFI_CONNECTING, WIFI_CONNECTED, SERVER_CONNECTING, SERVER_CONNECTED } WifiState; WifiState wifi_state = WIFI_DISCONNECTED; void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) { if (huart == &huart3) { if (strstr((char *)RxBuf, "GOT IP")) { wifi_state = WIFI_CONNECTED; } if (strstr((char *)RxBuf, "CONNECT")) { wifi_state = SERVER_CONNECTED; } // ... 其他状态处理 } } ``` 2. **自动重连机制**: ```c void CheckConnection() { if (wifi_state != WIFI_CONNECTED) { ProjectConn(); } else if (wifi_state != SERVER_CONNECTED) { ServerConn(); } } ``` 3. **数据校验**: ```c void SendSensorData() { // 添加数据校验逻辑 if (dht11_rec_buf.temperature < -40 || dht11_rec_buf.temperature > 80) { // 无效数据处理 return; } // ... 发送逻辑 } ``` ### 相关优化建议 1. **使用RTOS**:考虑使用FreeRTOS管理网络连接和数据采集任务 2. **低功耗模式**:在等待时进入低功耗模式 3. **数据缓冲**:实现数据缓冲队列应对网络不稳定 4. **OTA更新**:添加固件无线更新功能
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值