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

基于STM32的智能家居语音系统(单片机毕设)

前言

源代码下载链接:

  • https://download.csdn.net/download/m0_74712453/90071680

需要实物的可以私信博主或者在文章最下方添加好友。

目录

一、项目介绍和演示视频

二、硬件实现

1. 材料材料

2. 原理图和PCB

三、软件实现

1. 代码解析

1.1 main函数

1.2 SysParam_t

1.3 TIME_HandleType 

1.4 初始化函数

1.5 app_Process( SysParam_t *p_SysParamHandle )

2. 机智云平台搭建以及代码移植 

2.1 APP制作

2.2 给ESP8266模块烧录固件

2.3 代码移植

2.4 总结

3. SNR8016VR_DEV智能语音模块

3.1 智能公元平台

3.2 创建产品

3.3 配置语音模块

3.4 生成SDK固件烧录 


一、项目介绍和演示视频

        基于STM32构建的智能家居语音控制系统,采用ESP8266(01s)作为关键的WiFi模块。这一系统通过机智云开发平台实现与ESP8266的高效通信,遵循平台规范的协议,确保数据的可靠传输。系统支持WIFI_AIRLINK_MODE,实现一键智能配网,简化用户的设置过程。

        通过专用的手机APP,用户可以实时监测家中的环境参数,包括温度、湿度、气体浓度和光照强度等。此外,用户还可以便捷地控制家中的灯光与风扇开关,将智能家居的便捷性与舒适性完美结合,提升了现代居住空间的智能化体验。该系统不仅提升了居家生活的便利性,更通过语音控制功能赋予用户更为人性化的交互方式,助力构建更加智能、环保的家庭环境。

功能演示:

stm32的智能家居语音系统

二、硬件实现

1. 材料材料

  • 1、STM32F103C8T6最小系统板。
  • 2、ESP8266 01s 模块。
  • 3、SNR8016智能语音模块。
  • 4、DHT11温湿度模块。
  • 5、0.96寸OLED屏幕(I2C通信)。
  • 6、MQ-2烟雾气敏传感器。
  • 7、5v继电器。
  • 8、GY-30数字光照传感器。
  • 9、步进电机28BYJ48+ULN2003驱动板。
  • 10、200欧、4.7K电阻(0603封装)。
  • 11、LED灯(绿色、蓝色、黄色)。
  • 12、蜂鸣器。
  • 13、USB 5V供电模块。
  • 14、三极管、开关二极管。

2. 原理图和PCB

原理图设计:

PCB打样图:

三、软件实现

1. 代码解析

1.1 main函数

  • 1、初始化系统时钟,配置时钟树,系统时钟配置为72MHZ。
  • 2、配置NVIC中断为NVIC_PriorityGroup_1,1 bits for pre-emption priority     3 bits for subpriority */。
  • 3、初始化硬件延时,配置滴答定时器的时钟,实现毫秒延时功能。
  • 4、板级初始化,初始化各个外设。
  • 5、主循环:app_Process( &SysParamHandle );处理事件和任务。

代码如下:

int main ( void )
{ /* 系统时钟树配置 */RCC_Configuration();/* 中断系统配置 */NVIC_Configuration();/* 初始化硬件延时, 使用滴答定时器完成 */delay_init();/* 板级初始化 */app_BspInit( &SysParamHandle );Key2_long_press_down_handle();/* 主循环 */while ( 1 ){  app_Process( &SysParamHandle );delay_ms(1000);}
}

这里最关键的有两个函数,app_BspInit( &SysParamHandle );以及app_Process( &SysParamHandle ),我们再围绕这两个分析一下。

1.2 SysParam_t

  • 这个结构体记录的所有传感器的变量,每一个都非常重要。

代码如下:

typedef struct SysParamType
{ePageIDType PageID;eModeType eMode;u8 u8EventReg;u8 u8GizwistCode;u8 u8KeyCode;u8 u8TrashStatusBits;u8 u8CurtainFlg;u16 u16Lightness;float fMqValue;bool blWarn;u32 u32SensorTim;u32 u32LcdUpdateTim;u32 u32SyncDataTim;u32 u32CycleWarnTim;eMotorDutyCycle    eMotorStat;DHT11_Data_TypeDef     *psDHT11DataHandle;LD3322Handle_t         *psLdHandle;sKeyHandle_t         *p_keyhandle; dataPoint_t            *p_DataPoint;
}SysParam_t;

1.3 TIME_HandleType 

  • 这个结构体记录了注册进入定时器回调函数的数目,超时事件,以及对应的回调函数。

代码如下:

typedef struct{uint16_t ucSupportCnt;                          /*!< 注册的定时回调函数的数目 */TIME_FunType tCallFun[SUPPORT_FUN_MAX_NUM];     /*!< 注册的定时回调函数 */uint32_t ui1msTic;                              /*!< 1ms定时 */uint32_t uimsDelayTic;                          /*!< 1ms定时 */
} TIME_HandleType;

1.4 初始化函数

板级初始化:app_BspInit( &SysParamHandle )

代码如下:

