小小ESP8266居然有这么大的作用!!!可以让手机电脑通过wifi控制LED。#ESP8266 wifi 模块【上】
前言
本篇博文介绍的是用51单片机的串口通信的应用(ESP8266 WIFI 模块),包含wifi模块esp8266课程目标概述,wifi模块esp8266的AT指令联网数据交互,单片机发送AT指令实现ESP8266联网,通过网络TCP通信控制LED,白盒方式看到连接不上的原因,调试手段。看到这篇博文的朋友,可以先赞再看吗?
预备知识
一、基本电路标识识别和接线,例如VCC,GND。
二、C变量
三、基本输入输出
四、流程控制
五、函数
六、指针
七,字符串
如果以上知识不清楚,请自行学习后再来浏览。如果我有没例出的,请在评论区写一下。谢谢啦!
1.wifi模块esp8266课程目标概述
1.1官网介绍
- 官网介绍地址
[ESP8266 Wi-Fi SoC|乐鑫科技 (espressif.com.cn)](点击这里)
- 官方介绍
ESP8266EX
内置超低功耗 Tensilica L106 32
位 RISC
处理器,CPU
时钟速度最高可达 160 MHz
,支持实时操作系统 (RTOS)
和 Wi-Fi 协议栈
,可将高达 80%
的处理能力留给应用编程和开发。
1.2课程介绍
Wifi模块-ESP-01s :蓝牙,ESP-01s
,Zigbee
, NB-Iot
等通信模块都是基于AT
指令的设计
1.2.1 AT指令
AT指令集是从终端设备
(Terminal Equipment,TE)或数据终端
设备(Data TerminalEquipment,DTE)向终端适配器
(Terminal Adapter,TA)或数据电路终端
设备(Data CircuitTerminal Equipment,DCE)发送的
。
其对所传输的数据包大小有定义:即对于AT指令的发送,除AT两个字符外,最多可以接收1056
个字符的长度(包括最后的空字符)。
每个AT命令行中只能包含一条AT指令;对于由终端设备主动向PC端
报告的URC指示
或者response响应
,也要求一行最多有一个,不允许上报的一行中有多条指示或者响应。AT指令以回车作为结尾,响应或上报以回车换行为结尾。
2.wifi模块esp8266的AT指令联网数据交互
2.1初始配置和验证
ESP-01s
出厂波特率正常是115200
,但有些是9600
,。可以用串口助手来试,发送字符,如果在波特率9600
下字符清晰
,就是9600
,反之是115200
。 注意:AT指令,控制类都要加回车,数据传输时不加回车
- 上电后,通过串口输出一串系统开机信息,购买的部分模块可能电压不稳,导致乱码,以
ready
为准
###########################################################
ets Jan 8 2013,rst cause:2, boot mode:(3,0)
load 0x40100000, len 27728, room 16
tail 0
chksum 0x2a
load 0x3ffe8000, len 2124, room 8
tail 4
chksum 0x07
load 0x3ffe8850, len 9276, room 4
tail 8
chksum 0xba
csum 0xba
勩{揹宭?d`你r?靌?$`屻s抣嚐?$l ;l噧;?ready
###########################################################
由于体质的不一样,我的ESP8266呈现上面这样,好的ESP8266呈现如下
##########################################################################
arch:ESP8266, 1 型号
compile_time:Ai-Thinker|B&T PC串口调试助手厂商安信可
wifi_mac:4c75250dAE2F wifi模块esp8266唯一的地址mac地址
sdk_version:v3.4-22-g967752e2 sdk版本号
firmware_version:2.2.0 固件版本号
compile_time:Jun 30 2021 11:28:20 上电时间
ready 准备好
##########################################################################
- 上电后发送AT指令测试通信及模块功能是否正常
注意:发送AT指令时一定要勾选发新行才能正确执行AT指令
- 使用命令
AT+UART=9600,8,1,0,0
配置波特率为9600
当屏幕中出现以上图片情况,说明波特率配置成功。此时就需要点击关闭串口,在波特率处设置为9600再重新打开串口。
再次发送AT看看是否连接成功,如图表示连接成功。
2.2入网设置
2.2.1设置工作模式
使用AT+CWMODE = 1、2、3
设置模式为1 station(设备)
,2 AP(路由模式)
, 3 是双模即设备路由一体
。这里设置为模式3,方便观看ESP8266是否正常
如上图所示是已打开双模模式。
2.2.2以设备模式接入家中路由器配置
使用AT+CWJAP="wifi名称", "wifi密码"
,这里注意使用英文字符和半角符号
。
2.2.3查询IP地址
使用AT+CIFSR
指令查询IP地址
2.3.连接到 TCP server 服务器
2.3.1打开网络调试助手,设立TCP服务器
- 将电脑和
ESP8266
同时连接一个wifi热点
,这个热点建议用手机开热点,也可以连自家路由器。哪个能连上就连哪个。热点名称必须用英文。
- 打开电脑命令提示符,输入
ipconfig
按回车查询电脑IP地址
- 打开网络助手(精英版 V3.6),在
通讯设置
内协议类型选TCP服务器
,本地IP地址写上图圈出的IP
,端口号设置5000(这个可以任意设置
)。点击连接
2.3.2连接服务器
- 使用指令
AT+CIPSTART="TCP","192.168.253.12",5000
//指令,注意双引号逗号都要半角(英文)输入
图中1连接失败的原因是指令后面有空格,会出现不识别指令,这里要特别注意。
图中2是正常连接状态。
2.3.3发送数据
- 使用
AT+CIPSEND=4
(设置即将发送数据的长度为4字节)
- 发送数据:发送时要注意取消发送新行的勾选。字符位置得在
‘>’
号后面,不能有空格,不然显示不出来。
2.4透传
2.4.1什么是透传
透传通常是指在通信或数据传输中,某种设备或系统将接收到的数据直接传输到另一端,而不对数据进行解析或处理。这种传输方式可以让数据在不同系统或设备之间通过,而不会对数据进行修改或解释。
在无线通信中,透传常用于指信号或数据在一个设备上通过而不被修改,直接传递到另一个设备。例如,某些无线模块可以设置为透传模式,使得从传感器或控制器接收到的数据可以直接传输到另一端的设备,而不需要在中间设备进行解析或处理。
在计算机领域,透传也常用于描述数据在不同层或协议之间的传递,例如透传数据包指的是在网络设备中直接将数据包从一个接口传递到另一个接口,而不对数据包进行修改或解析。
总的来说,透传就是指数据在传输过程中不被修改或处理,直接从一个端口或设备传递到另一个端口或设备的过程。
2.4.1如何实现透传
-
使用
AT+CIPMODE=1
指令开启透传 -
使用
AT+CIPSEND
(带回车)指令实现随时发送
2.4.2如何退出透传
在透传发送数据过程中,若识别到单独的⼀包数据 “+++”
,则退出透传发送
3. 单片机发送AT指令实现ESP8266联网
3.1单片机发送AT指令实现ESP8266联网核心思路
- 利用之前配置好的串口发送支持单词型字符的工程配置
- 定义四个字符数组用于承接联网指令,连接服务器指令,打开透传指令,打开实时发送指令。
- 在主函数中每隔一秒发送承接联网指令,连接服务器指令,打开透传指令,打开实时发送指令,查看串口助手收到的字符是否一致。
- 设立适宜延时发送指令给ESP8266配置网络。使用白河测试。
3.2利用之前配置好的串口发送支持单词型字符的工程配置
3.3定义四个字符数组用于承接联网指令,连接服务器指令,打开透传指令,打开实时发送指令。
code char cNetwork[] = "AT+CWJAP=\"a\",\"123456789\"\r\n"; //连接网络指令,\"为转译功能,code的功能是单独存放大数据
code char cServer[] = "AT+CIPSTART=\"TCP\",\"192.168.253.12\",5000\r\n"; //连接服务器
char oTransparent[] = "AT+CIPMODE=1\r\n"; //打开透传
char rTimeT[] = "AT+CIPSEND\r\n"; //打开实时发送
3.4在主函数中每隔一秒发送联网指令,连接服务器指令,打开透传指令,打开实时发送指令。,查看串口助手收到的字符是否一致。
代码
sendString(cNetwork); //发送联网指令
Delay1000ms(); //延时1秒
sendString(cServer); //发送连接服务器指令
Delay1000ms(); //延时1秒
sendString(oTransparent); //发送打开实时发送指令
Delay1000ms(); //延时1秒
sendString(rTimeT); //发送打开实时发送指令
演示结果
3.5设立适宜延时发送指令给ESP8266配置网络。使用白盒测试。
设立适宜延时算法核心思想请见代码
//等待10秒,因为之前的ESP8266已有联网指令,所以会自动联网,而且等待模块启动
Delay5000ms();
Delay5000ms();
//发送联网指令
sendString(cNetwork);
//等待10秒,满足联网时间,不然会返回busy
Delay5000ms();
Delay5000ms();
//发送连接服务器指令
sendString(cServer);
//等待5秒
Delay5000ms();
//发送打开透传模式指令
sendString(oTransparent);
//等待5秒
Delay5000ms();
//发送打开实时发送指令
sendString(rTimeT);
//等待5秒
Delay5000ms();
白盒测试示意图
- 白盒测试接线图
白河测试运行结果
3.6完整程序代码
#include "reg52.h"
#include "string.h"
#include "intrins.h"
#define SIZE 32
sfr AUXR = 0x8e; //声明AUXR寄存器地址
sbit LED1 = P3^7; //使用位定义声明LED1
//建立接收电脑开关灯的指令变量
char LEDStatus[SIZE];
code char cNetwork[] = "AT+CWJAP=\"a\",\"123456789\"\r\n"; //连接网络指令,\"为转译功能,code的功能是单独存放大数据
code char cServer[] = "AT+CIPSTART=\"TCP\",\"192.168.253.12\",5000\r\n"; //连接服务器
char oTransparent[] = "AT+CIPMODE=1\r\n"; //打开透传
char rTimeT[] = "AT+CIPSEND\r\n"; //打开实时发送
/*void Delay1000ms() //@11.0592MHz
{
unsigned char i, j, k;
i = 8;
j = 1;
k = 243;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}*/
void Delay5000ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 36;
j = 5;
k = 211;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void UartInit(void) //自己配
{
//配置串口工作方式为方式1,从只收不发改为能收能发
SCON = 0x50;
//配置辅助寄存器,减少电磁辐射,稳定晶振频率
AUXR = 0x01;
//设置定时器工作方式为定时器1的8位自动重装
TMOD &= 0x0F;
TMOD |= 0x20;
//设置串口波特率为9600,0误差
TH1 = 0xFD;
TL1 = 0xFD;
//打开定时器1
TR1 = 1;
//打开总中断
EA = 1;
//打开串口中断
ES = 1;
}
void sendByte(char data_mas)
{
SBUF = data_mas;
while(!TI);
TI = 0; //一定要软件置零,不然会出现乱序
}
void sendString(char *str)
{
while(*str != '\0')
{
sendByte(*str);
str++;
}
}
void main()
{
//初始化灯的状态
LED1 = 1;
//初始化串口,配置波特率
UartInit();
//每延时1秒向电脑发送数据a
/*Delay1000ms();
sendString("一起来学串口通信!!!\r\n"); //\r\n 为串口中的换行,缺一不可
//怎么知道PC发了数据:由手册可知RI位为接受中断标志位,所以用查询的方法来判断RI是否等于1来开关灯*/
while(1)
{
//等待10秒,因为之前的ESP8266已有联网指令,所以会自动联网,而且等待模块启动
Delay5000ms();
Delay5000ms();
//发送联网指令
sendString(cNetwork);
//等待10秒,满足联网时间,不然会返回busy
Delay5000ms();
Delay5000ms();
//发送连接服务器指令
sendString(cServer);
//等待5秒
Delay5000ms();
//发送打开透传模式指令
sendString(oTransparent);
//等待5秒
Delay5000ms();
//发送打开实时发送指令
sendString(rTimeT);
//等待5秒
Delay5000ms();
}
}
void UART_handler() interrupt 4
{
//定义一个静态整型变量,在多次函数调用中只被执行一次初始化
static int i = 0;
//在串口中段函数中可以对发送接收中断标志进行处理
if(RI == 1)
{
RI = 0; //必须软件置零
LEDStatus[i] = SBUF;
i++; //数组标号增加,方便存放字符串
//如果用开灯指令开灯,关灯指令关灯
if(strstr(LEDStatus,"开灯")) //运用C语言字符串知识,使用的是字符串查找函数,查找到即返回1
{
LED1 = 0;
i = 0; //清零是为了方便存放下一次指令
memset(LEDStatus,'\0',SIZE); //字符串清零函数,实参为清零的字符串变量,清理成什么字符,清理的大小或数量
}
if(strstr(LEDStatus,"关灯"))
{
LED1 = 1;
i = 0;
memset(LEDStatus,'\0',SIZE);
}
}
if(TI);
}
4.通过网络TCP通信控制LED
4.1通过网络TCP通信控制LED的核心思路
- 修改串口中断函数中开灯的条件为字符
1
,关灯的调价为字符0
- 在主函数中定义一个定义配置网络标志位
mark
,mark\==0
时执行网络配置
,mark==1
时执行发送网络配置完毕!
字符串
注意:此工程延用单片机发送AT指令实现ESP8266联网的工程
4.2修改串口中断函数中开灯的条件为字符1
,关灯的调价为字符0
- 修改
if
语句中的判断语句
if(LEDStatus[0] == '1')
{
LED1 = 0;
}
if(LEDStatus[0] == '0')
{
LED1 = 1;
}
- 取消静态字符型变量
i
,删除i
的自增。 - 让
LEDStatus[0]=SUBF
,实现读取串口接收操作。
4.3在主函数中定义一个定义配置网络标志位mark,mark==0时执行网络配置,mark==1时执行发送网络配置完毕!字符串
- 定义定义配置网络标志位
mark
//定义配置网络标志位
char mark = 0;
mark\==0
时执行网络配置,mark==1
时执行发送网络配置完毕!字符串
while(1)
{
if(mark == 0)
{
//等待10秒,因为之前的ESP8266已有联网指令,所以会自动联网,而且等待模块启动
Delay5000ms();
Delay5000ms();
//发送联网指令
sendString(cNetwork);
//等待10秒,满足联网时间,不然会返回busy
Delay5000ms();
Delay5000ms();
//发送连接服务器指令
sendString(cServer);
//等待5秒
Delay5000ms();
//发送打开透传模式指令
sendString(oTransparent);
//等待5秒
Delay5000ms();
//发送打开实时发送指令
sendString(rTimeT);
//等待5秒
Delay5000ms();
mark = 1;
}
else
{
sendString("网络配置完毕!\r\n");
Delay1000ms();
}
}
4.4烧入程序注意事项
烧入程序时,应将ESP8266模块电源线拔掉。
4.5完整程序代码
#include "reg52.h"
#include "string.h"
#include "intrins.h"
#define SIZE 32
sfr AUXR = 0x8e; //声明AUXR寄存器地址
sbit LED1 = P3^7; //使用位定义声明LED1
//建立接收电脑开关灯的指令变量
char LEDStatus[SIZE];
code char cNetwork[] = "AT+CWJAP=\"a\",\"123456789\"\r\n"; //连接网络指令,\"为转译功能,code的功能是单独存放大数据
code char cServer[] = "AT+CIPSTART=\"TCP\",\"192.168.253.12\",5000\r\n"; //连接服务器
char oTransparent[] = "AT+CIPMODE=1\r\n"; //打开透传
char rTimeT[] = "AT+CIPSEND\r\n"; //打开实时发送
void Delay1000ms() //@11.0592MHz
{
unsigned char i, j, k;
i = 8;
j = 1;
k = 243;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay5000ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 36;
j = 5;
k = 211;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void UartInit(void) //自己配
{
//配置串口工作方式为方式1,从只收不发改为能收能发
SCON = 0x50;
//配置辅助寄存器,减少电磁辐射,稳定晶振频率
AUXR = 0x01;
//设置定时器工作方式为定时器1的8位自动重装
TMOD &= 0x0F;
TMOD |= 0x20;
//设置串口波特率为9600,0误差
TH1 = 0xFD;
TL1 = 0xFD;
//打开定时器1
TR1 = 1;
//打开总中断
EA = 1;
//打开串口中断
ES = 1;
}
void sendByte(char data_mas)
{
SBUF = data_mas;
while(!TI);
TI = 0; //一定要软件置零,不然会出现乱序
}
void sendString(char *str)
{
while(*str != '\0')
{
sendByte(*str);
str++;
}
}
void main()
{
//定义配置网络标志位
char mark = 0;
//初始化灯的状态
LED1 = 1;
//初始化串口,配置波特率
UartInit();
//每延时1秒向电脑发送数据a
/*Delay1000ms();
sendString("一起来学串口通信!!!\r\n"); //\r\n 为串口中的换行,缺一不可
//怎么知道PC发了数据:由手册可知RI位为接受中断标志位,所以用查询的方法来判断RI是否等于1来开关灯*/
while(1)
{
if(mark == 0)
{
//等待10秒,因为之前的ESP8266已有联网指令,所以会自动联网,而且等待模块启动
Delay5000ms();
Delay5000ms();
//发送联网指令
sendString(cNetwork);
//等待10秒,满足联网时间,不然会返回busy
Delay5000ms();
Delay5000ms();
//发送连接服务器指令
sendString(cServer);
//等待5秒
Delay5000ms();
//发送打开透传模式指令
sendString(oTransparent);
//等待5秒
Delay5000ms();
//发送打开实时发送指令
sendString(rTimeT);
//等待5秒
Delay5000ms();
mark = 1;
}
else
{
sendString("网络配置完毕!\r\n");
Delay1000ms();
}
}
}
void UART_handler() interrupt 4
{
//定义一个静态整型变量,在多次函数调用中只被执行一次初始化
//static int i = 0;
//在串口中段函数中可以对发送接收中断标志进行处理
if(RI == 1)
{
RI = 0; //必须软件置零
LEDStatus[0] = SBUF;
//如果用1指令开灯,0指令关灯
if(LEDStatus[0] == '1')
{
LED1 = 0;
}
if(LEDStatus[0] == '0')
{
LED1 = 1;
}
}
if(TI);
}
5.白盒方式看到连接不上的原因,调试手段
连接不上的原因是:简单的延时是无法确定ESP8266是否已联网,而且在之前使用该模块就已经配置过wifi信息,启动模块会联网,此时发送指令会失败,或者系统忙。所以需要优化代码。
结束语
很高兴您能看到这里,点个赞再走呗。谢谢您啦!!!