草庐IT

WIFI模块——ESP8266

侯毛毛啊 2023-04-19 原文

1、ESP8266简介

ESP8266是一款高性能的WIFI串口模块,内部集成MCU能实现单片机之间串口通信,是目前使用最广泛的一种WIFI模块之一。可以简单理解为一个WIFI转串口的设备,不用知道太多WIFI相关知识,只需要知道串口怎么使用就可以。



接线图:只需要将RXD、TXD、GND、VCC这4个引脚,分别和USB转TTL模块的TXD、RXD、GND、VCC相连接

需要注意,在USB转TTL模块上有3.3V和5V两个引脚可以作为VCC,但是一般选取5V作为VCC。若选取3.3V,可能会因为供电不足而引起不断的重启,从而不停的复位。

2、开发方式

ESP8266系列一般具有两种开发方式:AT指令开发和SDK开发。

AT指令:厂家出厂时预先在ESP8266芯片烧入好固件,封装好WiFi的协议栈,内部已经实现透传,而用户只需要使用一个USB转TTL的模块或者单片机的串口就能实现与WiFi模块的通信,发送AT指令来对WiFi模块进行控制。(和蓝牙透传模块类似)

SDK开发:由于ESP8266本身即是可编程的芯片,可以把它视为一个带有无线通信的单片机,而用户需要在专门的IDE中编写对应的程序,然后通过烧写固件的方式将程序写入到芯片中,因此,想要实现WiFi通信,需要自定义WiFi协议栈,对用户掌握的相关知识要求更高。

本篇主要是对AT指令开发的学习。

3、常用AT指令

AT指令不区分大小写,以回车、换行结尾。

4、应用模式

ESP266支撑单AP模式、单STA模式和混合模式(可以在两种模式下切换的状态。)

AP模式下,WiFi模块产生热点,提供无线接入服务,允许其它无线设备接入,提供数据访问,一般的无线路由/网桥工作在该模式下。该模式对应TCP传输协议中的服务端(TCP Server)。
STA模式下,WiFi模块为连接到无线网络的终端(站点),可以连接到AP,一般无线网卡工作在STA模式下。该模式对应TCP传输协议中的客户端(TCP Client)。

简单来说,AP模式可以将ESP8266作为热点,让其他的设备连接上它;STA模式可以连接上当前环境下的WIFI热点。

透传(透明传输),就是指不需要关心wifi协议是如何实现的,所需要做的就是A通过串口发数据,B通过串口收数据,整个过程中A串口和B串口就像是用导线直接连接起来了一样。使用者无需关心内部具体实现,模块对于使用者是“透明的”、似乎不存在的(因为可无视中间的实现原理)。

如果不开启透传模式,在每次发送数据前都必须先发送指令AT+CIPSEND=<param>。若开启了透传模式,就不需要在每次发送数据前都发送指令了,只需要发送一次AT+CIPSEND,之后发送的内容都会当成是数据。如果再次发送命令,要先退出透传模式(发送数据"+++"退出),否则会把命令了当成是数据发送过去。

ESP8266一般用于连接当前环境的热点,与服务器建立TCP连接,传输数据。大致流程如下:

AT+CWMODE=1:设置工作模式(STA模式)
AT+RST:模块重启(生效工作模式)
AT+CWJAP=“111”,“11111111”:连接当前环境的WIFI热点(热点名,密码)
AT+CIPMUX=0:设置单路连接模式
AT+CIPSTART=“TCP”,“xxx.xxx.xxx.xxx”,xxxx:建立TCP连接
AT+CIPMODE=1:开启透传模式
AT+CIPSEND:透传模式下,传输数据
+++:退出透传模式

5、主要代码

ESP8266的初始化包括以下函数:

ESP8266_TEST();//测试有无ESP8266
ESP8266_RESET();
ESP8266_SetMode();//设置模式
ESP8266_SetSAP();//设置热点
ESP8266_SetCIPMUX();//设置多路连接
ESP8266_SetCIPSERVER();//开启连接并设置端口号

