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"

#include <stdio.h>
#include <string.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 receivedData[128]; // 全局数组用于存储完整接收到的内容
extern __IO uint8_t receivedLength; // 当前接收到的数据长度,为0时表示未收到数据,大于0时表示收到了数据
extern const char* atCommands[] ;
//extern __IO uint16_t TimeCounter;//时间计数,单位ms
extern __IO uint8_t message_complete;//消息接收完成的标志位
extern __IO uint8_t Receive_begin;
extern volatile uint32_t last_receive_time;

uint8_t Flag_send = 0;

// 声明一个设备参数变量
DeviceParameters deviceParams;


/*弃用
void reset_receive()
{
	// 重置接收索引,准备接收下一段内容
	receivedIndex = 0;
	receivedLength = 0;
	memset(receivedData,0,sizeof(receivedData));
}*/
//启用
void Receive_Reset()
{
	message_complete = 0;
	receivedIndex =0;
	Receive_begin = 0;
	last_receive_time = HAL_GetTick();
	memset(receivedData,0,sizeof(receivedData));
}

// 发送指令并等待回复函数
HAL_StatusTypeDef sendCommandAndWait(const char* command, const char* expectedReply)
{
	uint8_t b_Reveived = 0;
	// 发送指令
	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 == message_complete )//如果还没有接收完所有数据,一直等待,直到接收完所有数据
	//{

	//}
	while(b_Reveived == 0)//如果没有收到回复消息,则一直循环等待
	{
		HAL_UART_Receive_IT(&huart1, &rxBuffer[receivedIndex], 1);
		if(1 == Receive_begin)
		{
			while(message_complete != 1)//如果还没有接收完所有数据,一直等待,直到接收完所有数据
			{

			}
			b_Reveived = 1;
		}
	}
	if (strstr((const char *)receivedData, expectedReply) != NULL)
	{

		//while(1)
		{
			//HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_4);
			//HAL_Delay(100);
		}

		// 重置接收,准备接收下一段内容
		//reset_receive();

		Receive_Reset();
		// 收到期望的回复
		return HAL_OK;
	}

	// 重置接收,准备接收下一段内容
	//reset_receive();
	Receive_Reset();
	
	return HAL_ERROR;
}

//等待wifi配网成功
HAL_StatusTypeDef WaitConnected()
{
	int Connected = 0;//是否配网完成
	// 持续等待回复,直到收到配网成功的回复;当TimeOut_flag为2时说明超时了
	while ( 1 != Connected)
	{
		//HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_9);
		//HAL_Delay(50);
		HAL_UART_Receive_IT(&huart1, &rxBuffer[receivedIndex], 1);
	    //if(0 != receivedLength)//收到数据了
	    //{

		  if(1 == Receive_begin)
		  {
	  	      while(message_complete != 1)
	  	      {

	  	      }

	    	//while( message_complete == 0)//判断是否接收完数据,如果未接收完,则一直循环,直到接收完
	    	//{

	    	//}

			if (strstr((const char *)receivedData, "ILOPEVENT:ILOP,CONNECTED") != NULL)
			{
				//reset_receive();
				Receive_Reset();

				Connected = 1;
				return HAL_OK;//配网成功
			}
			// 重置接收,准备接收下一段内容
			//reset_receive();
			Receive_Reset();

					
	    }
	}

	return HAL_TIMEOUT;
}


// 进入WiFi配网过程的函数
HAL_StatusTypeDef WiFiConfigInit()
{

	HAL_StatusTypeDef status;

	// 发送指令 "AT",直到收到的回复是OK
	status = sendCommandAndWait(atCommands[0], "OK");
	while (status != HAL_OK)
	{
		status = sendCommandAndWait("AT\r\n", "OK");
	}
	//HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_4);
	HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_9);
	  // 延时10秒
	//HAL_Delay(5000);

	// 发送指令 "AT+ILOPAWSAP\r\n"
	status = sendCommandAndWait("AT+ILOPAWSAP\r\n", "OK");
	while (status != HAL_OK)
	{
		status = sendCommandAndWait("AT+ILOPAWSAP\r\n", "OK");
	}
	//HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_4);
	HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_9);
	//HAL_Delay(5000);
	if(HAL_OK ==  WaitConnected())
	{
		HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_9);
	}
	else
	{
		while(1)
		{
			//HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_4);
			HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_9);
			HAL_Delay(100);
		}
		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)
	{
		// 重置接收,准备接收下一段内容
		Receive_Reset();

		disConnected = DISCONNECT_TRUE;//wifi断开
	}	

	return disConnected;
}


