In einem anderen Artikel schrieb ich [Korrigieren der Anzeige der 16x8-LED-Matrix]. Wenn Sie mit dieser LED-Matrix eine Anfrage zur Nachrichtenanzeige von Linux senden, erstellen wir ein Arduino, das die Nachricht scrollt und eine Antwort zurückgibt. Der Punkt dieses Artikels ist "Empfangen von Anfragen und asynchrones Anzeigen von Nachrichten in Arduino (genau genommen pseudoasynchron)".
Was zu verwenden.
usb 1-12: new full-speed USB device number 3 using xhci_hcd
usb 1-12: New USB device found, idVendor=0403, idProduct=6001
usb 1-12: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 1-12: Product: FT232R USB UART
usb 1-12: Manufacturer: FTDI
usb 1-12: SerialNumber: ALxxxxxx
usbcore: registered new interface driver usbserial_generic
usbserial: USB Serial support registered for generic
usbcore: registered new interface driver ftdi_sio
usbserial: USB Serial support registered for FTDI USB Serial Device
ftdi_sio 1-12:1.0: FTDI USB Serial Device converter detected
usb 1-12: Detected FT232RL
usb 1-12: FTDI USB Serial Device converter now attached to ttyUSB0
usb 1-6: new full-speed USB device number 4 using xhci_hcd
usb 1-6: New USB device found, idVendor=2341, idProduct=0058
usb 1-6: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 1-6: Product: Arduino Nano Every
usb 1-6: Manufacturer: Arduino LLC
usb 1-6: SerialNumber: FAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
cdc_acm 1-6:1.0: ttyACM0: USB ACM device
usbcore: registered new interface driver cdc_acm
cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters
serial_test.ino
#include <Wire.h>
void setup()
{
Wire.begin();
Serial.begin(115200);
Serial.println("serial test");
}
void loop()
{
String str;
if(Serial.available()>0) {
str = Serial.readString();
Serial.println("[" + str + "]");
}
}
screen Funktionsprüfung mit
$ screen /dev/ttyUSB0 115200
serial test
hogehoge
[hogehoge]
Wenn Sie eine Anfrage von Linux an arduino übergeben, wird eine Antwort zurückgegeben, wenn der Inhalt ausgeführt wird. Implementieren Sie vorerst die folgenden Funktionen als Ausgangspunkt. Daten werden in JSON übergeben.
Funktion | request | response |
---|---|---|
Bildlaufanzeige | {"textscr":"hello world !"} | {"status":200, "msg":"..."} |
Arduino Gesundheitscheck | {"status":{}} | {"status":200, "msg":"..."} |
Unten finden Sie einen Auszug aus dem Hauptcode von Arduino
test.ino
int sendResponse(int status, String msg) {
StaticJsonDocument<100> response;
response["status"] = status;
response["msg"] = msg;
serializeJson(response, Serial);
Serial.println();
}
int ExecCmd(String cmd, JsonVariant value) {
if(cmd == "status") {
sendResponse(100, "alive");
} else if(cmd == "textscr") {
JsonObject obj2 = value.as<JsonObject>();
String msg = obj2["msg"];
int size = obj2["size"];
if(size < 1 || size > 2) {
size = 1;
}
matrix.setTextSize(size);
matrix.setTextWrap(false);
matrix.setTextColor(LED_ON);
int l = msg.length();
for(int16_t x = 7; x >= -6*l; x--) {
matrix.clear();
matrix.setCursor(x,0);
matrix.print(msg);
matrix.writeDisplay();
delay(100);
}
sendResponse(200, "msg:" + msg + ",size:" + (String)size);
} else { // "status" : 404
sendResponse(404, "command not found:" + cmd);
}
}
StaticJsonDocument<200> request;
void loop() {
if(Serial.available() > 0) {
DeserializationError error = deserializeJson(request, Serial);
if (error) {
sendResponse(500, error.c_str());
return;
}
JsonObject obj = request.as<JsonObject>();
for (JsonPair p : obj) {
ExecCmd((String)p.key().c_str(), p.value());
}
}
}
test.ino
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_LEDBackpack.h>
#include <ArduinoJson.h>
#ifndef _swap_int16_t
#define _swap_int16_t(a, b) { int16_t t = a; a = b; b = t; }
#endif
class aitendo_KLED1608K33D_8x16matrix : public Adafruit_LEDBackpack, public Adafruit_GFX {
public:
aitendo_KLED1608K33D_8x16matrix(void);
void drawPixel(int16_t x, int16_t y, uint16_t color);
private:
};
aitendo_KLED1608K33D_8x16matrix::aitendo_KLED1608K33D_8x16matrix(void) : Adafruit_GFX(16, 8) {
}
void aitendo_KLED1608K33D_8x16matrix::drawPixel(int16_t x, int16_t y, uint16_t color) {
if ((y < 0) || (x < 0)) return;
if ((getRotation() % 2 == 0) && ((x >= 16) || (y >= 8))) return;
if ((getRotation() % 2 == 1) && ((y >= 16) || (x >= 8))) return;
// check rotation, move pixel around if necessary
switch (getRotation()) {
case 0:
if (x >= 8) {
x -= 8;
y += 8;
}
break;
case 1:
y = 16 - y - 1;
if(y >= 8) {
y -= 8;
x += 8;
}
_swap_int16_t(x, y);
break;
case 2:
x = 16 - x - 1;
y = 8 - y - 1;
if (x >= 8) {
x -= 8;
y += 8;
}
break;
case 3:
x = 8 - x - 1;
if(y >= 8) {
y -= 8;
x += 8;
}
_swap_int16_t(x, y);
break;
}
if (color) {
displaybuffer[x] |= 1 << y;
} else {
displaybuffer[x] &= ~(1 << y);
}
}
aitendo_KLED1608K33D_8x16matrix matrix = aitendo_KLED1608K33D_8x16matrix();
void setup() {
Serial.begin(115200);
Serial.println("16x8 LED Matrix");
matrix.begin(0x70);
matrix.setBrightness(5);
matrix.setRotation(0);
matrix.clear();
matrix.writeDisplay();
}
int sendResponse(int status, String msg) {
StaticJsonDocument<100> response;
response["status"] = status;
response["msg"] = msg;
serializeJson(response, Serial);
Serial.println();
}
int ExecCmd(String cmd, JsonVariant value) {
if(cmd == "status") {
sendResponse(100, "alive");
} else if(cmd == "textscr") {
JsonObject obj2 = value.as<JsonObject>();
String msg = obj2["msg"];
int size = obj2["size"];
if(size < 1 || size > 2) {
size = 1;
}
matrix.setTextSize(size);
matrix.setTextWrap(false);
matrix.setTextColor(LED_ON);
int l = msg.length();
for(int16_t x = 7; x >= -6*l; x--) {
matrix.clear();
matrix.setCursor(x,0);
matrix.print(msg);
matrix.writeDisplay();
delay(100);
}
sendResponse(200, "msg:" + msg + ",size:" + (String)size);
} else { // "status" : 404
sendResponse(404, "command not found:" + cmd);
}
}
StaticJsonDocument<200> request;
void loop() {
if(Serial.available() > 0) {
DeserializationError error = deserializeJson(request, Serial);
if (error) {
sendResponse(500, error.c_str());
return;
}
JsonObject obj = request.as<JsonObject>();
for (JsonPair p : obj) {
ExecCmd((String)p.key().c_str(), p.value());
}
}
}
Unten ist der Linux-Seitencode Zuerst habe ich endlich die USB-Verbindung zwischen der Linux-Box und Arduino überprüft, aber hier verwende ich Ubuntu, die Testumgebung des Windows Linux-Subsystems.
test.py
import serial
import time
import json
s = serial.Serial()
s.port = "/dev/ttyS4" #Stellen Sie eine Verbindung zu COM4 Arduino her
s.baudrate = 115200
s.timeout = 1
s.dtr = False #Verhindert, dass Arduino beim seriellen Verbinden zurückgesetzt wird
s.open()
time.sleep(1) #Warten Sie auf Gefühle
s.reset_input_buffer() #Reinigen des Empfangspuffers der seriellen Schnittstelle
def request(data):
print("request:", data)
s.write(json.dumps(data).encode()) # encode()Muss eine binäre Zeichenfolge sein
while True: #Warten Sie, bis die Antwort zurückkommt
msg = s.readline().decode()
if(len(msg) > 0):
print("response:", msg)
break
request({"textscr" : {"msg":"Hello World !!!"}})
request({"status" : {}})
Ausführungsergebnis Es ist richtig, dass die Antwort der Anfrage "textscr" {"status": 200, "msg": Hello World !!! "} lautet, aber es scheint, dass das erste Zeichen zu diesem Zeitpunkt verschüttet wurde. Berücksichtigen Sie die Fehlerbehandlung. Ist es?
Wie Sie dem Ausführungsergebnis entnehmen können, wird die Antwort erst zurückgegeben, wenn die Textscr-Anzeige abgeschlossen ist und ein anderer Befehl während des Wartens nicht akzeptiert wird. Es ist etwas schwierig zu handhaben. Der Textscroll auf der Arduino-Seite verwendet eine for-Schleife, um 100 ms auf die Anzeige von Zeichen zu warten und diese dann horizontal um 1 Punkt zu verschieben. Jedes Mal, wenn der Text um 1 Punkt verschoben wird, wird der Vorgang an loop () zurückgegeben und der nächste Schritt wird gescrollt. Ermöglicht den Empfang von Befehlen. Wenn während des Bildlaufs ein neuer Text gesendet wird, wird die vorhandene Anzeigeausführung verworfen und überschrieben.
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_LEDBackpack.h>
#include <ArduinoJson.h>
#ifndef _swap_int16_t
#define _swap_int16_t(a, b) { int16_t t = a; a = b; b = t; }
#endif
class aitendo_KLED1608K33D_8x16matrix : public Adafruit_LEDBackpack, public Adafruit_GFX {
public:
aitendo_KLED1608K33D_8x16matrix(void);
void drawPixel(int16_t x, int16_t y, uint16_t color);
private:
};
aitendo_KLED1608K33D_8x16matrix::aitendo_KLED1608K33D_8x16matrix(void) : Adafruit_GFX(16, 8) {
}
void aitendo_KLED1608K33D_8x16matrix::drawPixel(int16_t x, int16_t y, uint16_t color) {
if ((y < 0) || (x < 0)) return;
if ((getRotation() % 2 == 0) && ((x >= 16) || (y >= 8))) return;
if ((getRotation() % 2 == 1) && ((y >= 16) || (x >= 8))) return;
// check rotation, move pixel around if necessary
switch (getRotation()) {
case 0:
if (x >= 8) {
x -= 8;
y += 8;
}
break;
case 1:
y = 16 - y - 1;
if(y >= 8) {
y -= 8;
x += 8;
}
_swap_int16_t(x, y);
break;
case 2:
x = 16 - x - 1;
y = 8 - y - 1;
if (x >= 8) {
x -= 8;
y += 8;
}
break;
case 3:
x = 8 - x - 1;
if(y >= 8) {
y -= 8;
x += 8;
}
_swap_int16_t(x, y);
break;
}
if (color) {
displaybuffer[x] |= 1 << y;
} else {
displaybuffer[x] &= ~(1 << y);
}
}
aitendo_KLED1608K33D_8x16matrix matrix = aitendo_KLED1608K33D_8x16matrix();
#define DR_UNRELATED 0
#define DR_STOP 1
#define DR_OVERRIDE 2
#define DR_NEW 10
#define DR_CONTINUE 11
typedef struct {
const char *cmd;
int (*drawfunc)(int, JsonVariant);
} Cmds;
Cmds *drawing;
void setup() {
drawing = NULL;
Serial.begin(115200);
Serial.println("16x8 LED Matrix");
matrix.begin(0x70);
matrix.setBrightness(5);
matrix.setRotation(0);
matrix.clear();
matrix.writeDisplay();
}
int sendResponse(int status, String msg) {
StaticJsonDocument<100> response;
response["status"] = status;
response["msg"] = msg;
serializeJson(response, Serial);
Serial.println();
}
int cmdStatus(int stat, JsonVariant value) {
sendResponse((drawing ? 102 : 100), (drawing ? "drawing" : "free time"));
return(DR_UNRELATED);
}
int cmdTextscr(int stat, JsonVariant value) {
static String sMsg;
static int16_t l, x;
if(stat == DR_NEW) {
JsonObject obj = value.as<JsonObject>();
String msg = obj["msg"];
sMsg = msg;
l = msg.length();
x = 7;
matrix.setTextSize(1);
matrix.setTextWrap(false);
matrix.setTextColor(LED_ON);
}
if(x >= -6*l) {
matrix.clear();
matrix.setCursor(x,0);
matrix.print(sMsg);
matrix.writeDisplay();
delay(100);
x--;
} else {
//sendResponse(200, "finish textscr msg:" + msg);
return(DR_STOP);
}
if(stat == DR_NEW) {
sendResponse(200, "textscr msg:" + sMsg);
return(DR_OVERRIDE);
}
return(DR_UNRELATED);
}
Cmds cmds[] = {
{"status", cmdStatus},
{"textscr", cmdTextscr},
{"", NULL},
};
StaticJsonDocument<200> request;
JsonVariant JVNULL = JsonVariant();
void loop() {
if(Serial.available() > 0) {
DeserializationError error = deserializeJson(request, Serial);
if (error) {
sendResponse(500, error.c_str());
return;
}
JsonObject obj = request.as<JsonObject>();
for (JsonPair p : obj) {
String cmd = (String)p.key().c_str();
int i;
for(i = 0; cmds[i].cmd != ""; i++) {
if((String)cmds[i].cmd == cmd) {
int r = (*cmds[i].drawfunc)(DR_NEW, p.value());
switch(r) {
case DR_OVERRIDE:
drawing = &cmds[i];
break;
case DR_STOP:
drawing = NULL;
break;
}
break;
}
}
if(cmds[i].cmd == "") {
sendResponse(404, "command not found:" + cmd);
}
}
} else {
if(drawing) {
int r = drawing->drawfunc(DR_CONTINUE, JVNULL);
switch(r) {
case DR_STOP:
drawing = NULL;
break;
}
}
}
}
Auszug unten.
test2.ino
#define DR_UNRELATED 0 //Wird zurückgegeben, wenn die cmdxxxx-Verarbeitung andere laufende Anforderungen nicht überschreibt
#define DR_STOP 1 //Wird zurückgegeben, wenn die Verarbeitung von cmdxxxx abgeschlossen ist
#define DR_OVERRIDE 2 //Wird zurückgegeben, wenn die cmdxxxx-Verarbeitung eine andere laufende Anforderung überschreibt
#define DR_NEW 10 //Übergeben Sie es an cmdxxxx, wenn eine neue Anforderung eingeht
#define DR_CONTINUE 11 //Bestanden beim Aufruf von cmdxxxx in der nachfolgenden Verarbeitung
int cmdStatus(int stat, JsonVariant value) {
...
}
int cmdTextscr(int stat, JsonVariant value) {
...
}
typedef struct {
const char *cmd;
int (*drawfunc)(int, JsonVariant);
} Cmds;
Cmds *drawing;
Cmds cmds[] = {
{"status", cmdStatus},
{"textscr", cmdTextscr},
{"", NULL},
};
void loop() {
if(Serial.available() > 0) {
...
for (JsonPair p : obj) {
String cmd = (String)p.key().c_str(); //Speichern Sie die empfangene Anforderungszeichenfolge in cmd
int i;
for(i = 0; cmds[i].cmd != ""; i++) { //cmds, die mit cmd übereinstimmen[]Schleife, um Mitglieder zu finden und anzurufen
if((String)cmds[i].cmd == cmd) {
int r = (*cmds[i].drawfunc)(DR_NEW, p.value());
switch(r) {
case DR_OVERRIDE:
drawing = &cmds[i]; //Denken Sie an die Funktion, die Sie gerade aufgerufen haben, da sie weiterhin verarbeitet wird.
break;
case DR_STOP:
drawing = NULL; //Die Funktion, die ich gerade aufgerufen habe, ist abgeschlossen, sodass es keine Funktion gibt, mit der die Verarbeitung fortgesetzt werden kann
break;
}
break;
}
}
...
}
} else {
if(drawing) { //Wenn eine Anforderungsfunktion ausgeführt wird, rufen Sie diese Funktion auf
int r = drawing->drawfunc(DR_CONTINUE, JVNULL);
...
}
}
}
Auf der Linux-Seite müssen Sie jetzt nicht mehr nach dem Senden einer Anfrage warten, sondern können jederzeit eine Anfrage senden.
test2.py
import serial
import time
import datetime
import json
s = serial.Serial()
s.port = "/dev/ttyS4"
s.baudrate = 115200
s.timeout = 1
s.dtr = False #Verhindert, dass Arduino beim seriellen Verbinden zurückgesetzt wird
s.open()
time.sleep(1) #Warten Sie auf Gefühle
s.reset_input_buffer() #Reinigen des Empfangspuffers der seriellen Schnittstelle
def request(data):
print(datetime.datetime.now().strftime('%H:%M:%S'), "request:", data)
s.write(json.dumps(data).encode()) # encode()Muss eine binäre Zeichenfolge sein
while True: #Warten Sie, bis die Antwort zurückkommt
msg = s.readline().decode()
if(len(msg) > 0):
print(datetime.datetime.now().strftime('%H:%M:%S' ), "response:", msg)
break
request({"textscr" : {"msg":"Hello World !!!"}})
time.sleep(3)
request({"status" : {}})
time.sleep(1)
request({"textscr" : {"msg":"\\(^_^)/"}})
time.sleep(6)
request({"status" : {}})
test2.py Ausführungsergebnis
ubuntu:~$ python3 test.py
00:25:39 request: {'textscr': {'msg': 'Hello World !!!'}}
00:25:39 response: {"status":200,"msg":"textscr msg:Hello World !!!"}
00:25:42 request: {'status': {}}
00:25:42 response: {"status":102,"msg":"drawing"}
00:25:43 request: {'textscr': {'msg': '\\(^_^)/'}}
00:25:43 response: {"status":200,"msg":"textscr msg:\\(^_^)/"}
00:25:49 request: {'status': {}}
00:25:49 response: {"status":100,"msg":"free time"}
Die Zeit wird vor der Anfrage und Antwort hinzugefügt, um das Verständnis zu erleichtern. Sobald Sie mit dem Scrollen beginnen, wird eine Antwort zurückgegeben und eine neue Anforderung ausgeführt, wenn Sie während des Bildlaufs eine weitere Textanforderung senden. Perfekt. Ende.
Recommended Posts