基于ESP8266和STC89C52的寝室电费实时显示 | 我的日常分享

基于ESP8266和STC89C52的寝室电费实时显示

寝室电费实时显示

一、前言

在炎炎夏日,由于担心寝室电费突然没了,查电费又比较麻烦,前面做了一个电费实时显示的一个网站,有天看到了桌上的单片机和WiFi模块,我便想着WiFi模块能不能够联网,发送请求,返回数据,通过查阅ESP8266的手册,发现这些都是可以实现的,后面便是如何让ESP8266与STC89C52通信并显示数据了。

二、ESP8266模块

以下仅列举用到的命令,所有命令可查阅官方文档

ESP8266-01 WiFi模块用户手册V1.0

  • 简介
    一种WiFi模块。属于网络层以上的设备,拥有MAC地址和IP地址,支持UDP和TCP。
    图片

  • 参数
    图片

  • 引脚
    图片

PIN Function Description
1 URXD 1)UART_RXD,接收;
2)General Purpose Input/Output:GPIO3;
2 UTXD 1)UART_TXD,发送;
2)General Purpose Input/Output:GPIO1;
3)开机时禁止下拉;
3 RESET(GPIO 16) 外部Reset信号,低电平复位,高电平工作(默认高);
4 GND GND
5 VCC 3.3V,模块供电;
6 GPIO0 1)默认WiFi Status:WiFi工作状态指示灯控制信号;
2)工作模式选择:
悬空:Flash Boot,工作模式;
下拉:UART Download,下载模式;
7 CH_PD 1)高电平工作;
2)低电平模块供电关掉;
8 GPIO2 1)开机上电时必须为高电平,禁止硬件下拉;
2)内部默认已拉高

最简化启动模块,将VCC、GND接3.3v电源;CH_PD上拉,可通过一个电阻接到VCC。

  • 波特率
    ESP8266模块的默认波特率是115200,若想改变波特率请使用以下语句进行修改:

    1
    2
    3
    AT+CIOBAUD=<baudrate>,<databits>,<stopbits>,<parity>,<flow control>
    或者
    AT+UART=<baudrate>,<databits>,<stopbits>,<parity>,<flow control>

    连接stc89c52单片机建议把波特率设置为9600

    1
    2
    3
    AT+CIOBAUD=9600,8,1,0,0  
    或者
    AT+UART=115200,8,1,0,0
  • 用到的AT指令

    1
    2
    3
    测试连接
    AT\r\n
    响应:OK\r\n
    1
    2
    3
    设置 wifi 模式:
    AT+CWMODE=1\r\n
    响应:OK\r\n
    数字 WiFi应用模式
    1 STA(Station)模式
    2 AP模式
    3 AP+Station模式
1
2
3
连接路由:
AT+CWJAP="ssid","password"\r\n
响应:OK\r\n(有的模块回的是CONNECT OK\r\n)
1
2
3
连接到服务器:
  AT+CIPSTART="TCP","192.168.31.156",8088\r\n
  响应:OK\r\n
1
2
3
开启透传模式:
AT+CIPMODE=1\r\n
响应:OK\r\n
1
2
3
通知模块开始数据传输:
  AT+CIPSEND\r\n
  响应:>

这一步操作后,模块会回复一个“>”,代表接下来的所有串口数码均为数据,不解析成指令。

1
2
3
发送数据:
GET /php/query.php\r\n\r\n
响应:服务器返回的数据

二、ESP8266调试

1、利用单片机USB串口连接电脑调试

  1. 接线
    图片
    图片

  2. 调试
    连接WIFI
    图片

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    AT


    OK
    AT+CWMODE=1


    OK
    AT+CWJAP="5226","52265226"

    WIFI DISCONNECT
    WIFI CONNECTED
    WIFI GOT IP

    OK
    AT+CIPSTART="TCP","192.168.31.156",8088

    CONNECT

    OK
    AT+CIPMODE=1


    OK
    AT+CIPSEND


    OK

    >{"id":"123","dormitory":"5-226","lighting":"121.04","airconditioner":"164.98","time":""}

2、利用ESP8266连接单片机

需要把之前上面连接中的P31与P30口的线换一下,如图

  1. 接线
    图片

三、将ESP8266上单片机

