WIFI模块 和 AT指令再认识

WIFI模块ESP-01S 和 对应的新调试助手

 出场波特率是115200(注意,和之前的9600不同!),并且由于wifi模块也使用TTL协议,因此也需要通过CH340连接到电脑。

同时,需要用到新的调试助手(使用之前的也可以,但是这个更好,因为右侧有AT指令的提示)

电脑使用AT命令控制WIFI模块

 注意!AT指令,控制类都要加回车,数据传输时不加回车!!!

 注意!AT指令,控制类都要加回车,数据传输时不加回车!!!

 注意!AT指令,控制类都要加回车,数据传输时不加回车!!!

(之前编写代码使得串口接收点灯open指令的时候就需要回车,不太合理。。。)

注意!以下的模块是按照顺序来的,也就是说如果就想完成其中的一个模块,则需要查看之前的设置有没有都执行,否则可能不成功!

初始化 AT+RST

👇注意要勾选“发送新行”!👇

 改变波特率 AT+UART=9600,8,1,0,0

👇注意要勾选“发送新行”!👇

 修改之后关闭串口,选择波特率9600,再次 AT+RST  初始化:

 修改波特率成功!

入网设置

👇注意要勾选“发送新行”!👇

1. 设置工作模式 AT+CWMODE=3 //1是station(设备)模式;2是AP(路由)模式;3是双模

2. 以设备模式接入家中的路由器配置 AT+CWJAP="BELL846","541E5FE2C1E5" //前者为WIFI名字,后者为WIFI密码

 

3.  查询IP地址 AT+CIFSR

 //APIP地址是作为路由器时的网关

且由于刚刚开启了双模,所以现在的WIFI模块即是设备也是路由器,因此,此时打开电子设备的WIFI,应该可以看到由WIFI模块作为路由器发出的网络信号:

连接后查看IP地址:

 证明的确是WIFI模块发出的WIFI !

连接到TCP server

WIFI模块的网络协议是TCP协议,所以除了串口,还可以通过TCP协议与WIFI通讯,打开”网络调试助手“,选择TCP server;选择自己电脑的IP地址;端口号选择8080:

1. 连接到服务器 AT+CIPSTART="TCP","192.168.2.15",8880 //分别是协议类型,IP地址和端口号

2. 发送数据 AT+CIPSEND=4 //设置即将发送的数据长度为4个字节 

3. 看到 ' > ' 号之后,输入信息 MJMA,不带回车,所以要取消勾选”发送新行“!!如果超过4个字节,会显示Busy,并只发送四个字节:

 

4. 显示SEND OK之后,打开网络助手就可以看到发来的数据:

可见,是16进制的,如果把网络助手的设置修改一下,取消勾选16进制:

此时再发送一次:

 

