ESP8266与MQTT协议

本文详细介绍了ESP8266在STA模式和AP模式下的工作原理,以及如何通过AT指令进行设备配置,如设置工作模式、连接WIFI和服务器。还提供了相应的初始化代码和中断处理函数示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

工作模式:

  • STA模式        别人创建WIFI网络,ESP8266加入该网络
    • AP模式          产生WIFI网络
  • STA+AP     

物理层:

1.VCC 电源(3.3V~5V)

2 GND 电源地

3 TXD(TTL 电平,不能直接接 RS232 电平!),可接 单片机的 RXD

4 RXD(TTL 电平,不能直接接 RS232 电平!),可接 单片机的 TXD

5 RST 复位(低电平有效)

6 IO-0 进入固件烧写模式,低电平是烧写模式,高电平是运行模式(默认)

常用指令

命令

功能

备注

AT

测试模块是否正常

基础指令

ATE1/ATE0

开启/关闭回显

AT+CWMODE/AT+CWSAP_DEF

设置AP模式及AP参数

AT WIFI指令

AT +CWMODE=1

设置为Station 模式

AT +CWJAP

连接热点

AT+CIPSTART

建立TCP连接

AT TCP指令

AT+CIPMODE=1

开启透传传输

AT+CIPSEND

发送数据

+++

退出透传模式

AT+CIPCLOSE

关闭TCP连接

将电脑上面的串口助手上面AT指令发送给ESP8266:

电脑上面的串口助手 -- 串口1

  1. 首先USART1接收中断,接收上位机发过来的AT指令
  2. 将接收的AT指令,写入USART3->DR,就发送给ESP8266.
  3. ESP8266接收指令后,进行响应,响应的数据,使用USART3接收中断接收数据

为了看到esp8266响应的数据,将USART3接收的数据写入USART1->DR。

代码:

#include "esp32.h"
#include "delay.h"
#include "string.h"
#include "stdio.h"

NETDATA netdata={0};

/*************************************************
		函数功能:WIFI模块
		函数参数:   无
		函数返回值: 无

**************************************************/
void esp32Init()
{
		//ESP_RXD ---PA2 --复用推挽输出
		//ESP_TXD ---PA3  --复用浮空输入
	
		//1.使能时钟     --PA   --USART2
		RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
		
		//2.配置GPIOA  工作模式
	
		//PA2复用推挽输出
		GPIO_InitTypeDef WIFI_InitStruct={0};
		WIFI_InitStruct.GPIO_Mode=GPIO_Mode_AF;
		WIFI_InitStruct.GPIO_OType=GPIO_OType_PP;   //配置为复用推挽输出
		WIFI_InitStruct.GPIO_Pin=GPIO_Pin_2|GPIO_Pin_3;
		WIFI_InitStruct.GPIO_PuPd=GPIO_PuPd_NOPULL;  //配置为空   输出(不需要配)
		WIFI_InitStruct.GPIO_Speed=GPIO_High_Speed;   //输出速度
		GPIO_Init(GPIOA,&WIFI_InitStruct);
		
		GPIO_PinAFConfig(GPIOA,GPIO_PinSource2,GPIO_AF_USART2);
		GPIO_PinAFConfig(GPIOA,GPIO_PinSource3,GPIO_AF_USART2);
		

		//3.配置串口
		USART_InitTypeDef USART_InitStruct={0};
		USART_InitStruct.USART_BaudRate=115200;     //波特率
		USART_InitStruct.USART_Mode =USART_Mode_Rx|USART_Mode_Tx;  //接收模式与发送模式
		USART_InitStruct.USART_Parity =USART_Parity_No;     //禁止校验
		USART_InitStruct.USART_StopBits = USART_StopBits_1;   //停止位1位
		USART_InitStruct.USART_WordLength=USART_WordLength_8b;  //数据位8位
		USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None; //不使用硬件流控制 
		USART_Init(USART2,&USART_InitStruct);
	
			//4.使能接收中断  串口   接收中断     
		USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);
		
		//5.使能空闲中断
		USART_ITConfig(USART2,USART_IT_IDLE,ENABLE);
		
		//4-5配置NVIC
		NVIC_InitTypeDef NVIC_InitStruct={0};
		NVIC_InitStruct.NVIC_IRQChannel=USART2_IRQn;
		NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
		NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;
		NVIC_InitStruct.NVIC_IRQChannelSubPriority=0;
		NVIC_Init(&NVIC_InitStruct);
		
		//6使能USART2
		USART_Cmd(USART2,ENABLE);	
}


