IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> STM32玩转物联网实战篇:3.2.ESP8266 WIFI模块WEBClient解耦增强版(LWWC-轻量级Web客户端软件包) -> 正文阅读

[嵌入式]STM32玩转物联网实战篇:3.2.ESP8266 WIFI模块WEBClient解耦增强版(LWWC-轻量级Web客户端软件包)

1、准备开发板

开发板功能区分布图

在这里插入图片描述

开发板俯视图

在这里插入图片描述
我们在前面实现了一个WebClient,但是缺点就是模块之间耦合度太高,还有会出现堆栈溢出的情况,为了解决这些问题,我重新改写了代码,对模块之间进行解耦,让大家拿到任一个模块都可以单独运行起来得到想要的结果

3、在MDK中编写代码

WebClient客户端代码
web_strdup将字符串复制到新开辟的内存空间
webclient_header_fields_add将请求句柄封装到客户端缓存区
webclient_header_fields_get解析响应数据的单一消息报头
webclient_header_length_response获取请求头的长度
webclient_handle_response获取服务器响应的状态码
webclient_data_analysis获取服务器返回的数据包
HTTP请求方法
webclient_get_method客户端GET请求方法
webclient_post_method客户端POST请求方法

????LWWC(Light Weight Web Client),即轻量Web客户端,通过一些简单的字符串处理和解析函数,可以有效的进行常用HTTP协议组包和响应解析,各个模块之间经过解耦的编程思想,模块可以独立运行得出结果。占用内存非常小,可以满足一些小型嵌入式系统HTTP/HTTPS协议开发的需求。
这里只修改了webclient的代码,其余代码参考上一章。

在lwwc.h中编写以下代码:

#ifndef __LWWC_H_
#define __LWWC_H_
#include "sys.h"


#ifndef WEBCLIENT_OK
#define WEBCLIENT_OK 0
#endif

#ifndef WEBCLIENT_NOK
#define WEBCLIENT_NOK 1
#endif


void webclient_get_method(void);
void webclient_post_method(void);


#endif

在lwwc.c中编写以下代码:

#include "lwwc.h"
#include "ESP8266.h"
#include "usart.h"
#include "StringUtil.h"


//将字符串复制到新开辟的内存空间
char* web_strdup(const char* s)
{
	uint16_t len = strlen(s) + 1;
	char* tmp = (char*)malloc(len);

	if (!tmp)
			return NULL;

	memcpy(tmp, s, len);

	return tmp;
}


//将请求句柄封装到客户端缓存区
unsigned int webclient_header_fields_add(char* buffer, unsigned int bufsize, const char* fmt, ...)
{
    int length = strlen(buffer);
    if (length >= bufsize) {
        printf("Buffer uninitialized or exceeded.");
        return 0;
    }
    va_list args;
    va_start(args, fmt);
    length = vsnprintf(buffer + length, bufsize, fmt, args);
    if (length < 0)
    {
        printf("add fields header data failed, return length(%d) error.", length);
        return length;
    }
    va_end(args);

    return length;
}


//获取服务器响应的状态码
int webclient_handle_response(char* buffer)
{
    int rc = 0;
		char* mime_ptr = NULL;
    char* mime_buffer = NULL;
    const char* transfer_encoding;
    int i;
    int resp_status;

    /* get HTTP status code */
	
		mime_ptr = web_strdup(buffer);

    if (strstr(mime_ptr, "HTTP/1."))
    {
        char* ptr = mime_ptr;

        ptr += strlen("HTTP/1.x");
        

        while (*ptr && (*ptr == ' ' || *ptr == '\t'))
            ptr++;

        /* Terminate string after status code */
        for (i = 0; ((ptr[i] != ' ') && (ptr[i] != '\t')); i++);
        ptr[i] = '\0';
				
        resp_status = (int)strtol(ptr, NULL, 10);

    }
		
	if (mime_ptr)
	{
			free(mime_ptr);
	}		

    return resp_status;
}