void Clear_Buffer(void)//清空缓存
{
	u16 i;
	for(i=0;i<500;i++)
		USART2_ReceiveData[i]=0;//缓存
	USART2_ReceiveTims=0;
}
/*-------------------------------------------------
功能:测试有无ESP8266
返回值:0:无错误                                
        1:等待发送数据超时                                                      
-------------------------------------------------*/
u8 ESP8266_TEST(void)
{
	u8 timeout=5;
	Clear_Buffer();
	USART2_printf("AT\r\n");	
	while(timeout--)
	{
		Delay_10ms();
		if(strstr((const char*)USART2_ReceiveData,(const char*)"OK")!=NULL)
		{
			Clear_Buffer();
			return 0;				
		}

		USART2_printf("AT\r\n");	
	}
	return 1;
}
/*-------------------------------------------------
功能:测试有无ESP8266
返回值:0:无错误                                
        1:等待发送数据超时                                                      
-------------------------------------------------*/
u8 ESP8266_RESET(void)
{
	u8 timeout=50;
	Clear_Buffer();
	USART2_printf("AT+RST\r\n");	
	while(timeout--)
	{
		Delay_10ms();
		if(strstr((const char*)USART2_ReceiveData,(const char*)"OK")!=NULL)
		{
			Clear_Buffer();
			return 0;				
		}

		USART2_printf("AT+RST\r\n");	
	}
	return 1;
}
/*-------------------------------------------------
功能:设置模式 1-Station模式,2-AP模式(热点),3-AP兼Station模式		
返回值:0:无错误                                
        1:等待发送数据超时                                                      
-------------------------------------------------*/
u8 ESP8266_SetMode(void)
{
	u8 timeout=50;
	Clear_Buffer();
	USART2_printf("AT+CWMODE=2\r\n");	
	while(timeout--)
	{
		Delay_100ms();
		if(strstr((const char*)USART2_ReceiveData,(const char*)"OK")!=NULL)
		{
			Clear_Buffer();
			return 0;				
		}
		USART2_printf("AT+CWMODE=2\r\n");	
	}
	return 1;
}
/*-------------------------------------------------
功能:设置热点,1 信道,3 加密方式
返回值:0:无错误                                
        1:等待发送数据超时                                                      
-------------------------------------------------*/
u8 ESP8266_SetSAP(void)
{
	u8 timeout=50;
	Clear_Buffer();
	USART2_printf("AT+CWSAP=\"ZZBB\",\"12345678\",1,3\r\n");						
	while(timeout--)
	{
		Delay_100ms();
		if(strstr((const char*)USART2_ReceiveData,(const char*)"OK")!=NULL)
		{
			Clear_Buffer();
			return 0;				
		}
		USART2_printf("AT+CWSAP=\"ZZBB\",\"12345678\",1,3\r\n");						
	}
	return 1;
}
/*-------------------------------------------------
功能:设置多路连接
返回值:0:无错误                                
        1:等待发送数据超时                                                      
-------------------------------------------------*/
u8 ESP8266_SetCIPMUX(void)
{
	u8 timeout=50;
	Clear_Buffer();
	USART2_printf("AT+CIPMUX=1\r\n");						
	while(timeout--)
	{
		Delay_100ms();
		if(strstr((const char*)USART2_ReceiveData,(const char*)"OK")!=NULL)
		{
			Clear_Buffer();
			return 0;				
		}
		USART2_printf("AT+CIPMUX=1\r\n");						
	}
	return 1;
}
/*-------------------------------------------------
功能:开启连接并设置端口号
返回值:0:无错误                                
        1:等待发送数据超时                                                      
-------------------------------------------------*/
u8 ESP8266_SetCIPSERVER(void)
{
	u8 timeout=50;
	Clear_Buffer();
	USART2_printf("AT+CIPSERVER=1,8080\r\n");						
	while(timeout--)
	{
		Delay_100ms();
		if(strstr((const char*)USART2_ReceiveData,(const char*)"OK")!=NULL)
		{
			Clear_Buffer();
			return 0;				
		}
		USART2_printf("AT+CIPSERVER=1,8080\r\n");						
	}
	return 1;
}

ESP8266发送数据函数:

/*-------------------------------------------------
功能:ESP8266发送数据
形参:id-连接序号(0-7),databuff-发送数据,data_len-数据长度
返回值:0:无错误                                
        1:等待">"超时      
				2:未连接
				3:发送完成超时
-------------------------------------------------*/
u8 ESP8266_SendData(u8 id, char *databuff, u32 data_len)
{
	u32 i;
	u8 timeout=50;
	Clear_Buffer();
	USART2_printf("AT+CIPSEND=%d,%d\r\n",id,data_len);		
	while(timeout--)
	{  
		Delay_10ms();
		if(strstr((const char*)USART2_ReceiveData,(const char*)">"))                   //如果接收到>表示成功
			break;       						      //主动跳出while循环		
	}
	if(timeout==0)
		return 1;
	else
	{
		timeout=50;
//		Clear_Buffer();                     	  
			for(i=0;i<data_len;i++)
				USART2_printf(databuff); //发送数据	
			while(timeout--)
			{  
				Delay_10ms();
				if(strstr((const char*)USART2_ReceiveData,(const char*)"SEND OK"))
					return 0;		
											
				if(strstr((const char*)USART2_ReceiveData,(const char*)"link is not valid"))		
					return 0;		
						
			}
			return 3;
	}
}

ESP8266接收数据函数:

/*-------------------------------------------------
功能:ESP8266接收数据
形参:id-发送数据的设备序号(0-7),databuff-接收数据,data_len-接收数据长度
返回值:0:无错误                                
        1:无接收数据   
-------------------------------------------------*/
u16 IPDIndex=0;
u8 IPDFlag=0;
u8 IPDReceiveFlag=0;
u8 ESP8266_ReceiveData(u8 *id, char *databuff, char *data_len)
{
	u32 i;
	u32 NumberLen=0;
	char temp[500]={0};      //缓冲区,这里注意sscanf会吧,之前的数据全放里面,可能数组大小溢出
	char *presult;
	if(IPDReceiveFlag==1)
	{      
		
		Delay_10ms();                                    //延时
		for(i=0;i<IPDIndex;i++)
			USART2_ReceiveData[i]=0;
		sscanf((const char*)USART2_ReceiveData+IPDIndex,"%[^,],%[^,],%[^:]",temp,id,data_len);//截取各段数据,主要是id和数据长度,这个函数以0为结束	
		presult = strstr((const char*)USART2_ReceiveData+IPDIndex,":");                  //查找冒号。冒号后的是数据
		if( presult != NULL )                               //找到冒号
		{
			HEXtoNumber(data_len,&NumberLen);
			for(i=0;i<NumberLen;i++)
			{
				*(databuff+i)=*(presult+i+1);//冒号后的数据,复制到data
			}
	//		sprintf((char *)databuff,"%s",(presult+1)); //不用这个函数了,有数据长度,直接就对应的数据填进去就好了
		}
//			
		Clear_Buffer();                                  //WiFi接收数据量变量清零     
		IPDReceiveFlag=0;		
		return 1;                                           //有数据到来
	}	
	else 
	return 0;
}

有关WIFI模块——ESP8266的更多相关文章

  1. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  2. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  3. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  4. ruby - 当使用::指定模块时,为什么 Ruby 不在更高范围内查找类? - 2

    我刚刚被困在这个问题上一段时间了。以这个基地为例:moduleTopclassTestendmoduleFooendend稍后,我可以通过这样做在Foo中定义扩展Test的类:moduleTopmoduleFooclassSomeTest但是,如果我尝试通过使用::指定模块来最小化缩进:moduleTop::FooclassFailure这失败了:NameError:uninitializedconstantTop::Foo::Test这是一个错误,还是仅仅是Ruby解析变量名的方式的逻辑结果? 最佳答案 Isthisabug,or

  5. ruby - 获取模块中定义的所有常量的值 - 2

    我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c

  6. ruby - 模块嵌套代码风格偏好 - 2

    我的假设是moduleAmoduleBendend和moduleA::Bend是一样的。我能够从thisblog找到解决方案,thisSOthread和andthisSOthread.为什么以及什么时候应该更喜欢紧凑语法A::B而不是另一个,因为它显然有一个缺点?我有一种直觉,它可能与性能有关,因为在更多命名空间中查找常量需要更多计算。但是我无法通过对普通类进行基准测试来验证这一点。 最佳答案 这两种写作方法经常被混淆。首先要说的是,据我所知,没有可衡量的性能差异。(在下面的书面示例中不断查找)最明显的区别,可能也是最著名的,是你的

  7. ruby-on-rails - 使用 config.threadsafe 时从 lib/加载模块/类的正确方法是什么!选项? - 2

    我一直致力于让我们的Rails2.3.8应用程序在JRuby下正确运行。一切正常,直到我启用config.threadsafe!以实现JRuby提供的并发性。这导致lib/中的模块和类不再自动加载。使用config.threadsafe!启用:$rubyscript/runner-eproduction'pSim::Sim200Provisioner'/Users/amchale/.rvm/gems/jruby-1.5.1@web-services/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:105:in`co

  8. ruby-on-rails - Controller 中的 Rails 辅助模块 - 2

    我有一个Controller,我想为这个Controller创建一个助手,我可以在不包含它的情况下使用它。我尝试像这样创建一个与Controller同名的助手classCars::EnginesController我创建的助手是moduleCars::EnginesHelperdefcheck_fuellogger.debug("chekingfuel")endend我得到的错误是undefinedlocalvariableormethod`check_fuel'for#有没有我遗漏的约定? 最佳答案 如果你真的想在Controll

  9. ruby-on-rails - 具有同名的模块和类 - 2

    我有一个模块stat存在于目录结构中:lib/stat_creator/stat/在lib/stat_creator/stat.rb中,我在lib/stat_creator/stat/目录中有我需要的文件,以及:moduleStatCreatormoduleStatendend当我使用该模块时,我将这些类称为StatCreator::Stat::Foo.new现在我想要一个存在于应用程序中的根Stat类。我在app/models中制作了我的Stat类,并在routes.rb中进行了设置。但是,如果我转到Rails控制台并尝试在应用程序/模型中使用Stat类,例如:Stat.by_use

  10. ruby-on-rails - 使用 rspec 和 rails 测试嵌套模块 - 2

    这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:Testingmodulesinrspec目前我正在使用rspec成功测试我的模块,如下所示:require'spec_helper'moduleServicesmoduleAppServicedescribeAppServicedodescribe"authenticate"doit"shouldauthenticatetheuser"dopending"authenticatetheuser"endendendendend我的模块位于应用程序/服务/services.rb应用程序/服务/app_servi

随机推荐