STM32玩转物联网07-WIFI实验

前言
上一节我们学习了串口的简单使用,本节我们增加难度,做一个demo通过AT指令控制ESP8266,使用DMA方式接收ESP8266发来的数据,后续我们便开始通过ESP8266连接物联网云平台,敬请关注。
一、准备
1. ESP8266硬件准备
准备ESP8266模块,本实验使用便宜好用的ESP-01s模块,某宝只需要5RMB左右,很适合新手测试使用,ESP-01S默认支持AT指令,所谓AT指令是说WIFI厂商把复杂的TCP/IP协议坐在了ESP8266芯片内部了,单片机只需要通过串口发送AT+CMD形式的指令即可达到调用TCP/IP协议栈的功能,极大的降低了学习和开发成本。
在这里插入图片描述

2. ESP8266固件准备
更新AT MQTT固件,进入安信可官网,下载MQTT透传固件(固件号:1471),参考之前文章即可轻松完成烧录。
在这里插入图片描述

3. 硬件连接
注意串口2连接ESP01S模块,串口1连接串口工具
在这里插入图片描述

二、实例
1. 建立工程
将上节串口实验代码复制并修改名字为:7.WiFi,通过CubeMx关闭Usart2,打开Usart3,并设置DMA方法方式接收数据。
在这里插入图片描述
取消勾选USART3 global interrupt中断回调,打开DMA1 channel3 global interrupt。
在这里插入图片描述
Keil打开工程,查看stm32f1xx_it.c中相关配置如下:

/*** @brief This function handles DMA1 channel3 global interrupt.*/
void DMA1_Channel3_IRQHandler(void)
{/* USER CODE BEGIN DMA1_Channel3_IRQn 0 *//* USER CODE END DMA1_Channel3_IRQn 0 */HAL_DMA_IRQHandler(&hdma_usart3_rx);/* USER CODE BEGIN DMA1_Channel3_IRQn 1 *//* USER CODE END DMA1_Channel3_IRQn 1 */
}

按照下图顺序,创建Application/User/Driver文件夹。
在这里插入图片描述

同时在本地根目录中创建User文件夹,文件夹中创建esp8266.c和esp8266.h两个文件。
在这里插入图片描述

在Keil中Application/User/Driver处右击选择Add Existing Files to Group ‘Application/user/Driver’…选择上述创建的esp8266.c文件,将文件加入到工程。
在这里插入图片描述

将/User文件路径按照下图方式添加到工程,以便能访问到esp8266.h文件,
在这里插入图片描述

编辑esp8266.h内容如下,增加#ifndef #define #endif格式文件,防止因为重复包含头文件导致错误;重点关注Uart_Frame_Record_t结构体,该结构体内部访问共用体,希望结构体直接访问共用体内元素,需要增加#pragma anon_unions。