//解析响应数据的单一消息报头
const char* webclient_header_fields_get(char* resp_buf, const char* fields)
{
	char* dataPtr;
	char* mime_ptr = NULL;

	dataPtr = strstr(resp_buf,fields);
	if(dataPtr != NULL)
	{
		mime_ptr = strstr(dataPtr,":");
		if(mime_ptr != NULL)
		{
				mime_ptr += 1;
				while (*mime_ptr && (*mime_ptr == ' ' || *mime_ptr == '\t'))
					mime_ptr++;
				return mime_ptr;
		}
	}
	
	return NULL;
}


//获取服务器返回的数据包
uint8_t* webclient_data_analysis(char* buffer)
{
	char* dataptr;
	
	dataptr = strstr(buffer,"\r\n\r\n");
	if(dataptr != NULL)
	{
		dataptr += 4;
		return (uint8_t*)dataptr;
	}
	
	return NULL;
}

//客户端GET请求方法
void webclient_get_method(void)
{
		uint8_t uwRet = WEBCLIENT_NOK;
	uint8_t *dataPtr;
	char* mime_ptr = (char*)netDeviceInfo.netIOInfo->rxBuf; //接收缓冲区
	char postBuf[200];
	
	memset(postBuf,0,sizeof(postBuf));	//局部数组一定要清空
	
	webclient_header_fields_add(postBuf,sizeof(postBuf),"GET https://api.seniverse.com/v3/weather/now.json?key=smtq3n0ixdggurox&location=nanning&language=en&unit=c HTTP/1.1\r\n");
	webclient_header_fields_add(postBuf,sizeof(postBuf),"Host:www.baidu.com\r\n");
	webclient_header_fields_add(postBuf,sizeof(postBuf),"\r\n");
	
	if(ESP8266_DisconnectServer(0) != ESP8266_OK)	//断开服务器连接
		return;
	
	
	if(ESP8266_Link_Server(enumTCP,"api.seniverse.com","80",Single_ID_0) == ESP8266_OK)	//连接服务器
	{
	
		uwRet = ESP8266_SendData(DISABLE,(uint8_t*)postBuf,strlen(postBuf),Single_ID_0);	//发送数据
		
		if(uwRet == WEBCLIENT_OK)	//发送成功
		{
			dataPtr = ESP8266_GetIPD(DISABLE,2000);	//解析服务器返回的数据
			
			if(dataPtr != NULL)
			{
//				printf("begin dataPtr:%s\r\n",dataPtr);
//				printf("begin strlen(dataPtr):%d\r\n",strlen((char*)dataPtr));
				if(webclient_handle_response((char*)dataPtr) == 200)	//解析服务器返回的状态码
				{
//					printf("end dataPtr:%s\r\n",dataPtr);
//					printf("end strlen(dataPtr):%d\r\n",strlen((char*)dataPtr));

					dataPtr = webclient_data_analysis((char*)dataPtr);		//获取服务器返回的数据
					if(dataPtr != NULL)
					{
						if(strstr((char*)dataPtr,"+IPD,"))		//查找是否有IPD头
						{
							dataPtr = Filter_string((char*)dataPtr,(char*)"+IPD,",(char*)":");	//过滤IPD头
							if(dataPtr!=NULL)
							{
								printf("dataPtr:%s\r\n",dataPtr);
							}
						}
						else
						{
								printf("dataPtr:%s\r\n",dataPtr);
						}
					}
					
				}
			}
		}
	}
	
}

//客户端POST请求方法
void webclient_post_method(void)
{
	uint8_t uwRet = WEBCLIENT_NOK;
	uint8_t *dataPtr;
	char* mime_ptr = (char*)netDeviceInfo.netIOInfo->rxBuf;	//接收缓冲区
	char postBuf[200];
	
	memset(postBuf,0,sizeof(postBuf));	//局部数组一定要清空
	
	webclient_header_fields_add(postBuf,sizeof(postBuf),"POST /devices/583402349/datapoints HTTP/1.1\r\n");
	webclient_header_fields_add(postBuf,sizeof(postBuf),"api-key:rBIh6FFxeyW=kVJyybB2FzD5QAQ=\r\n");
	webclient_header_fields_add(postBuf,sizeof(postBuf),"Host: api.heclouds.com\r\n");
	webclient_header_fields_add(postBuf,sizeof(postBuf),"Content-Length:66\r\n");
	webclient_header_fields_add(postBuf,sizeof(postBuf),"\r\n");
	webclient_header_fields_add(postBuf,sizeof(postBuf),"{\"datastreams\":[{\"id\":\"test_stream\",\"datapoints\":[{\"value\":30}]}]}");
	
	if(ESP8266_DisconnectServer(0) != ESP8266_OK)	//断开服务器连接
		return;
	
	
	if(ESP8266_Link_Server(enumTCP,"api.heclouds.com","80",Single_ID_0) == ESP8266_OK)	//连接服务器
	{
	
		uwRet = ESP8266_SendData(DISABLE,(uint8_t*)postBuf,strlen(postBuf),Single_ID_0);	//发送数据
		
		if(uwRet == WEBCLIENT_OK)	//发送成功
		{
			dataPtr = ESP8266_GetIPD(DISABLE,5000);	//解析服务器返回的数据
			
			if(dataPtr != NULL)
			{
				
				//printf("dataPtr:%s\r\n",dataPtr);
				if(webclient_handle_response((char*)dataPtr) == 200)	//解析服务器返回的状态码
				{
				
					//printf("strlen(dataPtr):%d\r\n",strlen((char*)dataPtr));

					dataPtr = webclient_data_analysis((char*)dataPtr);		//获取服务器返回的数据
					if(dataPtr != NULL)
					{
						if(strstr((char*)dataPtr,"+IPD,"))		//查找是否有IPD头
						{
							dataPtr = Filter_string((char*)dataPtr,(char*)"+IPD,",(char*)":");	//过滤IPD头
							if(dataPtr!=NULL)
							{
								printf("dataPtr:%s\r\n",dataPtr);
							}
						}
						else
						{
								printf("dataPtr:%s\r\n",dataPtr);
						}
					}
					
				}
			}
		}
	}
	
}

在main.c中编写以下代码



int main(void)
{
  /* USER CODE BEGIN 1 */
	unsigned char* dataPtr = NULL;
	uint32_t request_time = 0;
	ESP8266_RETTYPE uwRet = ESP8266_NOK;
	uint32_t request_method=0; //0:GET请求,1:POST请求

  /* 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_LPUART1_UART_Init();
  MX_USART1_UART_Init();
  MX_TIM2_Init();
  /* USER CODE BEGIN 2 */
	
	TIM_Interupt_Enable(); //使能串口中断
	
	USART_Interupt_Enable(); //使能定时器中断

	
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		
		if(!netDeviceInfo.netWork)	//如果网络未连接
		{
			if(NET_DEVICE_Init() == ESP8266_OK)	
			{
				printf("初始化成功\r\n");
			}
		}
		
		if(time2Count - request_time >= 15000)		//(1ms * 2000)相当于延时2秒钟
		{
			if(netDeviceInfo.netWork)//如果网络连接成功
			{
				
				if(request_method)
				{
					webclient_post_method();
					request_method = 0; //切换GET请求
				}
				else
				{
					webclient_get_method();	
					request_method = 1; //切换POST请求
				} 
			}
		}
	
  }
  /* USER CODE END 3 */
}

4、实验现象

实现的功能
1、上电自动连接WIFI
2、如果是POST请求,则请求POST接口(我这里用的是ONENET的POST接口)
3、如果是GET请求,则请求GET接口(我这里用的是心知天气的GET接口)

POST请求(Onenet物联网平台)
在这里插入图片描述
GET请求(心知天气)
在这里插入图片描述

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-04-15 00:16:35  更:2022-04-15 00:19:16 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 4:26:19-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码