按照利用ESP8266连接单片机的接线图即可。扯一扯,当时脑子有点抽,一直忘记把串口的收发口线调换顺序,然后写程序用单片机向ESP8266发送指令根本没有用,我一度以为是我写的程序有问题,百度了各种文章尝试用其他方式配置端口,都没有效果,然后用串口调试助手调试是没有问题的,我一度怀疑人生了,就这样卡在这一步卡了两天,后面因为马上就要期末考,就把这个搁了几天,再度重新弄这个的时候,两个串口线我就瞎连的,尽然能够通过单片机发送指令,我当时欣喜若狂,后来突然觉悟了,是真的愚蠢,避坑避坑!!!。
接线没问题后就是写代码将上面的一些连接服务器指令通过单片机发送,获得数据后再数码管或者LCD1602上显示,这里我选择LCD1602。

  • 反馈识别:
    如何识别ESP8266返回的数据判断发送的指令是否成功,需不需要重新发送。
    由于考虑到单片机硬件资源紧张(存储空间小、晶振慢),所以我们要缩减对返回数据的识别。
    因此我这里采用的是关键字匹配。比如识别WIFI GOT IP,我只识别第一个字符w、第6个字符G和第10个字符I。就可以确认这个是WIFI GOT IP
    如果是出现干扰,可能性也是比较低的,我们的交互是在网络层的,下层也可以把出错的报文挡掉。
  • 如何进行调试:
    单片机开发,代码在哪步出错比较难发现,没有报错,也没有try catch语句,也没有C语言中黑乎乎的命令行。
    利用8个流水灯,如果执行了某一个语句,指定一个流水灯亮。我开始使用的是LCD1602上面显示数字,LCD老是自己不稳定,显示错乱啥的,很烦。文章后面我会把这些问题归纳一下。

四、代码

定义了函数指针,可以实现模块化事件化,关于函数指针如何使用,可阅读函数名,代表的是函数的入口地址

  • ASCII
    因为用于通讯,ASCII内所有的特殊字符我都写到了这一个头文件里。虽然下面只用到其中的几个,但以后可以重复利用这个头文件。

ASCII.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#ifndef __ASCIIS__
#define __ASCIIS__

#define NUL 0x00 // NULL
#define SOH 0x01 // Start of Heading
#define STX 0x02 // Start of Text
#define ETX 0x03 // End of Text
#define EOT 0x04 // End of Transmission
#define ENQ 0x05 // Enquiry
#define ACK 0x06 // Acknowledge
#define BEL 0x07 // Bell
#define BS 0x08 // Backspace
#define HT 0x09 // Horizontal Tab
#define LF 0x0A // Line Feed
#define NL 0x0A // New Line
#define VT 0x0B // Vertical Tab
#define FF 0x0C // Form Feed
#define NP 0x0C // New Page
#define CR 0x0D // Carriage Return
#define SO 0x0E // Shift Out
#define SI 0x0F // Shift In
#define DLE 0x10 // Data Link Escape
#define DC1 0x11 // Device Control 1
#define DC2 0x12 // Device Control 2
#define DC3 0x13 // Device Control 3
#define DC4 0x14 // Device Control 4
#define NAK 0x15 // Negative Acknowledge
#define SYN 0x16 // Synchronous Idle
#define ETB 0x17 // End of Transmission Block
#define CAN 0x18 // Cancel
#define EM 0x19 // End of Medium
#define SUB 0x1A // Substitute
#define ESC 0x1B // Escape
#define FS 0x1C // File Separator
#define GS 0x1D // Group Separator
#define RS 0x1E // Record Separator
#define US 0x1F // Unit Separator
#define SP 0x20 // Space

#endif
  • 延时函数

Delay.h

1
2
3
4
5
6
#ifndef __DELAY_H__
#define __DELAY_H__

void Delay(unsigned int xms);

#endif

Delay.c

1
2
3
4
5
6
7
8
9
10
11
12
13
void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
  • 定时器0

Timer0.h

1
2
3
4
5
6
#ifndef __TIMER0_H__
#define __TIMER0_H__

void Timer0Init(void);

#endif

Timer0.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <REGX52.H>

void Timer0Init(void)
{
TMOD &= 0xF0; //设置定时器0模式
TMOD |= 0x01; //设置定时器0模式
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1;
EA=1;
PT0=0;
}
  • LCD1602

