你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

RISC-V单片机如何玩转ESP8266 WIFI?

[复制链接]
gaosmile 发布时间:2020-7-8 17:38
     1.交互流程简介

    (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)发送指令:AT+CIPSERVER=1,8089,启动TCP Server

    (8)大循环中检测是否收到ESP01S数据,收到数据后立刻返回

2.程序框架简介

程序主要包括如下4个功能模块:ESP01S初始化、串口处理、Event回调函数、事件处理;串口处理模块包括串口接收和定时器判断一帧数据是否接收完成功能,Event回调函数主要用来通知应用层系统的状态,方便应用层做出相应,比如设备检测到其他TCP Client客户端接入模块,可以控制LED状态,事件处理模块主要包含应用程序大循环,大循环中检测系统事件状态,根据事件状态再大循环中做出响应。

二、系统功能模块详述

1.Event回调函数

本程序使用了函数指针,应用层将事件处理函数传到hal_common.c中int hal_sys_contex_init(sys_status_fun fun, void *user_data)函数

        void system_status_callback(int sock, int event)

        {

        system_context-》sock_id = sock;

        system_context-》event = event;

        switch (event)

        {

        case STA_CONNECTED:

        rt_kprintf(“Sock %d connected!\r\n”, sock);

        break;

        case STA_CLOSED:

        rt_kprintf(“Sock %d closed!\r\n”, sock);

        break;

        case STA_DATA_ARRIVED:

        rt_kprintf(“Sock %d data arrived!\r\n”, sock);

        break;

        default:

        break;

        }

        }

        typedef enum {

        STA_CONNECTED,

        STA_CLOSED,

        STA_DATA_ARRIVED, // clients send data to wifi

        STA_EVENT_MAX,

        }sys_event_e;

        typedef void (*sys_status_fun)(int sock, int event);

        typedef struct sys_ctx{

        int sock_id;

        sys_event_e event;

        char data_buf[SYS_CTX_UART_RECV_SIZE];

        sys_status_fun sys_status_cb;

        void *user_data;

        }sys_ctx_t;

        int hal_sys_contex_init(sys_status_fun fun, void *user_data)

        {

        sys_contex.sys_status_cb = fun;

        sys_contex.user_data = user_data;

        return 0;

        }

        int main(void)

        {

        hal_sys_contex_init(system_status_callback, RT_NULL);

        while(1)

        {

        }

        }

2.串口处理

串口处理模块包括串口接收和定时器判断一帧数据是否接收完成功能,串口接收函数代码如下:

        #define RX_BUF_MAX_LEN 1024 //最大接收缓存字节数

        struct STRUCT_USART_Fram_S //串口数据帧的处理结构体

        {

        char Data_RX_BUF [ RX_BUF_MAX_LEN ];

        uint16_t FramLength;

        struct {

        uint8_t FramStartFlag;

        uint8_t FramFinishFlag;

        } InfBit;

        } ;

        struct STRUCT_USART_Fram_S Esp8266_Frame_Record;

        void USART2_IRQHandler()

        {

        uint8_t ch = -1;

        if(RESET != usart_interrupt_flag_get(EVAL_COM2, USART_INT_FLAG_RBNE))

        {

        ch = usart_data_receive(EVAL_COM2);

        // if ( Esp8266_Frame_Record.FramLength 《 ( RX_BUF_MAX_LEN - 1 ) ) //预留1个字节写结束符

        // {

        Esp8266_Frame_Record .Data_RX_BUF [ Esp8266_Frame_Record.FramLength ] = ch;

        // }

        Esp8266_Frame_Record.FramLength ++;

        if (Esp8266_Frame_Record.FramLength 》= 1024)

        {

        Esp8266_Frame_Record.FramLength = 0;

        }

        cnt = Esp8266_Frame_Record.FramLength;

        // rt_kprintf(“。..。...uart recv : %c, count is %d\r\n”, ch, cnt);

        Esp8266_Frame_Record.InfBit.FramStartFlag = 1;

        }

        }

中断处理函数中,将接收的数据放到Esp8266_Frame_Record .Data_RX_BUF中,然后将

Esp8266_Frame_Record.InfBit.FramStartFlag置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;

        }

        }

注意:事件处理本质上是在此调用hal_sys_contex_get()-》sys_status_cb(sock_id, event)映射到应用层的void system_status_callback(int sock, int event)函数。

3.事件处理

事件处理的核心再while(1)中,根据系统当前事件状态做出响应,本节是检测到事件为数据类型时候,将数据原路返回。

        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();

        tcp_server_init();

        tcp_server_start();

        while(1)

        {

        if (STA_DATA_ARRIVED == system_context-》event)

        {

        // send back

        ESP8266_SendString ( DISABLE, system_context-》data_buf, rt_strlen(system_context-》data_buf), system_context-》sock_id );

        }

        rt_thread_mdelay(10);

        }

        return 0;

        }

三、运行

下载程序完毕后,重启设备,ESP01S启动一个WIFI热点,并启动TCP Server,log如下:

电脑连接热点,使用网络助手连接192.168.4.1:8089

网络助手发送数据给ESP01S

关闭网络助手,应用程序也可以检测到,如下Log所示


收藏 评论1 发布时间:2020-7-8 17:38

举报

1个回答
likang1202 回答时间:2020-7-9 09:23:49
顶一下

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版