STM32F103+ESP8266(WiFi)模組 實現AP模式下的TCP C/S 和 UDP Client

2021-04-28 15:00:02

前言

參考資料:
    STM32F1開發指南(精英版)-庫函數版本_V1.2.pdf
    ATK-ESP8266 WIFI使用者手冊_V1.2.pdf
    ATK_ESP8266V1.2.pdf
    ATK-ESP8266 WIFI模組使用說明(戰艦V3&精英版)_AN1509A.pdf
原始碼參考:正點原子 (庫函數版本,適合戰艦V3和精英STM32開發板)擴充套件實驗13 ATK-ESP8266 WIFI模組測試實驗) 這個例程功能比較全,也很強大,我對這個例程進行了精簡和刪改,LCD顯示也註釋了。
開發板:正點原子 STM32F103 精英版
語言:C語言
開發環境:Keil5
手機:準備的軟體是 網路偵錯助手 或 網路測試
在這裡插入圖片描述

開發板使用了 LED KEY TFTLCD USART SPI ESP8266模組

ESP8266模組 相關資料

更多參考底部
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述

程式碼下載:

碼雲 GitHub

功能介紹:

復位1秒後,進入ap_demo()函數,預設設定為AP模式,TCP 伺服器端,埠為8086。KEY0按下傳送測試資料,KEY_UP按下結束測試。期間會有串列埠列印,最好復位後就把串列埠開啟看資訊。
main.c中可以設定網路模式和IP地址。

u8 netpro = 0;	//網路模式 0,TCP伺服器 1,TCP使用者端 2,UDP模式
u8 ipbuf[16] = "192.168.4.2"; 	//IP (根據你的裝置連上模組後分配到的IP填寫)

common.c中可以設定 埠 wifi資訊等

//連線埠號:8086,可自行修改為其他埠.
const u8* portnum="8086";		 

//WIFI STA模式,設定要去連線的路由器無線引數,請根據你自己的路由器設定,自行修改.
const u8* wifista_ssid="wifi_name";			//路由器SSID號
const u8* wifista_encryption="wpawpa2_aes";	//wpa/wpa2 aes加密方式
const u8* wifista_password="password"; 	//連線密碼

//WIFI AP模式,模組對外的無線引數,可自行修改.
const u8* wifiap_ssid="ATK-ESP8266";			//對外SSID號
const u8* wifiap_encryption="wpawpa2_aes";	//wpa/wpa2 aes加密方式
const u8* wifiap_password="12345678"; 		//連線密碼 

接線

接ATK MODULE

在這裡插入圖片描述

在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述

沒有ATK MODULE情況

VCC   -5V
GND   -》  GND
TXD   -》  PB11
RXD   -》  PB10
RST   -》  PA4
IO_0  -》  PA15

在這裡插入圖片描述
在這裡插入圖片描述

效果圖

TCP 伺服器端

u8 netpro = 0;	//main.c ap_demo() 網路模式 0,TCP伺服器 1,TCP使用者端 2,UDP模式

燒寫完後,復位,開啟串列埠偵錯工具。
在這裡插入圖片描述
可以從上圖中看到,wifi的具體資訊

IP地址:192.168.4.1:8086
請用裝置連線WIFI熱點:SSID:ATK-ESP8266
加密方式:wpawpa2_aes
密碼:12345678
狀態:TCP伺服器

根據上面的資訊連線wifi(ATK-ESP8266),連線成功後檢視詳細資訊
在這裡插入圖片描述

網路偵錯助手

開啟軟體,選擇頂部「tcp client」,點選「增加」,輸入上面的IP地址和埠,進行「增加」
在這裡插入圖片描述
提示「連線成功」,並且左上角出現 小塊顯示增加的連線
在這裡插入圖片描述
此時串列埠收到連線資訊,連線成功
在這裡插入圖片描述
手機編輯文字「123321」,點選傳送,STM32按下KEY0傳送測試資料,頂部收到資料。最後長按連線塊,「斷開」連線。
在這裡插入圖片描述
串列埠列印如下
在這裡插入圖片描述