LCD1602.h

1
2
3
4
5
6
7
8
9
10
11
12
13
#ifndef __LCD1602_H__
#define __LCD1602_H__

void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_WriteCommand(unsigned char Command);

#endif

LCD1602.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#include <REGX52.H>

//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0

void LCD_Delay()
{
unsigned char i, j;

i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}

void LCD_WriteCommand(unsigned char Command)
{
LCD_RS=0;
LCD_RW=0;
LCD_DataPort=Command;
LCD_EN=1;
LCD_Delay();
LCD_EN=0;
LCD_Delay();
}

void LCD_WriteData(unsigned char Data)
{
LCD_RS=1;
LCD_RW=0;
LCD_DataPort=Data;
LCD_EN=1;
LCD_Delay();
LCD_EN=0;
LCD_Delay();
}

void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
if(Line==1)
{
LCD_WriteCommand(0x80|(Column-1));
}
else if(Line==2)
{
LCD_WriteCommand(0x80|(Column-1+0x40));
}
}

void LCD_Init()
{
LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
LCD_WriteCommand(0x01);//光标复位,清屏
}

void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
LCD_SetCursor(Line,Column);
LCD_WriteData(Char);
}

void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=0;String[i]!='\0';i++)
{
LCD_WriteData(String[i]);
}
}

int LCD_Pow(int X,int Y)
{
unsigned char i;
int Result=1;
for(i=0;i<Y;i++)
{
Result*=X;
}
return Result;
}

void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=Length;i>0;i--)
{
LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
}
}

void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{
unsigned char i;
unsigned int Number1;
LCD_SetCursor(Line,Column);
if(Number>=0)
{
LCD_WriteData('+');
Number1=Number;
}
else
{
LCD_WriteData('-');
Number1=-Number;
}
for(i=Length;i>0;i--)
{
LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
}
}

void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i,SingleNumber;
LCD_SetCursor(Line,Column);
for(i=Length;i>0;i--)
{
SingleNumber=Number/LCD_Pow(16,i-1)%16;
if(SingleNumber<10)
{
LCD_WriteData(SingleNumber+'0');
}
else
{
LCD_WriteData(SingleNumber-10+'A');
}
}
}

void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=Length;i>0;i--)
{
LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
}
}
  • 串口通信

stc52ser.h

1
2
3
4
5
6
7
8
9
10
11
12
#ifndef __STC52_SER__
#define __STC52_SER__

extern void (*SerialPort_Event_ByteReceived)(unsigned char byte); //事件:串口接收到字节

void SerialPort_Init_Low(); //初始化为11.0592MHz下的9600波特率
void SerialPort_Init_High(); //初始化为22.1184下的115200波特率
void SerialPort_Init_9600();//初始化为11.0592MHz下的9600波特率
void SerialPort_SendByte(unsigned char byte); //发送一个字节
void SerialPort_SendData(unsigned char* bytes); //发送一组字节

#endif

stc52ser.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <reg52.h>
#include "ASCIIS.h"
#include "stc52ser.h"

//定义一个指针变量作为Byte Received Event
void (*SerialPort_Event_ByteReceived)(unsigned char byte);

void SerialPort_Init_Low(){
TMOD = 0x20;
TH1 = 0xfd;
TL1 = 0xfd;
TR1 = 1;
SM0 = 0;
SM1 = 1;
REN = 1;
EA = 1;
ES = 1;
}

void SerialPort_Init_High(){
PCON |= 0x80;
TMOD = 0x20;
TH1 = 0xff;
TL1 = 0xff;
TR1 = 1;
SM0 = 0;
SM1 = 1;
REN = 1;
EA = 1;
ES = 1;
}

void SerialPort_Init_9600(){
PCON &= 0x7F; //波特率不倍速
SCON = 0x50; //8位数据,可变波特率
TMOD &= 0x0F; //设置定时器模式
TMOD |= 0x20; //设置定时器模式
TL1 = 0xFD; //设置定时初始值
TH1 = 0xFD; //设置定时重载值
ET1 = 0; //禁止定时器%d中断
TR1 = 1; //定时器1开始计时
EA = 1;
ES = 1;
}
void SerialPort_SendByte(unsigned char byte){
ES = 0;
SBUF = byte;
while(!TI);
// transmit interrupt
TI = 0;
ES = 1;
}
void SerialPort_SendData(unsigned char* bytes){
int i = 0;
while(bytes[i] != '\0'){
SerialPort_SendByte(bytes[i]);
i++;
}
}
void receivedInterruped() interrupt 4 {
if(RI==1){
(SerialPort_Event_ByteReceived)(SBUF);
//while(!RI);
RI = 0;
}

}
  • ESP8266无线模块