void wifi_task()
{
	HAL_UART_Receive_IT(&huart1, &rxBuffer[receivedIndex], 1);

	if(0 != Receive_begin)//说明接收到消息了
	{

		while( 0 == message_complete)
		{

		}

		if(DISCONNECT_TRUE == wifi_isDisconnected())//如果wifi断开了
		{
			WaitConnected();//等待wifi重连成功

		}
		else
		{
			parseWiFiCommand((char *)receivedData);
			//wilo_test();

			deviceControl();

			Receive_Reset();
					
		}
	}
	
	//上报状态
	if(Flag_send)
	{
		sendAllDataToWifi();
		Flag_send = 0;
	}

}



void parseWiFiCommand(const char* command)
{
    //const char* keyword = "+ILOPEVENT:SETJSON,property,";
	const char* keyword = "+ILOPEVENT:SETJSON";
    const char* powerstateKeyword = "\"powerstate\":";
    const char* powerstateValue = NULL;

#if 1

    // 检查指令是否以关键字开头
    if (strncmp(command, keyword, strlen(keyword)) == 0)
	{
    	// 定位到powerstate关键字的位置
	    powerstateValue = strstr(command, powerstateKeyword);
	    if (powerstateValue != NULL)
		{
	        // 解析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;
	            //HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_4);
	        }
	    	else
	    	{
	            while(1)
	    		{

	    		}
	        }
	        //return;
	    }
        //return;
    }
#endif

}


void deviceControl()
{
	if(0 == deviceParams.powerState)
	{
		//HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_SET);//灯灭
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_SET);//灯灭
	}
	else if(1 == deviceParams.powerState)
	{
		//HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_RESET);//灯亮
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_RESET);//灯亮
	}
}

// 发送数据
void sendAllDataToWifi() 
{
	const char *jsonString ="{\"powerstate\":1}";

	// 假设缓冲区大小为50
	char txBuffer_wifi[50];

	// 要发送的json数据长度值
	//int value = 18;
	int num = 1;//这里的num表示要发送的参数个数;
	int value = strlen(jsonString) + 2 * num;/   2*num表示转义字符\的个数,因为每个参数都会携带两个转义字符\     	

	// 格式化字符串并将结果存储在txBuffer_wifi中
	int len = snprintf(txBuffer_wifi, sizeof(txBuffer_wifi), "AT+ILOPSENDJSON=property,%d\r\n", value);

	// 检查格式化是否成功
	if (len >= sizeof(txBuffer_wifi)) 
	{
		// 缓冲区不足以容纳完整的字符串
		// 处理错误情况
	} 
	else 
	{
		// 发送指令
		WILO_UART_Transmit_IT(&huart1, (uint8_t*)txBuffer_wifi, len);
	}


	// 发送指令
	WILO_UART_Transmit_IT(&huart1, (uint8_t*)jsonString, strlen(jsonString));	

	return ;
}
void wilo_test()
{
	  HAL_UART_Receive_IT(&huart1, &rxBuffer[receivedIndex], 1);
	  	 // while(1 != Receive_begin)
	  {

	  }
	  if(1 == Receive_begin)
	  {
	      while(message_complete != 1)
	      {

	      }
		  //if (message_complete)
	      {
	          // 处理接收完成的消息
	          // ...
	    	  const char* keyword = "OK";
	    	  const char* result;
	    	  //HAL_Delay(1000);

	    	  //if(0 == strcmp(keyword,receivedData))
	    	  result = strstr(receivedData, keyword);
	    	  if(NULL != result)
	    	  {
	    		  //HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_4);//LED反转输出
					while (1)
					{
						HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_4);
						HAL_Delay(100);
					}
	    	  }
	    	  //HAL_Delay(100);
	    	  while(1);

	          Receive_Reset();
	      }

	  }
}


笔记

记录几个开发中的细节:

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}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乘凉~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值