void app_BspInit( SysParam_t *p_SysParamHandle )
{/* debug log uart config */DEBUG_UART_Config( );DEBUG_LOG("Bsp init\n");/* 上电延时,等待各个模块运行稳定 */delay_ms( 200 );/* 初始化定时器3, 中断频率 1000hz */FML_TIME_Init();/*****************************************************************************************************************//* *************************注册系统时间片处理函数************************************************************** *//*****************************************************************************************************************/FML_TIME_Register(Sys_timer_handle, 1);    //系统时间片,1tick = 1msFML_TIME_Start(Sys_timer_handle); //开启定时 /*****************************************************************************************************************//* *************************** 初始化IO设备 ******************************************************************** *//*****************************************************************************************************************//* 配置按键引脚 *///Key_GPIO_Config(p_SysParamHandle->p_keyhandle);    /* LED Fan IO 初始化 */LED_Init( );BEEP_Init();Moto_Init();/*****************************************************************************************************************//* ************************* 主模块开机运行检测 ***************************************************************** *//******************************************************************************************************************//* dht11 初始化 */DHT11_Init();/* 语音模块初始化 */ld3322_init( );RegisterLd3322(p_SysParamHandle->psLdHandle, CmdList, CMD_NUM);    /*!< 注册指令参数表 */Switch_GPIO_Config( );/* 机智云SDK初始化 */Gizwits_Init();/* 0.96OLED初始化 */OLED_Init();BH1750_Init();ADC_Sensor_Init();/*!< 延时确保初始页面错误 */delay_ms(300);/* OLED显示初始画面 */OLED_InitPage( ); }

函数讲解:

1、DEBUG_UART_Config以及DEBUG_LOG,这些是串口3发出的调试信息,我们这里忽略不理。

2、 FML_TIME_Init();初始化定时器2, 中断频率 1000hz,1ms进一次中断服务函数。这个中断大有用处,类似FreeRTOS的时间片轮转,每过1ms进行执行一次任务,这里首先进入中断,会判断是否有回调函数注册,有的话,就每毫秒去执行他一次,这里用于定时,因为传感器数据如果放在while里,不断的读,会导致读的太快,这很容易出现问题,并且也没有这个必要。

3、注册Sys_timer_handle回调函数,每过一毫秒执行一次。

代码如下:

static void Sys_timer_handle( void )
{u32SysTick++;static u32 warnLed_tick = 0;/* 键盘时间片 */if (SysParamHandle.p_keyhandle->u32_keyscan_time > 0){SysParamHandle.p_keyhandle->u32_keyscan_time--;    } if (SysParamHandle.u32SensorTim > 0){SysParamHandle.u32SensorTim--;    } if (SysParamHandle.u32LcdUpdateTim > 0){SysParamHandle.u32LcdUpdateTim--;    } if (SysParamHandle.u32SyncDataTim > 0){SysParamHandle.u32SyncDataTim--;    }if (SysParamHandle.u32CycleWarnTim > 0){SysParamHandle.u32CycleWarnTim--;    }if (u32SysTick - warnLed_tick > 500){warnLed_tick  = u32SysTick;if (SysParamHandle.blWarn == TRUE){WARN_LED_FLASH;}else{WARN_LED_OFF;}}/* 继电器 */gizTimerMs();
}

4、各个基本传感器外设的初始化。

5、RegisterLd3322(p_SysParamHandle->psLdHandle, CmdList, CMD_NUM);    /*!< 注册指令参数表 */,需要把CmdList里面的指令以及回调函数注册到p_SysParamHandle结构体里面的psLdHandle,语音模块在发送对应指令给STM32之后,可以对应特定的指令执行对应的回调函数,比如:开灯/关灯。

代码如下:

/* 指令列表 */
CmdHandle_t CmdList[CMD_NUM] = 
{"开灯",            TurnONLight,"关灯",            TurnOffLight,"开风扇",         TurnOnAirCondit,"关风扇",         TurnOffAirCondit,"开窗帘",         OpenCurtain,"关窗帘",         CloseCurtain,"自动模式",     SetAutoMode,"手动模式",     SetManualMode,"热点配网",     Key2_short_press_up_handle,"一键配网",     Key2_long_press_down_handle,
};

5、机智云SDK初始化 。

代码如下:

void Gizwits_Init( void )
{uart1_init(9600); gizwitsInit();gizwits_dataPoint_Init();extern GizwitsCallback gfunCallback;gfunCallback = GizwitsDataEventHandle;
}

首先初始化串口1,用于STM32与ESP8266进行通信。

代码如下:

void gizwitsInit(void)
{    pRb.rbCapacity = RB_MAX_LEN;pRb.rbBuff = rbBuf;if(0 == rbCreate(&pRb)){GIZWITS_LOG("rbCreate Success \n");}else{GIZWITS_LOG("rbCreate Faild \n");}memset((uint8_t *)&gizwitsProtocol, 0, sizeof(gizwitsProtocol_t));
}

之后创建一个环形BUFF,来接收ESP8266发来的数据帧。

gizwitsProtocol,这里有个结构体,是机智云协议中很重要的一个结构体。

代码如下:

/** Protocol main and very important struct */
typedef struct
{uint8_t issuedFlag;                             ///< P0 action typeuint8_t protocolBuf[MAX_PACKAGE_LEN];           ///< Protocol data handle bufferuint8_t transparentBuff[MAX_PACKAGE_LEN];       ///< Transparent data storage areauint32_t transparentLen;                        ///< Transmission data lengthuint32_t sn;                                    ///< Message SNuint32_t timerMsCount;                          ///< Timer Count protocolWaitAck_t waitAck;                      ///< Protocol wait ACK data structureeventInfo_t issuedProcessEvent;                 ///< Control eventseventInfo_t wifiStatusEvent;                    ///< WIFI Status eventseventInfo_t NTPEvent;                           ///< NTP eventseventInfo_t moduleInfoEvent;                    ///< Module Info eventsdataPointFlags_t  waitReportDatapointFlag;      ///< Store the data points to be reported flaguint8_t reportData[sizeof(gizwitsElongateP0Form_t)];    ///< Reporting actual data , Max , Can hold all datapoints valueuint32_t reportDataLen;                         ///< Reporting actual data lengthdataPoint_t gizCurrentDataPoint;                ///< Current device datapoints statusdataPoint_t gizLastDataPoint;                   ///< Last device datapoints statusmoduleStatusInfo_t wifiStatusData;              ///< WIFI signal intensityprotocolTime_t TimeNTP;                         ///< Network time information
#if MODULE_TYPEgprsInfo_t   gprsInfoNews;
#else  moduleInfo_t  wifiModuleNews;                   ///< WIFI module Info
#endif}gizwitsProtocol_t;

gizwitsProtocol_t 结构体是一个复杂的数据结构,用于管理和处理与设备通信相关的各种信息和状态。它主要用于在智能设备(如基于STM32的智能家居系统)和云平台(如机智云)之间进行协议数据的处理和传输。以下是结构体中各个字段的主要功能:

1.uint8_t issuedFlag: 这个字段表示当前操作的类型(例如,发送的命令或请求的类型)。通常用于标识不同的协议操作或数据类型。
2.uint8_t protocolBuf[MAX_PACKAGE_LEN]: 这是一个缓冲区,用于存储协议数据的处理。它接收和存储从网络接收到的数据包,或准备要发送的数据包。
3.uint8_t transparentBuff[MAX_PACKAGE_LEN]: 这是一个透明数据存储区,用于处理不经过协议解析的数据。它可能用于存储原始数据,以便在需要时直接传输或处理。
4.uint32_t transparentLen: 这个字段记录了透明数据的传输长度。它用于标记transparentBuff中数据的实际大小,以确保数据的完整传输和处理。
5.uint32_t sn: 消息序列号,用于标识每一条消息。它可以用于追踪消息的顺序和处理状态,以及用于消息的确认(ACK)机制。
6.uint32_t timerMsCount: 计时器计数器,用于追踪时间间隔。它可以用于超时检测或定时任务的执行。
7.protocolWaitAck_t waitAck: 这是一个数据结构,用于管理和存储等待确认(ACK)消息的相关信息。它帮助处理消息确认机制,确保消息的可靠传输。
8.eventInfo_t issuedProcessEvent: 控制事件的数据结构,用于记录和处理设备控制相关的事件,例如用户操作或状态变更。
9.eventInfo_t wifiStatusEvent: 记录WiFi状态事件的信息,例如连接状态、信号强度等,用于监控WiFi连接情况。
10.eventInfo_t NTPEvent: 记录网络时间协议(NTP)事件的信息,通常用于同步网络时间。
11.eventInfo_t moduleInfoEvent: 记录模块信息事件,例如设备的状态或配置变化。
12.dataPointFlags_t waitReportDatapointFlag: 存储待报告数据点的标志。用于指示哪些数据点需要被报告或发送。
13.uint8_t reportData[sizeof(gizwitsElongateP0Form_t)]: 用于存储实际报告的数据。它能够容纳所有数据点的值,准备将数据发送到云平台或其他系统。
14.uint32_t reportDataLen: 报告数据的实际长度,用于标记reportData中数据的大小。
15.dataPoint_t gizCurrentDataPoint: 当前设备数据点的状态,记录设备当前的所有传感器和控制点的实时数据。
16.dataPoint_t gizLastDataPoint: 上一次设备数据点的状态,用于与当前数据进行比较,以检测变化或执行必要的操作。
17.moduleStatusInfo_t wifiStatusData: WiFi信号强度的信息,用于监控和优化WiFi连接质量。
18.protocolTime_t TimeNTP: 网络时间信息,用于同步设备时间,确保时间戳的准确性。
19.#if MODULE_TYPE:

20.gprsInfo_t gprsInfoNews: 如果设备使用GPRS模块,该字段存储GPRS模块的信息。
#else:

21.moduleInfo_t wifiModuleNews: 如果设备使用WiFi模块,该字段存储WiFi模块的信息。

总的来说,gizwitsProtocol_t 结构体是一个综合性的数据管理和处理结构,涵盖了协议处理、数据存储、事件管理和模块信息等方面的功能,为智能设备与云平台的高效通信提供了支持。

void gizwits_dataPoint_Init( void )
{memset((uint8_t*)&currentDataPoint, 0, sizeof(dataPoint_t));/** Warning !!! DataPoint Variables Init , Must Within The Data Range **/ }/** User Area Device State Structure */
typedef struct {bool valuelight;bool valuefan;uint32_t valuetemperature;uint32_t valuehumi;
} dataPoint_t;

初始化currentDataPoint这个结构体,这个是用来APP显示实时数据的值,我们需要不断的更新里面的值,便于APP显示。

GizwitsDataEventHandle:

static void GizwitsDataEventHandle ( int code, void *pvParam )
{DEBUG_LOG("**********GizwitsDataEventHandle***********\n");dataPoint_t *psCurrentDP = (dataPoint_t *)pvParam;switch (code){case EVENT_light:if (psCurrentDP->valuelight == 1){TurnONLight( );}else{TurnOffLight( );}break;case EVENT_fan:if (psCurrentDP->valuefan== 1){TurnOnAirCondit( );}else{TurnOffAirCondit( );}break;case WIFI_NTP:break;    default:/* 按键事件 - 置位 *///SetBit(SysParamHandle.u8EventReg, Gizwits_EVENT_BIT);break;}
}

这个就明显了,回调函数,这样子我们就可以在收到对应事件后,处理对应任务,比如APP关灯事件到来,我们单片机回调TurnOffLight()函数。

6、OLED显示初始画面。

代码如下:

void OLED_InitPage(void)
{/* 清屏 */OLED_CLS();OLED_ShowCnAndAsciiStr(0,          0,        "温度:", 2);OLED_ShowCnAndAsciiStr(0,          2,        "湿度:", 2);OLED_ShowCnAndAsciiStr(0,          4,        "光照强度:", 2);OLED_ShowCnAndAsciiStr(0,          6,        "烟雾浓度:", 2);}

1.5 app_Process( SysParam_t *p_SysParamHandle )

while循环中不断轮询的函数,最为关键的一个函数。

void app_Process( SysParam_t *p_SysParamHandle )
{
/***************** 底层驱动 **********************/ /* 传感器数据过去 - 线程 */ drv_Sensor_Handle( p_SysParamHandle );/* ld3320语音识别模块 - 线程 */ drv_Ld3322_Handle(p_SysParamHandle->psLdHandle);/***************** 中间层 **********************/     /* 机智云云端协议处理 - 任务 */gizwitsHandle( p_SysParamHandle->p_DataPoint );/* 机智云数据同步 - 任务 */app_SyncData_Task( p_SysParamHandle );/* oled参数更新 - 任务 */app_OledUpdateParam( p_SysParamHandle );
/***************** 应用层事件 **********************/     /* 系统控制任务 - 线程 */ app_Ctl_Task( p_SysParamHandle );/* 机智云事件处理 - 线程 */ app_GizwitsDataEvent_Handle( p_SysParamHandle );
}

  /* 传感器数据过去 - 线程 */ 

void drv_Sensor_Handle( SysParam_t *p_SysParamHandle )
{if (p_SysParamHandle->u32SensorTim == 0){p_SysParamHandle->u32SensorTim = 200;p_SysParamHandle->u16Lightness = bh_data_read( );    //!< 读取光照强度get_mq2_value( &p_SysParamHandle->fMqValue );    //!< 读取烟雾浓度DHT11_Read_TempAndHumidity( p_SysParamHandle->psDHT11DataHandle );    //!< 读取温湿度}
}

200s来进行读取一次传感器数据,把数据更新到p_SysParamHandle结构体。

/* ld3320语音识别模块 - 线程 */  

void drv_Ld3322_Handle( LD3322Handle_t *psLdHandle )
{uint16_t index;if (psLdHandle->bl_rev_cmd_flg == CMD_REV_OK){psLdHandle->bl_rev_cmd_flg = CMD_REV_NO_OK;for (index=0; index<psLdHandle->u16_cmd_num; index++){if (!strcmp(psLdHandle->pCmdTable[index].cmd_str, psLdHandle->pu8_rev_cmd_buf)){psLdHandle->pCmdTable[index].funCallback();DEBUG_LOG("Ld3322 check OK\n");break;}}if (index == psLdHandle->u16_cmd_num){DEBUG_LOG("Ld3322 Erorr\n");}User_MemSet(psLdHandle->pu8_rev_cmd_buf, 0x0, 30);}
}

我们在进行语音命令被语音模块识别之后,语音模块会通过串口发送对应的指令给我们单片机,我们单片机根据指令,执行对应指令的回调函数。

/* 机智云云端协议处理 - 任务 */

nt32_t gizwitsHandle(dataPoint_t *currentData)
{int8_t ret = 0;
#ifdef PROTOCOL_DEBUGuint16_t i = 0;
#endifuint8_t ackData[RB_MAX_LEN];uint16_t protocolLen = 0;uint32_t ackLen = 0;protocolHead_t *recvHead = NULL;char *didPtr = NULL;uint16_t offset = 0;if(NULL == currentData){GIZWITS_LOG("GizwitsHandle Error , Illegal Param\n");return -1;}/*resend strategy*/gizProtocolAckHandle();ret = gizProtocolGetOnePacket(&pRb, gizwitsProtocol.protocolBuf, &protocolLen);if(0 == ret){GIZWITS_LOG("Get One Packet!\n");#ifdef PROTOCOL_DEBUGGIZWITS_LOG("WiFi2MCU[%4d:%4d]: ", gizGetTimerCount(), protocolLen);for(i=0; i<protocolLen;i++){GIZWITS_LOG("%02x ", gizwitsProtocol.protocolBuf[i]);}GIZWITS_LOG("\n");
#endifrecvHead = (protocolHead_t *)gizwitsProtocol.protocolBuf;switch (recvHead->cmd){case CMD_GET_DEVICE_INTO:gizProtocolGetDeviceInfo(recvHead);break;case CMD_ISSUED_P0:GIZWITS_LOG("flag %x %x \n", recvHead->flags[0], recvHead->flags[1]);//offset = 1;if(0 == gizProtocolIssuedProcess(didPtr, gizwitsProtocol.protocolBuf+sizeof(protocolHead_t)+offset, protocolLen-(sizeof(protocolHead_t)+offset+1), ackData, &ackLen)){gizProtocolIssuedDataAck(recvHead, ackData, ackLen,recvHead->flags[1]);GIZWITS_LOG("AckData : \n");}break;case CMD_HEARTBEAT:gizProtocolCommonAck(recvHead);break;case CMD_WIFISTATUS:gizProtocolCommonAck(recvHead);gizProtocolModuleStatus((protocolWifiStatus_t *)recvHead);break;case ACK_REPORT_P0:case ACK_WIFI_CONFIG:case ACK_SET_DEFAULT:case ACK_NINABLE_MODE:case ACK_REBOOT_MODULE:gizProtocolWaitAckCheck(recvHead);break;case CMD_MCU_REBOOT:gizProtocolCommonAck(recvHead);GIZWITS_LOG("report:MCU reboot!\n");gizProtocolReboot();break;case CMD_ERROR_PACKAGE:break;case ACK_PRODUCTION_TEST:gizProtocolWaitAckCheck(recvHead);GIZWITS_LOG("Ack PRODUCTION_MODE success \n");break;           case ACK_GET_NTP:gizProtocolWaitAckCheck(recvHead);gizProtocolNTP(recvHead);GIZWITS_LOG("Ack GET_UTT success \n");break; case ACK_ASK_MODULE_INFO:gizProtocolWaitAckCheck(recvHead);gizProtocolModuleInfoHandle(recvHead);GIZWITS_LOG("Ack GET_Module success \n");break;default:gizProtocolErrorCmd(recvHead,ERROR_CMD);GIZWITS_LOG("ERR: cmd code error!\n");break;}}else if(-2 == ret){//Check failed, report exceptionrecvHead = (protocolHead_t *)gizwitsProtocol.protocolBuf;gizProtocolErrorCmd(recvHead,ERROR_ACK_SUM);GIZWITS_LOG("ERR: check sum error!\n");return -2;}switch(gizwitsProtocol.issuedFlag){case ACTION_CONTROL_TYPE:gizwitsProtocol.issuedFlag = STATELESS_TYPE;gizwitsEventProcess(&gizwitsProtocol.issuedProcessEvent, (uint8_t *)&gizwitsProtocol.gizCurrentDataPoint, sizeof(dataPoint_t));memset((uint8_t *)&gizwitsProtocol.issuedProcessEvent,0x0,sizeof(gizwitsProtocol.issuedProcessEvent));  break;case WIFI_STATUS_TYPE:gizwitsProtocol.issuedFlag = STATELESS_TYPE;gizwitsEventProcess(&gizwitsProtocol.wifiStatusEvent, (uint8_t *)&gizwitsProtocol.wifiStatusData, sizeof(moduleStatusInfo_t));memset((uint8_t *)&gizwitsProtocol.wifiStatusEvent,0x0,sizeof(gizwitsProtocol.wifiStatusEvent));break;case ACTION_W2D_TRANSPARENT_TYPE:gizwitsProtocol.issuedFlag = STATELESS_TYPE;gizwitsEventProcess(&gizwitsProtocol.issuedProcessEvent, (uint8_t *)gizwitsProtocol.transparentBuff, gizwitsProtocol.transparentLen);break;case GET_NTP_TYPE:gizwitsProtocol.issuedFlag = STATELESS_TYPE;gizwitsEventProcess(&gizwitsProtocol.NTPEvent, (uint8_t *)&gizwitsProtocol.TimeNTP, sizeof(protocolTime_t));memset((uint8_t *)&gizwitsProtocol.NTPEvent,0x0,sizeof(gizwitsProtocol.NTPEvent));break;case GET_MODULEINFO_TYPE:gizwitsProtocol.issuedFlag = STATELESS_TYPE;gizwitsEventProcess(&gizwitsProtocol.moduleInfoEvent, (uint8_t *)&gizwitsProtocol.wifiModuleNews, sizeof(moduleInfo_t));memset((uint8_t *)&gizwitsProtocol.moduleInfoEvent,0x0,sizeof(moduleInfo_t));break;default:break;      }gizDevReportPolicy(currentData);return 0;
}

● 首先是一些局部变量的初始化,比较重要的是:“protocolHead_t *recvHead = NULL;”它的作用是保存解析出来的协议包头。

● 然后是协议的重发机制,它的作用是对发送后的协议数据进行超时判断,超时200ms进行重发,重发上限为三次:

 gizProtocolAckHandle();

● 接下来程序会从环形缓冲区中抓取一包的数据,

ret = gizProtocolGetOnePacket(&pRb, gizwitsProtocol.protocolBuf, &protocolLen);

● 当我们获得到一整包的数据,就会进入下面的if判断逻辑,进行协议的解析。

if(0 == ret)

{

}

● 这里保存了接收到的协议包头:

recvHead = (protocolHead_t *)gizwitsProtocol.protocolBuf;

● 然后是各协议命令的处理流程:

其中完成了《机智云 - 设备串口通讯协议》中相关的协议处理,如下:

● 协议判断完成后是一个状态机的判断,用来完成对应协议命令的处理:

例如在P0协议处理函数(gizProtocolIssuedProcess)中,当我们完成了控制型协议的解析,会让 issuedFlag = 1,如下:

case ACTION_CONTROL_TYPE:gizwitsProtocol.issuedFlag = STATELESS_TYPE;gizwitsEventProcess(&gizwitsProtocol.issuedProcessEvent, (uint8_t *)&gizwitsProtocol.gizCurrentDataPoint, sizeof(dataPoint_t));memset((uint8_t *)&gizwitsProtocol.issuedProcessEvent,0x0,sizeof(gizwitsProtocol.issuedProcessEvent));  break;

然后会执行如下的处理,执行gizwitsEventProcess函数

gizwitsEventProcess 中,完成了对应控制型事件的处理,其他状态的issuedFlag 同理。

● 之后是一个数据上报判断机制,主要执行了gizCheckReport函数

static void gizDevReportPolicy(dataPoint_t *currentData)
{static uint32_t lastRepTime = 0;uint32_t timeNow = gizGetTimerCount();uint8_t *waitReportDataPtr = NULL;if((1 == gizCheckReport(currentData, (dataPoint_t *)&gizwitsProtocol.gizLastDataPoint))){GIZWITS_LOG("changed, report data\n");if(0 == gizDataPoints2ReportData(currentData,gizwitsProtocol.reportData,(uint32_t *)&gizwitsProtocol.reportDataLen)){gizReportData(ACTION_REPORT_DEV_STATUS, gizwitsProtocol.reportData, gizwitsProtocol.reportDataLen);        }memcpy((uint8_t *)&gizwitsProtocol.gizLastDataPoint, (uint8_t *)currentData, sizeof(dataPoint_t));}if((0 == (timeNow % (600000))) && (lastRepTime != timeNow)){GIZWITS_LOG("Info: 600S report data\n");memset((uint8_t *)&gizwitsProtocol.waitReportDatapointFlag,0xFF,DATAPOINT_FLAG_LEN);if(0 == gizDataPoints2ReportData(currentData,gizwitsProtocol.reportData,(uint32_t *)&gizwitsProtocol.reportDataLen)){gizReportData(ACTION_REPORT_DEV_STATUS, gizwitsProtocol.reportData, gizwitsProtocol.reportDataLen);        }memcpy((uint8_t *)&gizwitsProtocol.gizLastDataPoint, (uint8_t *)currentData, sizeof(dataPoint_t));lastRepTime = timeNow;}free(waitReportDataPtr);
}

这段代码定义了一个 gizDevReportPolicy 函数,用于处理设备的数据报告。下面是详细解释:

总结:gizwitsHandle函数执行了很多功能,解析环形BUFF里面的数据帧,解析出数据帧里面的命令,根据命令去执行对应的回调函数,并且根据协议要求,发送回对应数据给ESP8266。

/* 机智云数据同步 - 任务 */

void app_SyncData_Task( SysParam_t *p_SysParamHandle )
{if (p_SysParamHandle->u32SyncDataTim == 0){p_SysParamHandle->u32SyncDataTim = 500;p_SysParamHandle->p_DataPoint->valuelight = LIGHT_SWUTCH_STAT;p_SysParamHandle->p_DataPoint->valuefan = AIRCONDI_SWUTCH_STAT;p_SysParamHandle->p_DataPoint->valuetemperature = p_SysParamHandle->psDHT11DataHandle->temp_int;p_SysParamHandle->p_DataPoint->valuehumi = p_SysParamHandle->psDHT11DataHandle->humi_int;}
}

将最新的传感器数据更新到 p_DataPoint结构体 。

总结:

这里就是代码的基本实现思路,至于如何读取传感器数据,这些细节的东西就不去涉及了。

2. 机智云平台搭建以及代码移植 

        机智云平台非常的方便,我们设置好对应的参数之后,他会自动给我们生成可以移植到STM32中的代码,我们只需要移植进去我们的工程,并且进行对应的修改,就可以实现STM32与机智云APP的互联。

主要材料准备

  • STM32F103C8T6开发板
  • ESP8266模块

2.1 APP制作

1.1 首先利用网上的一些物联网自助开发平台去制作APP,这里我选用机智云。浏览器搜索机智云 ,然后进入官网,如下图。

1.2 进入官网后点击右上角的 开发者中心 。

1.3 大部分同学还没注册过机智云账号,所以先去注册一个。

1.4 注册完成后,登录账号就进入了下方界面,点击左侧“智能产品”栏的“+创建”,开始制作APP。 

1.5 点击“+创建”后,就来到下图中的界面进行APP的类型选择(照着下图操作)。我们点击 照明 ,再点击 球泡灯 ,然后点击 自定义方案 ,最后点击灯。(这些操作只是先给APP选个模板而已,到时候功能可以不跟控灯功能相关) 

1.6 完成步骤1.5后,我们就相当于选好了APP的模板类型,接下来会弹出下方的界面,我们只要按照下图中红色框一样设置就行了(产品名称可以自己取),按图片操作完后,点击界面底部的创建。


​1.7 完成步骤1.6之后,就自动来到了下图的界面。这里我们开始给APP添加内容,点击下图的 去编辑。

然后参考下图红色框框部分进行填写(这里我们先实现往APP里添加一个窗开关的内容);

 

        在 标识名 这一项,我们取名字的时候尽量取得“清楚”,就是一眼就知道是什么意思。因为后面机智云自动生成的单片机程序代码里表示窗开关的的变量名就是根据这个标识名生成的。显示名称:就是等会APP上会显示的文字,比如我们填写“窗开关”,等会生成的APP上就会有个地方标注文字“窗开关”,然后我们继续填写下面的读写类型和数据类型,让APP上“窗开关”的文字旁边显示个按键,这样我们一眼就这个按键是用来控制窗开关的。

        如果只是起显示数值作用属于只读,比如显示温度值和湿度值。

        数据类型:窗的状态有“开”和“关”两种状态,所以数据类型是布尔值类型(也就是0和1)。

        填写好标识名、显示名称、读写类型、数据类型后点击界面下方的 确定。

1.8 完成上面的步骤后,就自动来到了下图的界面。这个时候我们的 只控制窗开关的APP 已经做好了。

2.2 给ESP8266模块烧录固件

 2.1 首先在机智云官网下载ESP8266固件到本地电脑上。

ESP8266 GAgent固件下载地址:https://devdocs.gizwits.com/download.html#166419072645267?1672219764470

2.2 确认下载的固件

2.3设备烧录。

完成上面步骤后,我们以管理员的方式打开资料里提供的烧录工具:

        

点击OK 

2.4 烧录设置。

2.3 代码移植

        现在APP制作完毕,ESP8266固件也烧录好了,接下来就是进入编写STM32程序的环节。(内部复杂的代码原理,有兴趣的去机智云官网学习,这里只是教大家怎么用,以最快的速度做出自己想要的毕设)

        3.1 机智云能够根据我们刚才制作的APP,自动生成APP与STM32通讯的代码工程,这一点机智云官方有说明(下图)。看不懂就不理它,反正等会我们会把自动生成的代码里关于APP与STM32通信相关的代码移植进我们自己的工程里边实现与APP相互通讯。

进行下方两张图的操作进行代码自动生成。

首先

然后

3.2 完成上图操作后,等待一会,代码就会自动生成完毕,我们将其下载下来,并解压后得到以下文件。我们只需要用到Gizwits文件夹和Utils文件夹里的内容。

 

将机智云自动生成代码工程里的Gizwits文件夹和Utils文件夹两个文件夹复制到资料(获取方法在文章底部)里提供的基础工程里边。基础工程内容就是在第九章的代码工程基础上多增加了两个串口功能(一个串口负责打印信息,一个串口负责与ESP8266进行通讯)和一个实现1ms定时的定时器功能。

 这里说明一下,基础工程需要具备什么条件呢?答案是:必须得有两个串口功能和实现1ms定时的定时器功能。这一点可以看下图,机智云官网上有提出。所以,如果不想用资料提供的基础工程做移植操作,而是想用你自己的工程来做移植操作的,只要你的项目还空出两个串口可以用,以及有个定时器,就可以继续按下文进行操作。

        我们首先要根据我们产品的需求,制定出我们需要的APP界面,因为我们使用的是机智云的代码,我们首先要烧录机智云的官方固件给esp8266,然后再去生成移植代码,在移植代码的基础上,移植或者在基础上重新修改。里面包含很多个文件:

协议API介绍: 

程序实现原理:

协议解析后,将P0数据区的有效数据点生成对应的数据点事件,再按事件处理数据点。

数据点转换事件的说明:

根据协议P0数据区的attr_flags位判断出有效数据点,并将其转化成对应的数据点事件,然后在事件处理函数中(gizwitsEventProcess)完成事件的处理。

程序初始化

数据协议结构体的定义

结构体dataPoint_t ,代码位置: MCU_STM32xxx_source\Gizwits\gizwits_protocol.h

说明:结构体dataPoint_t作用是存储用户区的设备状态信息,用户根据云端定义的数据点向其对应的数据位赋值后便不需关心数据的转换。

attrFlags_t、attrVals_t ,代码位置: MCU_STM32xxx_source\Gizwits\gizwits_protocol.h 

dataPoint_t 为应用层数据结构,开发者需要了解并会使用(具体使用方式请查看:“2.7.1 只读型数据的获取”一节)。

attrFlags_t、attrVals_t、devStatus_t为通信层数据结构,开发者需要结合通讯协议进行理解。我们这里只要移植,无需过多纠结,但是我们要知道,我们这里要用的四个值:灯、风扇、温度、湿度。

用户程序初始化

接下来看用户初始化相关代码(位置:gizwits_product.cuserInit() 函数):

其中完成了定时器、串口的初始化(详情查看2.3.4、2.3.5两节),以及一个环形缓冲区的初始化。

最后是一个通信处理模块结构体的变量的初始化,该变量为通信模块的全局变量:

其定义的位置:Gizwits\gizwits_protocol.c

定时器使用

定时器中断函数,代码位置:MCU_STM32xxx_source\Gizwits\gizwits_product.c 

注:在该中断函数内我们完成了周期为1ms的定时累加计数。

串口的使用 

串口中断函数,位置:MCU_STM32xxx_source\Gizwits\gizwits_product.c

配置模式说明 

设备需要进入配置模式才能进行联网,并与云端进行通信,在本示例工程中是通过按键触发进入相应的配置模式。

Wifi 配置接口说明:

/**

  • @brief WiFi配置接口
  • 用户可以调用该接口使WiFi模组进入相应的配置模式或者复位模组

  • @param[in] mode 配置模式选择:0x0, 模组复位 ;0x01, SoftAp模式 ;0x02, AirLink模式

  • @return 错误命令码
    */
    ·int32_t gizwitsSetMode(uint8_t mode)

程序中触发逻辑位置:MCU_STM32xxx_source\User\main.c

这些API函数都是机智云给我们封装好的了,我们只需要调用就ok。 

协议处理函数的实现

位置:MCU_STM32xxx_source\Gizwits\gizwits_protocol.c中gizwitsHandle() 函数:

其余协议处理函数功能如下所示: 

● 协议判断完成后是一个状态机的判断,用来完成对应协议命令的处理:

例如在P0协议处理函数(gizProtocolIssuedProcess)中,当我们完成了控制型协议的解析,会让 issuedFlag = 1,如下:

 

 然后会执行如下的处理,执行gizwitsEventProcess函数

gizwitsEventProcess 中,完成了对应控制型事件的处理,其他状态的issuedFlag 同理。

● 之后是一个数据上报判断机制,主要执行了gizCheckReport函数

 gizCheckReport函数的作用用来判断当前与上次上报数据的一致性,如果符合上报条件便上报,上报条件要符合协议“4.9 设备MCU向WiFi模组主动上报当前状态”中的描述。

2.4 总结

我们项目的要求是测出各个传感器数据以及用APP去控制风扇和灯和显示出传感器数据,前者是我们STM32底层工程以及处理好了,我们根据我们的需求制作搭建好机智云平台之后,生成移植代码,我们只需要把他的代码按需求移植到STM32基础程序里面,并且编写好UserHandle回调函数(处理我们收到APP的开关灯......事件该怎么办),并且将传感器的数值与机智云数据同步,这样子,我们就可以实现STM32与APP的搭建。

3. SNR8016VR_DEV智能语音模块

3.1 智能公元平台

开发平台地址

  • http:// http://smartpi.cn/#/


 

3.2 创建产品

3.3 配置语音模块

具体操作流程可以去看官方的教程,这里我只列举我这里需要用到。

配置串口

 唤醒词自定义

命令词自定义 

控制详情

收到对应的命令词就发送对应数据给STM32,STM32根据收到的命令执行对应的回调函数。 

其他配置 

3.4 生成SDK固件烧录 

相关文章:

基于STM32的智能家居语音系统(单片机毕设)

前言 源代码下载链接&#xff1a; https://download.csdn.net/download/m0_74712453/90071680 需要实物的可以私信博主或者在文章最下方添加好友。 目录 一、项目介绍和演示视频 二、硬件实现 1. 材料材料 2. 原理图和PCB 三、软件实现 1. 代码解析 1.1 main函数 1.2…...

ASP.NET Core 简单文件上传

使用异步 JavaScript 和 XML&#xff08;AJAX&#xff09;进行简单的文件上传&#xff1b;用 C# 编写的服务器端代码。 使用AJAX和ASP.NET Core MVC上传文件再简单不过了。这不依赖于jQuery。此代码允许上传多个文件&#xff0c;并与 .NET Core 3.1、.NET 6和.NET 8兼容。 如果…...

2502C++,C++继承的多态性

构 A{单 向量<串>记;元<类 T>静 空 ff(串&a){清理(记);名向量(a,记);串 b{"---ff---"};打印(b);T::g();} };构 B:公 A{元<类 T>静 空 f(){串 a{"错误.txt"};ff<T>(a);} };构 C:公 A{元<类 T>静 空 f(){串 a{"a12.c…...

【机器学习】13.十大算法之一K均值算法(K-means)聚类详细讲解

【机器学习】13.十大算法之一K均值算法&#xff08;K-means&#xff09;聚类详细讲解 一摘要二个人简介三K-均值聚类&#xff08;K-means&#xff09;3.1-K均值算法的基本原理3.1.1- 聚类分析的目标3.1.2- K - means算法算法原理 四K-means聚类算法的收敛性五证明K均值算法的收…...

Spring扩展点之Mybatis整合模拟

Spring扩展点之Mybatis整合 单独使用MyBaitis模拟整合MyBatis到Spring 单独使用MyBaitis 通过配置文件生成sqlSessionFactory&#xff0c;用sqlSessionFactory开启session。通过session获取到mapper执行对应的sql。 InputStream inputStream Resources.getResourceAsStream(…...

.NET MVC实现电影票管理

.NET MVC&#xff08;Model-View-Controller&#xff09;是微软推出的基于 Model-View-Controller 设计模式的 Web 应用框架&#xff0c;属于 ASP.NET Core 的重要组成部分。其核心目标是通过清晰的分层架构实现 高内聚、低耦合 的开发模式&#xff0c;适用于构建可扩展的企业级…...

自媒体账号管理工具:创作罐头使用指南

创作罐头使用指南 1. 关于创作罐头 创作罐头是免费的一站式自媒体运营工具&#xff0c;支持各大自媒体平台多账号管理、全网爆文库、原创检测、视频一键分发、团队管理、各平台数据分析等功能。 2. 安装与注册 2.1. 如何安装创作罐头 从我们的官网下载并安装软件 www.czgts.…...

基于数据可视化+SpringBoot+安卓端的数字化OA公司管理平台设计和实现

博主介绍&#xff1a;硕士研究生&#xff0c;专注于信息化技术领域开发与管理&#xff0c;会使用java、标准c/c等开发语言&#xff0c;以及毕业项目实战✌ 从事基于java BS架构、CS架构、c/c 编程工作近16年&#xff0c;拥有近12年的管理工作经验&#xff0c;拥有较丰富的技术架…...

VSCode离线安装插件

最近在其他电脑设备上部署vscode环境出现问题&#xff0c;在vscode里直接安装插件失败&#xff0c;软件提示如下&#xff1a;&#xff08;此前已经用此方法安装过中文插件&#xff09; 这里我们选择手动下载&#xff0c;会自动在浏览器中跳转到该插件的下载链接并自动下载插件&…...

基于Hadoop的汽车大数据分析系统设计与实现【爬虫、数据预处理、MapReduce、echarts、Flask】

文章目录 有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主 项目介绍爬虫数据概览HIve表设计Cars Database Tables 1. cars_data2. annual_sales_volume3. brand_sales_volume4. city_sales_volume5. sales_volume_by_year_and_brand6. sales_distri…...

SHELL32!Shell_MergeMenus函数分析

SHELL32!Shell_MergeMenus函数分析 UINT Shell_MergeMenus( [in] HMENU hmDst, [in] HMENU hmSrc, UINT uInsert, UINT uIDAdjust, UINT uIDAdjustMax, ULONG uFlags ); 参数 [in] hmDst 类型&#xff1a; HMENU 要向其添加 hmSrc…...

华为云deepseek大模型平台:deepseek满血版

华为云硅基流动使用Chatbox接入DeepSeek-R1满血版671B 1、注册&#xff1a; 华为云deepseek大模型平台注册&#xff1a;https://cloud.siliconflow.cn/i/aDmz6aVN 说明&#xff1a;填写邀请码的话邀请和被邀请的账号都会获得2000 万 Tokens&#xff1b;2个帐号间不会与其他关联…...

AutoGen 技术博客系列 八:深入剖析 Swarm—— 智能体协作的新范式

本系列博文在掘金同步发布, 更多优质文章&#xff0c;请关注本人掘金账号&#xff1a; 人肉推土机的掘金账号 AutoGen系列一&#xff1a;基础介绍与入门教程 AutoGen系列二&#xff1a;深入自定义智能体 AutoGen系列三&#xff1a;内置智能体的应用与实战 AutoGen系列四&am…...

从零开始开发纯血鸿蒙应用之网页浏览

从零开始开发纯血鸿蒙应用 〇、前言一、优化菜单交互1、BuilderFunction.ets2、改造 PageTitleBar 二、网址打开1、方式选择1、使用浏览器打开2、内部打开2.1、声明权限2.2、封装 WebViewPage2.2.1、组件字段2.2.2、aboutToAppear2.2.3、onBackPress2.2.4、标题栏2.2.4、网页内…...

【大模型LLM】DeepSeek LLM Scaling Open-Source Language Models with Longtermism

深度探索LLM&#xff1a;以长期主义扩展开源语言模型 0.论文摘要 开源大语言模型&#xff08;LLMs&#xff09;的快速发展确实令人瞩目。然而&#xff0c;以往文献中描述的扩展规律得出了不同的结论&#xff0c;这为LLMs的扩展蒙上了一层阴影。我们深入研究了扩展规律&#…...

分布式事务-本地消息表学习与落地方案

本文参考&#xff1a; 数据库事务系列04-本地消息表实现分布式事务 基础概念 本地消息表实现分布式事务最终一致性的核心&#xff1a;是通过上游本地事务的原子性持久性&#xff0c;配合中间件的重试机制&#xff0c;从而实现调用下游的最终一致性。 这里有几个要点可以解析一…...

Debezium系列之:记录一次源头数据库刷数据,造成数据丢失的原因

Debezium系列之:记录一次源头数据库刷数据,造成数据丢失的原因 一、背景二、查看topic日志信息三、结论四、解决方法一、背景 源头数据库在很短的时间内刷了大量的数据,部分数据在hdfs丢失了 理论上debezium数据采集不会丢失,就需要排查数据链路某个节点是否有数据丢失。 …...

PHP约课健身管理系统小程序源码

&#x1f3cb;️‍♂️ 约课健身管理系统小程序&#xff1a;重塑健身预约体验&#xff0c;引领数字化健身新时代 一款基于ThinkPHPUniapp框架&#xff0c;由米扬精心雕琢的约课健身管理系统小程序&#xff0c;专为健身房、健身工作室、运动会所、运动场馆、瑜伽馆、拳馆等泛健…...

Java之泛型

文章目录 首先接着上一篇&#xff08;集合&#xff09;文章&#xff0c;来个非常牛逼的易错题传统集合问题分析泛型快速入门案例泛型介绍泛型的好处泛型的语法泛型的声明泛型的实例化泛型使用举例泛型使用的注意事项和细节 自定义泛型自定义泛型方法 自定义泛型接口自定义泛型方…...

图论 之 最小生成树

文章目录 题目1584.连接所有点的最小费用 最小生成树MST&#xff0c;有两种算法进行求解&#xff0c;分别是Kruskal算法和Prim算法Kruskal算法从边出发&#xff0c;适合用于稀疏图Prim算法从顶点出发&#xff0c;适合用于稠密图&#xff1a;基本思想是从一个起始顶点开始&#…...

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 &#xff08;一&#xff09;实时滤波与参数调整 基础滤波操作 60Hz 工频滤波&#xff1a;勾选界面右侧 “60Hz” 复选框&#xff0c;可有效抑制电网干扰&#xff08;适用于北美地区&#xff0c;欧洲用户可调整为 50Hz&#xff09;。 平滑处理&…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)

概述 在 Swift 开发语言中&#xff0c;各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过&#xff0c;在涉及到多个子类派生于基类进行多态模拟的场景下&#xff0c;…...

Caliper 配置文件解析:config.yaml

Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...

全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比

目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec&#xff1f; IPsec VPN 5.1 IPsec传输模式&#xff08;Transport Mode&#xff09; 5.2 IPsec隧道模式&#xff08;Tunne…...

Linux --进程控制

本文从以下五个方面来初步认识进程控制&#xff1a; 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程&#xff0c;创建出来的进程就是子进程&#xff0c;原来的进程为父进程。…...

算法打卡第18天

从中序与后序遍历序列构造二叉树 (力扣106题) 给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 示例 1: 输入&#xff1a;inorder [9,3,15,20,7…...

JDK 17 序列化是怎么回事

如何序列化&#xff1f;其实很简单&#xff0c;就是根据每个类型&#xff0c;用工厂类调用。逐个完成。 没什么漂亮的代码&#xff0c;只有有效、稳定的代码。 代码中调用toJson toJson 代码 mapper.writeValueAsString ObjectMapper DefaultSerializerProvider 一堆实…...

嵌入式面试常问问题

以下内容面向嵌入式/系统方向的初学者与面试备考者,全面梳理了以下几大板块,并在每个板块末尾列出常见的面试问答思路,帮助你既能夯实基础,又能应对面试挑战。 一、TCP/IP 协议 1.1 TCP/IP 五层模型概述 链路层(Link Layer) 包括网卡驱动、以太网、Wi‑Fi、PPP 等。负责…...

VSCode 没有添加Windows右键菜单

关键字&#xff1a;VSCode&#xff1b;Windows右键菜单&#xff1b;注册表。 文章目录 前言一、工程环境二、配置流程1.右键文件打开2.右键文件夹打开3.右键空白处打开文件夹 三、测试总结 前言 安装 VSCode 时没有注意&#xff0c;实际使用的时候发现 VSCode 在 Windows 菜单栏…...

如何让非 TCP/IP 协议驱动屏蔽 IPv4/IPv6 和 ARP 报文?

——从硬件过滤到协议栈隔离的完整指南 引言 在现代网络开发中,许多场景需要定制化网络协议(如工业控制、高性能计算),此时需确保驱动仅处理特定协议,避免被标准协议(如 IPv4/IPv6/ARP)干扰。本文基于 Linux 内核驱动的实现,探讨如何通过硬件过滤、驱动层拦截和协议栈…...