esp8266.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#ifndef __ESP8266__
#define __ESP8266__

extern void (*ESP01_Event_WifiConnected)(); //事件:Wi-Fi已连接
extern void (*ESP01_Event_IpGot)(); //事件:IP地址已获得
extern void (*ESP01_Event_TcpServerConnected)(); //事件:已连接到TCP服务器
extern void (*ESP01_Event_MsgReceived)(unsigned char* head); //事件:已获得消息,head为消息数组头
extern void (*ESP01_Event_ATCipMode1)(); //事件:AT+CIPMODE=1指令执行成功
extern void (*ESP01_Event_ATCipSend)(); //事件:AT+CIPSEND指令执行成功

void ESP01_ATCipMode1(); //发送AT+CIPMODE=1指令 在main中调用
void ESP01_ATCipSend(); //发送AT+CIPSEND指令 在main中调用
void ESP01_ATCipSendRequests(); //GET /php/queryForEsp8266.php指令发送 在main中调用
void ESP01_Init(); //无线模块初始化
void ESP01_ConnectToTCPServer(); //发送AT+CIPSTART="TCP","192.168.31.156",8088指令 连接TCP服务器 在main中调用

#endif

esp8266.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#include <REGX52.H>
#include "stc52ser.h"
#include "ASCIIS.h"
#include "esp8266.h"
#include <string.h>
#include "Delay.h"

#define BUFFER_MAX_SIZE 99 //缓冲区大小 最大只能设置128 writeIndex最大只能为128
unsigned char buffer[BUFFER_MAX_SIZE]="\0"; //缓冲区:用于存放从ESP8266接收来的各种信息
unsigned char counter = 0; //用于ESP8266的执行步骤计数
unsigned char writeIndex = 0; //缓冲区写索引

//连接到TCP服务器的指令:AT+CIPSTART="TCP","192.168.1.110",1234。后面的CR和NL是AT指令的固定结尾,第一个NL发送时识别结尾。
//code unsigned char cmd_connectToTCPServer1[] = {0x41, 0x54, 0x2B, 0x43, 0x49, 0x50, 0x53, 0x54, 0x41, 0x52, 0x54, 0x3D, 0x22, 0x54, 0x43, 0x50, 0x22, 0x2C, 0x22, 0x31, 0x39, 0x32, 0x2E, 0x31, 0x36, 0x38, 0x2E, 0x31, 0x2E, 0x31, 0x31, 0x30, 0x22, 0x2C, 0x31, 0x32, 0x33, 0x34, CR, NL, NL};
//直接使用字符串也没问题 定义下面要使用到的命令
code unsigned char cmd_connectToTCPServer[]="AT+CIPSTART=\"TCP\",\"192.168.31.156\",8088\r\n";
code unsigned char cmd_ATCipMode1[]="AT+CIPMODE=1\r\n";
code unsigned char cmd_ATCipSend[]="AT+CIPSEND\r\n";
code unsigned char cmd_ATRequest1[]="GET /php/queryForEsp8266.php\r\n";


//定义6个指针变量存储函数地址用于实现事件化
void (*ESP01_Event_WifiConnected)();
void (*ESP01_Event_IpGot)();
void (*ESP01_Event_TcpServerConnected)();
void (*ESP01_Event_MsgReceived)(unsigned char* str);
void (*ESP01_Event_ATCipMode1)();
void (*ESP01_Event_ATCipSend)();

//4. 将信息插入到缓冲区并送给单片机。
void insertDataIntoBuffer(unsigned char byte){
//Delay(10);
//这个我在服务器端再每条数据后面加了#
if(byte == '#'){
//检测到'#'后,将信息送出到单片机
buffer[writeIndex] = '\0';
//执行事件ESP01_Event_MsgReceived
(ESP01_Event_MsgReceived)(buffer);
memset(buffer,0,BUFFER_MAX_SIZE);
writeIndex = 0;
return;
}
buffer[writeIndex] = byte;
writeIndex++;
}

