https://www.cnblogs.com/yangfengwu/p/11427504.html
SmartConfig/Airkiss 配網需要APP/微信公眾號,這節大家先使用我做好的APP/微信公眾號
APP下載:
https://www.cnblogs.com/yangfengwu/p/11249674.html
微信公眾號: 掃描這個二維碼關注我的公眾號
其余的步驟等寫完8266的配網程序,在下面演示.
如果想自己實現微信綁定可以看↓ (注:配置過程和源碼全部是公開的,大家看文章即可實現)
如果你已經有做網頁的經驗了,可以直接
如果你沒有做過網頁,你需要先看
然后需要把微信小程序篇的所有章節從頭到尾看一遍
現在開始寫WIFI的配網程序
其實官方給了例子
咱把例子寫個單獨的.C和.H文件,方便咱后期使用
smart_config.c
#include "esp_common.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "lwip/sockets.h" #include "lwip/dns.h" #include "lwip/netdb.h" #include "espressif/espconn.h" #include "espressif/airkiss.h" #define server_ip "192.168.101.142" #define server_port 9669 #define DEVICE_TYPE "gh_9e2cff3dfa51" //wechat public number #define DEVICE_ID "122475" //model ID #define DEFAULT_LAN_PORT 12476 LOCAL esp_udp ssdp_udp; LOCAL struct espconn pssdpudpconn; LOCAL os_timer_t ssdp_time_serv; uint8 lan_buf[200]; uint16 lan_buf_len; uint8 udp_sent_cnt = 0; const airkiss_config_t akconf = { (airkiss_memset_fn)&memset, (airkiss_memcpy_fn)&memcpy, (airkiss_memcmp_fn)&memcmp, 0, }; LOCAL void ICACHE_FLASH_ATTR airkiss_wifilan_time_callback(void) { uint16 i; airkiss_lan_ret_t ret; if ((udp_sent_cnt++) >30) { udp_sent_cnt = 0; os_timer_disarm(&ssdp_time_serv);//s //return; } ssdp_udp.remote_port = DEFAULT_LAN_PORT; ssdp_udp.remote_ip[0] = 255; ssdp_udp.remote_ip[1] = 255; ssdp_udp.remote_ip[2] = 255; ssdp_udp.remote_ip[3] = 255; lan_buf_len = sizeof(lan_buf); ret = airkiss_lan_pack(AIRKISS_LAN_SSDP_NOTIFY_CMD, DEVICE_TYPE, DEVICE_ID, 0, 0, lan_buf, &lan_buf_len, &akconf); if (ret != AIRKISS_LAN_PAKE_READY) { os_printf("Pack lan packet error!"); return; } ret = espconn_sendto(&pssdpudpconn, lan_buf, lan_buf_len); if (ret != 0) { os_printf("UDP send error!"); } os_printf("Finish send notify!\n"); } LOCAL void ICACHE_FLASH_ATTR airkiss_wifilan_recv_callbk(void *arg, char *pdata, unsigned short len) { uint16 i; remot_info* pcon_info = NULL; airkiss_lan_ret_t ret = airkiss_lan_recv(pdata, len, &akconf); airkiss_lan_ret_t packret; switch (ret){ case AIRKISS_LAN_SSDP_REQ: espconn_get_connection_info(&pssdpudpconn, &pcon_info, 0); os_printf("remote ip: %d.%d.%d.%d \r\n",pcon_info->remote_ip[0],pcon_info->remote_ip[1], pcon_info->remote_ip[2],pcon_info->remote_ip[3]); os_printf("remote port: %d \r\n",pcon_info->remote_port); pssdpudpconn.proto.udp->remote_port = pcon_info->remote_port; memcpy(pssdpudpconn.proto.udp->remote_ip,pcon_info->remote_ip,4); ssdp_udp.remote_port = DEFAULT_LAN_PORT; lan_buf_len = sizeof(lan_buf); packret = airkiss_lan_pack(AIRKISS_LAN_SSDP_RESP_CMD, DEVICE_TYPE, DEVICE_ID, 0, 0, lan_buf, &lan_buf_len, &akconf); if (packret != AIRKISS_LAN_PAKE_READY) { os_printf("Pack lan packet error!"); return; } os_printf("\r\n\r\n"); for (i=0; i<lan_buf_len; i++) os_printf("%c",lan_buf[i]); os_printf("\r\n\r\n"); packret = espconn_sendto(&pssdpudpconn, lan_buf, lan_buf_len); if (packret != 0) { os_printf("LAN UDP Send err!"); } break; default: os_printf("Pack is not ssdq req!%d\r\n",ret); break; } } void ICACHE_FLASH_ATTR airkiss_start_discover(void) { ssdp_udp.local_port = DEFAULT_LAN_PORT; pssdpudpconn.type = ESPCONN_UDP; pssdpudpconn.proto.udp = &(ssdp_udp); espconn_regist_recvcb(&pssdpudpconn, airkiss_wifilan_recv_callbk); espconn_create(&pssdpudpconn); os_timer_disarm(&ssdp_time_serv); os_timer_setfn(&ssdp_time_serv, (os_timer_func_t *)airkiss_wifilan_time_callback, NULL); os_timer_arm(&ssdp_time_serv, 1000, 1);//1s } void ICACHE_FLASH_ATTR smartconfig_done(sc_status status, void *pdata) { switch(status) { case SC_STATUS_WAIT: printf("SC_STATUS_WAIT\n"); break; case SC_STATUS_FIND_CHANNEL: printf("SC_STATUS_FIND_CHANNEL\n"); break; case SC_STATUS_GETTING_SSID_PSWD: printf("SC_STATUS_GETTING_SSID_PSWD\n"); sc_type *type = pdata; if (*type == SC_TYPE_ESPTOUCH) { printf("SC_TYPE:SC_TYPE_ESPTOUCH\n"); } else { printf("SC_TYPE:SC_TYPE_AIRKISS\n"); } break; case SC_STATUS_LINK: printf("SC_STATUS_LINK\n"); struct station_config *sta_conf = pdata; wifi_station_set_config(sta_conf); wifi_station_disconnect(); wifi_station_connect(); break; case SC_STATUS_LINK_OVER: printf("SC_STATUS_LINK_OVER\n"); if (pdata != NULL) { //SC_TYPE_ESPTOUCH uint8 phone_ip[4] = {0}; memcpy(phone_ip, (uint8*)pdata, 4); printf("Phone ip: %d.%d.%d.%d\n",phone_ip[0],phone_ip[1],phone_ip[2],phone_ip[3]); } else { //SC_TYPE_AIRKISS - support airkiss v2.0 airkiss_start_discover(); } smartconfig_stop(); break; } } void ICACHE_FLASH_ATTR smartconfig_task(void *pvParameters) { smartconfig_start(smartconfig_done); vTaskDelete(NULL); }
smart_config.h
#ifndef APP_INCLUDE_SMART_CONFIG_H_ #define APP_INCLUDE_SMART_CONFIG_H_ void smartconfig_task(void *pvParameters); #endif /* APP_INCLUDE_SMART_CONFIG_H_ */
然后主函數
wifi_station_disconnect(); wifi_set_event_handler_cb(wifi_event_monitor_handle_event_cb); wifi_set_opmode(STATION_MODE); smartconfig_set_type(SC_TYPE_ESPTOUCH_AIRKISS);//SmartConfig + AirKiss xTaskCreate(smartconfig_task, "smartconfig_task", 256, NULL, 2, NULL);
現在是模塊一啟動就進去配網...
編譯出錯
加上 -lairkiss\
下載進去,咱先測試下
SmartConfig:
下載完WIFI的程序,復位下WIFI
這個APP是我做的一個面向開發使用的,該APP源碼獲取方式: https://www.cnblogs.com/yangfengwu/p/11249674.html
AirKiss : 關注我的這個測試用的公眾號
復位WIFI模塊
好,現在優化下
按下固件按鈕(GPIO0)大約3S, 讓GPIO2那個燈快閃,進入配網模式,然后60S超時檢測.還有就是不讓WIFI打印官方內部寫的東西(打印的東西太多了...)
#include "esp_common.h" #include "gpio.h" #include "uart.h" #include "esp_timer.h" #include "hw_timer.h" #include "pwm.h" #include "data_dispose.h" #include "espconn.h" #include "esp_wifi.h" #include "lwip/api.h" #include "crc.h" #include "smart_config.h" LOCAL os_timer_t public_timer;//定時器 u32 public_timer_cnt=0;//累加 u32 public_timer_state=0;//狀態 u32 public_timer_out=0;//超時 u32 public_timer_cnt1=0;//累加 extern u8 Usart1ReadBuff[Usart1ReadLen];//接收數據的數組 extern u32 Usart1ReadCnt;//串口1接收到的數據個數 extern u32 Usart1ReadCntCopy;//串口1接收到的數據個數拷貝 extern u8 Usart1ReadFlage;//串口1接收到一條完整數據 #define SSID "Learn8266" //無線名稱 #define PWD "11223344" //密碼 struct softap_config soft_ap_Config;//AP模式配置 ResolveData ResolveDataTest;//解析數據IEEE754 //uint32 pin_info_list[1][3]={PERIPHS_IO_MUX_GPIO5_U,FUNC_GPIO5,5};//配置GPIO5作為PWM輸出 //int duty[1]={0};//高電平時間是0us /****************************************************************************** * FunctionName : user_rf_cal_sector_set * Description : SDK just reversed 4 sectors, used for rf init data and paramters. * We add this function to force users to set rf cal sector, since * we don't know which sector is free in user's application. * sector map for last several sectors : ABCCC * A : rf cal * B : rf init data * C : sdk parameters * Parameters : none * Returns : rf cal sector *******************************************************************************/ uint32 user_rf_cal_sector_set(void) { flash_size_map size_map = system_get_flash_size_map(); uint32 rf_cal_sec = 0; switch (size_map) { case FLASH_SIZE_4M_MAP_256_256: rf_cal_sec = 128 - 5; break; case FLASH_SIZE_8M_MAP_512_512: rf_cal_sec = 256 - 5; break; case FLASH_SIZE_16M_MAP_512_512: case FLASH_SIZE_16M_MAP_1024_1024: rf_cal_sec = 512 - 5; break; case FLASH_SIZE_32M_MAP_512_512: case FLASH_SIZE_32M_MAP_1024_1024: rf_cal_sec = 1024 - 5; break; default: rf_cal_sec = 0; break; } return rf_cal_sec; } //串口調用此函數就說明接收到了一條完整的數據,就可以去處理了 void UartReadCallback()//定義一個函數 { } static void wifi_event_monitor_handle_event_cb(System_Event_t *evt) { switch (evt->event_id) { case EVENT_STAMODE_CONNECTED://連接上路由器 printf("\n\tSTAMODE_CONNECTED\n"); printf("\tConnected to SSID %s, Channel %d\n", evt->event_info.connected.ssid, evt->event_info.connected.channel); break; case EVENT_STAMODE_DISCONNECTED://和路由器斷開 printf("\n\tSTAMODE_DISCONNECTED\n"); printf("\tDisconnect from SSID %s, reason %d\n", evt->event_info.disconnected.ssid, evt->event_info.disconnected.reason); break; case EVENT_STAMODE_AUTHMODE_CHANGE://這個是 啥.. printf("\n\tSTAMODE_AUTHMODE_CHANGE\n"); printf("\tAuthmode: %u -> %u\n", evt->event_info.auth_change.old_mode, evt->event_info.auth_change.new_mode); break; case EVENT_STAMODE_GOT_IP://連接上路由器,並獲取了IP printf("\n\tGOT_IP\n"); printf("\tIP:" IPSTR ",Mask:" IPSTR ",GW:" IPSTR "\n", IP2STR(&evt->event_info.got_ip.ip), IP2STR(&evt->event_info.got_ip.mask), IP2STR(&evt->event_info.got_ip.gw)); break; case EVENT_STAMODE_DHCP_TIMEOUT://連接上路由器,但是路由器給WIFI模塊分配IP等信息超時了 printf("\n\tSTAMODE_DHCP_TIMEOUT\n"); break; case EVENT_SOFTAPMODE_STACONNECTED://AP模式下,有設備連接WIFI模塊的無線 printf("\n\tSOFTAPMODE_STACONNECTED\n"); printf("\tStation: " MACSTR "join, AID = %d\n", MAC2STR(evt->event_info.sta_connected.mac), evt->event_info.sta_connected.aid); break; case EVENT_SOFTAPMODE_STADISCONNECTED://AP模式下,有設備斷開和WIFI模塊的無線連接 printf("\n\tSOFTAPMODE_STADISCONNECTED\n"); printf("\tstation: " MACSTR "leave, AID = %d\n", MAC2STR(evt->event_info.sta_disconnected.mac), evt->event_info.sta_disconnected.aid); break; case EVENT_SOFTAPMODE_PROBEREQRECVED://這是啥??,,,信號強度改變了 printf("\n\tSOFTAPMODE_PROBEREQRECVED\n"); printf("Station PROBEREQ: " MACSTR " RSSI = %d\n", MAC2STR(evt->event_info.ap_probereqrecved.mac), evt->event_info.ap_probereqrecved.rssi); break; default://其它錯誤 printf("\n\tswitch/case default\n"); break; } } //所有需要定時操作的函數在此函數中執行 LOCAL void ICACHE_FLASH_ATTR public_timer_callback(void) { if(GPIO_INPUT_GET(0) == 0)//按鍵按下 { public_timer_cnt++; if(public_timer_cnt>=300 && public_timer_state==0)//3S { printf("\nstartsmart\n"); public_timer_state=1; wifi_station_disconnect(); wifi_set_opmode(STATION_MODE); smartconfig_set_type(SC_TYPE_ESPTOUCH_AIRKISS);//SmartConfig + AirKiss xTaskCreate(smartconfig_task, "smartconfig_task", 256, NULL, 2, NULL); } } else { if(public_timer_state!=1 && public_timer_cnt>0 && public_timer_cnt<300)//短按復位 { printf("\nsystem_restart\n"); system_restart();//復位 } public_timer_cnt=0; } switch(public_timer_state) { case 0:break; case 1: public_timer_out++; public_timer_cnt1++; if(public_timer_out>=6000)//60S配網超時 { printf("\nsmartconfig_timeout\n"); system_restart();//復位 } if(public_timer_cnt1>10)//LED快閃 { public_timer_cnt1=0; GPIO_OUTPUT_SET(2, 1-GPIO_INPUT_GET(2));//LED快閃 } break; default:break; } } /****************************************************************************** * FunctionName : user_init * Description : entry of user application, init user function here * Parameters : none * Returns : none *******************************************************************************/ void user_init(void) { GPIO_OUTPUT_SET(5, 1); GPIO_OUTPUT_SET(2, 0); GPIO_OUTPUT_SET(0, 1); uart_init_new(); printf("SDK version:%s\n", system_get_sdk_version()); wifi_set_opmode(STATIONAP_MODE);//配置WiFi的模式STATION + AP AP--連接WIFI自身的無線實現通信 STATION--wifi連接路由器,手機或者電腦也連接路由器,實現通信 soft_ap_Config.ssid_len = strlen(SSID);//熱點名稱長度,與你實際的名稱長度一致就好 memcpy(soft_ap_Config.ssid,SSID,soft_ap_Config.ssid_len);//實際熱點名稱設置,可以根據你的需要來 memcpy(soft_ap_Config.password,PWD,strlen(PWD));//熱點密碼設置 soft_ap_Config.authmode = AUTH_WPA2_PSK;//加密模式 soft_ap_Config.channel = 1;//信道,共支持1~13個信道 soft_ap_Config.max_connection = 4;//最大連接數量,最大支持四個,默認四個 wifi_softap_set_config_current(&soft_ap_Config);//設置 Wi-Fi SoftAP 接口配置,不保存到 Flash // wifi_softap_set_config(&soft_ap_Config);//設置 Wi-Fi SoftAP 接口配置,保存到 Flash UartCallbackRegister(UartReadCallback);//把 UartReadCallback 函數地址傳過去,在串口里面調用 os_timer_disarm(&public_timer); os_timer_setfn(&public_timer, (os_timer_func_t *)public_timer_callback, NULL); os_timer_arm(&public_timer, 10, 1);//10ms wifi_set_event_handler_cb(wifi_event_monitor_handle_event_cb); }
然后還有兩個地方,無論是SmartConfig 還是 Airkiss 配網,配完網以后都重啟下
好,測試
按下大約3S,指示燈快閃
軟件就不截圖了,按照上面的步驟操作
SmartConfig 打印的信息
Airkiss 打印的信息
startsmart ------------------------------------------ state: 5 -> 0 (0) rm 0 bcn 0 del if1 mode : sta(68:c6:3a:d6:62:54) STAMODE_DISCONNECTED Disconnect from SSID qqqqq, reason 8 SC version: V2.5.4 scandone scandone SC_STATUS_FIND_CHANNEL TYPE: AIRKISS T|AP MAC: 34 96 72 16 9e 42 SC_STATUS_GETTING_SSID_PSWD SC_TYPE:SC_TYPE_AIRKISS ------------------------------------------------------ T|pswd : 11223344 T|ssid : qqqqq SC_STATUS_LINK scandone state: 0 -> 2 (b0) state: 2 -> 3 (0) state: 3 -> 5 (10) add 0 aid 1 pm open phy_2,type:2 0 0 cnt connected with qqqqq, channel 11 dhcp client start... STAMODE_CONNECTED Connected to SSID qqqqq, Channel 11 ip:192.168.0.100,mask:255.255.255.0,gw:192.168.0.1 GOT_IP IP:192.168.0.100,Mask:255.255.255.0,GW:192.168.0.1 SC_STATUS_LINK_OVER Finish send notify! ets Jan 8 2013,rst cause:2, boot mode:(3,6) 配網以后重啟 load 0x40100000, len 2408, room 16 tail 8 chksum 0xe5 load 0x3ffe8000, len 776, room 0 tail 8 chksum 0x84 load 0x3ffe8310, len 632, room 0 tail 8 chksum 0xd8 csum 0xd8 2nd boot version : 1.6 SPI Speed : 40MHz SPI Mode : DIO SPI Flash Size & Map: 32Mbit(512KB+512KB) jump to run user1 @ 1000 ?;?榗専銓#l腸{|$#溿?b|?鞄囙c瀦o飥ng?宭'?弻d寧l$屇d屼?$ ?n?倪銊cdd噞p劅銓bl刢?$s$勩?僩鋼{凔'|?ll$l`?;n?噲噑og済?鋭湝滀青?cc'o?c|?;so搇膁`c們g???sr'n躱?鋵湝??#bgo?#靸;so??l?'???{soo躱?鋵溰?c#gn?#|?;{g搇膁`肧DK version:1.5.0-dev(950076a) mode : sta(68:c6:3a:d6:62:54) + softAP(6a:c6:3a:d6:62:54) add if0 dhcp server start:(ip:192.168.4.1,mask:255.255.255.0,gw:192.168.4.1) add if1 bcn 100 scandone state: 0 -> 2 (b0) state: 2 -> 3 (0) state: 3 -> 5 (10) add 0 aid 1 cnt connected with qqqqq, channel 11 自動連接路由器 dhcp client start... STAMODE_CONNECTED Connected to SSID qqqqq, Channel 11 ip:192.168.0.100,mask:255.255.255.0,gw:192.168.0.1 GOT_IP IP:192.168.0.100,Mask:255.255.255.0,GW:192.168.0.1
好現在,不讓調試信息通過usart0打印
這個設置以后 printf就不會通過uart0打印了 ,會用uart1(GPIO2) 打印......
這個不強求哈!!!大家不修改也可以,我只是不希望讓系統一直打印各種信息,我擔心后面和單片機做通信的時候會出問題!
當然大家也可以直接用 USART_SendData(uint8 uart, uint8 TxChar) 發送數據,我只不過是封裝成可以用printf形式
還記得咱前面的某一節咱自己寫的printf不,不過呢,咱直接用lua源碼里面寫的,因為我寫的那個太占內存.....
把這部分代碼放到 uart.c 里面
static void kprintn (void (*)(const char), uint32_t, int, int, char); static void kdoprnt (void (*)(const char), const char *, va_list); void dbg_printf(const char *fmt, ...) { va_list ap; va_start(ap, fmt); kdoprnt(uart0_write_char, fmt, ap); va_end(ap); } void dbg_vprintf(const char *fmt, va_list ap) { kdoprnt(uart0_write_char, fmt, ap); } void kdoprnt(void (*put)(const char), const char *fmt, va_list ap) { register char *p; register int ch, n; unsigned long ul; int lflag, set; char zwidth; char width; for (;;) { while ((ch = *fmt++) != '%') { if (ch == '\0') return; put(ch); } lflag = 0; width = 0; zwidth = ' '; reswitch: switch (ch = *fmt++) { case '\0': /* XXX print the last format character? */ return; case 'l': lflag = 1; goto reswitch; case 'c': ch = va_arg(ap, int); put(ch & 0x7f); break; case 's': p = va_arg(ap, char *); if (p == 0) { p = "<null>"; } while ((ch = *p++)) put(ch); break; case 'd': ul = lflag ? va_arg(ap, long) : va_arg(ap, int); if ((long)ul < 0) { put('-'); ul = -(long)ul; } kprintn(put, ul, 10, width, zwidth); break; case 'o': ul = lflag ? va_arg(ap, uint32_t) : va_arg(ap, uint32_t); kprintn(put, ul, 8, width, zwidth); break; case 'u': ul = lflag ? va_arg(ap, uint32_t) : va_arg(ap, uint32_t); kprintn(put, ul, 10, width, zwidth); break; case 'x': ul = lflag ? va_arg(ap, uint32_t) : va_arg(ap, uint32_t); kprintn(put, ul, 16, width, zwidth); break; default: if (ch >= '0' && ch <= '9') { if (ch == '0' && width == 0 && zwidth == ' ') { zwidth = '0'; } else { width = width * 10 + ch - '0'; } goto reswitch; } put('%'); if (lflag) put('l'); put(ch); } } va_end(ap); } static void kprintn(void (*put)(const char), uint32_t ul, int base, int width, char padchar) { /* hold a long in base 8 */ char *p, buf[(sizeof(long) * 8 / 3) + 2]; p = buf; do { *p++ = "0123456789abcdef"[ul % base]; } while (ul /= base); while (p - buf < width--) { put(padchar); } do { put(*--p); } while (p > buf); }
需要修改一個地方
然后全部替換為
就可以實現printf的方式了
如果大家嫌麻煩也可以不用復制粘貼那部分
直接用 uart0_write_char()
現在只是模塊一開始啟動的時候打印些自身的信息,后期的都是打印的咱自己寫的
如果大家不希望打印信號強度
可以
好了,又完成一節