• 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 0
    
    extern 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",直到收到的回复是OK
    	status = 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);//灯灭
    	else
    		HAL_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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394

    笔记

    记录几个开发中的细节:

    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}
    
    • 1
    • 2
  • 相关阅读:
    mysql5.7获取json数组中的某个对象
    『LeetCode|每日一题』---->粉刷房子
    怎么渲染半透明乳白色物体
    快速实战SQL - 排序检索数据
    jpg怎么转换成png?
    SSM 图书管理在线销售系统
    【技术积累】Linux中的命令行【理论篇】【九】
    【愚公系列】2022年09月 微信小程序-webview内嵌网页的授权认证
    JSP基本概念
    从Java反序列化漏洞题看CodeQL数据流
  • 原文地址:https://blog.csdn.net/AnChenliang_1002/article/details/134270199