//识别回馈指令:用于识别接收到的是WIFI CONNECTED 还是 WIFI GOT IP等等
void parseCmd(){
//通过判断counter为多少,来确定在哪一步中
switch(counter){
case 1:
//WIFI CONNECTED
if(buffer[0] == 'W' && buffer[5] == 'C'){
//执行事件ESP01_Event_WifiConnected 在main中
(ESP01_Event_WifiConnected)();
counter += 1;
}
break;
case 2:
//WIFI GOT IP
if(buffer[0] == 'W' && buffer[5] == 'G'){
//执行事件ESP01_Event_IpGot 在main中
(ESP01_Event_IpGot)();
counter += 1;
}
break;
case 3:
//AT+CIPSTART="TCP","192.168.31.156",8088
if(buffer[0] == 'A' && buffer[3] == 'C')
counter += 1;
break;
case 4:
//CONNECT
if(buffer[0] == 'C' && buffer[3] == 'N' && buffer[6] == 'T'){
//执行事件ESP01_Event_TcpServerConnected 在main中
(ESP01_Event_TcpServerConnected)();
counter += 1;
}
break;
case 5:
//AT+CIPSEND
if(buffer[0] == 'A' && buffer[6] == 'M' && buffer[8] == 'D')
counter += 1;
break;
case 6:
//OK
if(buffer[0] == 'O' && buffer[1] == 'K'){
(ESP01_Event_ATCipMode1)();
counter += 1;
}
break;
case 7:
//AT+CIPSEND
if(buffer[0] == 'A' && buffer[6] == 'S' && buffer[8] == 'N')
counter += 1;
break;
case 8:
//OK
if(buffer[0] == 'O' && buffer[1] == 'K'){
(ESP01_Event_ATCipSend)();
//counter += 1;
/*当有串口中断时,
SerialPort_Event_ByteReceived事件改为insertDataIntoBuffer,
执行函数insertDataIntoBuffer
*/
SerialPort_Event_ByteReceived = &insertDataIntoBuffer;
}
}
}

//2. 这里开始向缓冲区存储信息,用于识别。
void insertBuffer(unsigned char byte){
if(byte == NL){
//收到尾(NL)后,则判断收到ESP8266返回的一行信息,将缓冲区的这一行信息送去识别
parseCmd();
//识别完成后,清空缓冲区
memset(buffer,0,BUFFER_MAX_SIZE);
writeIndex = 0;
return;
}
buffer[writeIndex++] = byte;
}

//1. 接收头:头是无用信息,但我们要通过头里面的一些字符,推算出什么时候到达第二步(WIFI CONNECTED)
void headerReceived(unsigned char byte){
if(byte == NL){
/*开始会返回一些无用的信息,每个ESP8266可能不一样,观察可以看到,返回的信息内
头内有2个NL(也就是\n),如果识别到了2个NL后跳到下一步,当有串口中断时,
将SerialPort_Event_ByteReceived=&insertBuffer,执行函数insertBuffer
*/
if(++counter == 2){
SerialPort_Event_ByteReceived = &insertBuffer; //跳到第二步
counter = 1;//counter置为1,后面通过判断counter为多少,来判断在哪一步
}
}
}


//同.h中的声明
void ESP01_Init(){
//将串口波特率设置为9600
SerialPort_Init_9600();
/*当有串口中断时,
SerialPort_Event_ByteReceived设为headerReceived,执行函数headerReceived
*/
SerialPort_Event_ByteReceived = &headerReceived; //事件注册
}

//同.h中的声明
//服务器连接指令发送 AT+CIPSTART="TCP","192.168.31.156",8088 在main中调用
void ESP01_ConnectToTCPServer(){
SerialPort_SendData(cmd_connectToTCPServer);
}
//AT+CIPMODE=1指令发送 在main中调用
void ESP01_ATCipMode1(){
SerialPort_SendData(cmd_ATCipMode1);
}
//AT+CIPSEND指令发送 在main中调用
void ESP01_ATCipSend(){
SerialPort_SendData(cmd_ATCipSend);
}
//GET /php/queryForEsp8266.php指令发送 在main中调用
void ESP01_ATCipSendRequests(){
SerialPort_SendData(cmd_ATRequest1);
}
  • 主函数

