ESP8266WiFi模块实现TCP连接服务器

在前面的博客里(STM32-ESP8266wifi模块实现)说到了通过AT命令配置ESP8266实现TCP连接。
他的流程是,
1,使能串口,及中断。
2,发送AT指令到ESP8266WiFi模块,进行配置一些参数。

串口配置

串口初始化

// //配置串口,串口初始化。(usart1/usart2)
void MX_USART1_UART_Init(void)
{huart1.Instance = USART1;huart1.Init.BaudRate = 115200;//设置波特率huart1.Init.WordLength = UART_WORDLENGTH_8B;//字长为8位数据格式huart1.Init.StopBits = UART_STOPBITS_1;//一个停止位huart1.Init.Parity = UART_PARITY_NONE;//无奇偶校验位huart1.Init.Mode = UART_MODE_TX_RX;//收发模式huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;huart1.Init.OverSampling = UART_OVERSAMPLING_16;huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;if (HAL_UART_Init(&huart1) != HAL_OK)//初始化{Error_Handler();} //在这个函数里使能usart1的接收中断,中断接收的每个字节存储在 uart1_receive_rx 中HAL_UART_Receive_IT(&huart1 , &uart1_receive_rx, 1);
}
void MX_USART2_UART_Init(void)
{huart2.Instance = USART2;huart2.Init.BaudRate = 115200;//设置波特率huart2.Init.WordLength = UART_WORDLENGTH_8B;//字长为8位数据格式huart2.Init.StopBits = UART_STOPBITS_1;//一个停止位huart2.Init.Parity = UART_PARITY_NONE;//无奇偶校验位huart2.Init.Mode = UART_MODE_TX_RX;//收发模式huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;huart2.Init.OverSampling = UART_OVERSAMPLING_16;huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;if (HAL_UART_Init(&huart2) != HAL_OK)//初始化{Error_Handler();}//使能usart2的接收中断,中断接收的每个字节存储在 uart2_receive_rx 变量中
//每接收一个字节就会进入一次中断USART1_IRQHandler
//处理数据的函数,读取接收寄存器,将数据赋值给结构体huart的pRxBuffer并清除中断标志,HAL_UART_Receive_IT(&huart2 , &uart2_receive_rx, 1);
}
HAL_UART_Receive_IT(&huart1 , uint8_t *pData, uint16_t Size);

功能:串口中断接收,以中断方式接收指定长度数据。大致过程是,设置数据存放位置,接收数据长度,然后使能串口接收中断。接收到数据时,会触发串口中断。再然后,串口中断函数处理,直到接收到指定长度数据,而后关闭中断,进入中断接收回调函数,不再触发接收中断。(只触发一次中断)

参数:

UART_HandleTypeDef *huart 操作句柄
*pData 接收到的数据存放地址
Size 接收的字节数

GPIO配置及开启中断