此时就成功显示了(无视最前面的4个字节,是我发错了

透传

1. 进行入网设置

2. 连接到服务器 AT+CIPSTART="TCP","192.168.2.15",8880

3. 开启透传模式 AT+CIPMODE=1

4. 发送数据 AT+CIPSEND

 

 5. 看到 ' > ' 号之后,和之前不同,勾不勾选”发送新行“都可以!,然后就可以发送数据,由于是透传模式,此时的数据不再收到字节限制!

 6. 退出透传模式:在透传数据过程中,只要识别到单独的一包数据”+++", 则退出透传模式

有时候点一次发送可能没反应,那就点两次!

 👆以上,就是 电脑 通过 串口 ,使用 AT 指令指挥WIFI模块进行的各种操作。

接下来,我将尝试把 电脑 换成 单片机 ,通过对单片机串口的编程,实现同样的效果。

单片机白盒控制WIFI模块

白盒测试

通过代码的方式,可以让单片机不断发送AT指令的字符串,但是如何确定AT指令生效了呢? 观察之前电脑上的AT指令,再输入AT指令之后,都会得到类似“CONNECT“ 或 “OK” 之类的回复,所以,可以采用以下的连接方式,51单片机给WIFI模块发送指令,WIFI模块给PC的串口助手发送消息,从而可以在PC端的串口助手观察WIFI模块的响应:

实物连接如下图:

 在单片机内的代码编写如下:

#include "reg52.h"
#include "intrins.h" //这个库加了,delay函数里面的nop()才不会报错
#include <string.h>


//对于比较占用空间的字符串,为了防止报错,可以再最前面加一个“code”
char init[] = "AT+RST\r\n";
code char conn_wifi[] = "AT+CWJAP=\"BELL846\",\"541E5FE2C1E5\"\r\n"; //在"号前加上\是转义,使得"成为一个单纯的符号
code char conn_server[] = "AT+CIPSTART=\"TCP\",\"192.168.2.15\",8880\r\n";
char touchuan[] = "AT+CIPMODE=1\r\n";
char send[] = "AT+CIPSEND\r\n";
char quit[] = "+++\r\n";

void UartInit(void)		//9600bps@11.0592MHz
{
	PCON &= 0x7F;		//波特率不倍速
	SCON = 0x50;		//8位数据,可变波特率
	AUXR &= 0xBF;		//定时器1时钟为Fosc/12,即12T
	AUXR &= 0xFE;		//串口1选择定时器1为波特率发生器
	TMOD &= 0x0F;		//清除定时器1模式位
	TMOD |= 0x20;		//设定定时器1为8位自动重装方式
	TL1 = 0xFD;		//设定定时初值
	TH1 = 0xFD;		//设定定时器重装值
	ET1 = 0;		//禁止定时器1中断
	TR1 = 1;		//启动定时器1
}

void printSTR(char *msg)
{
	while(*msg != '\0'){
		SBUF = *msg; //往发送缓冲器里写入数据,就完成了数据的发送
		while(TI == 0); //只有当TI为1时,才往下走,根据手册,TI只有在发送完8位数据后才会硬件自动置1
		TI = 0;
		msg++;
	}
	
}

void main()
{
	UartInit();
	D5 = 1;
	
	ES = 1;
	EA = 1; //打开中断!
	
	
	while(1){
		
		printSTR(init);
		Delay1000ms();
		Delay1000ms();
		Delay1000ms();
		Delay1000ms();
		Delay1000ms();
		printSTR(conn_wifi); //连接到WIFI
		Delay1000ms();
		Delay1000ms();
		Delay1000ms();
		Delay1000ms();
		Delay1000ms();
		printSTR(conn_server); //连接到服务器
		Delay1000ms();
		Delay1000ms();
		Delay1000ms();
		Delay1000ms();
		Delay1000ms();
		printSTR(touchuan); //开启透传模式
		Delay1000ms();
		Delay1000ms();
		Delay1000ms();
		Delay1000ms();
		Delay1000ms();
		printSTR(send); //准备发送数据	
		Delay1000ms();
		Delay1000ms();
		Delay1000ms();
		Delay1000ms();
		Delay1000ms();
		
	}
}

之后,使用stc-isp助手将代码烧写进入单片机,并使用安信可串口助手观察结果:

 可以看到,单片机的代码成功将AT指令给到了WIFI模块,此时再打开网络助手

可以看到,由于开启了透传,单片机发送的数据在触发透传之后都会传入网络助手,因此从网络助手的视角来说,单片机还在不断传输AT命令,因此需要改进代码,使得单片机能知道,已经成功开启了透传,并停止发送AT指令,开始发送真正的数据。 

但是对于白盒测试来说,结果算是成功。

单片机黑盒控制WIFI模块点亮LED

在白盒测试成功后,可以将WIFI模块的TX插回单片机:

此时,无法像白盒测试一样直观的了解连接进程,刚刚是由电脑上的串口助手来读取WIFI模块的信息,现在是由单片机来接收,所以可以在单片机的接收中断函数中对于 WIFI模块对AT指令的回复 和 点灯的指令 进行接收和识别,从而实现通过单片机来控制WIFI模块点灯!

同时,似乎无法像之前使用字符串比较的方式来捕获接收的字段,因为希望识别的应答字符串 有时候太长了,且增加cmd的字节数也很容易报错,总之就是空间会浪费过多。鉴于应答字符串就那么几条,比较单一,所以可以通过比较某几位的字符来确定是否接收到该字符串,从而大大提升效率。

#include "reg52.h"
#include "intrins.h" //这个库加了,delay函数里面的nop()才不会报错
#include <string.h>

sfr AUXR = 0x8E; //配置了这句话,才可以在UART的初始化里写AUXR寄存器,原因见STC89系列的手册
sbit D5 = P3^7;
sbit beep_go = P1^3;

static int i = 0; //此时这句命令只会被执行一次。避免每次发生中断i都会清0

char flag1;
char flag_ok = 0;
char flag_ready = 0;
char flag_wifi = 0;
char flag_fail = 0;

char cmd[12];
char open[12] = "open\r\n";//windows
char close[12] = "close\r\n";//windows
//char open[12] = "open\n";//ios
//char close[12] = "close\n";//ios


//对于比较占用空间的字符串,为了防止报错,可以再最前面加一个“code”
code char conn_wifi[] = "AT+CWJAP=\"BELL846\",\"541E5FE2C1E5\"\r\n"; //在"号前加上\是转义,使得"成为一个单纯的符号
code char conn_server[] = "AT+CIPSTART=\"TCP\",\"192.168.2.15\",8880\r\n"; 
char touchuan[] = "AT+CIPMODE=1\r\n";
char init[] = "AT+RST\r\n";
char send[] = "AT+CIPSEND\r\n";
char quit[] = "+++\r\n";



void Delay1000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 8;
	j = 1;
	k = 243;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void Delay300ms()		//@11.0592MHz
{
	unsigned char i, j, k;
 
	_nop_();
	i = 3;
	j = 26;
	k = 223;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}


void beep()
{
	beep_go = 1;
	beep_go = 0;
  Delay300ms();
	beep_go = 1;
}


void UartInit(void)		//9600bps@11.0592MHz
{
	PCON &= 0x7F;		//波特率不倍速
	SCON = 0x50;		//8位数据,可变波特率
	AUXR &= 0xBF;		//定时器1时钟为Fosc/12,即12T
	AUXR &= 0xFE;		//串口1选择定时器1为波特率发生器
	TMOD &= 0x0F;		//清除定时器1模式位
	TMOD |= 0x20;		//设定定时器1为8位自动重装方式
	TL1 = 0xFD;		//设定定时初值
	TH1 = 0xFD;		//设定定时器重装值
	ET1 = 0;		//禁止定时器1中断
	TR1 = 1;		//启动定时器1
}

void printSTR(char *msg)
{
	while(*msg != '\0'){
		SBUF = *msg; //往发送缓冲器里写入数据,就完成了数据的发送
		while(TI == 0); //只有当TI为1时,才往下走,根据手册,TI只有在发送完8位数据后才会硬件自动置1
		TI = 0;
		msg++;
	}
}


void ATreStart()
{
	printSTR(init);//初始化
	while(flag_ok == 0);
	flag_ok = 0;
	while(flag_ready == 0);
  flag_ready = 0;
  flag_fail = 0;
}

void ATinit()
{	
	printSTR(conn_wifi); //连接到WIFI
  //while(flag_wifi == 0);
	//flag_wifi = 0;
	while(flag_ok == 0);
	flag_ok = 0;

	
	printSTR(conn_server); //连接到服务器
	while(flag_ok == 0);
	flag_ok = 0;
	
	printSTR(touchuan); //开启透传模式
	while(flag_ok == 0);
	flag_ok = 0;
	
	printSTR(send); //准备发送数据	
	while(flag_ok == 0);
	flag_ok = 0;
	
	beep();//代表已经开启透传,可以发送数据了

}

void Dealstr()
{
		if(cmd[0] == 'D' && cmd[1] == 'P'){ //DP
			D5 = 0;//开灯
			memset(cmd,'\0',12); //将字符串清空
		}
		
		if(cmd[0] == 'D' && cmd[1] == 'C'){ //DC
			D5 = 1;//关灯
			memset(cmd,'\0',12); //将字符串清空
		}
		
		if(cmd[0] == 'O' && cmd[1] == 'K'){ //OK
			flag_ok = 1;
			memset(cmd,'\0',12); //将字符串清空
		}
		
		if(cmd[1] == 'e' && cmd[3] == 'd'){ //ready
			flag_ready = 1;
			memset(cmd,'\0',12); //将字符串清空
		}
		
		if(cmd[1] == 'I' && cmd[5] == 'G'){ //WIFI GOT IP, 注意这里第二个判断只能写5或更小的数字,因为下一个字母是O,i会直接清0
			flag_wifi = 1;
			memset(cmd,'\0',12); //将字符串清空
		}
		
		if(cmd[1] == 'A' && cmd[3] == 'L'){ //FAIL
			flag_fail = 1;
			beep();
			Delay1000ms();
			beep(); //滴滴两声提示错误
			
			memset(cmd,'\0',12); //将字符串清空
			ATreStart();
			ATinit();
		}
						
}
	
void main()
{
	UartInit();
	D5 = 1;
	
	ES = 1;
	EA = 1; //打开中断!
	
	Delay1000ms();//给WIFI模块上电时间
	ATinit();
	
	while(1){
		printSTR("mjm");
		Delay1000ms();
	}
}

void UARTinter() interrupt 4 //由于不管TI还是RI置1时,中断都会发生,所以为了逻辑严谨,可以在中断处理函数中添加判断
{
	if(RI == 1){ //如果是RI引起的中断
		char tmp;
		
		tmp = SBUF;
		
		if(tmp == 'r' || tmp == 'O' || tmp == 'W' || tmp == 'F' || tmp == 'D' || i == 12){ //ready, OK, WIFI GOT IP, FAIL, DP/C, 满了
			i = 0;
		}
		
		cmd[i] = tmp; //从SBUF里面读发来的数据
		i++;
		
		Dealstr();
		RI = 0;//软件复位
	
  }
	
}

运行结果:

所以可以成功连接!此时在网络调试助手中输入"DP"或“DC”就可以控制LED灯了。

 

WIFI模块(esp-01s)作为服务器

先将WIFI模块单独接入电脑:

1. 配置成双模 AT+CWMODE=3

 

2. 查网段 AT+CIFSR

 之前就做过这步,已经知道,这个WIFI就是AI_Thinker那个

3. 让电脑连接上WIFI模块作为路由的WIFI

 4. 使能多连接 AT+CIPMUX=1 

5. 建立TCPServer AT+CIPSERVER=1 //default port = 333

 

6. 打开网络调试助手,选择TCP Client 和对应的网络信息,并点击连接,可以在串口助手中看到连接信息

7. 发送数据 AT+CIPSEND=0,8 //发送8个字节在连接0通道上 

此时可以发送信息(不用加回车!)并在网络助手中收到!

 

8. 断开连接 AT+CIPCLOSE=0

单片机黑盒控制使WIFI模式配置成服务器

和之前一样,目标是由单片机发送AT指令,然后使用单片机来接收WIFI的指令并识别!接线依然:

#include "reg52.h"
#include "intrins.h" //这个库加了,delay函数里面的nop()才不会报错
#include <string.h>

sfr AUXR = 0x8E; //配置了这句话,才可以在UART的初始化里写AUXR寄存器,原因见STC89系列的手册
sbit D5 = P3^7;
sbit beep_go = P1^3;

static int i = 0; //此时这句命令只会被执行一次。避免每次发生中断i都会清0

char flag1;
char flag_ok = 0;
char flag_fail = 0;
char flag_con = 0;

char cmd[12];


code char mode[] = "AT+CWMODE=3\r\n";
code char mul_con[] = "AT+CIPMUX=1\r\n";
code char server[] = "AT+CIPSERVER=1\r\n";
code char send[] = "AT+CIPSEND=0,8\r\n";
code char end[] = "AT+CIPCLOSE=0\r\n";


void Delay1000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 8;
	j = 1;
	k = 243;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void Delay300ms()		//@11.0592MHz
{
	unsigned char i, j, k;
 
	_nop_();
	i = 3;
	j = 26;
	k = 223;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}


void beep()
{
	beep_go = 1;
	beep_go = 0;
  Delay300ms();
	beep_go = 1;
}


void UartInit(void)		//9600bps@11.0592MHz
{
	PCON &= 0x7F;		//波特率不倍速
	SCON = 0x50;		//8位数据,可变波特率
	AUXR &= 0xBF;		//定时器1时钟为Fosc/12,即12T
	AUXR &= 0xFE;		//串口1选择定时器1为波特率发生器
	TMOD &= 0x0F;		//清除定时器1模式位
	TMOD |= 0x20;		//设定定时器1为8位自动重装方式
	TL1 = 0xFD;		//设定定时初值
	TH1 = 0xFD;		//设定定时器重装值
	ET1 = 0;		//禁止定时器1中断
	TR1 = 1;		//启动定时器1
}

void printSTR(char *msg)
{
	while(*msg != '\0'){
		SBUF = *msg; //往发送缓冲器里写入数据,就完成了数据的发送
		while(TI == 0); //只有当TI为1时,才往下走,根据手册,TI只有在发送完8位数据后才会硬件自动置1
		TI = 0;
		msg++;
	}
}



void ATinit()
{	
	printSTR(mode);
	while(flag_ok == 0);
	flag_ok = 0;
	
	printSTR(mul_con);
	while(flag_ok == 0);
	flag_ok = 0;
	
	printSTR(server);
	while(flag_con == 0);
	flag_con = 0;
	
	beep();

}

void Dealstr()
{
	  if(cmd[0] == ':' && cmd[1] == 'o' && cmd[2] == 'p'){ //open
			D5 = 0; //亮灯
			memset(cmd,'\0',12); //将字符串清空
		}
		
		if(cmd[0] == ':' && cmd[1] == 'c' && cmd[2] == 'l'){ //close
			D5 = 1; //灭灯
			memset(cmd,'\0',12); //将字符串清空
		}
		
		if(cmd[0] == '0' && cmd[2] == 'C'){ //0,CONNECTED
			flag_con = 1;
			memset(cmd,'\0',12); //将字符串清空
		}
		
		if(cmd[0] == 'O' && cmd[1] == 'K'){ //OK
			flag_ok = 1;
			memset(cmd,'\0',12); //将字符串清空
		}
						
}
	
void main()
{
	UartInit();
	D5 = 1;
	
	ES = 1;
	EA = 1; //打开中断!
	
	Delay1000ms();//给WIFI模块上电时间
	ATinit();
	
	while(1){
		printSTR(send);
		Delay1000ms();
		Delay1000ms();
		printSTR("mjmMJM12"); //8个字节
		Delay1000ms();
		Delay1000ms();
	}
}

void UARTinter() interrupt 4 //由于不管TI还是RI置1时,中断都会发生,所以为了逻辑严谨,可以在中断处理函数中添加判断
{
	if(RI == 1){ //如果是RI引起的中断
		char tmp;
		
		tmp = SBUF;
		
		if(tmp == 'O'|| tmp == '0' || i == 12 || tmp == ':'){ //OK, '0,CONNECTED', 满了, 指令
			i = 0;
		}
		
		cmd[i] = tmp; //从SBUF里面读发来的数据
		i++;
		
		Dealstr();
		RI = 0;//软件复位
	
  }
	
}

运行效果

在运行代码后,连接到AIthinker的WIFI, 打开网络助手 点击连接听到蜂鸣器BEEP一声,并在网络助手中不断收到字符串,并且如果输入open 或 close 可以成功进行点灯和灭灯

  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
开发 ESP8266 WiFi 模块的 STM32 库函数需要进行以下步骤: 1. 确定 ESP8266 WiFi 模块AT 指令集 在使用 ESP8266 WiFi 模块之前,需要先了解其支持的 AT 指令集,包括 AT+RST、AT+CWMODE、AT+CWJAP、AT+CIPSTART、AT+CIPSEND 等。可以通过 ESP8266 WiFi 模块的官方文档或 AT 指令集手册来获取这些信息。 2. 初始化 STM32 的串口通信 ESP8266 WiFi 模块使用串口与 STM32 进行通信,因此需要在 STM32 上初始化串口通信。可以使用 STM32 的 USART 库函数来实现。 3. 封装 ESP8266 WiFi 模块AT 指令 在进行 ESP8266 WiFi 模块AT 指令通信时,需要将 AT 指令封装成一串字符串,并通过串口发送给 ESP8266 WiFi 模块。在 STM32 库函数中,可以封装一个函数来实现该功能。 4. 实现 ESP8266 WiFi 模块AT 指令响应 当 ESP8266 WiFi 模块接收到 STM32 发送的 AT 指令后,需要返回响应信息。可以通过 STM32 的串口接收中断来实现对 ESP8266 WiFi 模块响应信息的接收,并通过库函数将其处理。 5. 实现 WiFi 模块的网络连接 通过使用 ESP8266 WiFi 模块AT 指令,可以实现 WiFi 模块的网络连接。可以通过封装 STM32 库函数来实现 ESP8266 WiFi 模块的网络连接。 6. 实现 WiFi 模块的数据传输 通过 ESP8266 WiFi 模块AT 指令,可以实现 WiFi 模块的数据传输,包括数据发送和数据接收。可以封装 STM32 库函数来实现 ESP8266 WiFi 模块的数据传输。 总之,使用 STM32 库函数开发 ESP8266 WiFi 模块需要对 ESP8266 WiFi 模块AT 指令集有一定的了解,并且需要熟悉 STM32 的串口通信和 USART 库函数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值