STM32---WIFI模块ESP8266

发布于:2024-04-20 ⋅ 阅读:(24) ⋅ 点赞:(0)

模块介绍

模块连接

模块连接时基于串口方式连接,其模块与电脑(服务器)之间数据的发送与接收也是基于串口。
11

WIFI模块的模式

  • mode=1 :Station模式(连接到WIFI)
  • mode=2:AP模式(自己作为WIFI源供其他连接)
  • mode=3:AP+Station模式(以上两者模式的合并)

WIFI模块常用AT指令

2

透传模式理解

透传模式就是单片机通过串口形式与模块连接,而模块与上位机之间的数据交互的具体不用考虑。
3

  • 如果不开启透传模式,在每次发送数据前都必须先发送指令AT+CIPSEND=

     AT+CIPSEND=4
      
     OK
     >                //在 > 后面输入要上传的数据
    
  • 但是开启了透传模式,我们就不需要在每次发送数据前都发送指令AT+CIPSEND=了,只需要发送一次AT+CIPSEND,之后发送的所有内容全部当成是数据了!

代码实现

代码介绍

1、对串口的配置。
串口初始化、串口中断接收数据,串口发送函数封装(模块发送数据)

2、AT指令的发送,并发送AT指令时发送相关的数据:熟练运用spprintf()函数。

实现步骤

1. 重置模组为出厂模式:AT+RESTORE			示例:AT+RESTORE    		 OK 
2. 设置工作模式:AT+CWMODE=<mode>		示例:AT+CWMODE=1	     OK
3. 连接当前环境的WIFI热点:AT+CWJAP=<ssid>,< pwd >	
		< ssid >:字符串参数,当前WIFI的名字
		 < pwd >:字符串参数,连接密码
		 示例:AT+CWJAP="TCP_Server","12345678" 
     		  WIFI CONNECTED	      
     		  WIFI GOT IP 
4. 建立TCP连接通道	:AT+CIPSTART="TCP",<ip>,<port>
		 < ip >:字符串参数,IP地址
  		< port >:字符串参数,服务器端口
	示例: AT+CIPSTART="TCP","192.168.4.1",333
     	 CONNECTED
5. 开启透传模式:AT+CIPMODE=1
6. 发送数据: AT+CIPSEND=<length>
		 <length> 发送数据的字节长度
	示例: AT+CIPSEND=10
      OK
       >在此处填写要发送的内容
 注释:示例是在串口调试助手下的发送与返回。也是给代码编写提供示例。

.c文件

#include "delay.h"
#include "wifi.h"
#include "stdarg.h"	 	 
#include "stdio.h"	
#include "stdlib.h"
#include "string.h"	 
#include "usart.h"
#include "stm32f10x.h"
#include "sys.h" 
#include "lcd.h"



//串口接收缓存区 	
char USART2_RX_BUF[USART2_MAX_RECV_LEN]; 				//接收缓冲,最大USART3_MAX_RECV_LEN个字节.

//接收到的数据状态
//[15]:0,没有接收到数据;1,接收到了一批数据.
//[14:0]:接收到的数据长度
vu16 USART2_RX_STA=0;   	

void USART2_IRQHandler(void)
{
	u8 res;
	if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)//接收到数据
	{	 
			USART_ClearITPendingBit(USART2, USART_IT_RXNE);
	  	res =USART_ReceiveData(USART2);		 
			USART2_RX_BUF[USART2_RX_STA&0X3FFF]=res;	//记录接收到的值
			USART2_RX_STA++;		
			//USART_SendData(USART1,res);
			//printf("%x",res);
			USART2_RX_STA|=0x8000;			//标记接收完成
	}
}   