#ifndef __ESP8266_H
#define __ESP8266_H #include "main.h"
#include <stdio.h>
#include <string.h>
#include <stdbool.h>#pragma anon_unions// ESP8266 printf
#define ESP8266_USART(fmt, ...)  USART_printf (fmt, ##__VA_ARGS__)    
#define PC_USART(fmt, ...)       printf(fmt, ##__VA_ARGS__)       //这是串口打印函数,串口1,执行printf后会自动执行fput函数,重定向了printf。#define RX_BUF_MAX_LEN 1024       //最大字节数//ESP8266模式选择
typedef enum
{STA,AP,STA_AP  
}ENUM_Net_ModeTypeDef;//网络传输层协议,枚举类型
typedef enum{enumTCP,enumUDP,
} ENUM_NetPro_TypeDef;
//连接号,指定为该连接号可以防止其他计算机访问同一端口而发生错误
typedef enum{Multiple_ID_0 = 0,Multiple_ID_1 = 1,Multiple_ID_2 = 2,Multiple_ID_3 = 3,Multiple_ID_4 = 4,Single_ID_0 = 5,
} ENUM_ID_NO_TypeDef;//网络状态
typedef enum{WIFI_DISCONNECT= 0,WIFI_CONNECTED = 1,WIFI_GOT_IP = 2,WIFI_CLOUD_CONNECTED = 3,WIFI_CLOUD_FAILED = 4,
} ENUM_WIFI_STATUS_TypeDef;typedef struct _Uart_Frame_Record_t   //数据帧结构体
{char Data_RX_BUF[RX_BUF_MAX_LEN];union {__IO uint16_t InfAll;__IO uint16_t FramLength;}; }Uart_Frame_Record_t;extern Uart_Frame_Record_t Uart_Frame_Record;extern volatile int wifi_connect_status;//初始化和TCP功能函数
void ESP8266_Init(uint32_t bound);
void ESP8266_ATE0(void);
bool ESP8266_Send_AT_Cmd(char *cmd,char *ack1,char *ack2,uint32_t time);
bool ESP8266_Net_Mode_Choose(ENUM_Net_ModeTypeDef enumMode);
bool ESP8266_JoinAP( char * pSSID, char * pPassWord );
bool ESP8266_Enable_MultipleId ( FunctionalState enumEnUnvarnishTx );
bool ESP8266_Link_Server(ENUM_NetPro_TypeDef enumE, char * ip, char * ComNum, ENUM_ID_NO_TypeDef id);
bool ESP8266_UnvarnishSend ( void );
void ESP8266_ExitUnvarnishSend ( void );
uint8_t ESP8266_Get_LinkStatus ( void );uint8_t AT_Printf(char* fmt,...);
uint8_t ESP8266_SendCMD(uint8_t *cmd, uint8_t *ack, uint16_t waittime);
uint8_t ESP8266_SendData(uint8_t *tbuf, uint16_t len);
uint8_t ESP8266_APInit(char *name, char *password);
uint8_t ESP8266_STAInit(void);
uint8_t ESP8266_STAConnect(char *name, char *password);#endif

esp8266.c中内容如下所示:

#include "esp8266.h"
#include "usart.h"volatile int wifi_connect_status = 0;  Uart_Frame_Record_t Uart_Frame_Record= { 0 };  //定义了一个数据帧结构体//对ESP8266模块发送AT指令
// cmd 待发送的指令
// ack1,ack2;期待的响应,为NULL表不需响应,两者为或逻辑关系
// time 等待响应时间
//返回1发送成功, 0失败
bool ESP8266_Send_AT_Cmd(char *cmd,char *ack1,char *ack2,uint32_t time)
{Uart_Frame_Record.FramLength = 0; //重新接收新的数据包AT_Printf("%s\r\n", cmd);if(ack1==0&&ack2==0)     //不需要接收数据{return true;}delay_ms(time);   //延时Uart_Frame_Record.Data_RX_BUF[Uart_Frame_Record.FramLength ] = '\0';printf("------ %s", Uart_Frame_Record.Data_RX_BUF);if(ack1!=0&&ack2!=0){return ( ( bool ) strstr ( Uart_Frame_Record.Data_RX_BUF, ack1 ) || ( bool ) strstr ( Uart_Frame_Record.Data_RX_BUF, ack2 ) );}else if( ack1 != 0 )  //strstr(s1,s2);检测s2是否为s1的一部分,是返回该位置,否则返回false,它强制转换为bool类型了return ( ( bool ) strstr ( Uart_Frame_Record.Data_RX_BUF, ack1 ) );elsereturn ( ( bool ) strstr ( Uart_Frame_Record.Data_RX_BUF, ack2 ) );
}//发送恢复出厂默认设置指令将模块恢复成出厂设置
void ESP8266_ATE0(void)
{char count=0;delay_ms(1000); while(count < 10){if(ESP8266_Send_AT_Cmd("ATE0","OK",NULL,500)) {printf("OK\r\n");return;}++ count;}
}//发送恢复出厂默认设置指令将模块恢复成出厂设置
void ESP8266_AT_Restore(void)
{char count=0;delay_ms(1000); while(count < 10){if(ESP8266_Send_AT_Cmd("AT+RESTORE","OK",NULL,500)) {printf("OK\r\n");return;}++ count;}
}//选择ESP8266的工作模式
// enumMode 模式类型
//成功返回true,失败返回false
bool ESP8266_Net_Mode_Choose(ENUM_Net_ModeTypeDef enumMode)
{switch ( enumMode ){case STA:return ESP8266_Send_AT_Cmd ( "AT+CWMODE=1", "OK", "no change", 2500 ); case AP:return ESP8266_Send_AT_Cmd ( "AT+CWMODE=2", "OK", "no change", 2500 ); case STA_AP:return ESP8266_Send_AT_Cmd ( "AT+CWMODE=3", "OK", "no change", 2500 ); default:return false;}       
}//ESP8266连接外部的WIFI
//pSSID WiFi帐号
//pPassWord WiFi密码
//设置成功返回true 反之false
bool ESP8266_JoinAP( char * pSSID, char * pPassWord)
{char cCmd [120];sprintf ( cCmd, "AT+CWJAP=\"%s\",\"%s\"", pSSID, pPassWord );return ESP8266_Send_AT_Cmd( cCmd, "OK", NULL, 5000 );
}//ESP8266 透传使能
//enumEnUnvarnishTx  是否多连接,bool类型
//设置成功返回true,反之false
bool ESP8266_Enable_MultipleId (FunctionalState enumEnUnvarnishTx )
{char cStr [20];sprintf ( cStr, "AT+CIPMUX=%d", ( enumEnUnvarnishTx ? 1 : 0 ) );return ESP8266_Send_AT_Cmd ( cStr, "OK", 0, 500 );}//ESP8266 连接服务器
//enumE  网络类型
//ip ,服务器IP
//ComNum  服务器端口
//id,连接号,确保通信不受外界干扰
//设置成功返回true,反之fasle
bool ESP8266_Link_Server(ENUM_NetPro_TypeDef enumE, char * ip, char * ComNum, ENUM_ID_NO_TypeDef id)
{char cStr [100] = { 0 }, cCmd [120];switch (  enumE ){case enumTCP:sprintf ( cStr, "\"%s\",\"%s\",%s", "TCP", ip, ComNum );break;case enumUDP:sprintf ( cStr, "\"%s\",\"%s\",%s", "UDP", ip, ComNum );break;default:break;}if ( id < 5 )sprintf ( cCmd, "AT+CIPSTART=%d,%s", id, cStr);elsesprintf ( cCmd, "AT+CIPSTART=%s", cStr );return ESP8266_Send_AT_Cmd ( cCmd, "OK", "ALREAY CONNECT", 4000 );}//透传使能
//设置成功返回true, 反之false
bool ESP8266_UnvarnishSend ( void )
{if (!ESP8266_Send_AT_Cmd ( "AT+CIPMODE=1", "OK", 0, 500 ))return false;return ESP8266_Send_AT_Cmd( "AT+CIPSEND", "OK", ">", 500 );}//ESP8266 检测连接状态
//返回0:获取状态失败
//返回2:获得ip
//返回3:建立连接 
//返回4:失去连接 
uint8_t ESP8266_Get_LinkStatus ( void )
{if (ESP8266_Send_AT_Cmd( "AT+CIPSTATUS", "OK", 0, 500 ) ){if ( strstr ( Uart_Frame_Record.Data_RX_BUF, "STATUS:2\r\n" ) )return 2;else if ( strstr ( Uart_Frame_Record.Data_RX_BUF, "STATUS:3\r\n" ) )return 3;else if ( strstr ( Uart_Frame_Record.Data_RX_BUF, "STATUS:4\r\n" ) )return 4;       }return 0;
}//检测应答命令
static uint8_t* ESP8266_CheckCMD(uint8_t *str)
{
//    char *strx = 0;
//    if(Uart_Frame_Record.FramLength&0x8000)
//    { 
//        Uart_Frame_Record.Data_RX_BUF[Uart_Frame_Record.FramLength&0x7FFF] = 0;//添加结束符
//        strx = strstr((const char*)Uart_Frame_Record.Data_RX_BUF,(const char*)str);
//    }
//    return (uint8_t*)strx;return (uint8_t *)strstr((const char*)Uart_Frame_Record.Data_RX_BUF,(const char*)str);
}// 串口2 PA2 TX  PA3 RX
void Dev_UART3SendStr(uint8_t* tbuf, uint16_t tlen, uint8_t tByte){  uint16_t i = 0,j = 0;if(tlen > 0)j =  tlen;elsej = strlen((const char*)tbuf);for( i = 0; i < j; i++){if((tByte>0)&&(i==2)){HAL_UART_Transmit(&huart3, &tByte, 1, 10);}HAL_UART_Transmit(&huart3, &tbuf[i], 1, 10);}
}//cmd:发送的命令字符串
//ack:期待的应答结果,如果为空,则表示不需要等待应答
//返回值:0,发送成功  1,发送失败       
uint8_t ESP8266_SendCMD(uint8_t *cmd, uint8_t *ack,uint16_t waittime) 
{Uart_Frame_Record.FramLength = 0;memset((void *)Uart_Frame_Record.Data_RX_BUF, 0, sizeof(Uart_Frame_Record.Data_RX_BUF));Dev_UART3SendStr(cmd, 0, 0);if(ack&&waittime){while(--waittime){delay_ms(10);if(Uart_Frame_Record.FramLength&0x8000){if(ESP8266_CheckCMD(ack)){printf("AT: %s, ack: %s\r\n", cmd, Uart_Frame_Record.Data_RX_BUF);Uart_Frame_Record.FramLength = 0;                    return 0;  }else {Uart_Frame_Record.FramLength = 0;                    return 1;}}}if(waittime==0) {return 1;}}return 1;
}uint8_t AT_Printf(char* fmt,...)
{uint8_t  tbuf[300] = {0};uint16_t j = 0;va_list ap;va_start(ap, fmt);vsprintf((char*)tbuf, fmt, ap);va_end(ap);j = strlen((const char*)tbuf);HAL_UART_Transmit(&huart3, tbuf, j, 10);return 0; 
}uint8_t ESP8266_SendData(uint8_t *tbuf, uint16_t len)
{HAL_UART_Transmit(&huart3, tbuf, len, 10);return 0; 
}// STA模式下获取本地IP
void ESP8266_GetLocalIP(uint8_t* ipbuf)
{uint8_t *p,*p1;if(ESP8266_SendCMD( (uint8_t *)"AT+CIFSR\r\n", (uint8_t *)"OK", 50)){ipbuf[0] = 0;return;}p  = ESP8266_CheckCMD((uint8_t *)"\"");p1 = (uint8_t *)strstr((const char*)(p+1),"\"");*p1=0;sprintf((char*)ipbuf,"%s",p+1);
}//退出透传模式 0,退出成功; 1,退出失败
uint8_t ESP8266_QuitTrans(void)
{    ESP8266_SendData((uint8_t *)"+++", 3);delay_ms(500);                    //等待500msreturn ESP8266_SendCMD((uint8_t *)"AT\r\n",(uint8_t *)"OK",20);//退出透传判断
}//获取连接状态  0,未连接;1,连接成功.
uint8_t ESP8266_ConstaCheck(void)
{while(ESP8266_SendCMD((uint8_t *)"AT+CIPSTATUS\r\n",(uint8_t *)"OK",50));    return 0;
}uint8_t ESP8266_APInit(char *name, char *password)
{uint8_t Sbuf[60] ={0};while(ESP8266_SendCMD((uint8_t *)"AT\r\n",(uint8_t *)"OK",200)){//退出透传ESP8266_QuitTrans();//关闭透传模式            ESP8266_SendCMD((uint8_t *)"AT+CIPMODE=0\r\n",(uint8_t *)"OK",200);delay_ms(1000);}// 关闭回显while(ESP8266_SendCMD((uint8_t *)"ATE0\r\n",(uint8_t *)"OK",200));       // 设置波特率while(ESP8266_SendCMD((uint8_t *)"AT+UART=115200,8,1,0,0\r\n",(uint8_t *)"OK",200));    delay_ms(10);// 设置WIFI AP模式while(ESP8266_SendCMD((uint8_t *)"AT+CWMODE=2\r\n",(uint8_t *)"OK",200));while(ESP8266_SendCMD((uint8_t *)"AT+RST\r\n",(uint8_t *)"OK",200));        // 延时4秒等待重启成功    delay_ms(1000); delay_ms(1000);delay_ms(1000); delay_ms(1000);memset(Sbuf, 0 , sizeof(Sbuf));sprintf((char*)Sbuf, "AT+CWSAP=\"%s\",\"%s\",1,4\r\n", name, password);while(ESP8266_SendCMD(Sbuf, (uint8_t *)"OK", 1000));#ifdef UDP_Modewhile(ESP8266_SendCMD((uint8_t *)"AT+CIPMUX=0\r\n",(uint8_t *)"OK",200));       while(ESP8266_SendCMD((uint8_t *)"AT+CIPSTART=\"UDP\",\"255.255.255.255\",60156,42254,0\r\n",(uint8_t *)"OK",500));while(ESP8266_SendCMD((uint8_t *)"AT+CIPMODE=1\r\n",(uint8_t *)"OK",300));while(ESP8266_SendCMD((uint8_t *)"AT+CIPSEND\r\n",(uint8_t *)"OK",200));#endif    Uart_Frame_Record.FramLength = 0;memset((void *)Uart_Frame_Record.Data_RX_BUF, 0, sizeof(Uart_Frame_Record.Data_RX_BUF)); return 0;
}uint8_t ESP8266_STAConnect(char *name, char *password)
{uint8_t Sbuf[60] ={0};memset(Sbuf, 0 , sizeof(Sbuf));sprintf((char*)Sbuf,"AT+CWJAP=\"%s\",\"%s\"\r\n", name, password);   if(ESP8266_SendCMD( Sbuf, (uint8_t *)"WIFI GOT IP", 3000)){return 1;}return 0;
}uint8_t ESP8266_STAInit(void)
{   // 延时2秒等待串口初始化完成 while(ESP8266_SendCMD((uint8_t *)"AT\r\n",(uint8_t *)"OK",200)){//退出透传ESP8266_QuitTrans();//关闭透传模式        ESP8266_SendCMD((uint8_t *)"AT+CIPMODE=0\r\n",(uint8_t *)"OK",200);delay_ms(800);}// 关闭回显while(ESP8266_SendCMD((uint8_t *)"ATE0\r\n",(uint8_t *)"OK",200));       //    // 设置波特率
//    while(ESP8266_SendCMD((uint8_t *)"AT+UART=115200,8,1,0,0\r\n",(uint8_t *)"OK",200));delay_ms(10);// 设置WIFI STA模式while(ESP8266_SendCMD((uint8_t *)"AT+CWMODE=1\r\n",(uint8_t *)"OK",200));
//    while(ESP8266_SendCMD((uint8_t *)"AT+RST\r\n",(uint8_t *)"OK",200));     delay_ms(1000);
//    delay_ms(1000);
//    delay_ms(1000);return 1;  
}

2. 核心函数
main函数内容如下,调用__HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE)启动串口空闲中断,使用HAL_UART_Receive_DMA函数将Uart_Frame_Record.Data_RX_BUF设置为DMA接收存储区。

