1.簡介:
在2019年夏季的全國大學生電子設計大賽中,我們組選擇了電磁炮這個題目, 並且確定方案爲STM32+OPENMV4(串口通訊),但當時苦於沒有一個好的通信協議(畢竟當時還是小白~),只能選擇了按位讀取的辦法,但在玩ESP8266這麼久後突然想到各種物聯網接入貌似都是用JSON來傳輸數據的,於是我便想到用各種方式來發送JSON數據(TCP、串口、IIC、UDP、各種你能想到的通信方式~),我們只需要解決Json的數據解析工作即可,令人高興的是,Arduino方面我們有ArduinoJson庫,STM32方面keil5也提供了官方的JSON庫——Jansson,就算是其他單片機平臺,也不要怕,我們還有開源C++編寫的cJSON庫,我們只需要簡單移植,就可以讓你的單片機使用JSON。
2.硬件:
兩個連接了0.96寸OLED的ESP8266開發板;
3.開發平臺:
Arduino (1.8.10) 或 VScode 環境下 PlatformIO 插件
4.需要的庫:
U8g2 :https://github.com/olikraus/U8g2_Arduino
ArduinoJson V5版本:https://github.com/bblanchon/ArduinoJson.git
5.實驗代碼:
5.1 TCPClient端(負責JSON接收及解析):
/**
* @功能 兩塊ESP8266通過TCP發送Json消息並解析
* @author 劉澤文
* @date 2020/4/13
* @TCP Client客戶端
*/
#include <ESP8266WiFi.h>
#include <ArduinoJson.h>
#include <U8g2lib.h>
#include <Wire.h>
//以下三個定義爲調試定義
#define DebugBegin(baud_rate) Serial.begin(baud_rate)
#define DebugPrintln(message) Serial.println(message)
#define DebugPrint(message) Serial.print(message)
#define DebugPrintf(message) Serial.printf(message)
#define LED D4
const char* ssid = "liuzewen";
const char* password = "17609245102liu";
const char* Server = "192.168.31.53";
const int Port = 23;
short Status = 0;
uint8_t apple[60];
WiFiClient client;
//定義OLED型號
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
void setup() {
DebugBegin(115200);
u8g2.begin();
u8g2.enableUTF8Print();
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_wqy16_t_gb2312);
u8g2.setCursor(40, 40);
u8g2.print("Json解析");
u8g2.sendBuffer();
pinMode(LED,OUTPUT);
digitalWrite(LED,LOW);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
DebugPrint("\nConnecting to ");
DebugPrintln(ssid);
uint8_t i = 0;
while (WiFi.status() != WL_CONNECTED && i++ < 20) {
delay(500);
DebugPrint(".");
}
if (i == 21) {
DebugPrint("Could not connect to");
DebugPrintln(ssid);
while (1) {
delay(500);
}
}
DebugPrint("Ready! Use 'telnet ");
DebugPrint(WiFi.localIP());
}
void loop() {
if(Status==0 && WiFi.status()==WL_CONNECTED)
{
Status=1;
client.connect(Server, Port);
DebugPrint("連接到服務器~");
}
while(client.available()){
digitalWrite(LED,!digitalRead(LED));
client.read(apple,60);
StaticJsonBuffer<200> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(apple);
if (!root.success()) {
Serial.println("parseObject() failed");
return;
}
const char* name = root["name"];
int rand = root["rand"];
double data = root["data"][0];
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_wqy16_t_gb2312);
u8g2.setCursor(40, 16*1-2);
u8g2.print("Json解析");
u8g2.setCursor(0, 16*2-2);
u8g2.print("name:");
u8g2.setCursor(40, 16*2-2);
u8g2.print(name);
u8g2.setCursor(0, 16*3-2);
u8g2.print("rand:");
u8g2.setCursor(40, 16*3-2);
u8g2.print(rand);
u8g2.setCursor(0, 16*4-2);
u8g2.print("data:");
u8g2.setCursor(40, 16*4-2);
u8g2.print(data);
u8g2.sendBuffer();
delay(200);
if(!client.status()){
DebugPrint("跳出循環");
Status = 0;
break;
}
}
}
5.2 TCPServer端(負責JSON打包及發送):
/**
* @功能 兩塊ESP8266通過TCP發送Json消息並解析
* @author 劉澤文
* @date 2020/4/13
* @TCP Server服務端
*/
#include <ESP8266WiFi.h>
#include <ArduinoJson.h>
#include <U8g2lib.h>
#include <Wire.h>
//定義最多多少個client可以連接本server(一般不要超過4個)
#define MAX_SRV_CLIENTS 2
//以下三個定義爲調試定義
#define DebugBegin(baud_rate) Serial.begin(baud_rate)
#define DebugPrintln(message) Serial.println(message)
#define DebugPrint(message) Serial.print(message)
#define DebugPrintf(message) Serial.printf(message)
#define LED D4
const char* ssid = "liuzewen";
const char* password = "17609245102liu";
//創建server 端口號是23
WiFiServer server(23);
//管理clients
WiFiClient serverClients[MAX_SRV_CLIENTS];
//定義OLED型號
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
long pushtime = 0;
void setup() {
DebugBegin(115200);
u8g2.begin();
u8g2.enableUTF8Print();
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_wqy16_t_gb2312);
u8g2.setCursor(40, 40);
u8g2.print("Json發送");
u8g2.sendBuffer();
pinMode(LED,OUTPUT);
digitalWrite(LED,LOW);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
DebugPrint("\nConnecting to ");
DebugPrintln(ssid);
uint8_t i = 0;
while (WiFi.status() != WL_CONNECTED && i++ < 30) {
digitalWrite(LED,!digitalRead(LED));
DebugPrint(".");
delay(500);
}
if (i == 21) {
DebugPrint("Could not connect to");
DebugPrintln(ssid);
while (1) {
delay(500);
}
}
//啓動server
server.begin();
//關閉小包合併包功能,不會延時發送數據
server.setNoDelay(true);
DebugPrint("Ready! Use 'telnet ");
DebugPrint(WiFi.localIP());
DebugPrintln(" 23' to connect");
pushtime = millis();
}
void loop() {
uint8_t i;
//檢測是否有新的client請求進來
if (server.hasClient()) {
for (i = 0; i < MAX_SRV_CLIENTS; i++) {
//釋放舊無效或者斷開的client
if (!serverClients[i] || !serverClients[i].connected()) {
if (serverClients[i]) {
serverClients[i].stop();
}
//分配最新的client
serverClients[i] = server.available();
DebugPrint("New client: ");
DebugPrint(i);
break;
}
}
//當達到最大連接數 無法釋放無效的client,需要拒絕連接
if (i == MAX_SRV_CLIENTS) {
WiFiClient serverClient = server.available();
serverClient.stop();
DebugPrintln("Connection rejected ");
}
}
//檢測client發過來的數據
for (i = 0; i < MAX_SRV_CLIENTS; i++) {
if (serverClients[i] && serverClients[i].connected()) {
if (serverClients[i].available()) {
//get data from the telnet client and push it to the UART
while (serverClients[i].available()) {
//發送到串口調試器
Serial.write(serverClients[i].read());
}
}
}
}
if (Serial.available()) {
//把串口調試器發過來的數據 發送給client
size_t len = Serial.available();
uint8_t sbuf[len];
Serial.readBytes(sbuf, len);
//給每個Client客戶端發送數據
for (i = 0; i < MAX_SRV_CLIENTS; i++) {
if (serverClients[i] && serverClients[i].connected()) {
serverClients[i].write(sbuf, len);
delay(1);
}
}
}
if(millis()-pushtime >= 500){
digitalWrite(LED,!digitalRead(LED));
pushtime = millis();
int num = rand() % 130;
// Json對象對象樹的內存工具 靜態buffer
// 200 是大小 如果這個Json對象更加複雜,那麼就需要根據需要去增加這個值.
StaticJsonBuffer<256> jsonBuffer;
char json[60];
// StaticJsonBuffer 在棧區分配內存 它也可以被 DynamicJsonBuffer(內存在堆區分配) 代替
// DynamicJsonBuffer jsonBuffer;
//創建最外層的json對象 —— root對象,頂節點
JsonObject& root = jsonBuffer.createObject();
//給最外層json對象添加屬性
root["name"] = "liuzewen";
root["rand"] = num;
//在root對象中加入data數組
JsonArray& data = root.createNestedArray("data");
data.add(48.756080);
data.add(2.302038);
//root.printTo(server);
//root.printTo(serverClients[0]);
root.printTo(Serial);
DebugPrintln();
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_wqy16_t_gb2312);
u8g2.setCursor(40, 16*1-2);
u8g2.print("Json發送");
u8g2.setCursor(0, 16*2-2);
u8g2.print("name:");
u8g2.setCursor(40, 16*2-2);
u8g2.print("liuzewen");
u8g2.setCursor(0, 16*3-2);
u8g2.print("rand:");
u8g2.setCursor(40, 16*3-2);
u8g2.print(num);
u8g2.setCursor(0, 16*4-2);
u8g2.print("date:");
u8g2.setCursor(40, 16*4-2);
u8g2.print("48.756080");
u8g2.sendBuffer();
sprintf(json, "{\"name\":\"liuzewen\",\"rand\":%d,\"data\":[48.756080,2.302038]}",num);
int len = sizeof(json);
//Serial.printf("緩存大小是:%d",sizeof("{\"name\":\"liuzewen\",\"rand\":200,\"data\":[48.756080,2.302038]}"));
//給每個Client客戶端發送數據
for (i = 0; i < MAX_SRV_CLIENTS; i++) {
if (serverClients[i] && serverClients[i].connected()) {
serverClients[i].write(json, len);
//root.printTo(serverClients[i]);
delay(1);
}
}
}
}
6.實驗效果: