案例簡述:
以WIFI模塊(ESP8266)為開發對象,處在局域內網中的WIFI模塊,連接到另外一個局域內網的TCP服務器,形成WIFI模塊和服務器之間通信。本文先以電腦控制WIFI模塊的連接,熟悉AT指令的使用,再通過編程手段,由單片機去控制WIFI模塊,深入學習。
一.電腦端調試,控制WIFI模塊的連接
說明:將WIFI模塊通過串口與電腦連接,電腦通過串口調試軟件給模塊發送AT指令,控制WIFI模塊與其他局域網內的服務器建立連接。
步驟:
1. 所需條件:
1)兩台PC機,一個路由器,確保有台電腦可聯網,並且路由器也聯網,並分別連接在不同的局域網內,(支招:沒有路由器的可以通過一台電腦開WIFI作為路由器,但確保是兩個局域網內。沒有兩個局域網的,可以用手機開wifi熱點給電腦提供網絡,本實驗不怎么費手機流量,勿擔心)
2)聯網的電腦(B電腦)安裝花生殼軟件(注意用的是穿透版),登入保持在線。
3)在有花生殼的電腦(B電腦)開啟網絡調試助手軟件,另一台電腦(A電腦)開啟串口調試軟件。
4)有串口調試軟件的電腦(A電腦),通過USB轉TTL線與WIFI模塊相連接。
前期准備工作如下圖:
花生殼軟件:
網絡調試助手:
串口調試助手:
wifi模塊與電腦串口連接(只需要TX,RX,VCC,GND引腳)
2. WIFI 模塊連接到路由器
通過串口調試助手給wifi模塊發送AT指令,控制模塊。
1)復位WIFI模塊,指令:AT+RST(注意發送指令后必須加換行,下面同理)
指令說明:
指令實現:
1)選擇模式,指令:AT+CWMODE=3
指令說明:
指令實現:
1)連接到路由器,指令:AT+ CWJAP =”ldy”,”99999999”(路由器名稱和密碼,只能是非中文名稱)
指令說明:
指令實現:
3. 模塊與其他局域網服務器建立TCP連接
1)在B電腦上開啟花生殼和網絡調試助手,其中花生殼被映射的地址應為電腦本機IP地址,端口任意。網絡調試助手上的IP和端口應該設置為被花生殼所映射的IP和端口。IP被花生殼映射到外網域名和端口號,是將要被WIFI模塊連接的外網地址。如圖:
2)啟動單連接,指令:AT+ CIPMUX =0
指令說明:
指令實現:
3)連接到TCP服務器,
AT+CIPSTART=”TCP”,”14z95r6389.iask.in”,35447(改指令可以通過域名和端口號去連接,也可以通過IP和端口號連接,由於被穿透后是域名,故采用域名形式連接)
指令描述:
指令實現:
4)發送消息 AT+CIPSEND=5(5指的要發送消息的長度)
指令說明:
指令描述:
WIF模塊端發送:
服務器端接收:
5)接收服務器(接收到消息會有“+IPD”的數據頭)
說明:
接收實現:(接收到服務器端發的”zzz”字符)
二.單片機實現控制WIFI模塊與服務器連接
從上面電腦端實現了,對WIFI模塊連接到路由器后,再與服務器建立連接的過程,都是通過AT指令實現的,目的是為了熟悉AT指令的使用和調試。接下來就可以比較容易的通過單片機來控制WIFI模塊,將需要發送的AT指令寫入程序中。
實驗內容:單片機控制WIFI模塊,給服務器端發送長度為7位的字符串”abcdefg”
1.硬件條件
基於STM32單片機,通過USART3與WiFi模塊相連接。
2.程序核心代碼
本人已經寫好了發送AT指令的封裝函數,可靈活實現每個指令的定時等待和多次重發功能。可大大提高模塊使用的穩定性,現在附上主要代碼供參考。
主函數如下:
int main(void)
{ //通過域名形式連接到服務器
char *string
="AT+CIPSTART=\"TCP\",\"14z95r6389.iask.in\",35447";
char *Seddstr = "abcdefg"; //被發送的字符串
ALL_init();//初始化各種外設
LED_ALL2_ON;
delay_ms(1000);
WIFI_AT_Command( "AT+RST","ready",5,2,ENABLE);
delay_ms(1000);
if(Send_wifiAT("AT+CWSAP?")==0)//判斷是否連接上路由器
{
WIFI_AT_Command("AT+CWMODE=3","OK",3,2,DISABLE); //STATION兼AP模式
WIFI_AT_Command("AT+CWJAP=\"ldy\",\"99999999\"","CONNECTED",10,3,DISABLE); //連接的到路由器,需要等待較長時間
}
WIFI_AT_Command("AT+CIPMUX=0","OK",3,2,DISABLE); //單連接
WIFI_AT_Command((char*)string,"OK",5,3,ENABLE);
//連接到服務器
SendDATA_wifi(Seddstr,strlen(Seddstr));
//發送數據
while(1)
{
}
}
- 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
發送AT指令封裝函數如下:(自寫的封裝函數,可供網友移植)
/* 函數:WIFI_AT_Command 功能:(智能化發送指令)在規定時間內,可多次重發某個指令,多次發送失敗可復位 參數:b:發送內容,a:等待接收內容,timeout_S:發單次內最多允許等待 的時間,ReSendcount:最多可以重復發幾次(失敗情況),EN_Reset:如果失敗是否復位機器。 返回: 成功回1 失敗回0 */
char WIFI_AT_Command(char *b,char *a,u8 timeout_S , char ReSendcount,FunctionalState EN_Reset)
{
u16 count =0;
u8 i = 0;
WaitACKflag = 1; //WaitACKflag用於防止重入函數 strstr
CLR_Buf3();
ACK_Command = a;
for(i =1 ; (i<= ReSendcount && WaitACKflag); i++) //若失敗 ,重復發送ReSendcount次
{
CLR_Buf3();
USART_Puts(USART3 ,b);
USART_Puts(USART3 ,"\r\n");
while(WaitACKflag) //判斷在中斷里,等待變成0
{
count ++;
delay_ms(5);
if(count >200*timeout_S) //最多允許等待timeout_S S
{
count=0;
break;
}
}
}
ACK_Command="";
WaitACKflag =0;
if(count == 0 && i == ReSendcount) //重復發送ReSendcount次,還沒接收到響應指令(都失敗)
{
if(EN_Reset == ENABLE)//如果使能了復位模式
{
__set_FAULTMASK(1); // 關閉所有中端
NVIC_SystemReset(); //軟件直接復位(重來)
}
return 0;
}
return 1;
}
- 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
給服務器發送數據封裝函數:
/** 函數:SendDATA_wifi 功能:給服務器發送數據 參數:a:發送的數據 length:發送的長度 返回: **/
void SendDATA_wifi(char *a ,u16 length)
{
char Buf[30] = "";
sprintf(Buf,"AT+CIPSEND=%d",length);
WIFI_AT_Command(Buf,">",3,2,ENABLE);
WIFI_AT_Command(a,"SEND OK",4,2,ENABLE);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
串口USART3接收中斷函數:
/** 函數名 : USART3_IRQHandler 描述 : 串口3中斷服務程序 輸入 : 無 返回 : 無 說明 : **/
void USART3_IRQHandler(void)
{
u8 ch=0;
if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)
{
USART_ClearITPendingBit(USART3, USART_IT_RXNE);
ch = USART_ReceiveData(USART3);
Wifi_RXbuf[Wificount++] =(char)ch;
if(ch == '\n' || Wificount>=Uart3bufMAX)//防止超限
{
Wificount =0;
}
if(WaitACKflag ==1) //將判斷strstr函數寫在中斷里,WaitACKflag用於防止重入函數
{
if(strstr(Wifi_RXbuf,ACK_Command)!=NULL)
{
WaitACKflag=0;
}
}
else
{
Judge_UART3_box();//對接收服務器接收消息的處理
}
}
}
- 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
接收服務器消息函數:
/** 函數:Judge_UART3_box 功能:接收服務器消息判斷 參數: 返回: **/
void Judge_UART3_box()
{
if(strstr(Wifi_RXbuf,"+IPD")!=NULL)
{
//用戶自行定義
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
3.實驗現象
服務器端可以接收到WIFI模塊的數據如圖:(服務器端也可以給WIFI模塊發數據來控制單片機執行,接收函數也封裝好在上面的代碼中,感興趣的可以做些相關實驗)