/* USER CODE BEGIN PV */uint8_t  Wssid[20]     = "ioter";
uint8_t  Wpassword[20] = "1234567980";
/* USER CODE END PV */int main(void)
{/* USER CODE BEGIN 1 /int ret = 0;/ USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* 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_DMA_Init();MX_USART1_UART_Init();MX_USART3_UART_Init();/ USER CODE BEGIN 2 */printf("start application\r\n");// 使能空闲中断__HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);HAL_UART_Receive_DMA(&huart3, (uint8_t *)Uart_Frame_Record.Data_RX_BUF, RX_BUF_MAX_LEN);  // 启动DMA接收// 连接路由器ESP8266_STAInit();delay_ms(1000);if (wifi_connect_status != WIFI_GOT_IP){while(ESP8266_STAConnect((char *)Wssid, (char *)Wpassword));}/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);printf("reset gpio!\r\n");HAL_Delay(1000); HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);printf("set gpio!\r\n");HAL_Delay(1000);        }return ret;/* USER CODE END 3 */
}

USART3_IRQHandler函数如下, 当串口接收完一帧数据后,会触发空闲中断,中断回调函数检测到空闲中断被触发,停止DMA接收数据,置位Uart_Frame_Record.FramLength,然后对接收的数据处理,通过wifi_event_cb函数将WIFI连接状态传送出去。