網路測試

開啟手機軟體「網路測試」,選擇TCP
在這裡插入圖片描述
右上角 「建立連線」,填入上面串列埠列印的IP:埠 ,點選「確定」
在這裡插入圖片描述
右上角顯示「已連線」就是連上了,然後我們傳送「好傢伙」,再STM32按KEY0(傳送測試資料)
在這裡插入圖片描述
最後按右上角「已連線」,斷開連線
在這裡插入圖片描述
串列埠助手收到的資料如下
在這裡插入圖片描述

雙管齊下

在這裡插入圖片描述
在這裡插入圖片描述

TCP 使用者端

u8 netpro = 1;	//main.c ap_demo() 網路模式 0,TCP伺服器 1,TCP使用者端 2,UDP模式
u8 ipbuf[16] = "192.168.4.2"; 	//IP (根據你的裝置連上模組後分配到的IP填寫)

手機建立TCP 伺服器端 監聽8086埠,等待使用者端主動連線
在這裡插入圖片描述
注意下時間線0.0
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述

UDP 使用者端

u8 netpro = 2;	//main.c ap_demo() 網路模式 0,TCP伺服器 1,TCP使用者端 2,UDP模式
u8 ipbuf[16] = "192.168.4.2"; 	//IP (根據你的裝置連上模組後分配到的IP填寫)

在這裡插入圖片描述
手機建立UDP server,監聽8086埠
在這裡插入圖片描述

在這裡插入圖片描述
按下KEY0,主動傳送資料
在這裡插入圖片描述
手機連線建立,點選進入
在這裡插入圖片描述
在這裡插入圖片描述

核心程式碼

完整程式碼參考 碼雲 GitHub

main.c

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "lcd.h"
#include "key.h"
#include "usmart.h"
#include "malloc.h"
#include "usart3.h"
#include "common.h"

// AP模式測試
void ap_demo(void);

int main(void)
{
    delay_init();	    	 //延時函數初始化
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//設定中斷優先順序分組為組2:2位搶佔優先順序,2位響應優先順序
    uart_init(115200);	 	//串列埠初始化為115200
    usmart_dev.init(72);		//初始化USMART
    LED_Init();		  			//初始化與LED連線的硬體介面
    KEY_Init();					//初始化按鍵
    //LCD_Init();			   	//初始化LCD
    usart3_init(115200);		//初始化串列埠3
    my_mem_init(SRAMIN);		//初始化內部記憶體池
    //LCD_Clear(BLACK);

    delay_ms(1000);
    // atk_8266_test();		//進入ATK_ESP8266測試
	
	ap_demo();
}

// AP模式測試
void ap_demo(void)
{
    u8 timex = 0;
	u8 netpro = 0;	//網路模式 0,TCP伺服器 1,TCP使用者端 2,UDP模式
	u8 key;
	u8 ipbuf[16] = "192.168.4.2"; 	//IP (根據你的裝置連上模組後分配到的IP填寫)
	u8 *p;
	u16 t = 999;		//加速第一次獲取連結狀態
	u16 rlen = 0;
	u8 constate = 0;	//連線狀態
    while(atk_8266_send_cmd("AT","OK",20))//檢查WIFI模組是否線上
    {
        atk_8266_quit_trans();//退出透傳
        atk_8266_send_cmd("AT+CIPMODE=0","OK",200);  //關閉透傳模式
        printf("未檢測到模組!!!\r\n");
        delay_ms(800);
        printf("嘗試連線模組...\r\n");
    }
    while(atk_8266_send_cmd("ATE0","OK",20));//關閉回顯
    printf("ATK_ESP8266 WIFI模組測試\r\n");
    printf("WIFI AP\r\n");
    atk_8266_msg_show(0, 0, 0);

    while(1)
    {
        delay_ms(10);
        atk_8266_at_response(1);//檢查ATK-ESP8266模組傳送過來的資料,及時上傳給電腦
        printf("ATK-ESP WIFI-AP 測試\r\n");
        printf("正在設定ATK-ESP8266模組,請稍等...\r\n");

        p=mymalloc(SRAMIN,32);							//申請32位元組記憶體

PRESTA:
        if(netpro&0X02)   //UDP
        {
            printf("ATK-ESP WIFI-AP 測試\r\n");
            printf("正在設定ATK-ESP模組,請稍等...\r\n");

            sprintf((char*)p,"AT+CIPSTART=\"UDP\",\"%s\",%s",ipbuf,(u8*)portnum);    //設定目標UDP伺服器
            atk_8266_send_cmd("AT+CIPMUX=0","OK",100);  //單連結模式
            while(atk_8266_send_cmd(p,"OK",500));
        }
        else     //TCP
        {
            if(netpro&0X01)     //TCP Client    透傳模式測試
            {
                printf("ATK-ESP WIFI-AP 測試\r\n");
                printf("正在設定ATK-ESP模組,請稍等...\r\n");
                atk_8266_send_cmd("AT+CIPMUX=0","OK",20);   //0:單連線,1:多連線
                sprintf((char*)p,"AT+CIPSTART=\"TCP\",\"%s\",%s",ipbuf,(u8*)portnum);    //設定目標TCP伺服器
                while(atk_8266_send_cmd(p,"OK",200))
                {
                    printf("WK_UP:返回重選");
                    printf("ATK-ESP 連線TCP Server失敗"); //連線失敗
                    key=KEY_Scan(0);
                    if(key==WKUP_PRES)goto PRESTA;
                }
                atk_8266_send_cmd("AT+CIPMODE=1","OK",200);      //傳輸模式為:透傳
            }
            else					//TCP Server
            {
                printf("ATK-ESP WIFI-AP 測試\r\n");
                printf("正在設定ATK-ESP模組,請稍等...\r\n");
                atk_8266_send_cmd("AT+CIPMUX=1","OK",20);   //0:單連線,1:多連線
                sprintf((char*)p,"AT+CIPSERVER=1,%s",(u8*)portnum);
                atk_8266_send_cmd(p,"OK",20);     //開啟Server模式,埠號為8086
            }
        }

        printf("設定ATK-ESP模組成功!\r\n");
        delay_ms(200);
        printf("WK_UP:退出測試  KEY0:傳送資料\r\n");
        atk_8266_get_wanip(ipbuf);//伺服器模式,獲取WAN IP
        sprintf((char*)p,"IP地址:%s 埠:%s",ipbuf,(u8*)portnum);
        printf("%s\r\n",p);				//顯示IP地址和埠
        atk_8266_wificonf_show(30,180,"請用裝置連線WIFI熱點:",(u8*)wifiap_ssid,(u8*)wifiap_encryption,(u8*)wifiap_password);
        printf("狀態:%s\r\n",(u8*)ATK_ESP8266_WORKMODE_TBL[netpro]); 		//連線狀態
        USART3_RX_STA=0;
        while(1)
        {
            key=KEY_Scan(0);
            if(key==WKUP_PRES)			//WK_UP 退出測試
            {
                atk_8266_quit_trans();	//退出透傳
                atk_8266_send_cmd("AT+CIPMODE=0","OK",20);   //關閉透傳模式
				myfree(SRAMIN,p);		//釋放記憶體
                return;
            }
            else if(key==KEY0_PRES)	//KEY0 傳送資料
            {

                if((netpro==3)||(netpro==2))   //UDP
                {
                    sprintf((char*)p,"ATK-8266%s測試%02d\r\n",ATK_ESP8266_WORKMODE_TBL[netpro],t/10);//測試資料
                    printf("傳送資料:%s\r\n",p);
                    atk_8266_send_cmd("AT+CIPSEND=25","OK",200);  //傳送指定長度的資料
                    delay_ms(200);
                    atk_8266_send_data(p,"OK",100);  //傳送指定長度的資料
                    timex=100;
                }
                else if((netpro==1))   //TCP Client
                {
                    atk_8266_quit_trans();
                    atk_8266_send_cmd("AT+CIPSEND","OK",20);       //開始透傳
                    sprintf((char*)p,"ATK-8266%s測試%02d\r\n",ATK_ESP8266_WORKMODE_TBL[netpro],t/10);//測試資料
                    printf("傳送資料:%s\r\n",p);
                    u3_printf("%s",p);
                    timex=100;
                }
                else    //TCP Server
                {
                    sprintf((char*)p,"ATK-8266%s測試%02d\r\n",ATK_ESP8266_WORKMODE_TBL[netpro],t/10);//測試資料
                    printf("傳送資料:%s\r\n",p);
                    atk_8266_send_cmd("AT+CIPSEND=0,25","OK",200);  //傳送指定長度的資料
                    delay_ms(200);
                    atk_8266_send_data(p,"OK",100);  //傳送指定長度的資料
                    timex=100;
                }
            }

            if(timex)timex--;

            t++;
            delay_ms(5);
            if(USART3_RX_STA&0X8000)		//接收到一次資料了
            {
                rlen=USART3_RX_STA&0X7FFF;	//得到本次接收到的資料長度
                USART3_RX_BUF[rlen]=0;		//新增結束符
                sprintf((char*)p,"收到%d位元組,內容如下",rlen);//接收到的位元組數
                printf("%s\r\n",p); 			//顯示接收到的資料長度
                printf("接收資料:%s\r\n",USART3_RX_BUF);//顯示接收到的資料
                USART3_RX_STA=0;
                if(constate!='+')t=1000;		//狀態為還未連線,立即更新連線狀態
                else t=0;                   //狀態為已經連線了,10秒後再檢查
            }
            if(t==1000)//連續10秒鐘沒有收到任何資料,檢查連線是不是還存在.
            {
                constate=atk_8266_consta_check();//得到連線狀態
                if(constate=='+')printf("連線成功\r\n");  //連線狀態
                else printf("連線失敗\r\n");
                t=0;
            }
            if((t%20)==0)LED0=!LED0;
            atk_8266_at_response(1);
        }
    }
}


