TCP/IP(Transmission Control Protocol/Internet Protocol,傳輸控制協(xié)議/網(wǎng)際協(xié)議)是指能夠在多個不同網(wǎng)絡(luò)間實現(xiàn)信息傳輸?shù)膮f(xié)議簇。TCP/IP協(xié)議不僅僅指的是TCP 和IP兩個協(xié)議,而是指一個由FTP、SMTP、TCP、UDP、IP等協(xié)議構(gòu)成的協(xié)議簇,只是因為在TCP/IP協(xié)議中TCP協(xié)議和IP協(xié)議最具代表性,所以被稱為TCP/IP協(xié)議。
TCP可以分為服務(wù)端(TCP Server)和客戶端(TCP Client),服務(wù)端就相當于一個服務(wù)器,可以允許接入多個客戶端接入,接入之后相互之間就可以通過TCP協(xié)議進行數(shù)據(jù)傳輸。
關(guān)于TCP具體的原理介紹就不細說了,本文主要講解Arduino環(huán)境下怎么使用TCP來實現(xiàn)一個無線網(wǎng)絡(luò)的數(shù)據(jù)傳輸。
我們的MCU(esp8266或者esp32)可以作為服務(wù)端,也可以作為客戶端,看具體的需求來選。這里只講解PC端作為服務(wù)端,MCU這邊作為客戶端的情況。其他情況舉一反三即可。
本文主要實現(xiàn)的功能如下:
1 硬件簡介
我這里以ESP8266和ESP32為例講解,實際上根據(jù)自己的MCU選擇一種即可,方法和原理都是一樣的。
硬件配置如下:
模塊 | 型號 | 說明 |
---|---|---|
ESP8266 | ESP-12F | 這是安信可的一款模組,內(nèi)部主要是用樂鑫的ESP8266EX再加上一個片外FLASH組成,開發(fā)板型號是NodeMCU-12F(CH340版本) |
ESP32 | ESP-WROOM-32 | MCU是樂鑫的一款芯片,開發(fā)板型號ESP32 DEVKITV1 |
具體的硬件參數(shù)和電路原理圖這里就不發(fā)出來了,不同廠家做的開發(fā)板引腳可能會有點差別。
2 Arduino環(huán)境搭建
關(guān)于Arduino的環(huán)境搭建大家應(yīng)該都懂,這里就不多贅述了,不懂的同學可以參考一下我之前發(fā)的博客。
esp8266開發(fā)入門教程(基于Arduino)——環(huán)境安裝
使用VS code搭建Arduino IDE環(huán)境
3 建立TCP Server
在PC端測試的時候我們可以使用網(wǎng)絡(luò)調(diào)試工具來建立一個服務(wù)端,網(wǎng)絡(luò)調(diào)試工具網(wǎng)上都有很多,我比較習慣用NetAssist和sscom,sscom是串口和TCP一體的,既可以調(diào)試串口又可以調(diào)試網(wǎng)絡(luò),這個還是挺方便的,所以我這里就以sscom為例來講解吧。
當然了,用這種方式建立的服務(wù)器是有限制的,只有同一局域網(wǎng)下的設(shè)備能連上這個服務(wù)器,如果你有公網(wǎng)服務(wù)器那就最好了,可以不受限與局域網(wǎng)。
找不到工具的同學可以到我網(wǎng)盤上下載。
網(wǎng)盤鏈接:https://pan.baidu.com/s/1cATkEnPX1iIX9U64wrflsw
提取碼:1ysz
1)打開sscom,配置端口參數(shù)
參數(shù) | 值 |
---|---|
端口號 | TCPServer |
遠程 | 不用配置 |
本地 | 選擇自己的電腦的本地IP地址,端口任意,如:192.168.43.128, 1234 |
提示:不知道IP地址的可以在網(wǎng)絡(luò)適配器查找。
2)點擊 “偵聽”,然后等待client接入
如果有設(shè)備連接上,會有提示信息。
當然了,現(xiàn)在這里肯定不會有這個信息,因為我們的設(shè)備還沒有配置WIFI和TCP client,等后面我們把代碼燒錄進去就能連上了。
4 編寫代碼并運行測試
在Arduino IDE的ESP8266和ESP32開發(fā)板庫里面其實都有TCP相關(guān)的示例代碼,我在這個示例的基礎(chǔ)上做了一點修改,增加了串口和TCP的數(shù)據(jù)互傳。
ESP8266和ESP32的庫是不同的,但是TCP相關(guān)庫函數(shù)的基本用法是一樣的,我這個示例代碼做了ESP8266和ESP32的兼容,可以通用。
ESP8266和ESP32 TCP測試示例代碼如下:
/*
This sketch establishes a TCP connection to a "quote of the day" service.
It sends a "hello" message, and then prints received data.
*/
#ifdef ESP8266
#include <ESP8266WiFi.h> // esp8266
#else
#include <WiFi.h> // esp32
#endif
#ifndef STASSID
#define STASSID "mate40"
#define STAPSK "123456789"
#endif
const char* ssid = STASSID;
const char* password = STAPSK;
const char* host = "192.168.43.128";
const uint16_t port = 1234;
void setup() {
Serial.begin(115200);
// We start by connecting to a WiFi network
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
/* Explicitly set the ESP8266 or ESP32 to be a WiFi-client, otherwise, it by default,
would try to act as both a client and an access-point and could cause
network-issues with your other WiFi-devices on your WiFi-network. */
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void loop() {
static bool wait = false;
Serial.print("connecting to ");
Serial.print(host);
Serial.print(':');
Serial.println(port);
// Use WiFiClient class to create TCP connections
WiFiClient client;
if (!client.connect(host, port)) {
Serial.println("connection failed");
delay(5000);
return;
}
// This will send a string to the server
Serial.println("sending data to server");
if (client.connected()) {
client.println("hello from ESP8266");
}
#if 0
// wait for data to be available
unsigned long timeout = millis();
while (client.available() == 0) {
if (millis() - timeout > 5000) {
Serial.println(">>> Client Timeout !");
client.stop();
delay(60000);
return;
}
}
#endif
// Read all the lines of the reply from server and print them to Serial
Serial.println("receiving from remote server");
while (client.connected() || client.available() || Serial.available()) {
while (Serial.available()) {
char data;
data = Serial.read();
if (client.connected()) {
client.print(data);
}
}
while (client.available()) {
char ch = static_cast<char>(client.read());
Serial.print(ch);
}
}
#if 1
// Close the connection
Serial.println();
Serial.println("closing connection");
client.stop();
#endif
if (wait) {
delay(300000); // execute once every 5 minutes, don't flood remote service
}
wait = true;
}
注意:示例代碼里面有幾個地方需要根據(jù)自己的實際情況修改之后才能正常使用。還有電腦和設(shè)備(esp8266或esp32)要在同一個局域網(wǎng)下,不懂什么是局域網(wǎng)的話可以把電腦和設(shè)備連接到同一個WIFI下。
參數(shù) | 值 |
---|---|
STASSID | 你的WIFI名稱,示例:“test” |
STAPSK | 你的WIFI密碼,示例:“12345678” |
host | 服務(wù)器地址,也就是你建立TCP Server時設(shè)置的IP地址,示例:“192.168.43.128” |
port | 服務(wù)器端口,也就是你建立TCP Server時設(shè)置的端口,示例:1234 |
esp8266運行測試如下:
連接esp8266的串口,方便打印設(shè)備運行的信息,這樣就可以更好的看到TCP連接的情況。
打開TCP Server,等待設(shè)備連接,如果這個時候MCU已經(jīng)連上了WIFI并且可以訪問到這個服務(wù)端的話,就能連接上。
TCP成功連接之后,就可以互發(fā)數(shù)據(jù)了。esp8266會將串口接收到的數(shù)據(jù)轉(zhuǎn)發(fā)到TCP Server,TPC Server發(fā)送過來的數(shù)據(jù)轉(zhuǎn)發(fā)到串口發(fā)送給PC端。
esp32運行測試如下:
esp32的運行結(jié)果和esp8266是完全一樣的。
結(jié)束語
好了,關(guān)于Arduino TCP/IP的編程和使用方法就講到這里。因為時間的關(guān)系,我沒有做TCP數(shù)據(jù)傳輸速度的測試,以后有時間的話再補上吧(如果還記得的話?