void USART3_IRQHandler(void)
{if(__HAL_UART_GET_FLAG(&huart3, UART_FLAG_IDLE) != RESET)  // 空闲中断标记被置位{__HAL_UART_CLEAR_IDLEFLAG(&huart3);  // 清除中断标记HAL_UART_DMAStop(&huart3);           // 停止DMA接收Uart_Frame_Record.FramLength = RX_BUF_MAX_LEN - __HAL_DMA_GET_COUNTER(huart3.hdmarx);  // 总数据量减去未接收到的数据量为已经接收到的数据量Uart_Frame_Record.Data_RX_BUF[Uart_Frame_Record.FramLength] = 0;  // 添加结束符     Uart_Frame_Record.FramLength |= 1 << 15;if (strstr(Uart_Frame_Record.Data_RX_BUF, "WIFI CONNECTED")){wifi_event_cb(WIFI_CONNECTED);}else if(strstr(Uart_Frame_Record.Data_RX_BUF, "WIFI DISCONNECT")){wifi_event_cb(WIFI_DISCONNECT);}else if(strstr(Uart_Frame_Record.Data_RX_BUF, "WIFI GOT IP")){wifi_event_cb(WIFI_GOT_IP);}HAL_UART_Receive_DMA(&huart3, (uint8_t *)Uart_Frame_Record.Data_RX_BUF, RX_BUF_MAX_LEN);  // 重新启动DMA接收}
}