void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{GPIO_InitTypeDef GPIO_InitStruct = {0};if(uartHandle->Instance==USART1){/* USART1 clock enable */__HAL_RCC_USART1_CLK_ENABLE();//使能串口USART1时钟__HAL_RCC_GPIOA_CLK_ENABLE();//使能GPIO时钟/**USART1 GPIO ConfigurationPA9     ------> USART1_TXPA10     ------> USART1_RX*/配置GPIOGPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;GPIO_InitStruct.Alternate = GPIO_AF7_USART1;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);//根据GPIO_INITTypeDef结构体中Pin来找到对应的要操作的引脚位置//初始化我们需要用到的引脚的工作模式,包括具体引脚的工作速度、是否复用模式、上下拉等等参数。/* USART1 interrupt Init */HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);HAL_NVIC_EnableIRQ(USART1_IRQn);}else if(uartHandle->Instance==USART2){/* USART2 clock enable */__HAL_RCC_USART2_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();/**USART2 GPIO ConfigurationPA2     ------> USART2_TXPA3     ------> USART2_RX*/GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;GPIO_InitStruct.Alternate = GPIO_AF7_USART2;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);//根据GPIO_INITTypeDef结构体中Pin来找到对应的要操作的引脚位置//初始化我们需要用到的引脚的工作模式,包括具体引脚的工作速度、是否复用模式、上下拉等等参数。/* USART2 interrupt Init */HAL_NVIC_SetPriority(USART2_IRQn, 0, 0);HAL_NVIC_EnableIRQ(USART2_IRQn);}
}

初始化之后的引脚恢复成默认的状态–各个寄存器复位时的值

void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{if(uartHandle->Instance==USART1){/* Peripheral clock disable */__HAL_RCC_USART1_CLK_DISABLE();/**USART1 GPIO ConfigurationPA9     ------> USART1_TXPA10     ------> USART1_RX*/HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);//将初始化之后的引脚恢复成默认的状态–各个寄存器复位时的值/* USART1 interrupt Deinit */HAL_NVIC_DisableIRQ(USART1_IRQn);}else if(uartHandle->Instance==USART2){/* Peripheral clock disable */__HAL_RCC_USART2_CLK_DISABLE();/**USART2 GPIO ConfigurationPA2     ------> USART2_TXPA3     ------> USART2_RX*/HAL_GPIO_DeInit(GPIOA, GPIO_PIN_2|GPIO_PIN_3);//将初始化之后的引脚恢复成默认的状态–各个寄存器复位时的值/* USART2 interrupt Deinit */HAL_NVIC_DisableIRQ(USART2_IRQn);}
}

串口中断服务函数

串口产生中断,就会自动调用USART1_IRQHandler,USART2_IRQHandler中断服务函数,以串口1USART1为例;

void USART1_IRQHandler(void)
{ uint32_t timeout=0;uint32_t maxDelay=0x1FFFF;
#if SYSTEM_SUPPORT_OS       //使用OSOSIntEnter();
#endifHAL_UART_IRQHandler(&huart1); //调用HAL库中断处理函数,通过这个中断处理函数会调用UART_Receive_IT(huart);timeout=0;while (HAL_UART_GetState(&huart1)!=HAL_UART_STATE_READY)//等待就绪{timeout++;超时处理if(timeout>maxDelay)break;     }timeout=0;while(HAL_UART_Receive_IT(&huart1,uart1_receive_rx, 1)!=HAL_OK)//一次处理完成之后,重新开启中断并设置RxXferCount为1{timeout++; //超时处理if(timeout>maxDelay) break;  }
#if SYSTEM_SUPPORT_OS       //使用OSOSIntExit();
#endif
} 

这个函数中,首先调用HAL_UART_IRQHandler(&huart1);
其主要用于判断中断类型。通过这个中断处理函数会调用UART_Receive_IT(huart);
该函数是将接收到的数据保存到指定的串口缓冲区,也就是变量uart1_receive_rx;。该函数每执行一次(接受一个字符),pRxBufferPtr指针加1,并保存接收到的字符到 uart1_receive_rx ,同时RxXferCount数据减1;接着再判断,RxXferCount自减后是否等于0.如果等于0 ,则关闭接收完成中断,进行中断回调函数。如果需要再一次开启时。需要再一次开启中断,也就是调用 HAL_UART_Receive_IT()函数

定义接收buffer

我们在usart.c 文件中要定义相关中断接收buffer。

//USART1
static uint8_t  uart1_receive_rx;
char            buf1[256];
uint8_t         uart1_b;
//USART2
static uint8_t  uart2_receive_rx;
char            buf2[256];
uint8_t         uart2_b;

中断接收回调函数

//将uart1,uart2接收数据加进buf中。
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if (huart->Instance == USART1){       if( uart1_b< sizeof(uart1_receive_buf) ){buf2[uart1_b++] = uart1_receive_rx;}HAL_UART_Receive_IT(&huart1 , &uart1_receive_rx, 1);}if (huart->Instance == USART2){if( uart1_b< sizeof(buf2) ){buf2[uart2_b++] = uart2_receive_rx;}HAL_UART_Receive_IT(&huart2 , &uart2_receive_rx, 1);}
}

