网站首页
IC库存
IC展台
电子资讯
技术资料
PDF文档
我的博客
IC72论坛
ic72 logo
资料首页最新产品 技术参数 电路图 设计应用 解决方案 代理商查询 IC替换 IC厂商 电子辞典
关键字: 技术文章 PDF资料 IC价格 电路图 代理商查询 IC替换 IC厂商 电子辞典

RISC-V单片机快速入门05-玩转ESP8266 WIFI模块②

上一节,我们使用串口工具发送AT指令操作ESP-01S,本节,使用GD32VF103代替传偶工具完成和ESP-01S模块的交互过程。

一、基础知识

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!rn", sock);  break;  case STA_CLOSED:         rt_kprintf("Sock %d closed!rn", sock);  break;  case STA_DATA_ARRIVED:         rt_kprintf("Sock %d data arrived!rn", 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 %drn", 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 %drn", 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 %srn", 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 :%srn", 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所示

热门搜索:SBB830-QTY10 ADS1013IDGSR 2866352 2856142 1301380020 TLM626NS TLP606 UL800CB-15 2839237 LED12-C2 ADS1013IDGSR 2882828 2320296 B3429D PS2408RA PS361206 TRAVELER3USB 2320322 PS3612 TLP808TEL 2762265 48VDCSPLITTER TLM825GF TLP712B 01M1001JF
COPYRIGHT:(1998-2010) IC72 达普IC芯片交易网
客户服务:service@IC72.com 库存上载:IC72@IC72.com
(北京)联系方式: 在线QQ咨询:点击这里给我发消息 联系电话:010-82614113 传真:010-82614123
京ICP备06008810号-21 京公网安备 11010802032910 号 企业资质