接着我们看下ESP8266_SendCMD函数,该函数实现发送自定义AT指令,并根据结果判断AT指令是否执行成功,该函数为本节核心内容,函数首先清空缓存,然后调用串口发送函数将AT指令发送出去,然后进入while(–waittime)等待超时,如果正常收到数据Uart_Frame_Record.FramLength最高位会被置位,判断是否接收到ack数据。

//cmd:发送的命令字符串
//ack:期待的应答结果,如果为空,则表示不需要等待应答
//返回值:0,发送成功  1,发送失败       
uint8_t ESP8266_SendCMD(uint8_t *cmd, uint8_t *ack,uint16_t waittime) 
{Uart_Frame_Record.FramLength = 0;memset((void *)Uart_Frame_Record.Data_RX_BUF, 0, sizeof(Uart_Frame_Record.Data_RX_BUF));Dev_UART3SendStr(cmd, 0, 0);if(ack&&waittime){while(--waittime){delay_ms(10);if(Uart_Frame_Record.FramLength&0x8000){if(ESP8266_CheckCMD(ack)){printf("AT: %s, ack: %s\r\n", cmd, Uart_Frame_Record.Data_RX_BUF);Uart_Frame_Record.FramLength = 0;                    return 0;  }else {Uart_Frame_Record.FramLength = 0;                    return 1;}}}if(waittime==0) {return 1;}}return 1;
}

3. 程序执行
编译后下载程序,打开路由器或者设置WIFI热点,ioter:1234567980, 注意不要选择5G,ESP8266仅2.4G,串口1打印数据如下所示,看到WIFI GOT IP说明设备联网成功,并且得到了DHCP分配的IP地址。
在这里插入图片描述

三、小结
如您在使用过程中有任何问题,请加QQ群进一步交流。

QQ交流群:573122190 (备注:物联网项目交流)

小叶老师出品:种一棵树最好的时间是十年前,其次是现在!

完整代码获取:
https://download.csdn.net/download/weixin_45006076/89472819

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

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

