ESP8266是我第一個,也是唯一一個接觸過的無線網絡模塊,我非常喜歡!大部分網上的教程都是ARM架構單片機配用ESP8266。我比較摳門,給大家上51版的。
我記得當時和老板承諾可以做成無線通信的時候我也不是很確定,心里一直打鼓。好在最后做出來了,很有成就感!所以今天的代碼案例是我把我之前在公司寫的項目代碼簡化之后分享給大家的。雖然結構有點惡心,但應該還是入得了眼的。
如果有沒看懂的地方,大家評論區告訴我。
需求
利用ESP8266芯片,通過無線網絡同電腦建立TCP連接。接收電腦傳來的消息并顯示在LCD上。
每條信息以\結尾。
每條信息字符數不超過32。
信息內容只能是ASCII表內的字符。
清單
硬件
學習板
簡介
由于這次要用到WIFI模塊,沒法用Proteus模擬,所以就上真家伙。
自己焊板子就太麻煩了,所以就買學習板(其實我不會焊)。
QX-MINI51
這是我入的學習板,你也可以入其他的,如果把握不大就跟我入一樣的。
這個是我在淘寶上小挑了一陣子選的板子:QX-MINI51。尺寸不大不小,想玩的基本都有。配備的單片機是STC89C52。
淘寶鏈接
電路
下面是QX-MINI51在本節會用到的電路圖
STC89C52
使用89C52芯片,和我們之前用的單片機一樣。
供電&USB串口
CH340芯片是用于普通串口和USB轉換的,其上的RXD為串口輸入,TXD為串口輸出。UD+和UD-對應USB數據線。
雖說是用了USB,其實和普通串口通信線用法一致,只是人家成品方便我們使用封裝成了USB。這里不深究。
流水燈
流水燈在本節中的角色是輔助調試(具體的看后面),這里有用的信息就是讓你知道這8個流水燈接哪了。
ESP8266
簡介
主角,簡而言之就是Wi-Fi模塊,屬于網絡層以上的設備。擁有MAC地址和IP地址,支持UDP和TCP。
ESP8266
這款的型號是ESP8266-01,其他的和QX-MINI51配合使用不太方便。
淘寶鏈接
參數
型號 主芯片 無線標準 工作電壓 安全機制 支持模式
ESP8266-01 ESP8266 IEEE 802.11b/g/n 3.3V WEP/WPA-PSK/WPA2-PSK STA、AP、STA+AP
STA 模式:ESP8266模塊通過路由器連接互聯網,手機或電腦通過互聯網實現對設備的遠程控制。
AP 模式:ESP8266模塊作為熱點,實現手機或電腦直接與模塊通信,實現局域網無線控制。
STA+AP 模式:兩種模式的共存模式,即可以通過互聯網控制可實現無縫切換,方便操作。
引腳圖
上圖對8個針腳進行說明。
UTXD GND CH_PD GPIO2 GPIO16 GPIO0 VCC URXD
發送 接地 高電平工作 |||電源 接收
本例只用到這五個引腳(畫“\”的不用),其他引腳的說明資料請自行到淘寶鏈接處下載。
AT指令
操作ESP8266芯片是靠AT指令的,類似之前的操作LCD1602(《51單片機實戰:液晶顯示器のLCD1602》)。操作LCD1602的指令都是一個字節的十六進制碼,比較難記和理解。AT指令是字符串形式的指令,一般都是單詞縮寫,對可笑的人類比較友好。
之前和LCD1602交互是靠并口傳輸,而這次是用串口傳輸(串口傳輸簡例:《51單片機實戰:與計算機異步串行通信》),所以這次的Wi-Fi通信是建立在串口通信基礎上的。
AT指令集下載鏈接
AT指令使用示例下載鏈接
波特率
注意,這個模塊的默認波特率是115200,本例也是根據這個波特率進行演示的。若想改變波特率請使用以下語句進行修改:
AT+CIOBAUD=<baudrate>,<databits>,<stopbits>,<parity>,<flow control>
如:
AT+CIOBAUD=9600,8,1,0,0
軟件
程序 說明 下載
UartAssist 串口調試助手,用來給單片機發送消息 度娘網盤
NetAssist 網絡調試助手,在電腦端建立TCP連接與單片機的ESP8266進行通信 度娘網盤
STC-ISP STC單片機工具集,很強大,可燒錄程序,可串口調試等等 度娘網盤
CH340驅動 CH340的USB驅動,如果沒有這個驅動,你的電腦可能識別不到單片機(識別到CH340就相當于識別到單片機的串口。) 度娘網盤
51單片機波特率初值計算工具 用于計算在各種波特率和晶振頻率等參數下計時器的初值,屬于輔助工具,省的還得算。 度娘網盤
分析
調試
在開始用單片機直接和無線模塊通信之前,首先要繞過單片機直接和無線模塊通信以確定其可以使用和接入默認網絡(接入一個熱點后,模塊每次斷電后啟動都會自動連接該熱點),這樣可以讓單片機少做很多事情(要知道我們用的是51單片機,硬件資源極其有限,能省則省)。
TXD/RXD反接
首先要繞過單片機直接給ESP8266下指令,就要用電腦的串口。但ESP-01是針腳接口,所以我們可以利用QX-MINI51上的針腳和USB接口。
回看前面QX-MINI51的主控芯片和USB的電路圖,可以發現,單片機的串口引腳是被并聯式的暴露再外的,分別為:P30 - P31和USB,前者為針腳接口,后者為USB接口。且它們的RXD和TXD的數據信息是一摸一樣的,注意并不是兩個獨立的串口,是同一個串口。比方說,單片機要往出發送一個1,P30針腳和USB都會是往出發送一個1。
所以我們利用這個特點,將ESP8266的TXD接到P31(單片機的TXD),RXD接到P30(單片機的RXD),這樣就等于讓ESP8266直接和USB打交道,也就是和電腦直接打交道了。
為什么叫反接,我一般管RXD對TXD叫正接。嗯…
接線圖
強勢秀一波畫工!
我覺得應該可以看得懂吧,ESP8266的引腳說明請看前面的引腳圖。看紅色號碼對應接線,其中4、5、6號引腳不用。
實物圖
這個圖就很難看出線是怎么連的了,所以你要忍受我丑陋的畫工。
接入網絡
打開串口調試助手,調好參數
串口調試助手,設置參數
其中串口號你連的哪個串口就設置哪個串口號,我是連的COM3。
另一個要注意的就是波特率要115200(ESP-01的默認波特率,也可以統一改為9600)。
打開串口后,給開發板上電。你的串口調試助手會有信息出來(文本顯示,不要十六進制顯示)。
?諄MEM CHECK FAIL!!!
d{$弬s
Ai-Thinker Technology Co. Ltd.
invalid
顯示的信息類似上面,你可以先給個測試命令AT看看是否可以接受指令
注意!每個指令后要跟回車再發送!
如果返回OK則說明指令可以被接收并識別。
如果下面的指令都會返回ERROR(在沒有給錯指令的情況下),可以嘗試AT+RST重啟模塊。
1. 更改模式
指令:AT+CWMODE?
一般情況下,第一次使用會返回2,也就是AP模式,我們不用它發熱點,所以要改回Station模式(模式1)。
指令:AT+CWMODE?
一般情況下,第一次使用會返回2,也就是AP模式,我們不用它發熱點,所以要改回Station模式(模式1)。
指令:AT+CWMODE=1
返回:OK則成功
2. 接入熱點(連Wi-Fi)
指令:AT+CWJAP=<SSID>,<Password>
參數:<SSID>處填寫熱點名稱,<Password>處填寫密碼。兩者都要用雙引號括起來。
例如:AT+CWJAP="CMCC","123456"
指令:AT+CWJAP=<SSID>,<Password>
參數:<SSID>處填寫熱點名稱,<Password>處填寫密碼。兩者都要用雙引號括起來。
例如:AT+CWJAP="CMCC","123456"
返回:WIFI CONNECTED:連接到熱點
返回:WIFI GOT IP:分配到IP,走到這一步,就算已經連入到熱點了。
如果忘記SSID了,想看一下可以使用下面的指令,列出廣播的SSID(隱藏的不會顯示)。
指令:AT+CWLAP
3. 連接TCP服務器
首先打開NetAssist,設置TCP Server,然后建立連接(注意防火墻)。注意,Server必須在Client所在內網或其外網(我的是在同一個內網)。
網絡調試助手
首先打開NetAssist,設置TCP Server,然后建立連接(注意防火墻)。注意,Server必須在Client所在內網或其外網(我的是在同一個內網)。
網絡調試助手
指令:AT+CIPSTART=<Type>,<DomainName>,<Port>
參數:<Type>處寫TCP或UDP,<DomainName>處寫域名,<Port>處寫端口號。
本例:AT+CIPSTART="TCP","192.168.1.110",1234
返回:
CONNECT
OK
說明連接成功。
在NetAssist中,數據接收框的下面有一個連接對象,點開后發現除了All Connections之外,多了一個客戶,就確定客戶連接到服務器了。
NetAssist
在下方文本框輸入信息后發送,可在串口調試助手中看到ESP8266所接收到的信息
UartAssist收到的信息:+IPD,10:Hello 簡書
到這里就說明網絡連接及建立TCP都可以順利完成,在下面的單片機操作中就會變得方便很多。
注意,ESP8266每次斷電后重新上電,最多只會自動連到之前連接的熱點,但不會自動連接到TCP服務器,所以,建立連接要交給單片機來做。
問題
波特率
本例要使用的波特率為115200的,不是9600。引申出來的問題就是:算初值(方法詳見:《51單片機實戰:與計算機異步串行通信》 - 知識點 - 波特率 - 溢出率)。
手算真的很麻煩,因為在參數固定的情況下,算起來已經很煩了,更何況那些參數可能還會變得情況。
所以上神器:
初值計算器
反饋及識別
我們要做的是讓單片機在收到ESP8266回饋的WIFI GOT IP后發出連接TCP服務器的指令。
發送指令不用多說,只要記得在后面跟"換行(CR)"和"新行(NL)"字符就行(這兩個是不一樣的)。
1. 關鍵字符配對
如果是電腦程序的高級語言編程,這個問題就不存在了。但是我們給單片機寫程序就要牢記它的一些點(《扯會兒單片機開發:開始》),比如硬件資源十分緊張。
一個是因為它存儲空間很小,另一個是因為晶振太慢,所以我們要想辦法縮減配對時間。因為單片機的使用往往很單一,所以策略都是根據情況來設定的。比如本例,單片機接收的回饋無非那么幾種,所以我制定的策略就是關鍵字符配對。
比如識別WIFI GOT IP,我只是別第一個字符W和第6個字符G,就說明我收到的就是這個回饋信息。如果收到第一個是W,只有這條指令的第六個字符是G,所以就可以確定。如果是出現干擾,可能性也是比較低的,我們的交互是在網絡層的,下層也可以把出錯的報文擋掉。
總體來說還是蠻可靠的,如果你有更棒的方法,請在評論區告訴我,大家一起學習進步。
2. 利用流水燈
上面就是理論工作,已經做得7788了。但實際經驗告訴我,如果的代碼哪里也出岔子了在51單片機開發中真的比較難發現,他不像高級程序語言可以報錯,可以try - catch。但這個就別想了,所以我們要自己想辦法,讓他可以反饋我們的程序至少是正常運行的,這樣可以節省很多時間。
我在這里介紹的我的方法是利用LED,或成組的流水燈(更好)。承租的流水燈一般是8個,可以直接顯示一個字節的信息,可能有人問為什么不用LCD?你若會LCD或者看過《51單片機實戰:液晶顯示器のLCD1602》就會發現,LCD本身的開發就有點復雜了。你很難保證這個子程序運行正常,更別提用它抓錯了。只能是不推薦哈,我覺得不可靠。LED的話就很簡單了,就是個關開,一般不會出錯。
QX-MINI51開發板上自帶流水燈,你要是入的其他開發板,一般都是有的。如果沒有,就單買LED回來(如果不知道去哪買,鏈接)。
我一般會怎么做呢,先讓流水燈直接顯示串口接收的數據,為了知道我們至少是能接收到東西的。然后利用上面的關鍵字符識別,收到WIFI CONNECTED亮一號燈,收到WIFI GOT IP亮二號燈,收到CONNECT OK亮三號燈。這樣,根據燈亮滅的情況就能確定哪一步出了問題,然后定位到代碼或者設置。
還是那句話,如果你有更棒的方法,歡迎在評論區交流。
到這里就做完了所有理論上的準備工作,也就是理論上我們已經可以實現這個程序了,下面代碼實現。
代碼
說下這次代碼比較新穎的地方,一個是用到了.c和.h文件組合的模塊形式,另一個是用到了函數指針(函數名也被括起來的那個)。前者這種寫法是為了將各子功能模塊化,.h文件里的內容相當于面向對象編程里的public,.c文件一個是實現.h內的函數,另一個就是隱藏函數和變量,相當于private。后者是用來充當高級語言中的“事件”,讓函數調用變得更加靈活,其具體用法請自己查資料或者看相關C語言書籍。
總而言之,這次的代碼是模塊化和事件化的,類似面向對象的編碼風格。
準備
因為用于通訊,所以我把ASCII內所有的特殊字符都寫到一個頭文件里。雖然本例只用到其中的幾個,但以后重復利用這個頭文件。
ASCII.h
#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
LCD
這里都是關于LCD1602顯示器的主要代碼,與文章《51單片機實戰:液晶顯示器のLCD1602》所講的一樣,這里就不給出注釋了。
lcd1602.h
#ifndef __LCD1602__
#define __LCD1602__
typedef bit BOOL;
void LCD_writeCmd(unsigned char cmd); //寫命令
void LCD_writeData(unsigned char dat); //寫數據
void LCD_writeLine(unsigned char *line); //寫行數據
void LCD_init(); //初始化
void delay(unsigned int z); //粗略的延時器
#endif
lcd1602.c
#include <reg52.h>
#include "lcd1602.h"
#define LCD_CLEAR 0x01
#define LCD_Display_Mode 0X38
#define DISPLAY_OFF 0x08
#define DISPLAY_ON_NO_CURSOR 0x0c
#define DISPLAY_ON_WITH_CURSOR_NO_BLINK 0x0e
#define DISPLAY_ON_WITH_CURSOR_BLINK 0x0f
#define AUTO_BACK_STEP 0x04
#define AUTO_NEXT_STEP 0x06
#define AUTO_DISPLAY_MOVE_LEFT 0x07
#define AUTO_DISPLAY_MOVE_RIGHT 0x05
#define ALL_MOVE_LEFT 0x18
#define ALL_MOVE_RIGHT 0x1c
#define CURSOR_MOVE_LEFT 0x10
#define CURSOR_MOVE_RIGHT 0x14
#define FIRST_ROW 0x80
#define SECOND_ROW FIRST_ROW+0x40
sbit enable = P0^5;
sbit RS = P0^7;
sbit RW = P0^6;
void delay(unsigned int z)
{
unsigned int x,y;
for(x=z;x>0;x--)
for(y=220;y>0;y--);
}
void LCD_writeCmd(unsigned char cmd){
RS = 0;
P2 = cmd;
delay(5);
enable = 1;
delay(5);
enable = 0;
}
void LCD_writeData(unsigned char dat)
{
RS = 1;
P2 = dat;
delay(5);
enable = 1;
delay(5);
enable = 0;
}
void LCD_writeLine(unsigned char *line){
unsigned char i=0;
BOOL flag = 0;
LCD_writeCmd(LCD_CLEAR); //每次送來信息都清屏,可以一直刷新顯示送來的信息。
LCD_writeCmd(FIRST_ROW);
while(line[ i] != '\0'){
LCD_writeData(line[i++]);
if(i>15 && flag == 0){
LCD_writeCmd(SECOND_ROW);
flag = 1;
}
delay(5);
}
}
void LCD_init()
{
RW = 0;
enable = 0;
LCD_writeCmd(LCD_Display_Mode);
LCD_writeCmd(DISPLAY_ON_NO_CURSOR);
LCD_writeCmd(AUTO_NEXT_STEP);
LCD_writeCmd(LCD_CLEAR);
}
串口通信
這里用于單片機和ESP8266交互,與文章《51單片機實戰:與計算機異步串行通信》相似。其中的不同點前面已經說過。
stc52ser.h
#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_SendByte(unsigned char byte); //發送一個字節
void SerialPort_SendData(unsigned char* bytes); //發送一組字節
#endif
stc52ser.c
#include <reg52.h>
#include "ASCIIS.h"
#include "stc52ser.h"
//Byte Received Event
void (*SerialPort_Event_ByteReceived)(unsigned char byte);
//initialize registers pertinent to serial port
void SerialPort_Init_Low(){
//set and run Timer1
//mode2: 8bit, auto reload initial value
//9600bps and 11.0592MHz => 0xfd(initial value)
TMOD = 0x20;
TH1 = 0xfd;
TL1 = 0xfd;
TR1 = 1;
//set serial port configuration and enable receive
//mode1: asyc 10bit(8 data bit), alterable baud rate
SM0 = 0;
SM1 = 1;
REN = 1;
//set interruption
//enable all and serial port interruption
EA = 1;
ES = 1;
}
//initialize registers pertinent to serial port for esp8266
void SerialPort_Init_High(){
//SMOD = 1
PCON |= 0x80;
//set and run Timer1
//mode2: 8bit, auto reload initial value
//115200bps and 22.1184MHz => 0xfd(initial value)
TMOD = 0x20;
TH1 = 0xff;
TL1 = 0xff;
TR1 = 1;
//set serial port configuration and enable receive
//mode1: asyc 10bit(8 data bit), alterable baud rate
SM0 = 0;
SM1 = 1;
REN = 1;
//set interruption
//enable all and serial port interruption
EA = 1;
ES = 1;
}
//Send a byte
void SerialPort_SendByte(unsigned char byte){
ES = 0;
SBUF = byte;
while(!TI);
// transmit interrupt
TI = 0;
ES = 1;
}
//Send a data of byte sequence end by 'EOT'
void SerialPort_SendData(unsigned char* bytes){
int i = 0;
while(bytes[ i] != EOT){
SerialPort_SendByte(bytes[ i]);
i++;
}
}
//Occured when byte received
void receivedInterruped() interrupt 4 {
TR0 = 0;
(*SerialPort_Event_ByteReceived)(SBUF);
while(!RI);
RI = 0;
}
簡單說一下,這里留了兩個初始化函數,SerialPort_Init_Low()用于11.0592MHz下的9600波特率,SerialPort_Init_High()用于22.1184MHz下的115200波特率(此例用這個)。這樣寫只是為了以后可以重用(軟工狗的矯情)。
無線
這里是最主要的代碼,都是關于ESP8266的,也是作為一個模塊給主函數調用。
esp8266.h
#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為消息數組頭
void ESP01_Init(); //無線模塊初始化
void ESP01_ConnectToTCPServer(); //連接TCP服務器
#endif
esp8266.c
#include <reg52.h>
#include "stc52ser.h"
#include "ASCIIS.h"
#include "esp8266.h"
#define BUFFER_MAX_SIZE 99 //緩沖區大小
unsigned char buffer[BUFFER_MAX_SIZE]; //緩沖區:用于存放從ESP8266接收來的各種信息
//連接到TCP服務器的指令:AT+CIPSTART="TCP","192.168.1.110",1234。后面的CR和NL是AT指令的固定結尾,EOT用于SerialPort_SendData發送時識別結尾。
code unsigned char cmd_connectToTCPServer[] = {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, EOT};
int counter = 0; //用于ESP8266的執行步驟計數
int writeIndex = 0; //緩沖區寫索引
void (*ESP01_Event_WifiConnected)();
void (*ESP01_Event_IpGot)();
void (*ESP01_Event_TcpServerConnected)();
void (*ESP01_Event_MsgReceived)(unsigned char* head);
//注意:下面代碼推薦從后往前看,從注釋標"1. "處開始。
void prepareForData(unsigned char byte); //因為第四步和第三步會相互調用,所以這里只是做了個聲明(C語言的矯情點)。
//4. 將信息插入到緩沖區并送給單片機。
void insertDataIntoBuffer(unsigned char byte){
if(byte == '\\'){
//檢測到'\'后,將信息送出到單片機
buffer[writeIndex] = '\0';
(*ESP01_Event_MsgReceived)(buffer);
SerialPort_Event_ByteReceived = &prepareForData; //回到第三步,準備接收下一條信息
writeIndex = 0;
return;
}
buffer[writeIndex++] = byte;
}
//3. 準備信息:這里是過度步驟,前面可以觀察到,ESP8266在接收發來的信息時是有個頭的,這里的作用就是去頭。
void prepareForData(unsigned char byte){
if(byte == ':'){
SerialPort_Event_ByteReceived = &insertDataIntoBuffer;
writeIndex = 0;
}
}
//識別回饋指令:用于識別接收到的是WIFI CONNECTED(連上熱點)還是WIFI IP GOT(獲得IP)還是CONNECT(連上TCP服務器)
void parseCmd(){
switch(counter){
case 1:
if(buffer[0] == 'W' && buffer[5] == 'C'){
(*ESP01_Event_WifiConnected)();
counter += 1;
}
break;
case 2:
if(buffer[0] == 'W' && buffer[5] == 'G'){
(*ESP01_Event_IpGot)();
counter += 1;
}
break;
case 3:
if(buffer[0] == 'A' && buffer[3] == 'C')
counter += 1;
break;
case 4:
if(buffer[0] == 'C' && buffer[3] == 'N' && buffer[6] == 'T'){
(*ESP01_Event_TcpServerConnected)();
SerialPort_Event_ByteReceived = &prepareForData; //連接到TCP服務器后,進入第三步。
}
}
}
//2. 這里開始向緩沖區存儲信息,用于識別。
void insertBuffer(unsigned char byte){
if(byte == NL){
//收到尾(NL)后,將緩沖區的回饋信息送去識別
parseCmd();
writeIndex = 0;
return;
}
buffer[writeIndex++] = byte;
}
//1. 接收頭:頭是無用信息,但我們要通過頭里面的一些字符,推算出什么時候到達第二步(WIFI CONNECTED)
void headerReceived(unsigned char byte){
if(byte == NL){
//頭內有5個NL,只要數夠5個,下一個就是第二步的內容了。
if(++counter == 5){
SerialPort_Event_ByteReceived = &insertBuffer; //跳到第二步
counter = 1;
}
}
}
//同.h中的聲明
void ESP01_Init(){
SerialPort_Init_High();
SerialPort_Event_ByteReceived = &headerReceived; //事件注冊
}
//同.h中的聲明
void ESP01_ConnectToTCPServer(){
SerialPort_SendData(cmd_connectToTCPServer);
}
主函數
main.c
#include <reg52.h>
#include "lcd1602.h"
#include "esp8266.h"
//連接到Wi-Fi后,亮第一個燈
void EventHandler_WifiConnected(){
P1 &= 0xFE;
}
//獲得IP后,亮第二個燈
void EventHandler_IpGot(){
P1 &= 0xFD;
ESP01_ConnectToTCPServer();
}
//連接到TCP服務器后,亮第三個燈
void EventHandler_TcpServerConnected(){
P1 &= 0xFB;
}
//將ESP8266送來的信息,送去LCD顯示。
void EventHandler_MsgReceived(unsigned char* head){
LCD_writeLine(head);
}
//初始化
void init(){
ESP01_Event_WifiConnected = &EventHandler_WifiConnected; //事件注冊
ESP01_Event_IpGot = &EventHandler_IpGot; //事件注冊
ESP01_Event_TcpServerConnected = &EventHandler_TcpServerConnected; //事件注冊
ESP01_Event_MsgReceived = &EventHandler_MsgReceived; //事件注冊
ESP01_Init();
LCD_init();
}
void main(){
init();
while(1);
}
編譯
編譯前要設置一下目標參數,如下圖。
目標設置
注意這里要改成XDATA,不然編譯通不過的。
效果
開始前請確定在同一個網絡下,并且服務端已開啟。
初始化效果
我只是把單片機連到移動電源上了。
服務端
為了能讓1602第一行顯示Hello,第二行顯示World,中間可以留了11個空格。
客戶端
結語
猴!到這里這個程序就算完成了。這個比那些用手機控制開關燈要復雜一些。所以你只要掌握了這個例子,那些都不在話下了