//初始化IO 串口2
//bound:波特率	  
void wifi_usart2_init(u32 bound)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	// GPIOA时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE); //串口2时钟使能

 	USART_DeInit(USART2);  //复位串口2
		 //USART2_TX   PA2
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; 
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
  GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA2
   
    //USART2_RX	  PA3
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);  //初始化PA3
	
	
		//设置中断优先级
	NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;//抢占优先级2
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;		//子优先级2
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
	
	USART_InitStructure.USART_BaudRate = bound;//波特率一般设置为9600;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
	USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式
  
	USART_Init(USART2, &USART_InitStructure); //初始化串口	2
	//使能接收中断
  USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启中断 
	USART_Cmd(USART2, ENABLE);                    //使能串口 

	USART2_RX_STA=0;		//清零
}
/******************************************************************************
      函数说明:发送数据到串口2
      入口数据:DATA_BUF  发送的数据           
                len   发送的长度          
      返回值:  无
******************************************************************************/
void esp8266_send_data(u8 *DATA_BUF,u8 len)	//发送数据到串口2
{
	u16 j; 
	if(len <= 0)
		return ;
	if(len>USART2_MAX_SEND_LEN)			//最多只能发MAX_LEN个数据
	{
		for(j=0;j<USART2_MAX_SEND_LEN;j++)							//循环发送数据
		{
			USART_SendData(USART2,DATA_BUF[j]); 
			while(USART_GetFlagStatus(USART2,USART_FLAG_TC)==RESET); //循环发送,直到发送完毕   	
		} 
	}
	else
	{ 
		for(j=0;j<len;j++)							//循环发送数据
		{
			USART_SendData(USART2,DATA_BUF[j]); 
			while(USART_GetFlagStatus(USART2,USART_FLAG_TC)==RESET); //循环发送,直到发送完毕   	
		} 
	}
} 
/******************************************************************************
      函数说明:检查是否有相应回复的数据
      入口数据:str 检查的字符串          
                           
      返回值:  str出现的位置开始
******************************************************************************/
u8* esp8266_check_cmd(u8 *str)		//检查回复是否有字符串str
{
	USART2_RX_STA = 0;
	return (u8*)strstr((const char*)USART2_RX_BUF,(const char*)str);	
}
/******************************************************************************
      函数说明:连接WIFI 		TCP服务器   
								根据电脑上连接的WIFI和IP地址,建立模块与电脑上服务器之间的连接
								将模块连接与WIFI(wifi名字和密码),并确认是那台电脑上(电脑上的ip地址)的服务器
								电脑与模块需要连接在同以WIFI下
								使模块与电脑通过串口,连接于电脑端的服务器软件或平台
      入口数据:id  		WIFI帐号
								key			WIFI密码
								ip			TCP服务器的IP地址
								port		TCP服务器的端口号
                           
      返回值:  连接成功返回0,	WIFI连接失败返回-1, TCP连接失败返回-2
******************************************************************************/