相关文章

在C++中,构造器(Builder)模式的思考(《C++20设计模式》及常规设计模式对比)

文章目录 一、前言二、为什么需要Builder Pattern,Builder Pattern到底解决了什么实际问题&#xff1f;为什么不用set()方法&#xff1f;2.1 初学者有那些对象的属性初始化方法呢&#xff1f;2.1.1 构造函数的弊端2.1.1.1 对于属性的初始化只能是固定的顺序 2.1.2 用set()函数初…

兰州理工大学24计算机考研情况,好多专业都接受调剂,只有计算机专硕不接收调剂,复试线为283分!

兰州理工大学&#xff08;Lanzhou University of Technology&#xff09;&#xff0c;位于甘肃省兰州市&#xff0c;是甘肃省人民政府、教育部、国家国防科技工业局共建高校&#xff0c;甘肃省高水平大学和“一流学科”建设高校&#xff1b;入选国家“中西部高校基础能力建设工…

redis主从复制、哨兵、集群

在实际的生活环境中&#xff0c;如果只使用一个redis进行读写操作&#xff0c;那么面对庞大的访问人群是崩溃的&#xff0c;所以可以有几个redis&#xff0c;一个用来做主机&#xff0c;提供修改数据操作&#xff0c;而这个主机用来控制其他redis&#xff0c;即将更新的发送&am…

Windows程序设计课程作业-3(文件并发下载)

目录 目录 1.作业内容 2.作业要求 3.主要思路 1&#xff09;窗体和组件初始化 2&#xff09;下载管理器实例化 3&#xff09;按钮点击事件处理 4&#xff09;窗体加载事件处理 5&#xff09;下载消息处理 4.主要难点 1&#xff09;多线程管理&#xff1a; 2&#xff09…

材料科学SCI期刊,中科院3区,收稿范围广,易录用

一、期刊名称 International Journal of Material Forming 二、期刊简介概况 期刊类型&#xff1a;SCI 学科领域&#xff1a;材料科学 影响因子&#xff1a;2.4 中科院分区&#xff1a;3区 三、期刊征稿范围 该杂志发表和传播材料成型领域的原创研究。该研究应构成对材料…

理解广角镜头的视野和畸变

为什么广角镜头的视野会比长焦镜头的视野大呢&#xff1f; 我之前用等光程解释了景深&#xff0c;也解释了为什么焦距越远&#xff0c;成像越大&#xff0c;但是从来没有提到过视野范围这个概念。实际上在我之前建立的数学模型中&#xff0c;物曲面S是无限大的&#xff0c;像曲…

Chromium 调试指南2024 - 远程开发(下)

1. 引言 在《Chromium 调试指南2024 - 远程开发&#xff08;上&#xff09;》中&#xff0c;我们探讨了远程开发的基本概念、优势以及如何选择合适的远程开发模式。掌握了这些基础知识后&#xff0c;接下来我们将深入了解如何在远程环境中高效地进行Chromium项目的调试工作。 …

鹅算法(GOOSE Algorithm,GOOSE)求解复杂城市地形下无人机避障三维航迹规划,可以修改障碍物及起始点(Matlab代码)

一、鹅算法 鹅优化算法&#xff08;GOOSE Algorithm&#xff0c;GOOSE)从鹅的休息和觅食行为获得灵感&#xff0c;当鹅听到任何奇怪的声音或动作时&#xff0c;它们会发出响亮的声音来唤醒群中的个体&#xff0c;并保证它们的安全。 参考文献 [1]Hamad R K, Rashid T A. GOO…

数据结构和算法(1) ---- Queue 的原理和实现

Queue 的定义和结构 队列(Queue) 是只允许在一端进行插入&#xff0c;在另一端进行删除的线性表 队列是一种先进先出(First In First Out)的线性表&#xff0c;简称 FIFO(First IN First OUT), 允许插入的一端称为队尾, 允许删除的一端称为队列头 队列的基本结构如下图所示&a…

FreeCAD中智能指针分析

