关于无线传输的基础知识,参考:
无线通信技术概览_路溪非溪的博客-CSDN博客
学了这么多,发现信息技术主要就是数据的存储、处理以及传输这几个过程。通过各种各样的技术,来实现这几个目标。
wifi模块
现在常用的是wifi模块,如下图所示:
比如ESP8266系列wifi模组。
将wifi模块连接上wifi后,就可以进行网络通信,这时我们需要一个服务器,让wifi跟服务器之间进行数据的交互。
联网的本质就是获取远端的数据,或者向远端发送数据,即两者之间进行数据交互,和串口、SPI、IIC等通信没有本质的区别。
所以,为什么wifi模块能联网,连上网意味着什么?为什么需要输入密码?
当wifi模块处于无线电磁波之中,wifi模块就可以探测到这种电磁波,我们输入密码,就是一种软件处理的认证方式,让我们的wifi模块可以正确地接收并解析所处的电磁波信号。一旦建立了电磁波连接,就和用导线直接连接是一样的道理,此时就可以和其他目标进行数据交互了,这就是wifi模块连上网络的含义。
所谓的服务器,就是一个终端,那里储存了一些我们想要的数据。我们通过网络去获取这些数据而已。
使用过程
wifi模块和单片机之间,可以通过串口直接相连。
单片机可以给wifi模块发送指令,来使得wifi模块实现一些功能,比如连接wifi。
AT指令
AT指令是应用于终端设备与PC应用之间的连接与通信的指令。AT 即Attention。每个AT命令行中只能包含一条AT指令;对于AT指令的发送,除AT两个字符外,最多可以接收1056个字符的长度(包括最后的空字符)。
AT指令是以AT作首, 字符结束的字符串,AT指令的响应数据包在其中。每个指令执行成功与否都有相应的返回。其他的一些非预期的信息(如有人拨号进来、线路无信号等),模块将有对应的一些信息提示,接收端可做相应的处理。
AT指令是统一固定的吗?
AT 指令着重应用在蜂窝模块、WiFi 模块、BLE 模块中,目的是为了简化嵌入式设备联网的复杂度。AT 标准定义了 AT 命令的格式本身,比如命令以 AT 为前缀开头,以“或者”结尾,这被现有的 AT 模块所延用。但是,由于每个厂家的模块不一样,实现的功能不一样,导致每个 AT 模块厂家有自己的一套私有的 AT 命令集,每一个 AT 模块厂家实现的 AT 指令集解析器也不一样。
在购买某款wifi模组时,厂家一般会给到对应的说明书,里面就详细描述了各种AT指令,以及使用示范。
在wifi模块中,涉及到单片机、wifi模块以及服务器端,那么这个AT指令,是从哪里向哪里发送的呢?
AT指令是传给wifi模块的,比如单片机或者上位机给wifi模块发送一个AT指令,控制其进行特定的动作或行为。
ESP8266
esp8266是一款wifi模块。
主要是针对物联网的应用,比如说做可穿戴设备、智能家居、智能安防等等。
Esp8266相当于是你家里的”路由器”,帮助你把电脑、手机连上互联网,至于上网做什么,想象空间就很大了。
其内部结构图如下所示:
简介:
引脚图:
参考的原理图:
Esp8266的功能就是数据透传,比如说单片机往服务器上报端点数据,服务器往单片机下发端点数据。
什么是数据透传?
数据透传就是透明传送,是指在数据的传输过程中,通过无线的方式这组数据不发生任何形式的改变,仿佛传输过程是透明的一样,同时保证传输的质量,原封不动地到了最终接收者手里。
物联网时代要想实现智能设备的数据透传就需要仰仗无线透传模块的力量,从技术层面看,蓝牙、WiFi、ZigBee 等优势明显的无线传输技术成为物联网主流的无线传输方式。依赖于这些无线传输技术延生的蓝牙模块、WiFi 模块、ZigBee 模块可实现发送方和接收方数据的长度和内容完全一致,不需对数据做任何处理,相当于一条数据线或者串口线,可广泛应用在工业、环保、气象、地质、农业等诸多行业。
ESP8266的AT指令
注:以下做简单记录,具体查阅其使用手册。
……
……
……
以上三类AT指令,基础AT指令是用来测试模块、重启模块等;wifi指令主要是用来配网的;TCP/IP指令主要是用来配置wifi模块连接服务器的。
以下简单展示下几个常用的指令:
比如通过用户名和密码连入网络:
断开AP连接
上电自动连接AP
AP
Access Point,也就是无线接入点,是一个无线网络的创建者,是网络的中心节点。一般家庭或办公室使用的无线路由器就是一个AP。 如果我们的手机作为热点,也是AP。
STAStation,每一个连接到无线网络中的终端(如笔记本电脑、PDA及其它可以联网的用户设备)都可称为一个站点。 比如我们手机连接其他wifi时,就是一个站点。
SSID
可以理解成登入某网络时的用户名。
SSID是Service Set Identifier的缩写,意思是:服务集标识。SSID技术可以将一个无线局域网分为几个需要不同身份验证的子网络,每一个子网络都需要独立的身份验证,只有通过身份验证的用户才可以进入相应的子网络,防止未被授权的用户进入本网络。
SmartConfig配置
什么是SmartConfig?
智能家居/家电现阶段还处于普及阶段,由于家庭wifi网络的普及,目前普遍采用wifi与路由器完成连接,与手机/云端进行数据交互。
智能硬件,如智能插座、智能空调、智能空气净化器,智能灯泡,智能门锁由于不具备人机交互界面,不能像电脑一样的搜索/选择指定路由器,输入连接SSID和密码的界面,所以必须先解决正确连接路由问题。
目前流行的wifi配置模式一般有以下2种:
1、softAP方案
硬件处于AP模式,手机用station模式,手机连接智能硬件的AP后组成局域网,手机发送需要连接路由的SSID和密码至智能硬件,智能硬件主动去连接指定路由后,完成连接。
AP模式需要手动切换手机wifi连接的网络,先连接智能硬件的AP网络,配置完成后再恢复连接正常wifi网络,有一定的复杂性。
2、smartconfig(一键配置)方案
smartconfig实际就是手机端发送多播一串经过处理的数据,然后接收端,接受到这个数据之后,解析到wifi密码,连接上wifi。
智能硬件处于混杂模式下,监听网络(局域网)中的所有报文,手机APP将SSID和密码编码到UDP报文中(在APP界面中输入SSID和密码),通过广播包或组播报发送(并非点对点),智能硬件接收到UDP报文后解码,得到正确的SSID和密码,然后主动连接指定SSID的路由,完成连接。
对于smartconfig我还有个疑惑,根本就没有连接渠道,智能硬件如何接收这些网络报文呢?这里面用到了一些具体的技术,其中有一种叫做airkiss,飞吻技术。
AirKiss
Air Kiss 技术是一种创新性的信息传递技术。通过该技术可以便捷的向一台 与外界没有建立任何一种实质性连接(包括有线、无线、蓝牙、NFC 等)的设备传 递信息(可以是环境中 Wifi 的 ssid、密码等信息)。 Air Kiss 技术示意图如下图所示,设备 A 与外界没有建立任何一种实质性连 接,可以称之为信息孤岛。通过 Air Kiss 技术,设备 B 可以将环境中的 Wifi 的 ssid 与密码便捷的隔空传递给 A,从而使得 A 能够快速的接入 Wifi。 Air Kiss(飞吻)原意为情侣之间在没有身体接触的情况下,通过吻自己的手, 再作抛掷给对方状,隔空以示情爱。这就与 B 设备隔空向信息孤岛 A 设备传递 信息的这一技术的思想很相似,因此将该技术命名为 Air Kiss 技术。
随着移动互联网与物联网技术的发展,越来越多的设备具有了无线网络的接入能力。这些设备的特点是小型化以及低功耗,大多数类似的设备都没有配置屏幕以及键盘等输入外设,因此如何将无线网络的ssid与密码传输到这类设备成为一大难题。 Air Kiss技术正是为解决上述难题而产生的。通过该技术,可以在不增加任 何外设开销的情况下,通过另外一台已经接入无线网络的设备(比如手机),向与 外界没有任何连接(包括有线、无线、蓝牙、NFC 等)的设备传递ssid与密码等信 息。 因此Air Kiss技术可以作为任意没有配置屏幕以及键盘等外设,同时又需要接入无线网络的设备的ssid与密码传输方案。类似设备包括物联网智能控制芯片、 电子相册、智能手环、智能手表等。
以下将以智能插座为例,说明 Air Kiss 技术的应用方案和交互流程。
智能插座属于物联网智能控制类设备,它可用于家电(比如电灯、热水器等) 的智能化开关控制。智能插座的特点是小型化且低功耗,显而易见,该设备并不适合于配置屏幕与键盘等输入外设。在这种情况下,Air Kiss 技术能完美解决其 ssid 与密码的传输与设置问题。 Air Kiss 技术对应用设备的硬件几乎没有额外的要求,仅需在设备上配置一 个按键,用户在长按后会进入Air Kiss模式,如下图所示。在本例中,智能插座在按下了 Air Kiss 按键之后,指示灯闪烁,成为了 Air Kiss 技术中信息的接收 方。另外,用户需在手机端(或者其它具有无线网络接入能力的设备)安装 Air Kiss 软件,安装完成之后,手机端便具有了 Air Kiss 信息传输能力,成为 Air Kiss 技术中的信息发送方。用户使用 Air Kiss 的交互流程如下:
①按下智能插座上的 Air Kiss 模式按键,Air Kiss 指示灯闪烁,智能插座进入信 息接收状态。
②打开手机端进入 Air Kiss 的 ssid 与密码发送界面中,当前无线网络环境下 AP 的 ssid 已经帮用户填入,用户只需要填写密码,然后点击发送即可。整个 Air Kiss 过程将在 15 秒内完成。
相对于外设辅助传输(是指需要在设备上增加相应的外设比如蓝牙,NFC 等辅助完成输)Air Kiss 技术无需外设的辅助,减少了实现的成本,适用性较为广泛。
智能配置的基本原理
理解智能配置的原理,关键在于理解“混杂模式”。
正常的wifi设备都有一个MAC地址,其硬件电路会自动过滤目标MAC地址跟其MAC不同的数据包。开启混杂模式就是我们平常时说的抓包,就是空中符合802.11格式的数据包都接收进来,不管MAC是否一样。
很明显,手机智能配置APP并不知道该wifi设备的MAC地址,所以手机wifi发送出的数据包,通过家里的路由器转发出去时,wifi设备必须要在混杂模式下才能接收到这些数据包。查询模块的ip地址
建立连接
设置成透传模式
单片机和wifi模块之间使用串口DMA收发,以及空闲中断即可。略。
/* Includes ------------------------------------------------------------------*/ #include "MyApplication.h" /* Private define-------------------------------------------------------------*/ #define TCP_Server (uint8_t*)"AT+CIPSTART=\"TCP\",\"192.168.1.129\",8888\r\n" //电脑端模拟的TCP服务器 //#define TCP_Server (uint8_t*)"AT+CIPSTART=\"TCP\",\"192.168.1.132\",8888\r\n" //手机端模拟的TCP服务器 /* Private variables----------------------------------------------------------*/ /* Private function prototypes------------------------------------------------*/ static void Init(void); //ESP8266初始化 static void SmartConifg(void); //WIFI模块配网 static void TCP_Connect_Server(void); //通过TCP连接服务器 static void Transfer_SHT30(void); //传送SHT30的温湿度 static void Receive_Information(void); //接收信息 static void DMA_Receive_Set(void); //DMA重新设置 static void Error(void); //错误信息 static void SendAT(uint8_t *,uint8_t *); //发送AT指令 /* Public variables-----------------------------------------------------------*/ ESP8266_t ESP8266 = { FALSE, TIMER6_10S, FALSE, Init, SmartConifg, TCP_Connect_Server, Transfer_SHT30, Receive_Information, DMA_Receive_Set, Error }; /* * @name Init * @brief ESP8266初始化 * @param None * @retval None */ static void Init() { //复位模组 HAL_GPIO_WritePin(WIFI_RST_GPIO_Port,WIFI_RST_Pin,GPIO_PIN_RESET); HAL_Delay(10); HAL_GPIO_WritePin(WIFI_RST_GPIO_Port,WIFI_RST_Pin,GPIO_PIN_SET); //使能模组 HAL_GPIO_WritePin(WIFI_EN_GPIO_Port,WIFI_EN_Pin,GPIO_PIN_SET); //延时500ms,等待WIFI模块稳定,准备好接收AT指令 HAL_Delay(500); //同步波特率 Timer6.usDelay_Timer = 0; do { //DMA重新接收设置 ESP8266.DMA_Receive_Set(); //发送AT指令 UART2.SendString((uint8_t*)"AT\r\n"); //延时100ms,等待接收完成 HAL_Delay(100); //打印信息 printf("%s",UART2.pucRec_Buffer); //超时处理 if(Timer6.usDelay_Timer >= TIMER6_10S) { ESP8266.Error(); break; } } while(strstr((const char*)UART2.pucRec_Buffer,"OK") == NULL); } /* * @name SendAT * @brief 发送AT指令 * @param AT_Command -> 待发送的AT指令 Respond_Str -> 回应数据中包含的字符串 * @retval None */ static void SendAT(uint8_t * AT_Command,uint8_t * Respond_Str) { uint8_t* const Ptr_AT_Command = AT_Command; uint8_t* const Ptr_Respond_Str = Respond_Str; //DMA重新接收设置 ESP8266.DMA_Receive_Set(); //发送AT指令 UART2.SendString(Ptr_AT_Command); //打印信息 printf("%s",Ptr_AT_Command); //等待模块回应数据,超时错误处理 Timer6.usDelay_Timer = 0; while(strstr((const char*)UART2.pucRec_Buffer,"\r\n") == NULL) { if(Timer6.usDelay_Timer > TIMER6_100mS) { ESP8266.Error(); break; } } //延时10ms,接收完全部字节 HAL_Delay(10); //模块回应数据处理处理 if(strstr((const char*)UART2.pucRec_Buffer,(const char*)Ptr_Respond_Str) == NULL) { ESP8266.Error(); } //打印信息 printf("%s",UART2.pucRec_Buffer); } /* * @name SmartConifg * @brief WIFI模块配网 * @param None * @retval None */ static void SmartConifg() { if(ESP8266.SmartConifg_Flag == TRUE) { //清除TCP连接成功标志位,避免串口空闲中断清除缓存信息,导致无法判断配网是否成功 ESP8266.TCP_Connect_Status = FALSE; //关闭指示灯 LED.LED_OFF(LED2); LED.LED_OFF(LED3); //退出透传模式 *(UART2.pucSend_Buffer + 0) = '+'; *(UART2.pucSend_Buffer + 1) = '+'; *(UART2.pucSend_Buffer + 2) = '+'; UART2.SendArray(UART2.pucSend_Buffer,3); HAL_Delay(1000); //配网 SendAT((uint8_t*)"AT\r\n",(uint8_t*)"OK"); //测试AT SendAT((uint8_t*)"ATE0\r\n",(uint8_t*)"OK"); //关闭回显 SendAT((uint8_t*)"AT+CWMODE_CUR=1\r\n",(uint8_t*)"OK"); //WIFI模块设置为STA模式 SendAT((uint8_t*)"AT+CWAUTOCONN=1\r\n",(uint8_t*)"OK"); //上电自动连接到AP SendAT((uint8_t*)"AT+CWSTARTSMART=2\r\n",(uint8_t*)"OK"); //开启 SmartConfig(SmartConfig类型为AirKiss) printf("Start SmartConfig:\r\n"); //等待配网,3分钟超时退出 Timer6.usDelay_Timer = 0; while(Timer6.usDelay_Timer < TIMER6_3min) { //DMA重新接收设置 ESP8266.DMA_Receive_Set(); //LED2指示灯快闪 HAL_Delay(100); LED.LED_Flip(LED2); //打印信息 printf("%s",UART2.pucRec_Buffer); //判断获取AP if(strstr((const char*)UART2.pucRec_Buffer, "Smart get wifi info") != NULL) //获取到AP信息 { Timer6.usDelay_Timer = TIMER6_3min - TIMER6_10S; } //判断连接AP if(strstr((const char*)UART2.pucRec_Buffer, "connected wifi") != NULL) //成功连接到AP { SendAT((uint8_t*)"AT+CWSTOPSMART\r\n",(uint8_t*)"OK"); //停止SmartConfig break; } } //输出信息 if(Timer6.usDelay_Timer < TIMER6_3min) { printf("\r\n\r\nSmartconfig Success!\r\n"); ESP8266.TCP_Reconnect_Timer = TIMER6_10S; //立马连接TCP //清除配网标志位 ESP8266.SmartConifg_Flag = FALSE; } else { printf("\r\n\r\nSmartconfig Fail!\r\n"); ESP8266.TCP_Reconnect_Timer = 0; } //关闭指示灯 LED.LED_OFF(LED2); } } /* * @name TCP_Connect_Server * @brief 通过TCP连接服务器 * @param None * @retval None */ static void TCP_Connect_Server() { uint8_t AP_Connect_Flag = FALSE; //AP连接标志位,为TRUE,才进行TCP连接 SendAT((uint8_t*)"AT\r\n",(uint8_t*)"OK"); //测试AT SendAT((uint8_t*)"ATE0\r\n",(uint8_t*)"OK"); //关闭回显 SendAT((uint8_t*)"AT+CWMODE_CUR=1\r\n",(uint8_t*)"OK"); //WIFI模块设置为STA模式 //获取IP Timer6.usDelay_Timer = 0; do { //DMA重新接收设置 ESP8266.DMA_Receive_Set(); //发送AT指令 UART2.SendString((uint8_t*)"AT+CIFSR\r\n"); //延时1000ms,等待接收完成 HAL_Delay(1000); //打印信息 printf("%s",UART2.pucRec_Buffer); //10s没有获取IP,跳出等待 if(Timer6.usDelay_Timer >= TIMER6_10S) { ESP8266.Error(); break; } } while(strstr((const char*)UART2.pucRec_Buffer,"0.0.0.0") != NULL); //控制WIFI指示灯 if(Timer6.usDelay_Timer < TIMER6_10S) { LED.LED_ON(LED2); AP_Connect_Flag = TRUE; printf("AP connect success!\r\n"); } else { LED.LED_OFF(LED2); AP_Connect_Flag = FALSE; printf("AP connect fail,auto entry Smartconfig mode!\r\n"); ESP8266.SmartConifg_Flag = TRUE; } //等待稳定连接到AP Timer6.usDelay_Timer = 0; do { //DMA重新接收设置 ESP8266.DMA_Receive_Set(); //发送AT指令 UART2.SendString((uint8_t*)"AT\r\n"); //延时100ms,等待接收完成 HAL_Delay(100); //打印信息 printf("%s",UART2.pucRec_Buffer); //10s没有同步,超时错误处理 if(Timer6.usDelay_Timer >= TIMER6_10S) { ESP8266.Error(); break; } } while(strstr((const char*)UART2.pucRec_Buffer,"OK") == NULL); //连接服务器 if(AP_Connect_Flag == TRUE) { printf("Connect TCP Server!\r\n"); Timer6.usDelay_Timer = 0; do { //DMA重新接收设置 ESP8266.DMA_Receive_Set(); //发送AT指令 UART2.SendString(TCP_Server); //延时500ms,等待接收完成 HAL_Delay(500); //打印信息 printf("%s",UART2.pucRec_Buffer); //10s没有连接到TCP Server if(Timer6.usDelay_Timer >= TIMER6_10S) { printf("Connect TCP Server Failure!\r\n"); ESP8266.TCP_Connect_Status = FALSE; LED.LED_OFF(LED3); break; } //连接到服务器 if(strstr((const char*)UART2.pucRec_Buffer,"CONNECT") != NULL) { printf("Connect TCP Server Success!\r\n"); //使能透传模式 SendAT((uint8_t*)"AT+CIPMODE=1\r\n",(uint8_t*)"OK"); //使能透传 SendAT((uint8_t*)"AT+CIPSEND\r\n",(uint8_t*)">"); //开始发送 ESP8266.TCP_Connect_Status = TRUE; LED.LED_ON(LED3); break; } } while(strstr((const char*)UART2.pucRec_Buffer,"CONNECT") == NULL); //DMA重新接收设置,开始接收TCP服务器的指令 ESP8266.DMA_Receive_Set(); } } /* * @name Transfer_SHT30 * @brief 传送SHT30的温湿度 * @param NONE * @retval None */ static void Transfer_SHT30() { float Temp_float = 0; uint16_t Temp_uint16 = 0; //温度值 -40至125℃,精度0.1℃ if(SHT30.fTemperature < 0) { Temp_float = 0 - SHT30.fTemperature; *(UART2.pucSend_Buffer + 0) = '-'; } else { Temp_float = SHT30.fTemperature; *(UART2.pucSend_Buffer + 0) = ' '; } Temp_uint16 = (uint16_t)(Temp_float*10); if(Temp_uint16 < 10) //0.x { *(UART2.pucSend_Buffer + 1) = ' '; *(UART2.pucSend_Buffer + 2) = ' '; *(UART2.pucSend_Buffer + 3) = '0'; *(UART2.pucSend_Buffer + 4) = '.'; *(UART2.pucSend_Buffer + 5) = Temp_uint16 + '0'; } else if(Temp_uint16 < 100)//x.x { *(UART2.pucSend_Buffer + 1) = ' '; *(UART2.pucSend_Buffer + 2) = ' '; *(UART2.pucSend_Buffer + 3) = Temp_uint16/10 + '0'; *(UART2.pucSend_Buffer + 4) = '.'; *(UART2.pucSend_Buffer + 5) = Temp_uint16%10 + '0'; } else if(Temp_uint16 < 1000)//xx.x { *(UART2.pucSend_Buffer + 1) = ' '; *(UART2.pucSend_Buffer + 2) = Temp_uint16/100 + '0'; *(UART2.pucSend_Buffer + 3) = Temp_uint16%100/10 + '0'; *(UART2.pucSend_Buffer + 4) = '.'; *(UART2.pucSend_Buffer + 5) = Temp_uint16%10 + '0'; } else//xxx.x { *(UART2.pucSend_Buffer + 1) = Temp_uint16/1000 + '0'; *(UART2.pucSend_Buffer + 2) = Temp_uint16%1000/100 + '0'; *(UART2.pucSend_Buffer + 3) = Temp_uint16%100/10 + '0'; *(UART2.pucSend_Buffer + 4) = '.'; *(UART2.pucSend_Buffer + 5) = Temp_uint16%10 + '0'; } //数据传送 UART2.SendString((uint8_t *)"The Temperature of SHT30 is "); HAL_Delay(3); //延时,等待字符串发送完 时间 = (11*1000ms)/115200 * 28 = 2.68ms UART2.SendArray(UART2.pucSend_Buffer,6); HAL_Delay(1); //延时,等待数组发送完 时间 = (11*1000ms)/115200 * 6 = 0.58ms UART2.SendString((uint8_t *)"℃\r\n"); HAL_Delay(1); //延时,等待字符串发送完 时间 = (11*1000ms)/115200 * 4 = 0.39ms //湿度值 0 - 100%RH,精度1%RH if(SHT30.ucHumidity < 10) { *(UART2.pucSend_Buffer + 0) = ' '; *(UART2.pucSend_Buffer + 1) = SHT30.ucHumidity + '0'; } else { *(UART2.pucSend_Buffer + 0) = SHT30.ucHumidity/10 + '0'; *(UART2.pucSend_Buffer + 1) = SHT30.ucHumidity%10 + '0'; } *(UART2.pucSend_Buffer + 2) = '%'; *(UART2.pucSend_Buffer + 3) = 'R'; *(UART2.pucSend_Buffer + 4) = 'H'; //数据传送 UART2.SendString((uint8_t *)"The Humidity of SHT30 is "); HAL_Delay(3); //延时,等待字符串发送完 时间 = (11*1000ms)/115200 * 25 = 2.39ms UART2.SendArray(UART2.pucSend_Buffer,5); } /* * @name Receive_Information * @brief 接收信息 * @param None * @retval None */ static void Receive_Information() { if(ESP8266.TCP_Connect_Status == TRUE) { printf("Received information from the TCP server\r\n"); printf("%s",UART2.pucRec_Buffer); printf("\r\n"); //切换继电器状态 if(strstr((const char*)UART2.pucRec_Buffer,"Flip Relay") != NULL) { Relay.Relay_Flip(); } if(strstr((const char*)UART2.pucRec_Buffer,"Flip Buzzer") != NULL) { if(Buzzer.Status == Buzzer_Status_OFF) { Buzzer.ON(); } else { Buzzer.OFF(); } } //DMA重新接收设置,接收TCP服务器的新指令 ESP8266.DMA_Receive_Set(); } } /* * @name DMA_Receive_Set * @brief DMA接收设置 * @param None * @retval None */ static void DMA_Receive_Set(void) { //串口2禁止DMA接收 HAL_UART_DMAStop(&huart2); //清缓存 Public.Memory_Clr(UART2.pucRec_Buffer,strlen((const char*)UART2.pucRec_Buffer)); //串口2开启DMA接收 HAL_UART_Receive_DMA(&huart2,UART2.pucRec_Buffer,UART2_Rec_LENGTH); } /* * @name Error * @brief 错误信息 * @param None * @retval None */ static void Error() { HAL_GPIO_WritePin(OUT_NPN_GPIO_Port,OUT_NPN_Pin,GPIO_PIN_SET); } /************************************* End Of File *************************************/