//编写中断服务函数(在启动文件中)
void USART2_IRQHandler(void)
{
		u8 data=0;
		//先判断终端是否产生
					//获取终端状态
		if(USART_GetITStatus(USART2,USART_IT_RXNE)==SET)//接收中断产生
		{
				USART_ClearITPendingBit(USART2,USART_IT_RXNE);//清中断
				data = USART_ReceiveData(USART2);//保存串口助手发过来的AT指令集
				netdata.rxbuff[netdata.rxcount++] = USART_ReceiveData(USART2);//保存串口助手发过来的AT指令集
				USART_SendData(USART1,data);//转发AT指令到USART1以及串口上面
		}
					//获取终端状态
		if(USART_GetITStatus(USART2,USART_IT_IDLE)==SET)//空闲中断产生
		{
				USART2->DR;
			/*
			清中断 
			--对于空闲中断清理   特殊在于:
			需要先读取 SR     USART_GetITStatus(USART2,USART_IT_IDLE)这个语句相当于读取了 SR
			在读DR  就可以了
			*/ 
		}
}


/*———————————————————————————————————————————————————————————————————————————
		函数功能:                                  发送一个字节函数
		函数参数:   要发送的数据
		函数返回值: 无
—————————————————————————————————————————————————————————————————————————————*/


void Usart2SendByte(uint8_t data)
{
		//判断发送寄存器是否有数据-- 判断上次数据是否发送完成
		while(USART_GetFlagStatus(USART2,USART_FLAG_TC)==RESET);
		USART_SendData(USART2,data);
}


/*———————————————————————————————————————————————————————————————————————————
		函数功能:                                  发送字符串函数
		函数参数:   要发送的数据
		函数返回值: 无
———————————————————————————————————————————————————————————————————————————*/

void Usart2SendStr(char *data)
{
		while(*data!='\0')
		{
			Usart2SendByte(*data++);
		}
}

/*———————————————————————————————————————————————————————————————————————————
		函数功能:                                  发送一定长度的函数
		函数参数:   要发送的数据
		函数返回值: 无
———————————————————————————————————————————————————————————————————————————*/
void Usart2Sendbuff(char *buff,u16 len)
{
	u32 i=0;
	for(i=0;i<len;i++)
	{
		Usart2SendByte(buff[i]);
	}
	
}

ESP8266连接WIFI

  1. 首先测试ESP工作是否正常;发送“AT”指令,正常返回OK;
  2. 然后设置ESP工作模式;发送“AT +CWMODE=1”,设置成功返回“OK”;
  3. 连接WIFI;发送“AT+CWJAP="WIFI名","WIFI密码";设置成功返回“WIFI GOT IP”;
  4. 此时ESP已经连接上局域网。

连接服务器

  1. 在已经连接上局域网的前提下,建立TCP连接;发送“AT+CIPSTART="TCP","地址",“端口号”;设置成功返回“OK”。
  2. 设置透传模式;发送“AT+CIPMODE=1”,设置成功返回“OK”
  3. 设置发送数据指令模式;发送“AT+CIPSEND”,设置成功返回“>”

代码编写

#include "ESP8266.h"
#include "delay.h"
#include "string.h"
#include "stdio.h"

/*
函数功能:WIFI模块
函数参数:   无
函数返回值: 无

*/

NETDATA netdata={0};

void ESP8266Init()
{
		//ESP_EN ---PE6  --通用推挽输出
		//ESP_RXD ---PB10  --复用推挽输出
		//ESP_TXD ---PB11  --浮空输入
	
		//1.使能时钟     --PB PE 端口  --USART3
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);
		
		//2.配置GPIOB  E 工作模式
		//PB10复用推挽输出
		GPIO_InitTypeDef GPIO_InitStruct={0};
		GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
		GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;
		GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
		GPIO_Init(GPIOB,&GPIO_InitStruct);
		
		//PB11复用浮空输入
		GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;  //浮空输入
		GPIO_InitStruct.GPIO_Pin=GPIO_Pin_11;
		GPIO_Init(GPIOB,&GPIO_InitStruct);
		
		//PE6通用推挽输出
		GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;  
		GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6;
		GPIO_Init(GPIOE,&GPIO_InitStruct);
		
		GPIO_SetBits(GPIOE,GPIO_Pin_6);

		//3.配置串口
		USART_InitTypeDef USART_InitStruct={0};
		USART_InitStruct.USART_BaudRate=115200;     //波特率
		USART_InitStruct.USART_Mode =USART_Mode_Rx|USART_Mode_Tx;  //接收模式与发送模式
		USART_InitStruct.USART_Parity =USART_Parity_No;     //禁止校验
		USART_InitStruct.USART_StopBits = USART_StopBits_1;   //停止位1位
		USART_InitStruct.USART_WordLength=USART_WordLength_8b;  //数据位8位
		USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None; //不使用硬件流控制 
		USART_Init(USART3,&USART_InitStruct);
	
			//4.使能接收中断  串口   接收中断     
		USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);
		
		//5.使能空闲中断
		USART_ITConfig(USART3,USART_IT_IDLE,ENABLE);
		
		//4-5配置NVIC
		NVIC_InitTypeDef NVIC_InitStruct={0};
		NVIC_InitStruct.NVIC_IRQChannel=USART3_IRQn;
		NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
		NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;
		NVIC_InitStruct.NVIC_IRQChannelSubPriority=0;
		NVIC_Init(&NVIC_InitStruct);
		
		//6使能USART3
		USART_Cmd(USART3,ENABLE);	
}

