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 可以成功进行点灯和灭灯!
文章来源:https://www.toymoban.com/news/detail-756597.html
文章来源地址https://www.toymoban.com/news/detail-756597.html
到了这里,关于WIFI模块 和 AT指令再认识的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!