单片机能上网才能通过网络实现更多功能,如何实现让单片机上网,可以用到ESP8266-wifi模块和4g CAT1模块
WIFI模块 ESP8266
ESP8266概述
ESP-01s是面向物联网应用的高性价比,高度集成的UART-WIFI透传的单片机模块,超低功耗
我们现阶段主要研究WIFI模块的使用,内部的原理和协议以后有能力了再研究
一般该模块默认支持的波特率是115200,其他波特率无法发送数据
8266联网后,就可以实现远程通信,8266可以发送数据给其他与他网络相连模块,其他模块接收到数据后就可以通过代码进行相关操作。
相关配置
基于AT指令,AT指令模式下,发送的AT指令都要新行发送,不然无法识别
上电设置
AT+RST:重置模块,重置成功回复OK即正常
AT:用于测试通信和模块功能是否正常,正常回复OK
入网设置
第一个是AP模式,模块作为网关的IP地址,第二个是AP模式,模块作为网关的MAC地址,第三个是station模式,模块连上网络后作为设备的ip地址,第四个是station模式,模块连上网络后作为设备的MAC地址
AT+CIPSTART="TCP","电脑本机IP",端口号:将模块作为客户端与电脑服务器连接,在此端口收发信息,成功连接回复CONNCET,OK
AT+CIPSEND=4:作为客户端连上服务器成功后,设置即将发送数据的长度,设置成功后弹出>,再发送要发的数据,记得取消新行,因为新行也会占用字节。发送的数据不够时按发送,不会发送,直到凑够字节数才会一次性发送;发送的数据过多,会回复busy,再截断;发送成功后会回复SEND OK
注意:AT模式下,发数据每次发送数据都要先设置发送的长度再发送数据
设备之间通过网络连接
当模块通过串口调试助手AT指令配置连上的wifi和电脑连上的wifi相同,说明二者在通一个局域网,可以通过相关软件实现通信,应用层的网络协议是TCP协议,即模块与电脑通过软件进行通信,是在应用层所用的协议是TCP协议,模块发送信息到路由器,路由器接收到信息转发给电脑,实现数据通信
电脑上安装一个网络调试助手,将电脑设置为TCP服务器,设置本机的IP地址和端口号,模块可以作为客户端在调试助手上让模块连接上此服务器的端口号,这样模块与电脑就连接上了,可以通过网络进行通信
将电脑设置为服务器
让模块连接此端口
AT+CIPSTART="TCP","电脑本机IP",端口号
发送数据,接收成功
透传模式发送数据
由于之前的模式下,每次发送数据都要规定发送数据的长度,不方便,所以可以设置发送数据为透传模式发送
AT+CIPMODE=1:设置透传模式,正常回复OK
AT+CIPSEND:设置发送
设置之后,就可以任意发送数据了,每次输入后直接发送就可以正常发送
若要退出透传模式,发送+++,即可退出透传模式回到AT指令模式
总结:要让模块与电脑连接,首先在串口调试助手,配置波特率,设置模块工作模式,连接电脑连上的WIFI,然后再网络调试助手,设置电脑的ip和端口,最后在串口调试助手,连接端口,连接成功后,可以设置透传模式,然后发送数据
单片机配置8266与设备通信
设备模式
之前配置8266的属性,是在PC机,让PC机串口连接8266,发送AT指令配置8266。同样51单片机也可以串口连接8266,然后让51单片机发送AT指令同样可以配置8266
配置好8266后,就可以让单片机与8266串口通信,8266接收到信息再和电脑网络通信,实现单片机与电脑通过网络通信
上电后让51单片机通过串口向8266一条一条发送AT指令,发送一条指令后等待,8266收到AT指令后会回复OK,单片机检测收到OK后,再发送下一条指令,入网成功并连接到服务器后,就可以取下串口,让单片机和服务器通过网络通信了
代码
#include "reg52.h"
#include <intrins.h>
#include <string.h>
sfr AUXR = 0x8E;
sbit led = P3 ^ 7;
sbit ledy = P3 ^ 6;
char OK_FLAG[8];
char AT_OK = 0;
char SEND_OK = 0;
char TOPLOC = 0;
char again_flag = 0;
char stop_flag = 0;
char RESET[] = "AT+RST\r\n";
char BTRATE[] = "AT+UART=9600,8,1,0,0\r\n";
char STATIONMS[] = "AT+CWMODE=1\r\n";
code char LJWIFI[] = "AT+CWJAP=\"RedmiK30\",\"123456789\"\r\n";
code char LJFWQ[] = "AT+CIPSTART=\"TCP\",\"192.168.20.134\",1234\r\n";
char TCMS[] = "AT+CIPMODE=1\r\n";
char SENDMSOK[] = "AT+CIPSEND\r\n";
char AT[] = "AT\r\n";
void UartInit(void) //9600bps@11.0592MHz
{
//½µµÍϵͳ¶ÔÍâ½çµÄµç´Å·øÉä
AUXR = 0x01;
//SCONÅäÖÃ
SM0 = 0;
SM1 = 1;
REN = 1;
//PCONÅäÖÃ
PCON = 0x10; //²¨ÌØÂʲ»¼Ó±¶×î¸ßλSMOD=0,½øÐд®¿ÚģʽѡÔñµÚ6λSMOD0=0;
//²¨ÌØÂÊÅäÖÃ
//1¡¢¶¨Ê±Æ÷1ģʽΪ8λ×Ô¶¯ÖØÔØ
TMOD &= 0x0F;
TMOD |= 0x20;
//9600²¨ÌØÂʵijõÖµ
TH1 = 0xFD;
TL1 = 0xFD;
TR1 = 1;
EA = 1;
ES = 1;
}
void UnitCLOCK0()
{
TMOD &= 0xF0;
TMOD |= 0x01;
TH0 = (65536 - (50000 / 1.085)) / 256;
TL0 = (int)(65536 - (50000 / 1.085)) % 256;
EA = 1;
ET0 = 1;
TR0 = 0;
}
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 sendms(char *p)
{
while (*p != '\0')
{
SBUF = *p;
while (!TI);
TI = 0;
p++;
}
}
void sendabcd(char p, char h)
{
int cnt = 26;
while (cnt--)
{
SBUF = p;
while (!TI);
TI = 0;
SBUF = h;
while (!TI);
TI = 0;
p++;
}
}
void Unit8266()
{
sendms(STATIONMS);
while (!AT_OK);
AT_OK = 0;
while (1)
{
if (stop_flag == 0)
{
sendms(LJWIFI);
//¿ª¶¨Ê±Æ÷ÖжÏ
TR0 = 1;
while (!AT_OK)
{
if (again_flag == 1)
{
again_flag = 0;
break;
}
}
if (AT_OK == 1)
{
led = 0;
ledy = 1;
TR0 = 0;
break;
}
}
if (stop_flag == 1)
{
ledy = 0;
led = 1;
TR0 = 0;
break;
}
}
AT_OK = 0;
sendms(LJFWQ);
while (!AT_OK);
if (AT_OK == 1)ledy = 0;
AT_OK = 0;
}
void TOUCHUAN()
{
sendms(TCMS);
while (!AT_OK);
AT_OK = 0;
// sendms(BTRATE);
// while (!AT_OK);
// AT_OK = 0;
sendms(SENDMSOK);
while (!AT_OK);
AT_OK = 0;
}
void main()
{
char msg = 'a';
char *huan = "\r\n";
char h = ' ';
int cnt = 0;
UartInit();
UnitCLOCK0();
Delay1000ms();
Unit8266();
TOUCHUAN();
Delay1000ms();
while (1)
{
sendabcd(msg, h);
Delay1000ms();
sendms(huan);
Delay1000ms();
}
}
void light() interrupt 4
{
if (RI == 1)
{
char tmp = SBUF;
RI = 0;
if (tmp == 'O' || tmp == 'o')
{
TOPLOC = 0;
memset(OK_FLAG, '\0', sizeof(OK_FLAG));
}
OK_FLAG[TOPLOC] = tmp;
TOPLOC++;
if (OK_FLAG[0] == 'O' && OK_FLAG[1] == 'K')
{
AT_OK = 1;
memset(OK_FLAG, '\0', sizeof(OK_FLAG));
}
if (OK_FLAG[0] == 'o' && OK_FLAG[1] == 'n' && OK_FLAG[2] == 'b')
{
led = 0;
memset(OK_FLAG, '\0', sizeof(OK_FLAG));
}
if (OK_FLAG[0] == 'o' && OK_FLAG[1] == 'f' && OK_FLAG[3] == 'b')
{
led = 1;
memset(OK_FLAG, '\0', sizeof(OK_FLAG));
}
if (OK_FLAG[0] == 'o' && OK_FLAG[1] == 'n' && OK_FLAG[2] == 'y')
{
ledy = 0;
memset(OK_FLAG, '\0', sizeof(OK_FLAG));
}
if (OK_FLAG[0] == 'o' && OK_FLAG[1] == 'f' && OK_FLAG[3] == 'y')
{
ledy = 1;
memset(OK_FLAG, '\0', sizeof(OK_FLAG));
}
if (TOPLOC == 8)
{
TOPLOC = 0;
}
}
if (TI == 1)
{
}
}
void Repeat() interrupt 1
{
static int cnt = 0;
static char flag = 0;
TH0 = (65536 - (50000 / 1.085)) / 256;
TL0 = (int)(65536 - (50000 / 1.085)) % 256;
cnt++;
if (cnt == 400)
{
again_flag = 1;
stop_flag = 1;
}
if (cnt % 20 == 0)
{
if (flag == 0)
{
led = !led;
ledy = 1;
}
if (flag == 1)
{
ledy = !ledy;
led = 1;
}
}
if (cnt % 400 == 0)
{
again_flag = 1;
flag = !flag;
}
}
小知识:若要接收服务器的指令,来让单片机做相关工作,可以通过串口中断来一个一个接收字符并设置一个buffer数组,当某字符为指令的首字符时,将该字符存入到buffer数组的首地址,后面的字符依次存入buffer,当buffer满足指令的条件后,即可进行相关操作
路由模式
除了将8266配置为设备模式,还可以将8266配置为路由模式。路由模式后可以将自身作为一个服务器,让其他设备连上8266这个路由器发出wifi后,设备和8266就在同一个局域网,然后设备连接8266服务器的端口后,便可以和8266网络通信
服务器的相关AT指令
AT+CWMODE=3:设置双模式
AT+CIPMUX=1:让多个客户端可以连接服务器
AT+CIPSERVER=1:建立服务器,默认端口333
AT+CIPSEND=通道号,字节数:8266作为服务器,向某个客户端发送数据
接收数据时:8266收到的数据为 +IPD,通道号,字节数:接收的信息
AT+CIPCLOSE=0:关闭所有客户端的连接,关闭后回复:通道号,CLOSED OK
代码
#include "reg52.h"
#include <intrins.h>
#include <string.h>
sfr AUXR = 0x8E;
sbit led = P3 ^ 7;
sbit ledy = P3 ^ 6;
sbit key1 = P2 ^ 1;
char OK_FLAG[8];
char AT_OK = 0;
char CONNECT_OK = 0;
char TOPLOC = 0;
char CLOSE_FLAG = 0;
char SERVER_CLOSE = 0;
char SEND_OK = 0;
char RESET[] = "AT+RST\r\n";
char APMS[] = "AT+CWMODE=2\r\n";
char SENDMS[] = "AT+CIPSEND=0,6\r\n";
char CANCONNECT[] = "AT+CIPMUX=1\r\n";
char CREATESERVER[] = "AT+CIPSERVER=1\r\n";
char CLOSESERVER[] = "AT+CIPCLOSE=0\r\n";
void UartInit(void) //9600bps@11.0592MHz
{
//½µµÍϵͳ¶ÔÍâ½çµÄµç´Å·øÉä
AUXR = 0x01;
//SCONÅäÖÃ
SM0 = 0;
SM1 = 1;
REN = 1;
//PCONÅäÖÃ
PCON = 0x10; //²¨ÌØÂʲ»¼Ó±¶×î¸ßλSMOD=0,½øÐд®¿ÚģʽѡÔñµÚ6λSMOD0=0;
//²¨ÌØÂÊÅäÖÃ
//1¡¢¶¨Ê±Æ÷1ģʽΪ8λ×Ô¶¯ÖØÔØ
TMOD &= 0x0F;
TMOD |= 0x20;
//9600²¨ÌØÂʵijõÖµ
TH1 = 0xFD;
TL1 = 0xFD;
TR1 = 1;
EA = 1;
ES = 1;
}
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 sendms(char *p)
{
while (*p != '\0')
{
SBUF = *p;
while (!TI);
TI = 0;
p++;
}
}
void Delay100ms() //@11.0592MHz
{
unsigned char i, j;
i = 180;
j = 73;
do
{
while (--j);
}
while (--i);
}
void Delay20ms() //@11.0592MHz
{
unsigned char i, j;
i = 36;
j = 217;
do
{
while (--j);
}
while (--i);
}
void Unit8266()
{
sendms(APMS);
while (!AT_OK);
AT_OK = 0;
sendms(CANCONNECT);
while (!AT_OK);
AT_OK = 0;
sendms(CREATESERVER);
while (!AT_OK);
if (AT_OK == 1)led = 0;
AT_OK = 0;
while (!CONNECT_OK);
CONNECT_OK = 0;
EX0 = 1;
IT0 = 1;
}
void main()
{
char *huan = "\r\n";
char h = ' ';
int cnt = 0;
UartInit();
Delay1000ms();
Unit8266();
Delay1000ms();
while (1)
{
if (SEND_OK == 1 && SERVER_CLOSE == 0)
{
sendms(SENDMS);
Delay20ms();
sendms("hello");
sendms(huan);
Delay1000ms();
}
}
}
void light() interrupt 4
{
if (RI == 1)
{
char tmp = SBUF;
RI = 0;
if (tmp == 'O' || tmp == ':' || tmp == 'N' || tmp == 'C')
{
TOPLOC = 0;
memset(OK_FLAG, '\0', sizeof(OK_FLAG));
}
OK_FLAG[TOPLOC] = tmp;
TOPLOC++;
if (OK_FLAG[0] == 'N' && OK_FLAG[1] == 'E')
{
CONNECT_OK = 1;
SERVER_CLOSE = 0;
SEND_OK = 1;
led = 0;
ledy = 0;
memset(OK_FLAG, '\0', sizeof(OK_FLAG));
}
if (OK_FLAG[0] == 'C' && OK_FLAG[1] == 'L')
{
int n = 2;
while (n--)
{
ledy = 0;
Delay100ms();
ledy = 1;
Delay100ms();
}
SEND_OK = 0;
ledy = 1;
memset(OK_FLAG, '\0', sizeof(OK_FLAG));
}
if (OK_FLAG[0] == 'O' && OK_FLAG[1] == 'K')
{
AT_OK = 1;
memset(OK_FLAG, '\0', sizeof(OK_FLAG));
}
if (OK_FLAG[1] == 'o' && OK_FLAG[2] == 'n' && OK_FLAG[3] == 'b' && OK_FLAG[0] == ':')
{
led = 0;
memset(OK_FLAG, '\0', sizeof(OK_FLAG));
}
if (OK_FLAG[1] == 'o' && OK_FLAG[2] == 'f' && OK_FLAG[4] == 'b' && OK_FLAG[0] == ':')
{
led = 1;
memset(OK_FLAG, '\0', sizeof(OK_FLAG));
}
if (OK_FLAG[1] == 'o' && OK_FLAG[2] == 'n' && OK_FLAG[3] == 'y' && OK_FLAG[0] == ':')
{
ledy = 0;
memset(OK_FLAG, '\0', sizeof(OK_FLAG));
}
if (OK_FLAG[1] == 'o' && OK_FLAG[2] == 'f' && OK_FLAG[4] == 'y' && OK_FLAG[0] == ':')
{
ledy = 1;
memset(OK_FLAG, '\0', sizeof(OK_FLAG));
}
if (TOPLOC == 8)
{
TOPLOC = 0;
}
}
if (TI == 1)
{
}
}
void do1() interrupt 0
{
Delay100ms();
if (key1 == 0)
{
if (!SERVER_CLOSE)
{
SERVER_CLOSE = 1;
sendms(CLOSESERVER);
led = 1;
}
}
}
4g模块
4g模块功能概述
有了4g模块和单片机向结合,4g模块连接好天线,插入了SIM卡后,然后进行相关AT指令配置后,可以直接向公网服务器进行数据交互。
比如公网有一台服务器,给4g模块配置AT指令,让4g模块作为客户端连接公网的服务器,连接成功后,4g模块就可以在任何有4g信号的地方和该服务器进行数据交互。
由此,如果以后手机通过app,将自己的4g模块作为客户端连接上了一个公网服务器,单片机也发送了AT指令让自己的4g模块作为客户端引入连接上了此公网服务器,且公网服务器具有信息自动中转功能。那么就可以实现手机远程发送信息,服务器接收到手机客户端的信息后,再将此信息转发给单片机的4g模块客户端,4g模块通过串口再转发给单片机,这样就实现了手机app和单片机的数据交互(条件是两个4g模块都连上了相同的公网服务器)
4g模块优点
4g模块对于wifi模块的优点就在于,只要插上了SIM卡,且SIM卡有流量,而且周围有较好的4g信号,就能上网。
而wifi模块必须要先连上公网的路由器,才能上网,对于某些地方如果没有路由器,wifi模块就上不了网,有一定的局限性
相关配置
插好卡,连好天线后,最后一个灯会常亮,证明SIM卡插入成功,然后就可以进行相关配置
默认是透传模式,想要通过AT指令配置4g模块,那么在透传模式下如果串口收到“+++”帧数据后,3 秒内 RX 引脚收到任意 AT 指令,则模式切换到 AT模式
内网穿透
由于4g模块无法识别内网IP,只能识别公网IP,那么如果想让4g模块连接到内网的服务器,可以借助花生壳软件,为内网IP分配一个公网IP,这样4g模块就可以检测到这个公网IP,从而连上这个服务器
单片机配置4g模块与服务器通信
8266需要单片机先为其发送AT指令是因为:8266上电后默认AT指令模式,之前配置好的AT指令重新上电后,只有部分会自行生效。如果想让其连接服务器,再进行透传模式发送数据,需要单片机上电后给他发送连接服务器的AT指令和透传模式的AT的指令,且8266执行成功了,才能进入透传模式发数据。
而配置4g模块时,起初先通过串口配置AT指令,上位机会收到4g模块通过串口的回复信息,配置成功重新上电后,便是一个已经配好指令的4g模块了。
4g模块上电会根据已配置的AT指令,内部进行相关的指令操作,不会向外界发送任何信息,所有的指令执行完毕,连上服务器后,就直接进入透传模式,收发数据。所以配置好之后,就不需要单片机在配置AT指令了,等待4g模块自行入网,成功后就可以直接通信。
代码
#include "reg52.h"
#include <intrins.h>
#include <string.h>
sfr AUXR = 0x8E;
sbit led = P3 ^ 7;
sbit ledy = P3 ^ 6;
char OK_FLAG[8];
char TOPLOC = 0;
void UartInit(void) //9600bps@11.0592MHz
{
//½µµÍϵͳ¶ÔÍâ½çµÄµç´Å·øÉä
AUXR = 0x01;
//SCONÅäÖÃ
SM0 = 0;
SM1 = 1;
REN = 1;
//PCONÅäÖÃ
PCON = 0x10; //²¨ÌØÂʲ»¼Ó±¶×î¸ßλSMOD=0,½øÐд®¿ÚģʽѡÔñµÚ6λSMOD0=0;
//²¨ÌØÂÊÅäÖÃ
//1¡¢¶¨Ê±Æ÷1ģʽΪ8λ×Ô¶¯ÖØÔØ
TMOD &= 0x0F;
TMOD |= 0x20;
//9600²¨ÌØÂʵijõÖµ
TH1 = 0xFD;
TL1 = 0xFD;
TR1 = 1;
EA = 1;
ES = 1;
}
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 sendms(char *p)
{
while (*p != '\0')
{
SBUF = *p;
while (!TI);
TI = 0;
p++;
}
}
void sendabcd(char p, char h)
{
int cnt = 26;
while (cnt--)
{
SBUF = p;
while (!TI);
TI = 0;
SBUF = h;
while (!TI);
TI = 0;
p++;
}
}
void main()
{
char msg = 'a';
char *huan = "\r\n";
char h = ' ';
int cnt = 28;
UartInit();
while(cnt--){
Delay1000ms();
}
while (1)
{
sendabcd(msg, h);
sendms(huan);
Delay1000ms();
Delay1000ms();
Delay1000ms();
}
}
void light() interrupt 4
{
if (RI == 1)
{
char tmp = SBUF;
RI = 0;
if (tmp == 'o')
{
TOPLOC = 0;
memset(OK_FLAG, '\0', sizeof(OK_FLAG));
}
OK_FLAG[TOPLOC] = tmp;
TOPLOC++;
if (OK_FLAG[0] == 'o' && OK_FLAG[1] == 'n' && OK_FLAG[2] == 'b')
{
led = 0;
memset(OK_FLAG, '\0', sizeof(OK_FLAG));
}
if (OK_FLAG[0] == 'o' && OK_FLAG[1] == 'f' && OK_FLAG[3] == 'b')
{
led = 1;
memset(OK_FLAG, '\0', sizeof(OK_FLAG));
}
if (OK_FLAG[0] == 'o' && OK_FLAG[1] == 'n' && OK_FLAG[2] == 'y')
{
ledy = 0;
memset(OK_FLAG, '\0', sizeof(OK_FLAG));
}
if (OK_FLAG[0] == 'o' && OK_FLAG[1] == 'f' && OK_FLAG[3] == 'y')
{
ledy = 1;
memset(OK_FLAG, '\0', sizeof(OK_FLAG));
}
if (TOPLOC == 8)
{
TOPLOC = 0;
}
}
if (TI == 1)
{
}
}