參考用圖

在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述

在這裡插入圖片描述

拓展

STA模式

TCP伺服器端

準備2個手機,或者能產生wifi訊號的裝置。
一個手機開啟手機熱點,設定wifi資訊
在這裡插入圖片描述
另一個手機連線熱點,檢視詳細資訊,分配到的ip是 192.168.43.39
在這裡插入圖片描述
修改main.c,呼叫 atk_8266_test();

atk_8266_test();		//進入ATK_ESP8266測試
// ap_demo();

修改common.c,填寫新的STA模式的wifi資訊

//連線埠號:8086,可自行修改為其他埠.
const u8* portnum="8086";		 

//WIFI STA模式,設定要去連線的路由器無線引數,請根據你自己的路由器設定,自行修改.
const u8* wifista_ssid="ikaros";			//路由器SSID號
const u8* wifista_encryption="wpawpa2_aes";	//wpa/wpa2 aes加密方式
const u8* wifista_password="12345678"; 	//連線密碼

//WIFI AP模式,模組對外的無線引數,可自行修改.
const u8* wifiap_ssid="ATK-ESP8266";			//對外SSID號
const u8* wifiap_encryption="wpawpa2_aes";	//wpa/wpa2 aes加密方式
const u8* wifiap_password="12345678"; 		//連線密碼 

修改 wifista.catk_8266_wifista_test(void) ,IP改成另一個手機的IP(這裡給使用者端模式用的,暫時沒用)

u8 ipbuf[16] = "192.168.43.39"; 	// IP快取

程式重編,燒寫,開啟串列埠,看到提示按鍵
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述

TCP使用者端

這裡就用到上面說的ip了
修改 wifista.catk_8266_wifista_test(void) ,IP改成另一個手機的IP(這裡給使用者端模式用的,暫時沒用)

u8 ipbuf[16] = "192.168.43.39"; 	// IP快取

不重複贅述,直接上結果
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述