WIFI模块 和 AT指令再认识

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

WIFI模块 和 AT指令再认识_第1张图片WIFI模块 和 AT指令再认识_第2张图片WIFI模块 和 AT指令再认识_第3张图片

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

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

WIFI模块 和 AT指令再认识_第4张图片

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

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

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

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

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

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

初始化 AT+RST

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

WIFI模块 和 AT指令再认识_第5张图片

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

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

WIFI模块 和 AT指令再认识_第6张图片

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

WIFI模块 和 AT指令再认识_第7张图片

 修改波特率成功!

入网设置

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

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

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

 

3.  查询IP地址 AT+CIFSR

WIFI模块 和 AT指令再认识_第8张图片 //APIP地址是作为路由器时的网关

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

WIFI模块 和 AT指令再认识_第9张图片

连接后查看IP地址:

WIFI模块 和 AT指令再认识_第10张图片

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

连接到TCP server

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

WIFI模块 和 AT指令再认识_第11张图片

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

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

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

 WIFI模块 和 AT指令再认识_第12张图片

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模块的响应:

WIFI模块 和 AT指令再认识_第13张图片

实物连接如下图:

WIFI模块 和 AT指令再认识_第14张图片

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

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


//对于比较占用空间的字符串,为了防止报错,可以再最前面加一个“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)		//[email protected]
{
	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助手将代码烧写进入单片机,并使用安信可串口助手观察结果:

WIFI模块 和 AT指令再认识_第15张图片

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

WIFI模块 和 AT指令再认识_第16张图片

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

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

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

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

WIFI模块 和 AT指令再认识_第17张图片

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

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

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

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)		//[email protected]
{
	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;//软件复位
	
  }
	
}

运行结果:

WIFI模块 和 AT指令再认识_第18张图片

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

 WIFI模块 和 AT指令再认识_第19张图片WIFI模块 和 AT指令再认识_第20张图片

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

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

WIFI模块 和 AT指令再认识_第21张图片

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 和对应的网络信息,并点击连接,可以在串口助手中看到连接信息

WIFI模块 和 AT指令再认识_第22张图片

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

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

 

8. 断开连接 AT+CIPCLOSE=0

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

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

WIFI模块 和 AT指令再认识_第23张图片

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

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)		//[email protected]
{
	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 可以成功进行点灯和灭灯

WIFI模块 和 AT指令再认识_第24张图片

WIFI模块 和 AT指令再认识_第25张图片

你可能感兴趣的:(智能路由器,单片机,c语言)