int esp8266_connect_ap_tcp(u8 *ssid,u8 *password,u8 *ip,u8 *port)	//发送WIFI账号,密码
{
		u8 idkey_buf[64]={0};
		u8 ip_server[64]={0};
		u8 i;
		int n;
		int m;
		char *ipbuf;
		char *ipbuf1;
		//u8 debuf[1] = """;
		int datelen1,datelen2;
		//将发送的数据通过sprintf存入数组
		//然后发送AT指令和等待模块连接,返回相应的数据
		datelen1 = sprintf((char *)idkey_buf,"AT+CWJAP=\"%s\",\"%s\"\r\n",ssid,password);//连接指令
		datelen2 = sprintf((char *)ip_server,"AT+CIPSTART=\"TCP\",\"%s\",%s\r\n",ip,port);//连接指令
		esp8266_send_data("AT+RSTORE\r\n",11);
	
		delay_ms(1000);         //延时3S等待重启成功
		delay_ms(1000);
		//设置工作模式 1:station模式   2:AP模式  3:兼容 AP+station模式
		esp8266_send_data("AT+CWMODE=1\r\n",13);
		delay_ms(1000);
		delay_ms(1000);
		esp8266_send_data(idkey_buf,datelen1);	//让模块连接上自己的路由		"WIFI GOT IP"
		delay_ms(1000);
		delay_ms(1000);
		delay_ms(1000);
		delay_ms(1000);
		delay_ms(1000);
		delay_ms(1000);
		delay_ms(1000);
		if(esp8266_check_cmd("WIFI CONNECTED"))
		{
			delay_ms(1000);
			esp8266_send_data("AT+CIFSR\r\n",10);									//查询本模块IP地址
			delay_ms(1000);
			delay_ms(1000);
			delay_ms(1000);
			ipbuf = (char*)esp8266_check_cmd("+CIFSR:");		
			
			//得到IP地址最后3 位 例如:192.168.1.120 得到 120			//显示的是ESP8266模块的IP地址的后三位
			for(i=0;i<3;i++)  
			{
				ipbuf = strstr(ipbuf,".");
				ipbuf ++;
			}			
			ipbuf1 = strstr(ipbuf,"\"");
			n = ipbuf1-ipbuf;
			ipbuf[n] = '\0';
			m = atoi(ipbuf); //将字符格式 转换为int						//发送AT指令后,模块返回的是字符串,需要将后三位转化为数字
			printf("clinet IP is:%d\r\n",m);
			LCD_ShowString(40,0,"   ",RED,WHITE);	//接收数据显示至lcd屏
			LCD_ShowString(40,0,(u8 *)ipbuf,RED,WHITE);	//接收数据显示至lcd屏
			esp8266_send_data(ip_server,datelen2);	//建立TCP连接  这四项分别代表了 要连接的ID号0~4   连接类型  远程服务器IP地址   远程服务器端口号
			delay_ms(1000);
			delay_ms(1000);
			delay_ms(1000);
			delay_ms(1000);
			if(esp8266_check_cmd("CONNECT"))		//判断是否连接成功
			{
			 return m; 
			}
				
			else 
				return -2;
		}
		return -1;
}
/******************************************************************************
      函数说明:发送数据到服务器
								模块建立TCP连接到服务器,并发送数据
      入口数据:data  发送的数据     
								len   发送的长度
                           
      返回值:  若无TCP连接返回0,有返回1
******************************************************************************/
u8 esp8266_send_serverdata(u8 *data,u8 len)		//给服务器发数据,检查若无连接TCP 则return 0;连上则发送
{
	//检查TCP连接状态	AT+CIPSTATUS    STATUS:3
	u8 Send_ServerBuf[32] = {0};
	u8 len2=0;
	esp8266_send_data("AT+CIPSTATUS\r\n",14);			
	delay_ms(10);
	if(esp8266_check_cmd("STATUS:3"))					//检查回复
	{
		len2=sprintf((char *)Send_ServerBuf,"AT+CIPSEND=%d\r\n",(int)len);
		esp8266_send_data(Send_ServerBuf,len2);//发送len个字节的数据到服务器端
		delay_ms(10);
		esp8266_send_data(data,len);
		return 1;
	}
	else
		return 0;
}
/******************************************************************************
      函数说明:解析服务器发送的有效数据
      参数:recv_buf  接收数组指针  
                           
      返回值:  有效数据的长度
******************************************************************************/
u16 esp8266_rev_serverdata(u8 *recv_buf)
{	
		u8 i,j;
		int len;
		char *USART_RX_BUF1;
		char *USART_RX_BUF2;
		u8 lens[3]={0};

		delay_ms(20);
		if(USART2_RX_STA&0X8000)		//接收到一次数据了
		{
			//"\r\n+IPD,20:http://www.baidu.com"
			if(strstr((const char*)USART2_RX_BUF,"+IPD"))
			{			
				USART_RX_BUF1=strstr(USART2_RX_BUF,",");	//查找第一个 ","所在位置 返回指针
				USART_RX_BUF2=strstr(USART2_RX_BUF,":"); //查找第一个  ":"所在位置 返回指针
				j=USART_RX_BUF2-USART_RX_BUF1;   //数据长度计算 指针相减
				if (j>3) j=3;
				for(i=0;i<j;i++)
				{
					lens[i]=USART_RX_BUF1[i+1];
				}				
				len = atoi((const char *)lens);			//字符串转整数
				for(i=0;i<len;i++)
				{
					recv_buf[i] = USART_RX_BUF2[i+1];
				}
				recv_buf[len]='\0';
				USART2_RX_STA = 0;
				return len;
			}
		}
		USART2_RX_STA = 0;
		return 0;
}

.h文件

#ifndef __WIFI_H
#define __WIFI_H	 
#include "sys.h"     

#define USART2_MAX_RECV_LEN		200		//最大接收缓存字节数
#define USART2_MAX_SEND_LEN		200				//最大发送缓存字节数