下面一张流程图也可以很好的理解串口中断接收:

函数流程图:

HAL_UART_Receive_IT(中断接收函数) -> USART_IRQHandler(void)(中断服务函数) -> HAL_UART_IRQHandler(UART_HandleTypeDef *huart)(中断处理函数) -> UART_Receive_IT(UART_HandleTypeDef *huart) (接收函数) -> HAL_UART_RxCpltCallback(huart);(中断回调函数)

串口发送数据:

HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)

功能:串口发送指定长度的数据。如果超时没发送完成,则不再发送,返回超时标志(HAL_TIMEOUT)。
参数:

UART_HandleTypeDef *huart 转发huart1/huart2的句柄
*pData 需要发送的数据
Size 发送的字节数
Timeout 最大发送时间,发送数据超过该时间退出发送

//举例:
HAL_UART_Transmit(&huart1, uart1_receive_rx, uart1_b, 0xffff);   //串口发送uart1_b字节数据,最大传输时间0xffff

串口的转发函数

// 这个函数在我们来手动测试AT命令时需要用到串口转发函数,下篇博文会自动完成相关AT命令的操作;
void uart_forward(void)
{if ( strstr(buf1, "/r/n") ){HAL_UART_Transmit(&huart2 ,(uint8_t *)buf1, uart1_b, 0xFF);//最大传输时间0xFFclear_buf1();//这是一个宏用来清理buf1中的数据。保证每次转发的数据都是最新的数据}if ( uart2_b > 0 ){HAL_UART_Transmit(&huart1, (uint8_t *)buf2, uart2_b, 0xFF);clear_buf2(); }}
//宏定义:
extern char                     buf1[256];
extern uint8_t                 uart1_b;#define clear_buf1() do { memset( buf1, 0, sizeof(buf1)); \uart1_b=0; } while(0)extern char                      buf2[256];
extern uint8_t                   uart2_b;#define clear_buf2() do { memset(buf2, 0, sizeof(buf2)); \uart2_b=0; } while(0)

这样我们可以用AT命令从串口接收数据到转发数据来配置esp8266wifi模块。

esp8266.c

接下我们写一下通过AT命令连接WiFi和连接服务器的代码;

一、ESP8266WiFi模块初始化
1, AT+RST 重启、复位ESP8266命令
2, AT 确认模块是否正常工作
3, AT+GMR 获取WiFi模块的软件版本信息
4, AT+CWMODE_CUR=1 设置WiFi为Station模式
5, AT+CWDHCP_CUR=1,1 设置使能Station模式的DHCP服务;
二、连网
1, AT+CWJAP_CUR=“路由器的ID”,“密码” 连接无线路由器
2, AT+CIPSTA_CUR? 查询是否获取到IP地址
三、TCP连接
3, AT+CIPSTART=“TCP”,“192.168.2.172”,12345 IP和端口
4,AT+CIPSEND=bytes (等收到模块返回 > 后再输入bytes个字节数据将会通过WiFi模块发送出去;)
5, AT+CIPCLOSE //关闭TCP连接;

但是,由于这个流程是我们自己需要每次使用AT指令去实现,比较麻烦。所以我们自己需要编写程序代码来自动实现这些功能。 这样,我们就可以直接连接好服务器来接收ESP8266WiFi模块发送到服务器的数据了。

在写代码之前我们做一个简单的梳理,我们现在可以通过桥接好的串口1,2给esp8266wifi模块发送AT命令了,具体流程是:pc通过串口1发送AT命令到串口转发程序(通信猫测试软件;)然后通过串口2转发AT命令到esp8266wifi模块; 每当我们发送一个AT命令完成时,esp8266WiFi模块都会做相应的reply,正确执行会reply “AT命令加OK”;否则会reply "At命令加ERROR ";
比如:

// 我们将实现的功能按模块来封装,每一个函数模块来执行相应地功能,最后将其连贯成一个功能;
//WiFi模块初始化,这个函数是用来初始化WiFi模块的一些配置,如设置station模式,使能DHCP自动获取IP
//这个函数是一个无参函数,相对于连接WiFi和连接服务器函数来说,只需要输入我们的所配置的AT指令,不需要变化;
void esp8266_wifi_init(void)
{AT_send("AT+RST\r\n", 500);clear_buf();HAL_Delay(500);AT_send("AT\r\n");clear_buf();AT_send("AT+GMR"\r\n, 500);clear_buf();AT_send("AT+CWMODE_CUR=1", 500);clear_buf();AT_send("AT+CWDHCP_CUR=1,1", 500);clear_buf();
}//发送AT指令函数,将AT指令发送到串口2。
//之前我们实现了AT指令从串口1一接收,发送给串口2,串口2转发到esp8266.
int AT_send(char *at_buf2, unsigned int timeout)//timeout:
{int            rv = -1;unsigned int           i;// 0 - 255if(!at_buf2 || strlen(at_buf2) <= 0){return -1;esp8266wifi_print("error to get data\r\n");}esp8266wifi_print("Start to send AT command to esp8266\n");HAL_UART_Transmit(wifi_huart2, (uint_8 *)at_buf2, strlen(at_buf2), 1000);//当我们发送一个数据到esp8266WiFi模块,它会reply;for(i=0; i<timeout; i++){if (strstr(at_buf2, "OK\r\n")){rv = 0;esp8266wifi_print("\r\nget data%s", at_buf2);return 0;}if (strstr(at_buf2, "ERROR\r\n")){rv = 1;esp8266wifi_print("\r\n error to get data:%s", at_buf2);return 1;}if (strstr(at_buf2, "FAIL\r\n")){rv = 1;esp8266wifi_print("\r\n error to connecte WIFI");}HAL_Delay(5);return 0; }
}
//接下来我们初始化完成之后就可以去加入网络了,连接WiFi;
int esp8266_enter_network(char  *id, char *password)
{int    rv ;char    at_buf2[256];if (!id || strlen(password) <= 0){esp8266wifi_print("\r\n error to get data");return -1;}memset(at_buf2, 0, sizeof(at_buf2));snprintf(at_buf2, sizeof(at_buf2), "AT+CWJAP_CUR="%s","%s"\r\n", id, password);AT_send(at_buf2, 8000);chear_buf();return 0;
}
//下面我们就可以连接服务器了。
int esp8266_socket_connecte(char *serverip, int port)
{char at_buf2[256];int  rv = -1;if (!serverip || !port){esp8266wifi_print("\r\n error to get data");return  rv;} AT_send("AT+CIPMUX=0\r\n", 500);memset(at_buf2, 0, sizeof(at_buf2));snprintf(at_buf2, sizeof(at_buf2), "AT+CIPSTART="%s","%d"\r\n", serverip, port);AT_send(at_buf2,500);clear_buf();
}
int esp8266_socket_disconnecte(void)
{int    rv=0;AT_send("AT+CIPCLOSE\r\n", 500);return rv;
}//下面就可以发送数据给server了。
int sock_send_data(unsigned char *data, int at_uart2_bytes)
{int  sta;char  at_buf2[64];memset(at_buf2, 0, sizeof(at_buf2));snprintf(at_buf2, sizeof(at_buf2), "AT+CIPSEND="%d"\r\n", at_uart2_bytes);if (strstr(at_buf2, ">\r\n")){sta = 1;esp8266wifi_print("send data to server\r\n");}else{sta = 0;esp8266wifi_print("send data to server error\r\n");}if (sta != 0){AT_send_data(data, at_uart2_bytes, 800);return at_uart2_bytes;}
}
//发送我们编写数据data的函数,用来发送我们想要给server的信息;
int AT_send_data(unsigned char *data, int at_uart2_bytes, unsigned char timeout)
{int rv = -1;unsigned int  i;if (!data || at_uart2_bytes <= 0){esp8266wifi_print("ERROR %s:%d %s(): Invalid input arguments\r\n", __FILE__, __LINE__, __FUNCTION__);return -1;}esp8266wifi_print(">>>Start to send data \r\n");clear_buf();HAL_UART_Transmit(wifi_huart2, (uint8_t *)data, at_uart2_bytes, 1000);for (i=0; i<timeout; i++){if (strstr(at_buf2, "OK\r\n")){rv = 0;esp8266wifi_print(">>>Start to send data :%s\r\n", at_buf2);return rv;}if (strstr(at_buf2, "ERROR\r\n")){rv =1;esp8266wifi_print(">>>Start to send data error:%s\r\n", at_buf2);return rv;}HAL_Delay(5);}
}

esp8266.h

#ifndef _ESP8266_H_
#define _ESP8266_H_#define  at_buf2       buf2
#define  at_uart2_bytes   uart2_b
#define  wifi_huart2      huart2#ifdef CONFIG_DEBUG_WIFI
#define esp8266wifiprint(format,args...) printf(format, ##args)
#else
#define esp8266wifiprint(format,args...) do{} while(0)
#endifextern    void esp8266_wifi_init(void);
extern  int AT_send(char *at_buf2, unsigned int timeout);
extern int AT_send_data(unsigned char *data, int at_uart2_bytes, unsigned int timeout);
extern  int esp8266_enter_network(char  *id, char *password);
extern  int esp8266_socket_connecte(char *serverip, int port);
extern int int esp8266_socket_disconnecte(void);

main.c

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"esp8266.h"//添加WiFi ID PASSORD   , serverip, port ,
#define DEF_ROUTER_SSID          "Router_wifi"
#define DEF_ROUTER_PWD           "Router@wifi"
#define DEF_ROUTER_IP            "192.168.101.5"#define SOCKET_SERVER_IP         "192.168.101.5"
#define SOCKET_SERVER_PORT       12345//初始化,连接WiFi,连接服务器。esp8266_wifi_init();esp8266_enter_network(DEF_ROUTER_SSID, DEF_ROUTER_PWD);esp8266_socket_connecte(SOCKET_SERVER_IP, SOCKET_SERVER_PORT);

ESP8266WiFi模块实现代码相关推荐

  1. 无线智能插座ESP8266Wi-Fi模块代码烧录

    该无线智能插座的ESP8266Wi-Fi模块的代码烧录,将分以下几个步骤进行描述,如下所示: (1)利用买好的ESP8266Wi-Fi模块代码烧录器,将ESP8266Wi-Fi模块接入,如下图所示: ...

  2. 基于STM32F1单片机、ESP8266WIFI模块、DHT11温湿度传感的WIFI网络温湿度传输系统

    基于STM32F1单片机.ESP8266WIFI模块.DHT11温湿度传感的WIFI网络温湿度传输系统 功能说明 温湿度采集端 温湿度监控端 硬件材料 硬件连接 主要代码 温湿度采集端 温湿度监控端 ...

  3. STM32单片机通过ESP8266WiFi模块与Android APP实现数据传输(二)---上位机搭建

    事物的难度远远低于对事物的恐惧 完成对STM32单片机和ESP8266 WiFi模块的配置之后,接下来需要完成Android APP代码的编写以及实现. 1.添加网络权限 因为我们需要对WiFi进行操 ...

  4. ESP8266-WIFI模块使用AT指令连接外网服务器

    ESP8266-WIFI模块使用AT指令连接外网服务器 第一步用java代码写一个服务器,代码如下: 代码解释:我是用nio写了一个,异步通信,用到了线程池,比较简单.当wifi模块连接后,会自动创建 ...

  5. esp8266WiFi模块通过MQTT连接华为云

    esp8266WiFi模块通过MQTT连接华为云 总结: 一. MQTT透传AT固件烧录 二. 串口调试 2.1 设置模块为STA模式 2.2 连接WiFi 2.3 设置MQTT的登陆用户名与密码 2 ...

  6. Arduino用esp8266WiFi模块连接到服务器

    昨天用串口工具测试了一波esp8266WiFi模块连接云服务.没有问题 今天我决定用芯片来控制它,本来想用51,后面感觉太lou,又决定要stm32, 这个感觉不错,但是32芯片查资料确实麻烦,后面我 ...

  7. android arduino wifi模块,零知开源分享-ESP8266wifi模块的使用

    本帖最后由 零知实验室-roc 于 2019-5-14 14:01 编辑 1.说明 MCU:零知开源开发板-标准板 wifi模块:ESP-12F WiFi模块.png (85.41 KB, 下载次数: ...

  8. ESP8266wifi模块连接原子云实现手机与单片机的通信

    买正点原子的开发板时送了一块ESP8266wifi模块,一直没使用,最近几天刚好有时间就拿出来玩了一下,现在实现过程分享出来. 用到的模块: 1.STM32F103C8T6最小系统板 2.正点原子ES ...

  9. 通过ESP8266WIFI模块让51单片机向后端交互数据

    这一次做的是用ESP8266WIFI模块,让51单片机与后端交互数据.简单地发了一个字符串. 模块连接部分:VCC接电源,GND接地,模块的TXD接单片机的RXD,模块的RXD接单片机的TXD. 需要 ...

  10. 基于STM32的ESP8266WiFi模块波形检测仪

    使用STM32f103c8t6制作简易示波器将波形检测后上传到网页进行描点绘图.我负责下位机部分我的同学负责网页部分. 附带网址用Django写网页通过tcp-client,接收单片机所发的数据,进行 ...

最新文章

  1. Python Day26:多态、封装、内置函数:__str__、__del__、反射(反省)、动态导入模块...
  2. Java 处理0x00特殊字符
  3. 线段树 ---- 线段树上区间二分 或者单点二分 codeforces C. Greedy Shopping
  4. logback的配置文件
  5. 注册用户模块 password bug
  6. mysql多表查询插入更新_Mysql多表查询,多表插入和多表更新
  7. [MySQL基础]MySQL语法规范介绍
  8. h5 php js实验总结,H5学习_番外篇_PHP数据库操作
  9. python每个字符后添加空格_python实现指定字符串补全空格的方法
  10. 寄存器(内存访问)07 - 零基础入门学习汇编语言19
  11. c# bool?和bool_C#中的bool关键字
  12. 【tool】常见功能测试点
  13. VMware vSAN 6.7实战(六)配置vSAN存储策略
  14. servlet实现mvc
  15. phar打包thinkphp5项目
  16. 2019下半年软件设计师下午题
  17. Java 集合类入门篇
  18. 炒伦敦金哪个平台正规?2021香港排名前10伦敦金交易平台一览
  19. matlab日期转儒略历,matlab儒略日转为日期
  20. 陪读21:《像利弗莫尔一样交易·买在关键点》——板块时机

热门文章

  1. Java从入门到放弃第1天
  2. ABAP调用HTTP服务
  3. 电信校园网宽带创翼破解,路由器PPPOE拦截法
  4. Matlab PCA+SVM人脸识别(二)——GUI界面设计
  5. NOIP2016普及组复赛 解题分析
  6. 微信小程序扫一扫获取二维码的值
  7. 国务院正式发布《新一代人工智能发展规划》
  8. oppo9s刷机教程_OPPO R9s 目前最简单的刷Recovery ROOT 方法,强烈推荐
  9. 用python实现PSNR与SSIM
  10. 如何判断数码管是共阴极还是共阳极