实现原理 FreeCAD中有两套智能指针&#xff0c;一个是OCC的智能指针handle&#xff0c;另一个是自己定义的智能指针Reference&#xff0c;两种智能指针都是通过引用计数方式管理指针。 1.1 OCC智能指针handle OCC在基础类包中定义了一个模板类handle&#xff0c;该类包含一个私…

大学物理(下)笔记

摘录来自笔记网站的笔记。笔记网站详见https://onford.github.io/Notes/。 大学物理&#xff08;下&#xff09;笔记 部分常用物理常量的计算值 C h a p t e r 9 Chapter9 Chapter9 恒定磁场 毕奥-萨伐尔定律 磁场和电场在很多性质上是有共性的&#xff0c;很多时候可以拿它…

【pytorch05】索引与切片

索引 a[0,0]第0张图片的第0个通道 a[0,0,2,4]第0张图片&#xff0c;第0个通道&#xff0c;第2行&#xff0c;第4列的像素点&#xff0c;dimension为0的标量 选择前/后N张图片 a[:2,:1,:,:].shape前两张图片&#xff0c;第1个通道上的所有图片的数据 a[:2,1:,:,:].shape前两张…

ADD属性驱动架构设计(一)

目录 一、架构设计过程 1.1、架构设计过程 1.1.1、设计目的 1.1.2、质量属性&#xff08;非功能需求&#xff09; 1.1.3、核心功能&#xff08;功能需求&#xff09; 1.1.4、架构关注 1.1.5、约束条件 1.2、基于设计过程 二、什么是ADD? 三、为什么选择ADD? 四、作…

本地离线模型搭建指南-中文大语言模型底座选择依据

搭建一个本地中文大语言模型&#xff08;LLM&#xff09;涉及多个关键步骤&#xff0c;从选择模型底座&#xff0c;到运行机器和框架&#xff0c;再到具体的架构实现和训练方式。以下是一个详细的指南&#xff0c;帮助你从零开始构建和运行一个中文大语言模型。 本地离线模型搭…

鸿蒙开发系统基础能力:【@ohos.hiAppEvent (应用打点)】

应用打点 本模块提供了应用事件打点能力&#xff0c;包括对打点数据的落盘&#xff0c;以及对打点功能的管理配置。 说明&#xff1a; 本模块首批接口从API version 7开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。 导入模块 import hiAppEve…

今日分享:中国石油年金系统交互、视觉设计和vue开发

金融系统交互及UI设计时&#xff0c;需注意简洁明了、色彩合理、字体统一、交互易用、安全感和用户控制。确保用户快速理解、安全操作并提升体验。

数据结构~~时间、空间复杂度

目录 一、什么是数据结构 什么是算法 算法的复杂度 二、时间复杂度 三、空间复杂度 四、总结 一、什么是数据结构 数据结构(Data Structure)是计算机存储、组织数据的方式&#xff0c;指相互之间存在一种或多种特定关系的 数据元素的集合。 数据结构关注的是数据的逻辑结…

快速搭建Jenkins自动化集成cicd工具

一、简介 jenkins是一款优秀的自动化持续集成运维工具&#xff0c;可以极大的简化运维部署的步骤。 传统的项目部署需要手动更换最新的项目代码&#xff0c;然后打包并运行到服务器上。 使用Jenkins可以自动化实现&#xff0c;当代码编写完成并提交到git后&#xff0c;Jenki…

通过 cloudflare 白嫖个人 docker 镜像加速服务

不知为何&#xff0c;现在大多数的 docker hub 镜像加速站都停止服务&#xff0c;而官方站点又因某些原因访问不到或延迟很高。所以&#xff0c;今天来记录一种通过 CloudFlare 搭建一个自己的镜像加速服务。 0、必看&#xff01;&#xff01;&#xff01; 注意&#xff1a; 此…

pywebview打包本地的html

51.安装 pip install pywebview 2.新建start.py import webview import timeclass API:def say_hello(self, name):time.sleep(2) # 模拟一个耗时操作return fHello, {name}!def main():api API()webview.create_window(pywebview Example, index.html, js_apiapi)webview.…