extern char  USART2_RX_BUF[USART2_MAX_RECV_LEN]; 		//接收缓冲,最大USART2_MAX_RECV_LEN字节
extern u8  USART2_TX_BUF[USART2_MAX_SEND_LEN]; 		//发送缓冲,最大USART2_MAX_SEND_LEN字节
extern vu16 USART2_RX_STA;   						//接收数据状态

void wifi_usart2_init(u32 bound);				//串口2初始化 

int esp8266_connect_ap_tcp(u8 *ssid,u8 *password,u8 *ip,u8 *port); //发送WIFI账号,密码/TCP服务器的IP,接口
u16 esp8266_rev_serverdata(u8 *USART_RX_buf);//解析服务器发送的有效数据
u8 esp8266_send_serverdata(u8 *data,u8 len);

#endif

main.c文件

#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "lcd.h"
#include "wifi.h"
#include "key.h"
#include "timer.h"
#include "beep.h"
#include "lcd_init.h"

//技术支持:

 int main(void)
 { 	
	u16 rlen=0;
	int add;
	u8 key;
	
	u16 led0pwmval=0;    	//PWM用变量
	u8 dir=1;							//PWM初始递增
	u8 revbuf[200] = {0}; //接收buffer
	u8 heartbeat[5]={0x55,0x00,0x00,0x00,0xaa}; //心跳包格式
	
	u8 ledflag = 1; 	//LED处理变量
	u8 beepflag = 0;//蜂鸣器处理变量
	u8 picflag = 0;//图片处理变量
	u8 pwmflag = 1;//PWM处理变量
	
	u8 beepfirst=1;//定义此变量来解决蜂鸣器上电后默认响的问题
	u8 picjif=0;//定义此变量解决PWM时刷新图片导致PWM观察不明显的问题

	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
	delay_init();	    	 //延时函数初始化	  
	uart_init(115200);	 	 //串口1初始化为115200
	
	wifi_usart2_init(115200);
	
	LED_Init();		  		 //初始化LED
 	LCD_Init();					 //初始化LCD
	KEY_Init();					//初始化KEY
	BEEP_Init();				//初始化BEEP
	TIM1_PWM_Init(899,0);//初始化TIM1
	
	LCD_Fill(0,0,LCD_W,LCD_H,WHITE);//进行清屏
	LCD_ShowString(0,0,(u8*)"地址:     LED:  ",RED,WHITE);
	LCD_ShowString(0,16,(u8*)"蜂鸣器:   PWM:  ",RED,WHITE);
	
	add=esp8266_connect_ap_tcp("TZH-WiFi","88888888","192.168.0.25","8234");
	if(add)
	{
		heartbeat[1] = add&0xff;
		esp8266_send_serverdata(heartbeat,5);
	}
	LCD_ShowPicture(0,32,128,128,gImage_ta);
	
		while(1)
		{	
			
			key=KEY_Scan(0); //进行按键扫描 不检测连按
			if( key == KEYLEFT_PRES ) //KEYLEFT按下,连接服务器
			{
				//连接wifi ap ssid ="TZHXXKJ" password = "1105_tzh" tcp server ip="192.168.1.147" port="8234"
				add=esp8266_connect_ap_tcp((u8*)"TZH-WiFi","88888888","192.168.0.25","8234"); 
				if(add)
				{
					heartbeat[1] = add&0xff;
					esp8266_send_serverdata(heartbeat,5);
				}
			}
//-------------------------------------------------------------------------------------------------------			
			if(key==KEYRIGHT_PRES) //KEYRIGHT按下,往服务器发送数据
			{	
				
				esp8266_send_serverdata((u8*)"123456789",9);
				
			}
			
//-------------------------------------------------------------------------------------------------------					
			if(!ledflag) //LED 相关处理
			{
				LED1=0;
				LCD_ShowString(112,0,(u8*)"开",RED,WHITE);				
			}
			else
			{
				LED1=1;
				LCD_ShowString(112,0,(u8*)"关",RED,WHITE);	
			}
			
			if(!beepflag) //蜂鸣器 相关处理
			{
				if(beepfirst) //第一次上电时蜂鸣器不响
				{
					
					BEEP=0;
					LCD_ShowString(56,16,(u8*)"关",RED,WHITE);	
				}
				else	
				{					
					BEEP=1;
					LCD_ShowString(56,15,(u8*)"开",RED,WHITE);	
				}
			}
			else
			{
				BEEP=0;
				LCD_ShowString(56,16,(u8*)"关",RED,WHITE);	
			}
//-------------------------------------------------------------------------------------------------------					
			if(picflag) //动态图片相关处理
			{
				LCD_ShowPicture(0,32,128,128,gImage_gif1);
				LCD_ShowPicture(0,32,128,128,gImage_gif2);
			}
//-------------------------------------------------------------------------------------------------------					
			if(!pwmflag)//PWM 相关处理
			{
				if(picflag)//如果动态图片刷新为真
				{
					picjif=1;//记录该状态
					picflag=0;//先禁止动态图片刷新 否则影响PWM观察
				}
				if(dir)led0pwmval += 15;
				else 	led0pwmval -= 15;
				if(led0pwmval>800)dir=0;
				if(led0pwmval==0)dir=1;	   					 
				TIM_SetCompare1(TIM1,led0pwmval);
				LCD_ShowString(112,16,(u8*)"开",RED,WHITE);	
			}
			else//PWM关闭
			{
				if(picjif)//如果记录状态为真,说明动态图片刷新被禁止
				{
					picjif=0;//清除该状态变量
					picflag=1;//恢复动态图片刷新
				}
				TIM_SetCompare1(TIM1,0);			
				LCD_ShowString(112,16,(u8*)"关",RED,WHITE);					
			}
			
//-------------------------------------------------------------------------------------------------------					
//-------------------------------------------------------------------------------------------------------		
			delay_ms(10);
			rlen=esp8266_rev_serverdata(revbuf);		//接收服务器发过来的数据
			if(rlen)
			{
				if(revbuf[2] == 1) //LED 相关处理
				{
					ledflag=revbuf[3];
				}
				if(revbuf[2] == 2)//蜂鸣器 相关处理
				{
					beepfirst=0;
					beepflag=revbuf[3];
				}	
				if(revbuf[2] == 3)//图片显示 相关处理
				{
					switch(revbuf[3])
					{
						case 0x01:picflag=0;picjif=0;LCD_ShowPicture(0,32,128,128,gImage_ta);break;
						case 0x02:picflag=0;picjif=0;LCD_ShowPicture(0,32,128,128,gImage_yun);break;
						case 0x03:picflag=1;picjif=0;break;
						default:
										LCD_ShowPicture(0,32,128,128,gImage_ta);
					}
				}						
				if(revbuf[2] == 4) //PWM 相关处理
				{
					pwmflag=revbuf[3];
				}
			}
			
			
		}		//end while(1)
}