//编写中断服务函数(在启动文件中)
void USART3_IRQHandler(void)
{
		u8 data=0;
		//先判断终端是否产生
					//获取终端状态
		if(USART_GetITStatus(USART3,USART_IT_RXNE)==SET)//接收中断产生
		{
				USART_ClearITPendingBit(USART3,USART_IT_RXNE);//清中断
				data = USART_ReceiveData(USART3);//保存串口助手发过来的AT指令集
				netdata.rxbuff[netdata.rxcount++]=USART_ReceiveData(USART3);
				USART_SendData(USART1,data);//转发AT指令到USART1以及串口上面
		}
					//获取终端状态
		if(USART_GetITStatus(USART3,USART_IT_IDLE)==SET)//空闲中断产生
		{
				USART3->DR;
			/*
			清中断 
			--对于空闲中断清理   特殊在于:
			需要先读取 SR     USART_GetITStatus(USART2,USART_IT_IDLE)这个语句相当于读取了 SR
			在读DR  就可以了
			*/ 
		}
}

//发送一个字节函数
void Usart3SendByte(uint8_t data)
{
	//判断发送寄存器是否有数据-- 判断上次数据是否发送完成
	while(USART_GetFlagStatus(USART3,USART_FLAG_TC)==RESET);
	USART_SendData(USART3,data);
}

//发送字符串函数
void Usart3SendStr(char *data)
{
	while(*data!='\0')
	{
		Usart3SendByte(*data++);
	}
}
void Esp8266ConnectHost(void)
{
	NetSendCmdCheckAck("AT\r\n","OK",100,2);
	NetSendCmdCheckAck("AT+CWMODE=1\r\n","OK",100,2);//设置为STA模式
	NetSendCmdCheckAck("AT+CWJAP=\"LYJ\",\"11111111\"\r\n","WIFI GOT IP",10000,2);//连接热点
	Delay_nms(2000);
	NetSendCmdCheckAck("AT+CIPSTART=\"TCP\",\"122.114.122.174\",43491\r\n","OK",1000,2);//连接服务器
	NetSendCmdCheckAck("AT+CIPMODE=1\r\n","OK",100,2);//设置透传模式
	NetSendCmdCheckAck("AT+CIPSEND\r\n",">",100,2);//发送数据指令
	Usart3SendStr("12345");//发送的数据
	Delay_nms(5000);
	Usart3SendStr("+++");//退出透传
	Delay_nms(1000);
	NetSendCmdCheckAck("AT+CIPCLOSE\r\n","OK",100,2);//退出服务器连接
	
}


//比对,查找目标字符串
//src 被检查的字符串
//dest :要查找的目标
char *FindStr(char *src,char *dest,uint16_t overtime)
{
	while(strstr(src,dest)==NULL &&(overtime--) )
	{
		Delay_nms(1);
	}
	return strstr(src,dest);
}

/*
	发送AT指令并检查应答
	cmd: AT指令
	ack: AT指令的回应数据
	overtime:超时时间
	cnt:循环发送次数
*/
uint8_t NetSendCmdCheckAck(char *cmd,char *ack,uint16_t overtime,u8 cnt)
{
	memset(netdata.rxbuff,0,sizeof(netdata.rxbuff));
	netdata.rxcount =0;
	netdata.rxover =0;
	if(*cmd)
	{
		do{
			Usart3SendStr(cmd);
			if(FindStr((char *)netdata.rxbuff,ack,overtime)!=NULL)
			{
				return 0;
			}
			else
			{
				printf("比对失败,指令重发\r\n");
			}
			
		}while(cnt--);
	}
}




评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值