18-ESP8266 SDK开发基础入门篇--TCP 服务器 RTOS版,串口透传,TCP客户端控制LED
https://www.cnblogs.com/yangfengwu/p/11112015.html
?
先規定一下協議
aa 55 02 01 F1 4C 控制LED點亮 ?F1 4C為CRC高位和低位
aa 55 02 00 30 8C 控制LED熄滅 ?30 8C為CRC高位和低位
aa 55 03 ?占空比(四字節 高位在前,低位在后) CRC校驗高位,CRC校驗低位
?
預留一個問題 ?我用客戶端發送 aa 55 11 00 00 01 F4 ? ? WIFI接收到是 ?F4 01 00 00 00 01 F4?
aa 55 10 XX XX XX ?卻沒有問題 ?, 大家都沒有遇到過這種情況嗎???求解答
我認為是編碼問題
但是我嘗試了
?
?好幾個編碼都會有問題,而且我用了手頭的所有調試助手都是有問題..所以PWM先不做了,先做控制LED點亮和熄滅
?
?
改一下協議
00 01 70?C0 控制LED點亮 ?70 C0 ?為CRC高位和低位
00 00 B0 01?控制LED熄滅 ? B0?01 ?為CRC高位和低位
?
?
首先修改一個小小小bug ?,其實這節咱用不到,只不過測試的時候發現的問題...
?
?
?
現在實現一個功能 ?透傳(TCP客戶端發送的數據,TCP服務器接收以后直接轉發到串口;串口接收的數據TCP服務器直接發給TCP客戶端)
首先說一下哈,咱的發送也用一個任務來執行
不過呢這個發送任務一定要在什么時候創建呢???
客戶端連接以后為這個客戶端創建一個發送任務
?
?主要是避免,發送任務里面的變量別一進來其實是不存在的.......所以有了客戶端連接再創建這個任務
?
然后呢 ,還要解決一個問題,,假設客戶端掉線了,咱是不是應該刪除掉那個發送任務哈
所以
其實創建任務的時候最后一個變量,可以填這個變量
?
?然后刪除這個任務就是
?
?
?
?
其實和上一版程序沒啥大區別,也就是上面的區別
還有一個是,我把以前局部的變量設置成全局的了
?
?
?對了其實
這兩個一定是全局,因為我發送的時候用得到
?
?其實其它的就沒有什么了...(前提你把我前面的文章都學了)
/** ESPRSSIF MIT License** Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>** Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,* it is free of charge, to any person obtaining a copy of this software and associated* documentation files (the "Software"), to deal in the Software without restriction, including* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,* and/or sell copies of the Software, and to permit persons to whom the Software is furnished* to do so, subject to the following conditions:* * The above copyright notice and this permission notice shall be included in all copies or* substantial portions of the Software.* * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.**/#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"//typedef void (*UartCallback)(void);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模式配置 xTaskHandle xHandleTcpSendDate;//發送數據任務的句柄,我用來刪除發送任務用 err_t err;//接收操作所有API函數的時候返回的錯誤信息 struct netconn *conn, *newconn;//conn 保存自身TCP服務器的信息 newconn-保存連接客戶端的信息 int i = 0; struct pbuf *q;//用此變量來操作鏈表,可以看一下 https://www.cnblogs.com/yangfengwu/p/5778872.html u32 data_len =0;//獲取接收的數據個數 unsigned char TcpRead[1024]={0};//接收數據緩存的數組,最大接收1024字節 struct netbuf *recvbuf;//創建接收數據的結構體,這是lwip提供的緩存數據用的/******************************************************************************* 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()//定義一個函數 {}//發送數據任務 void TcpSendDateThread(void *date) {conn->send_timeout=5;//設置發送超時時間,一定要加,否則任務就阻塞住了while(1){if(Usart1ReadFlage)//串口接收到一條完整的數據 {Usart1ReadFlage = 0;err = netconn_write(newconn ,Usart1ReadBuff,Usart1ReadCntCopy ,NETCONN_COPY);//發送數據if(err != ERR_OK){//發送失敗 }}vTaskDelay(10/portTICK_RATE_MS);//如果沒有數據要發送會執行這個,一定要加這個任務延時哈 }vTaskDelete(NULL); }void TcpServerThread(void *date) {static ip_addr_t ipaddr;//存儲客戶端的地址static u16_t port;//存儲客戶端的端口號 conn = netconn_new(NETCONN_TCP);//創建一個TCP//注意哈,首先要明白你無論創建 TCP服務器或者客戶端,或者UDP,你創建的時候必須設置下TCP服務器或者客戶端,或者UDP的IP地址和端口號.//網絡之間通信嘛,這是必須的,只有你有IP和端口號了,別人才能和你通信netconn_bind(conn,IP_ADDR_ANY,8888); //設置conn(TCP服務器) 的IP地址是自己網卡上的IP 設置TCP服務器通信的端口號是8888 (無論創建 TCP服務器或者客戶端,或者UDP,都是必須的) netconn_listen(conn); //使用監聽函數,說明是創建TCP服務器,只有作為服務器才是監聽客戶端連接嘛//設置任務阻塞時間為10ms (注意哈,這個和vTaskDelay(10/portTICK_RATE_MS)類似,但是一定要用這個//下面的netconn_accept(conn,&newconn);函數是完全阻塞的,,如果你不設置conn->recv_timeout 程序就停止在那里了,除非有客戶端連接conn->recv_timeout=5;//任務延時5mswhile(1){err = netconn_accept(conn,&newconn);//等待客戶端連接,有客戶機連接,或者超時了就會往下執行if (err == ERR_OK)//只有客戶機連接了,并且沒有其它錯誤才會進入 {netconn_getaddr(newconn,&ipaddr,&port,0); //得到客戶端的IP地址和端口號 最后一個參數 1獲取本地IP地址,0獲取遠程IP地址//打印客戶端的IP地址printf("ClientIP:%d.%d.%d.%d Connected\n",(uint8_t)(ipaddr.addr),(uint8_t)(ipaddr.addr >> 8),(uint8_t)(ipaddr.addr >> 16),(uint8_t)(ipaddr.addr >> 24));printf("Port:%d\n",port);//打印客戶端的端口號 xTaskCreate(TcpSendDateThread, "TcpSendDateThread", 1024, NULL, 9, &xHandleTcpSendDate);//創建發送數據任務while(1)//一直在這個里面接收處理數據 {err = netconn_recv(newconn,&recvbuf);//如果一直接受不到數據或者不是其它錯誤信息,不會往下執行if(err== ERR_OK)//接收到客戶端發過來的數據 {taskENTER_CRITICAL();//關閉中斷,禁止其它任務打斷,防止讀數據出現錯誤 data_len = 0;for( q = recvbuf->p; q != NULL; q = q->next ) //遍歷完整個pbuf鏈表 {//判斷要拷貝到緩存數組中的數據是否大于緩存數組的剩余空間,如果大于//的話就只拷貝緩存數組中剩余長度的數據,否則的話就拷貝所有的數據if( q->len > ( 1024-data_len ) )memcpy(TcpRead+data_len,q->payload,(1024-data_len));//拷貝數據elsememcpy( TcpRead+data_len, q->payload, q->len );data_len += q->len;if(data_len > 1024)//超出TCP客戶端接收數組,跳出break;}taskEXIT_CRITICAL();//打開中斷for(i=0;i<data_len;i++){USART_SendData(UART0, TcpRead[i]);//接收的數據發給串口 }}else if(err == ERR_CLSD) //客戶端斷開連接 {vTaskDelete(xHandleTcpSendDate);//刪除發送數據任務netconn_close(newconn);//關閉連接netconn_delete(newconn);//刪除連接printf("ClientIP:%d.%d.%d.%d Disconnected\n",(uint8_t)(ipaddr.addr),(uint8_t)(ipaddr.addr >> 8),(uint8_t)(ipaddr.addr >> 16),(uint8_t)(ipaddr.addr >> 24));break;//退出 }}}else{conn->recv_timeout=10;//任務延時10ms }}vTaskDelete(NULL); }void LedThread(void *date) {while(1){vTaskDelay(1000/portTICK_RATE_MS);GPIO_OUTPUT_SET(2,1-GPIO_INPUT_GET(2));}vTaskDelete(NULL); }/******************************************************************************* 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);//讓兩個燈初始的狀態一樣,GOIO2是反接的,0的時候是亮 // GPIO_OUTPUT_SET(5, 0); uart_init_new();printf("SDK version:%s\n", system_get_sdk_version()); // printf("Ai-Thinker Technology Co. Ltd.\r\n%s %s\r\n", __DATE__, __TIME__); // printf("Hello,World!\r\n"); // xTaskCreate(LedControl, "LedControl", 1024, NULL, 11, NULL);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//下面的函數大家點進去一看注釋就明白了 // espconn_init();//"espconn.h" 195行 // TcpServer.type = ESPCONN_TCP; //創建TCP // TcpServer.state = ESPCONN_NONE; //一開始的狀態 // TcpServer.proto.tcp = &esptcp; //設置TCP的IP和回調函數存儲用 // TcpServer.proto.tcp->local_port = 8888;//監聽的端口號 // espconn_regist_connectcb(&TcpServer, TcpServerListen);//注冊 // espconn_accept(&TcpServer);//啟動監聽UartCallbackRegister(UartReadCallback);//把 UartReadCallback 函數地址傳過去,在串口里面調用 xTaskCreate(TcpServerThread, "TcpServerThread", 1024, NULL, 8, NULL);xTaskCreate(LedThread, "LedThread", 1024, NULL, 11, NULL); }?
測試
? ? ? ?
?
?
?
?
?現在寫控制燈亮滅的程序
00 01?70?C0?控制LED點亮 ?70 C0 ?為CRC高位和低位
00 00?B0 01?控制LED熄滅 ? B0?01 ?為CRC高位和低位
?
最簡單的
?
?
// 00 01 70 C0 控制LED點亮 70 C0 為CRC高位和低位 // 00 00 B0 01 控制LED熄滅 B0 01 為CRC高位和低位if(TcpRead[0] == 0){if(TcpRead[1] == 0x01 && TcpRead[2] == 0x70 && TcpRead[3] == 0xC0 )//控制LED點亮 {GPIO_OUTPUT_SET(5,1);}else if(TcpRead[1] == 0x00 && TcpRead[2] == 0xB0 && TcpRead[3] == 0x01 )//控制LED熄滅 {GPIO_OUTPUT_SET(5,0);}}?
測試
?
?
?
?
?
?
?
?
?好下節咱做C# TCP客戶端,控制LED
?
說一下哈 ?那個CRC咱先不上菜...咱先簡簡單單的學
我給大家了一個計算工具
?
?
?
?
https://www.cnblogs.com/yangfengwu/p/11192594.html
?
轉載于:https://www.cnblogs.com/yangfengwu/p/11130428.html
總結
以上是生活随笔為你收集整理的18-ESP8266 SDK开发基础入门篇--TCP 服务器 RTOS版,串口透传,TCP客户端控制LED的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 10个绕过反病毒的恶意用户技巧
- 下一篇: PowerDesigner15在win7