数据接收讲解

主要部分:

rlen=esp8266_rev_serverdata(revbuf);		//接收服务器发过来的数据
if(rlen)
{
	if(revbuf[2] == 1) //LED 相关处理
	{
		ledflag=revbuf[3];
	}
	if(revbuf[2] == 2)//蜂鸣器 相关处理
	{
		beepfirst=0;
		beepflag=revbuf[3];
	}	
	if(revbuf[2] == 3)//图片显示 相关处理
	{
		switch(revbuf[3])
		{
			case 0x01:picflag=0;picjif=0;LCD_ShowPicture(0,32,128,128,gImage_ta);break;
			case 0x02:picflag=0;picjif=0;LCD_ShowPicture(0,32,128,128,gImage_yun);break;
			case 0x03:picflag=1;picjif=0;break;
			default:
							LCD_ShowPicture(0,32,128,128,gImage_ta);
		}
	}						
	if(revbuf[2] == 4) //PWM 相关处理
	{
		pwmflag=revbuf[3];
	}
}

上位机发送的数据

 > [1,OnAccept] -> PASS(192.168.1.177:18323)
 > [1,OnReceive] -> 192.168.1.177:18323 (5 bytes)
-> HEX: 55 B1 00 00 AA 
-> ASCII: U?

其中最主要看HEX十六进制数据
根据代码和接受的数据,可知,其最后在物理层连接部分,只是串口的应用。