main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#include <REGX52.H>
#include "lcd1602.h"
#include "esp8266.h"
#include "ASCIIS.h"
#include <string.h>
#include "Delay.h"
#include "Timer0.h"
#include "stc52ser.h"

//连接到Wi-Fi后,亮第一个灯
void EventHandler_WifiConnected(){
//P2_0=1;
LCD_ShowString(1,1,"1");
Delay(100);
LCD_ShowString(1,1,"Load...");
}

//获得IP后,LCD第1行第1列显示2
void EventHandler_IpGot(){
LCD_ShowString(1,1," ");//清屏
LCD_ShowString(1,1,"2");
ESP01_ConnectToTCPServer();
}

//连接到TCP服务器后,LCD第1行第1列显示3
void EventHandler_TcpServerConnected(){

LCD_ShowString(1,1,"3");
//设置传透模式
ESP01_ATCipMode1();
}

//设置传透模式成功,LCD第1行第1列显示4
void ESP01_EventHandler_ATCipMode1(){
LCD_ShowString(1,1,"4");
//打开发送数据
ESP01_ATCipSend();
}


//打开发送数据成功,LCD第1行第1列显示5
void ESP01_EventHandler_ATCipSend(){
LCD_ShowString(1,1,"5");
Timer0Init();
}
static unsigned char temp=0;
unsigned char strLength[2]={0};
//将ESP8266送来的信息,送去LCD显示。
void EventHandler_MsgReceived(unsigned char* str){

unsigned char *arr[16]={NUL};
unsigned char i=0;
//str=121.04,163.42#
//第1次切割
arr[i]=strtok(str,",");
//第2~n次切割
while(arr[i] != NUL){
i++;
arr[i]=strtok(NUL,",");
}

LCD_ShowString(1,1,"lighting:");
if(strlen(arr[0])!=strLength[0]){
//LCD_WriteCommand(0x01);//光标复位,清屏
LCD_ShowString(1,10," ");//清屏
//记录本次数据长度,与下次对比,如果不相等,则清屏一次
//防止数据长度变短后,原来的数据后半部分仍在LCD中显示
strLength[0] = strlen(arr[0]);
}
LCD_ShowString(1,10,arr[0]);

LCD_ShowString(2,1,"aircondi:");
if(strlen(arr[1])!=strLength[1]){
LCD_ShowString(2,10," ");//清屏
//记录本次数据长度,与下次对比,如果不相等,则清屏一次
strLength[0] = strlen(arr[0]);
}
LCD_ShowString(2,10,arr[1]);

strLength[1] = strlen(arr[1]);
//确认没有死机 在LCD1602第2行16列显示递增的数字
LCD_ShowNum(2,16,temp,1);
temp++;
if(temp>9){
temp=0;
}
}

//初始化
void init(){
ESP01_Event_WifiConnected = &EventHandler_WifiConnected; //事件注册
ESP01_Event_IpGot = &EventHandler_IpGot; //事件注册
ESP01_Event_TcpServerConnected = &EventHandler_TcpServerConnected; //事件注册
ESP01_Event_MsgReceived = &EventHandler_MsgReceived; //事件注册
ESP01_Event_ATCipMode1 = ESP01_EventHandler_ATCipMode1; //事件注册
ESP01_Event_ATCipSend = ESP01_EventHandler_ATCipSend; //事件注册
ESP01_Init();//ESP8622初始化
LCD_Init();//LCD初始化
}

void main(){
init();
LCD_ShowString(2,1,"testStr");
while(1);
}
static int T0Count=0,tmp=0;
void Timer0_Routine() interrupt 1
{
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
T0Count++;
//每隔800ms执行,发送GET /php/queryForEsp8266.php请求
if(T0Count>=800)
{
T0Count=0;
//发送GET /php/queryForEsp8266.php指令
ESP01_ATCipSendRequests();
}
}

五、效果

六、问题汇总

  1. LCD1602经常性出现字符乱码错乱,可能是由于插上ESP8266后电压不够导致的,其自身也不稳定。
  2. 单片机hex下载不进行,由于ESP8266占用了串口,关掉ESP8622或者拔掉接收口的线。