物联网loT开发——ESP8666 ESP-01SWiFi模块使用

1. 引言:物联网与ESP01S的简介

        物联网:就是把各种日常物品(如家电、汽车、传感器等)通过互联网与计算设备连接,使它们能够相互沟通并进行智能化处理和控制。比如单片机从传感器获取的温湿度信息,通过无线网络传输到平台,经过平台算法处理再反馈给单片机进行温度或湿度控制

        esp01s:它能当作这其中传输数据的中间桥梁。连接上WiFi和目标端口,单片机发送给esp01s的信息就能传输到目标端口上

2. ESP01S硬件概述

  • ESP01S模块的硬件构成
  • 一般买回的esp01s,只需要接VCC GND TX RX,出厂默认波特率为115200。
  • 上电:正常工作验证
  • 本模块可以工作在三种模式:1. STA 2 .AP 3 .AP+STA,出厂设置为第三种
  • 上电后,蓝色灯微弱闪烁后熄灭,红灯长亮
  • 手机搜索无线网络,可见 ESP_XXXXXX 已经处于列表中
  • 3.ESP01S配置:通过USB转TTL-CH340模块连接AT指令配置

  • 硬件需要:esp01s USB转TTL-CH340模块 stm32f103c8t6最小系统板
  • 连线:
  • esp01s的TX与RX与stm32的RX与TX交叉相连(自己选择单片机的一个串口,一般用串口1),esp01s的vcc与gnd用stm32进行供电。
  • USB转TTL-CH340模块的GND与stm32单片机GND相连。
  • stm32单片机插上stlink用电脑供电
  • 电脑使用xcom串口助手进行串口选择(14这个数字不确定)(保证自己电脑已经安装了CH340转串口驱动)
  • 进行AT指令测试
  • 发送:AT(注意如果没有勾选发送新行,必须手动回车一下),返回:OK
  • 发送:AT+RST,返回:如下图所示
  • 作为客户端Client,连接WiFi和目标服务器Serve,还是使用该串口助手,连线保持不变
  • 1.发送:AT+RST。
  • 2.发送:AT+CWMODE=1(设置STA模式),返回:OK(成功)
  • 3.发送:AT+CWLAP(查询当前无线路由器列表),返回:
  • 4.发送:AT+CWJAP=”WiFi账号”,”WiFi密码”(字符串格式,英文),返回:WIFI GOT IP(成功) ERROR(失败)。这里成功,我们就成功连接上了WiFi。可以使用手机热点,开2-4G频段,5G连接不上
  • 5.发送:AT+CIPMUX=0(设置单路连接模式)(意思是只连接一个服务器),返回:OK
  • 6.发送:AT+CIPSTART="TCP","本地主机地址",端口号(如下图所示)(TCP为网络协议的一种,读者感兴趣可以深入了解)(该软件可以自己去搜索下载:NetAssist)(这里就相当于连接上服务器了)连接成功之后,ALL Connections后面会带有1
  • 7.给客户端发送消息:发送:AT+CIPSEND=5(就是告诉WiFi,我即将要发送长度为5个的字符串),返回:收到此命令后先换行返回”>”,然后开始接收串口数据 当数据长度满 length 时发送数据。 如果未建立连接或连接被断开,返回 ERROR 如果数据发送成功,返回 SEND OK。于是,你就可以发送Hello字符串,服务器就会接收到Hello的字符串
  • 8.如果每次都要使用AT+CIPSEND肯定不方便,于是我们可以开启透传模式(顾名思义:发送给WiFi的每一个数据,全都自动传给服务器。前提是必须保证服务器和WiFi已经成功连接,否则开启失败)
  • 发送:AT+CIPMODE=1(设置透传模式),成功返回:OK
  • 发送:AT+CIPSEND,成功返回:OK
  • 于是接下来你发的所有数据全都传给服务器了
  • 要退出透传模式:方法1——断电重启WiFi模块,方法2——连续发送三个‘+’,间隔为15ms以上(不容易成功)
  • 4.ESP01S使用:stm32f103C8T6做主控连接WIFI

  • 连线:ESP01s的VCC与GND连接上stm32的VCC与GND。ESP的RX与TX与stm32的串口2的RX与TX交叉相连。
  • stm32串口初始化:利用stm32HAL库初始化串口2(可以自己选择),保证收发正常(这里不在过多概述)
  • stm32初始化WiFi的代码:
  • uint8_t esp8266_Init(void) //ESP01s初始化,printf函数以及重定义到串口1作为调试信息
    {
    //状态检测
    	printf("准备配置模块\r\n");
    	printf("准备退出透传模式\n");
    	if(esp8266_quit_trans())
    	{
    		printf("退出透传模式失败,准备重启\r\n");
    		return 6;
    	}else printf("退出透传模式成功\r\n");
    		
    	printf("查询模块是否在线\r\n");
    	if(esp8266_send_cmd("AT","OK",100))
    	{
    		printf("模块不在线准备重启\r\n");
    		return 1;
    	}else printf("设置查询在线成功\r\n");
    	
    //设置
    	printf("准备设置STA模式\r\n");
    	if(esp8266_send_cmd("AT+CWMODE=1","OK",50))
    	{
    		printf("设置STA模式失败准备重启\r\n");
    		return 1;
    	}else printf("设置STA模式成功\r\n");
    	
    	printf("准备重启\r\n");
    	if(esp8266_send_cmd("AT+RST","OK",50))
    	{
    		printf("重启失败,准备重启\r\n");
    		return 2;
    	}else printf("重启成功,等待三秒\r\n");
    	
    	printf("准备设置自动连接\r\n");
    	if(esp8266_send_cmd("AT+CWAUTOCONN=1","OK",50))
    	{
    		printf("设置连接失败,准备重启\r\n");
    		return 3;
    	}else printf("设置连接成功\r\n");
    	
    	printf("准备链接路由器\r\n");
    	if(esp8266_Connect_AP())
    	{
    		printf("连接路由器失败,等待重启\r\n");
    		return 4;
    	}else printf("连接路由器成功\r\n");
    	
    	HAL_Delay(3000);//延时等待WIFI模块就绪
    
    //TCP连接
    	printf("设置为单路连接\r\n");
    	if(esp8266_send_cmd("AT+CIPMUX=0","OK",100))
    	{
    		printf("关闭多路连接失败,准备重启\r\n");
    		return 7;
    	}else printf("设置关闭多路连接成功\r\n");
    
    	printf("准备链接服务器\r\n");
    	if(esp8266_Connect_Server())
    	{
    		printf("连接服务器失败,等待重启\r\n");
    		return 8;
    	}else printf("连接服务器成功\r\n");
    		
    	printf("设置为透传模式\r\n");
    	if(esp8266_send_cmd("AT+CIPMODE=1","OK",50))
    	{
    		printf("设置透传失败,准备重启\r\n");
    		return 6;
    	}else printf("设置透传成功\r\n");
    
    //发送数据
    	printf("设置开启透传模式\r\n");
    	if(esp8266_send_cmd("AT+CIPSEND","OK",1000))
    	{
    		printf("开启透传失败,准备重启\r\n");
    		return 9;
    	}else printf("开启透传成功\r\n");
    	USART2_RX_STA = 0;//清除串口2的RX获取标志位
    	memset(USART2_RX_BUF,0,USART2_REC_LEN);//清空串口2的缓冲区
    	
    	return 0; //一切顺利返回0
    }
    uint8_t esp8266_send_cmd(char *cmd, char *ack, uint16_t waittime) //ESP8266发送指令(底层函数)
    {
    	uint8_t res = 0;
    	USART2_RX_STA = 0;
    	memset(USART2_RX_BUF,0,USART2_REC_LEN); //将串口2的缓存空间清0
    	WIFI_printf("%s\r\n", cmd); //这里实际是通过串口2发送给WiFi模块
    	if(waittime) //需要等待应答
    	{
    		while(--waittime) //等待倒计时
    		{
    			HAL_Delay(10);//HAL库延时函数
    			if(USART2_RX_STA&0x8000) //接收到期待的应答结果,STA的最高位为标志位
    			{
    				if(esp8266_check_cmd((uint8_t *)ack))
    				{
    					HAL_Delay(10);
    					break; //得到有效数据
    				}
    				USART2_RX_STA=0; //串口3标志位清0
    			} 
    		}
    		if(waittime==0)res=1;
    	}
    	return res;
    }
    //命令检查函数
    uint8_t* esp8266_check_cmd(uint8_t *str) //ESP8266检查指令(底层函数)
    {
    	char *strx=0;
    	if(USART2_RX_STA&0X8000) //接收到一次数据了
    	{
    		USART2_RX_BUF[USART2_RX_STA&0X7FFF] = 0; //添加结束符
    		strx=strstr((const char*)USART2_RX_BUF,(const char*)str);
    	} 
    	return (uint8_t*)strx;
    }
    //WIFI发送函数
    void WIFI_printf (char *fmt, ...)
    {
    	char buff[USART2_REC_LEN+1];  //用于存放转换后的数据 [长度]
    	uint16_t i=0;
    	va_list arg_ptr;
    	va_start(arg_ptr, fmt);
    	vsnprintf(buff, USART2_REC_LEN+1, fmt, arg_ptr);//数据转换
    	i=strlen(buff);//得出数据长度
    	if(strlen(buff)>USART2_REC_LEN)i=USART2_REC_LEN;//如果长度大于最大值,则长度等于最大值(多出部分忽略)
        HAL_UART_Transmit(&huart2,(uint8_t *)buff,i,0xffff);//串口发送函数(串口号,内容,数量,溢出时间)
        va_end(arg_ptr);
    }
    //ESP8266退出判断(底层函数)
    uint8_t esp8266_quit_trans(void) 
    {
    	while((USART2->SR&0X40)==0); //等待发送空
    	USART2->DR='+';      
    	HAL_Delay(15); //大于串口组帧时间(10ms)
    	while((USART2->SR&0X40)==0); //等待发送空
    	USART2->DR='+';      
    	HAL_Delay(15); //大于串口组帧时间(10ms)
    	while((USART2->SR&0X40)==0); //等待发送空
    	USART2->DR='+';      
    	HAL_Delay(500); //等待500ms
    	return esp8266_send_cmd("AT","OK",20); //退出透传判断
    }
    //连接WiFi的底层函数
    uint8_t esp8266_Connect_AP()
    {
    	uint8_t i=10;
    	char *p = (char*)malloc(50);//分配存储空间的指针
        //SSID与PASS为WiFi账号与密码
    	sprintf((char*)p,"AT+CWJAP=\"%s\",\"%s\"",SSID,PASS);//发送连接AT指令
    	while(esp8266_send_cmd(p,"WIFI GOT IP",1000) && i)//循环判断等待连接AP的结果
    	{
    		printf("链接AP失败,尝试重新连接\r\n"); //连接失败的反馈信息
    		i--;
    	}
    	free(p);//释放分配的空间和指针
    	if(i) return 0;//执行成功返回0
    	else return 1;//执行失败返回1
    }
    //ESP8266连接到服务器
    uint8_t esp8266_Connect_Server() 
    {
    	uint8_t i=10;
    	char *p = (char*)malloc(70);//分配存储空间的指针
        //IOT_DOMAIN_NAME为IP地址,IOT_PORTNUM为端口号。配置AT指令时有提到
    	sprintf((char*)p,"AT+CIPSTART=\"TCP\",\"%s\",%s",IOT_DOMAIN_NAME,IOT_PORTNUM);
    	while(esp8266_send_cmd(p,"CONNECT",1000) && i)
    	{
    		printf("链接服务器失败,尝试重新连接\r\n");
    		i--;
    	}
    	free(p);//释放分配的空间和指针
    	if(i)return 0;//执行成功返回0
    	else return 1;//执行失败返回1
    }
  •         主函数里面调用:while(esp8266_Init());//连接服务器。

            一切正常之后。代表服务器以及连接成功。之后所有通过串口2给WiFi模块发送的消息都将传给服务器。到此我们物联网就实现了第一步。

    6.常见问题与解决方法

  • 无法连接WIFI:       
  • 确保账号、密码正确
  • 确保热点是2-4G频段
  • 确保AT指令正确
  • AT指令通讯失败:
  • 波特率没有设置正确,检查串口助手的波特率
  • 如果波特率设置为115200,但还是AT指令收发不了,尝试找给esp01s烧录出厂固件的资料。
  • 7.建议

            如果想要深入了解物联网的底层,可以看看其他的文章。本文只为后面物联网的连接、数据上传、下发操作做准备,不会过多的讲解原理。

    新人写手,有什么问题、错误可以随时交流,

    作者:嵌入式硬件探索

    物联沃分享整理
    物联沃-IOTWORD物联网 » 物联网loT开发——ESP8666 ESP-01SWiFi模块使用

    发表回复