RISC-V单片机快速入门06-控制ESP8266启动Http Server

前言:

上一节,我们使用GD32VF103控制ESP-01S启动TCP Server,然后让多个网络调试助手连接ESP-01S并与之通信,本节我们在上一节基础上完成控制ESP-01S启动HTTP Server的功能,使用网页访问ESP-01S。

一、基础知识

1.HTTP简介

HTTP是Hypertext Transfer Protocol的缩写,Hypertext(超文本)是可以根据客户端请求而跳转的结构化信息。HTTP协议的请求及相应方式设计如下图所示:
在这里插入图片描述
从图中可以看出,服务器端响应客户端请求后立刻断开连接,连接不会维持很久,即使同一个客户端再次发送请求,服务端也无法辨认出是否是原先的那个客户端发出的请求,会以相同的方式处理新的请求。

2.HTTP请求

HTTP请求是客户端向服务端发送请求消息,请求消息可以分为请求行、消息头、消息体三个部分;请求行含有请求方式信息(GET/POST等),GET用于请求数据,POST主要用于传输数据;消息头包括一些访问的域名、用户代理、Cookie等信息;消息体就是请求的数据,仅在POST方式请求时候输入。
在这里插入图片描述

3.HTTP响应

HTTP响应是指服务端根据客户端发送的请求中的动作要求做出具体的动作,然后将结果返回给客户端。 HTTP响应消息可以分为状态行、头信息、消息体三个部分;状态行含有请求的状态信息,这是其与请求消息相比最大的区别。
在这里插入图片描述

4.交互流程简介

(1)设备上电,先控制8266的复位引脚为低电平,让模块复位

(2)发送指令:ATE0,取消回显

(3)发送指令:AT+CWMODE=2,设置ESP01S为AP模式

(4)发送指令:AT+CIPMUX=1,设置多路连接,AP模式最多支持5个设备连接

(5)发送指令:AT+CWSAP=“ESP01S_test”,“12345678”,1,3,启动一个WIFI热点

(6)发送指令:AT+CIPSERVER=1,8089,启动TCP Server

(7) 大循环中检测是否收到ESP01S数据,收到数据后判断,如果是网页发来数据,返回HTTP数据。

二、程序说明

程序主要包括如下4个功能模块:ESP-01S初始化、串口处理、Event回调函数、事件处理;Http协议是基于TCP协议的,本节是在上一节基础上进行的,Event回调函数代码和上一节保持一致即可,ESP-01S初始化部分改动也较小,修改TCP server超时时间,设置1秒超时,即客户端访问数据后,服务器返回数据后主动断开连接,修改函数如下:

ESP8266_StartOrShutServer ( 1, "8089", "1" )

2.1 串口处理

串口处理模块包括串口接收和定时器判断一帧数据是否接收完成功能,一帧数据接收是否完成的判断逻辑是:定时器会定期检测,如果FramStartFlag为1,说明串口正在接收数据,没接收一个数据,FramLength加1,因此,当进入定时器中断函数,判断FramStartFlag为1情况下FrameLength如果不再增加,说明一帧数据接收完成。

static void timeout1(void *parameter)
{
    int sock_id = -1;
    char buff[128] = { 0x00 };
    int len = 0;
    sys_event_e event = STA_EVENT_MAX;
    
//  rt_kprintf("timer's cnt is %d, FrameLength is %d\r\n", cnt, Esp8266_Frame_Record.FramLength);
    if (1 == Esp8266_Frame_Record.InfBit.FramStartFlag)
    {
        if (cnt == Esp8266_Frame_Record.FramLength && cnt != 0)
        {
            cnt = 0;
            Esp8266_Frame_Record .Data_RX_BUF [ Esp8266_Frame_Record.FramLength ]  = 0x00;
            rt_kprintf("timer --------> data %s\r\n", Esp8266_Frame_Record.Data_RX_BUF);
            if (rt_strstr(Esp8266_Frame_Record.Data_RX_BUF, "CONNECT"))
            {
                sscanf(Esp8266_Frame_Record.Data_RX_BUF, "%d,%s", &sock_id, buff);
                event = STA_CONNECTED;
            }else if (rt_strstr(Esp8266_Frame_Record.Data_RX_BUF, "CLOSED"))
            {
                sscanf(Esp8266_Frame_Record.Data_RX_BUF, "%d,%s", &sock_id, buff);
                event = STA_CLOSED;
            }else if (rt_strstr(Esp8266_Frame_Record.Data_RX_BUF, "+IPD"))
            {
                rt_memset(hal_sys_contex_get()->data_buf, 0x00, SYS_CTX_UART_RECV_SIZE);
                sscanf(Esp8266_Frame_Record.Data_RX_BUF, "%*[^+]+IPD,%d,%d:%[^\r]", &sock_id, &len, hal_sys_contex_get()->data_buf);
                event = STA_DATA_ARRIVED;
                rt_kprintf("parsed +IPD :%s\r\n", hal_sys_contex_get()->data_buf);
            }
            // call sys_status_cb
            if (hal_sys_contex_get()->sys_status_cb)
            {
                hal_sys_contex_get()->sys_status_cb(sock_id, event);
            }
            
            Esp8266_Frame_Record.InfBit.FramFinishFlag = 1;
            Esp8266_Frame_Record.InfBit.FramStartFlag = 0;
        }else
        {
            cnt = Esp8266_Frame_Record.FramLength;
        }
    }else
    {
        cnt = 0;
        Esp8266_Frame_Record.FramLength = 0;
    }
}

上述代码为上一节的代码,根据串口收到的数据内容,将数据分为三类:连接通知、断开通知、数据传输通知,本节使用http client访问,会同时收到"CONNECT“和"+IPD",因此需要将代码做如下修改:增加同时收到"CONNECT"和"+IPD"判断,方便主程序检测到网页访问。

static void timeout1(void *parameter)
{
    int sock_id = -1;
    char buff[128] = { 0x00 };
    int len = 0;
    sys_event_e event = STA_EVENT_MAX;
    
    if (1 == Esp8266_Frame_Record.InfBit.FramStartFlag)
    {

        if (cnt == Esp8266_Frame_Record.FramLength && cnt != 0)
        {
            cnt = 0;
            Esp8266_Frame_Record .Data_RX_BUF [ Esp8266_Frame_Record.FramLength ]  = 0x00;

            // http data include both "CONNECT" and "IPD"
            if (rt_strstr(Esp8266_Frame_Record.Data_RX_BUF, "CONNECT") &&                     rt_strstr(Esp8266_Frame_Record.Data_RX_BUF, "+IPD"))
            {
                rt_memset(hal_sys_contex_get()->data_buf, 0x00, SYS_CTX_UART_RECV_SIZE);
                sscanf(Esp8266_Frame_Record.Data_RX_BUF, "%*[^+]+IPD,%d,%d:%[^\r]", &sock_id, &len, hal_sys_contex_get()->data_buf);
                event = STA_DATA_ARRIVED;
           }
            else if (rt_strstr(Esp8266_Frame_Record.Data_RX_BUF, "CONNECT"))
            {
                    sscanf(Esp8266_Frame_Record.Data_RX_BUF, "%d,%s", &sock_id, buff);
                event = STA_CONNECTED;
            }else if (rt_strstr(Esp8266_Frame_Record.Data_RX_BUF, "CLOSED"))
            {
                    sscanf(Esp8266_Frame_Record.Data_RX_BUF, "%d,%s", &sock_id, buff);
                event = STA_CLOSED;
            }else if (rt_strstr(Esp8266_Frame_Record.Data_RX_BUF, "+IPD"))
            {
                rt_memset(hal_sys_contex_get()->data_buf, 0x00, SYS_CTX_UART_RECV_SIZE);
                sscanf(Esp8266_Frame_Record.Data_RX_BUF, "%*[^+]+IPD,%d,%d:%[^\r]", &sock_id, &len, hal_sys_contex_get()->data_buf);
                event = STA_DATA_ARRIVED;
            }
            // call sys_status_cb
            if (hal_sys_contex_get()->sys_status_cb)
            {
                hal_sys_contex_get()->sys_status_cb(sock_id, event);
            }
            
            Esp8266_Frame_Record.InfBit.FramFinishFlag = 1;
            Esp8266_Frame_Record.InfBit.FramStartFlag = 0;
        }else
        {
            cnt = Esp8266_Frame_Record.FramLength;
        }
    }else
    {
            cnt = 0;
        Esp8266_Frame_Record.FramLength = 0;
    }
}

2.2 事件处理

事件处理模块主要包含应用程序大循环,大循环中检测系统事件状态,根据事件状态再大循环中做出响应;上一节此处做的处理比较简单,将收到的数据原路返回,本节需要判断网页发送的数据内容,返回不同的数据给网页,网页访问http://192.168.4.1:8089/getdata 返回{“pm25”:2},网页访问http://192.168.4.1:8089/index 返回

index

char *response = "HTTP/1.1 200 OK \r\n\r\n{\"pm25\":2}";
char *response_index = "HTTP/1.1 200 OK \r\n\r\n<h1>index</h1>";

int main(void)
{
    /* enable the LED clock /
    rcu_periph_clock_enable(RCU_GPIOA);
    / configure LED GPIO port */
    gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_1);
    gpio_bit_reset(GPIOA, GPIO_PIN_1);
    // create iwdt_thread
    dynamic_thread = rt_thread_create("led_thread", led_process_thread_entry,
                                        RT_NULL, 512, 2, 10);
    rt_thread_startup(dynamic_thread);
    // init sys_ctx
    hal_sys_contex_init(system_status_callback, RT_NULL);
    system_context = hal_sys_contex_get();
    hal_timer_init();
    ESP8266_Init();
    rt_thread_mdelay(1000);
    ESP8266_Ate0();
    http_server_init();
    http_server_start();

    while(1)
    {
        if (STA_DATA_ARRIVED == system_context->event)
        {
            if (rt_strstr(system_context->data_buf, "/getdata"))
            {
                rt_kprintf("ready to send data………. %s\r\n", response);
                ESP8266_SendString ( DISABLE, response, rt_strlen(response), system_context->sock_id );
                system_context->event = STA_CONNECTED;
            }else if(rt_strstr(system_context->data_buf, "/index"))
            {
                rt_kprintf("ready to send data………. %s\r\n", response_index);
                ESP8266_SendString ( DISABLE, response_index, rt_strlen(response_index), system_context->sock_id );
                system_context->event = STA_CONNECTED;
            }
        }
        rt_thread_mdelay(10);
    }
    return 0;
}

三、运行

下载程序完毕后,重启设备,ESP01S启动一个WIFI热点,并启动TCP Server,log如下:
在这里插入图片描述
电脑连接热点,网页访问http://192.168.4.1:8089/index
|
网页访问http://192.168.4.1:8089/getdata
|
从上文可知,ESP-01S已经启动了HTTP Server并能接收网页的访问。

四、结语

如您在使用过程中有任何问题,请加QQ群进一步交流。

QQ交流群:906015840 (备注:物联网项目交流)

资料获取:关注下方公众号,回复risc-v即可

一叶孤沙出品:一沙一世界,一叶一菩提
在这里插入图片描述
如果您觉得本教程对您有用,欢迎转发或者点击再看支持下~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

物联网客栈

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

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

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

打赏作者

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

抵扣说明:

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

余额充值