Wenn es um das Einbetten geht, wird es häufig durch serielle Kommunikation getestet. Wenn Sie Ihr eigenes IoT-Gerät herstellen, gibt es keine Shell, sodass ein einfacher serieller Monitor ins Spiel kommt.
Wäre in diesem Fall der Standard TeraTerm? Makros sind ebenfalls erheblich.
Wenn ich jedoch das serielle Ergebnis verarbeiten oder das Ergebnis in CSV konvertieren möchte, möchte ich Python oder etwas anderes verwenden (in meinem Fall ist es nur eine Frage der Vertrautheit, nicht welches besser ist). Ich denke, dass die Verwendung von pyserial wahrscheinlich der Königsweg ist.
Aber,
Es fühlt sich seltsam an, in Java gefangen zu sein (was?). In einem anderen Fall habe ich mit Python und C gespielt, also habe ich diesmal versucht, die serielle Kommunikation durch Anwenden zu realisieren. Erstellen Sie den seriellen Kommunikationsteil mit DLL und greifen Sie über ctypes darauf zu. Dies ist ausreichend für einen langsamen Nachrichtenaustausch, z. B. integriert.
Ich hoffe, es wird hilfreich sein, wie man Windows-spezifische Steuerelemente von Python verwendet.
Überprüfen Sie unten. Da es sich um einen Prototyp handelt, möchte ich Ihnen vergeben.
Das Tutorial ist unten http://starship.python.net/crew/theller/ctypes/tutorial.html
Ich denke, dass DLLs mit Visual C ++ auf normale Weise codiert werden können. Auf der anderen Seite benötigt die Python-Seite etwas Einfallsreichtum, und es ist notwendig, Funktionen mithilfe von ctypes zu definieren. Ich denke jedoch, dass es schneller ist, sich das obige Tutorial und den tatsächlichen Code anzusehen, sodass ich den Code sofort verfügbar machen werde.
Unten ist der Code auf der DLL-Seite.
#include "stdafx.h"
#include "stdio.h"
#include "windows.h"
#define DLL_API __declspec(dllexport)
#define WCHAR_PORT_NUMBER_BUF_LENGTH (16 * 2)
#define SERIAL_BUFFER_SIZE (1024)
extern "C" DLL_API INT32 __stdcall SERIAL_open(char *port, INT32 baud);
extern "C" DLL_API char * __stdcall SERIAL_read(void *len);
extern "C" DLL_API INT32 __stdcall SERIAL_write(char *text, INT32 len);
extern "C" DLL_API void __stdcall SERIAL_close(void);
static HANDLE SERIAL_handle = NULL;
static char SERIAL_recv[SERIAL_BUFFER_SIZE + 1];
DLL_API INT32 __stdcall SERIAL_open(char *port, INT32 baud)
{
TCHAR tcPort[WCHAR_PORT_NUMBER_BUF_LENGTH];
DCB comDcb;
BOOL success;
INT32 ret = 0;
COMMTIMEOUTS comTimeouts;
memset(tcPort, 0, 32);
MultiByteToWideChar(CP_OEMCP,
MB_PRECOMPOSED,
port,
strlen(port),
tcPort,
WCHAR_PORT_NUMBER_BUF_LENGTH / 2);
SERIAL_handle = CreateFile(tcPort, GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, 0, NULL);
if (SERIAL_handle == INVALID_HANDLE_VALUE) {
return -1;
}
success = SetupComm(SERIAL_handle, SERIAL_BUFFER_SIZE, SERIAL_BUFFER_SIZE);
if (success == FALSE)
{
ret = -2;
goto error;
}
memset(&comDcb, 0, sizeof(DCB));
comDcb.DCBlength = sizeof(DCB);
comDcb.BaudRate = baud;
comDcb.fParity = FALSE;
comDcb.Parity = NOPARITY;
comDcb.ByteSize = 8;
comDcb.StopBits = ONESTOPBIT;
success = SetCommState(SERIAL_handle, &comDcb);
if (success == FALSE) {
ret = -3;
goto error;
}
memset(&comTimeouts, 0, sizeof(COMMTIMEOUTS));
comTimeouts.ReadIntervalTimeout = 500;
comTimeouts.ReadTotalTimeoutMultiplier = 0;
comTimeouts.ReadTotalTimeoutConstant = 500;
comTimeouts.WriteTotalTimeoutMultiplier = 0;
comTimeouts.WriteTotalTimeoutConstant = 500;
success = SetCommTimeouts(SERIAL_handle, &comTimeouts);
if (success == FALSE)
{
ret = -4;
goto error;
}
success = PurgeComm(SERIAL_handle, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
if (success == FALSE)
{
ret = -5;
goto error;
}
return 0;
error:
CloseHandle(SERIAL_handle);
return ret;
}
DLL_API char * __stdcall SERIAL_read(void *len)
{
BOOL success;
DWORD recvLen = 0;
INT32 *lenToPython = (INT32 *)len;
success = ReadFile(SERIAL_handle, SERIAL_recv, SERIAL_BUFFER_SIZE, &recvLen, NULL);
if (success == FALSE || recvLen == 0) {
*lenToPython = 0;
return "";
}
*lenToPython = (INT32)recvLen;
SERIAL_recv[recvLen] = '\0';
return SERIAL_recv;
}
DLL_API INT32 __stdcall SERIAL_write(char *text, INT32 len)
{
BOOL success;
DWORD dummy = 0;
success = WriteFile(SERIAL_handle, text, strlen(text), &dummy, NULL);
if (success == TRUE)
{
return 0;
}
else {
return -1;
}
}
DLL_API void __stdcall SERIAL_close(void)
{
if (SERIAL_handle == NULL) {
return;
}
CloseHandle(SERIAL_handle);
}
Die folgenden vier Funktionen sind vorbereitet. Es ist sehr einfach.
//Hafen offen, Hafen="COMxx"Baud ist bps. Der Rückgabewert ist 0 für Erfolg und negativ für Fehler
INT32 SERIAL_open(char *port, INT32 baud)
//Daten lesen. Beim Aufruf enthält len die Anzahl der gelesenen Bytes und char die empfangenen Daten.
//Mit einer Zeitüberschreitung von 500 ms*len=Es kann 0 sein.
char * SERIAL_read(void *len)
//Daten schreiben. Die Textzeichenfolge ist len Bytes (wie Sie dem Code entnehmen können, beträgt das Maximum 1024 Bytes)
INT32 SERIAL_write(char *text, INT32 len)
//Hafen geschlossen
void SERIAL_close(void)
Erstellen Sie diesen Code als DLL in Visual Studio. In diesem Fall sind folgende Punkte zu beachten.
Der eigentliche Code soll serielle Kommunikation gemäß dem Lehrbuch unter Verwendung der Win32-API sein (es tut mir eher leid, dass es sich um eine verschlechterte Version handelt). .. Wenn Sie mit erstellen, können Sie normal eine DLL erstellen. Ich werde die Python-Seite so schreiben, als würde ich nur diese DLL verwenden.
Die folgenden Websites waren beim Erstellen des Programms sehr hilfreich. http://www.geocities.co.jp/SiliconValley-SanJose/5309/serial.html http://www.ys-labo.com/BCB/2007/070512%20RS232C%20zenpan.html
Es ist die Python-Seite. Der Code der Klasse, die die serielle Kommunikation unter Verwendung der obigen DLL durchführt, wird unten gezeigt. Übrigens ist es der Code, wenn der Dateiname der DLL serial_if.dll lautet.
#!/usr/bin/env python
from ctypes import *
'''
Describe serial DLL's functions.
'''
dll = windll.serial_if
dll.SERIAL_open.argtype = (c_char_p, c_int)
dll.SERIAL_open.restype = c_int
dll.SERIAL_read.argtype = c_void_p
dll.SERIAL_read.restype = c_char_p
dll.SERIAL_write.argtype = (c_char_p, c_int)
dll.SERIAL_write.restype = c_int
'''
Serial Device Driver
'''
class SerialDriver:
def open(self, port, baud):
int_ret = dll.SERIAL_open(port, baud);
if int_ret == 0:
return True
else:
return False
def read(self):
read_len = c_int(0)
text = dll.SERIAL_read(byref(read_len))
return text, read_len.value
def write(self, text):
write_ret = dll.SERIAL_write(text, len(text))
if write_ret == 0:
return True
else:
return False
def close(self):
dll.SERIAL_close();
Beschreiben der Funktionen der seriellen DLL. In den Kommentar wird die Beschreibung für den Umgang mit der DLL geschrieben.
Dieses Mal haben wir die Beschreibung übernommen, die DLL mit windll verwendet. Legen Sie zu diesem Zeitpunkt zunächst den Namen der zu verwendenden DLL wie folgt fest.
dll = windll.serial_if
# windll.(DLL-Dateiname)Geben Sie die entsprechende DLL mit an. Das obige Beispiel ist seriell_if.Bedeutet dll
Definieren Sie als Nächstes die Argumente und den Rückgabewert jeder von der DLL exportierten Funktion anhand der Beschreibung der ctypes. Ich werde es im Vergleich mit der C-Funktion unten schreiben.
# INT32 SERIAL_open(char *port, INT32 baud);
dll.SERIAL_open.argtype = (c_char_p, c_int)
dll.SERIAL_open.restype = c_int
# char * SERIAL_read(void *len);
dll.SERIAL_read.argtype = c_void_p
dll.SERIAL_read.restype = c_char_p
# INT32 SERIAL_write(char *text, INT32 len);
dll.SERIAL_write.argtype = (c_char_p, c_int)
dll.SERIAL_write.restype = c_int
# void SERIAL_close(void);
#Keine Definition erforderlich, wenn keine Argumente oder Rückgabewerte vorhanden sind
Wenn Sie eine Person sind, die sowohl C als auch Python ausgeführt hat, können Sie die grundlegende Schreibmethode verstehen, indem Sie die oben genannten vergleichen. Tutorial ist hilfreich für den Umgang mit detaillierten Typen.
Danach können Sie die definierte Funktion normal aufrufen. Bitte beachten Sie Folgendes. Seien Sie besonders vorsichtig, wenn Sie mit einem Zeiger einen Wert von C erhalten.
Die obige SerialDriver-Klasse ruft eine DLL-Funktion auf, um eine serielle Kommunikation durchzuführen. Diejenigen, die diese Klasse verwenden, sind so implementiert, dass sie die c-Typen nicht kennen müssen.
In Bezug auf den Wert war die folgende Site des Stapelüberlaufs hilfreich. http://stackoverflow.com/questions/2330587/how-to-convert-ctypes-c-long-to-pythons-int
Das folgende Programm verwendet die SerialDriver-Klasse, um die eigentliche serielle Kommunikation durchzuführen und die seriell empfangenen Daten zu protokollieren. Dies basiert übrigens auf der Annahme, dass die SerialDriver-Klasse mit dem Dateinamen serial_lib.py geschrieben wurde (wie Sie anhand des Imports im folgenden Code sehen können).
#!/usr/bin/env python
from serial_lib import SerialDriver
from datetime import datetime
import sys
import time
def serial_read(serial, keyword):
text = ""
text_len = 0
while text.find(keyword) < 0:
read_text, read_len = serial.read()
if read_len > 0:
text_len += read_len
text += read_text
return text
def serial_test():
filename = datetime.now().strftime('%Y%m%d%H%M%S') + ".txt"
f = open(filename, "w")
serial = SerialDriver()
ret = serial.open("COM3", 115200)
print "python:SERIAL_open=" , ret
if ret == False:
sys.exit()
text = serial_read(serial,"teraterm command1")
print text
f.write(text)
text = "python response1\r\n"
serial.write(text)
text = serial_read(serial,"teraterm command2")
print text
f.write(text)
text = "python response2\r\n"
serial.write(text)
f.close()
serial.close()
if __name__ == "__main__":
serial_test()
print "python: complete"
#EOF
Außerdem habe ich diese Datei als serial_test.py geschrieben. Dies ist die Voraussetzung für die folgende Erklärung.
Wie Sie dem Code entnehmen können, besteht er aus den folgenden Funktionen.
--serial_test Hauptverarbeitung --serial_read Serielle Empfangsverarbeitung
Wie Sie anhand des DLL-Codes sehen können, kann das Empfangsergebnis 0 Byte betragen, da das Zeitlimit in 500 ms abläuft. Daher wird hier der Vorgang des weiteren Lesens ausgeführt, bis ein bestimmtes Schlüsselwort empfangen wurde (der Mechanismus ist also so, dass er nur entfernt werden kann, wenn dieses Schlüsselwort kommt. Für dieses w wurden keine Gegenmaßnahmen ergriffen).
Der Hauptprozess (serial_test-Funktion) wird gemäß dem folgenden Ablauf verarbeitet.
Abgesehen davon, wenn es COM10 oder höher ist, ist es oben unbrauchbar und Sie müssen es als \\. \ COM10 "beschreiben (MS-ähnliche Spezifikationen wie unten gezeigt) https://support.microsoft.com/ja-jp/help/115831/howto-specify-serial-ports-larger-than-com9
Die andere Partei der obigen Funktion serial_test wurde experimentell mit dem folgenden TeraTerm-Makro ausgeführt.
timeout=30
sendln 'teraterm command1'
wait 'python response1'
sendln 'teraterm command2'
Der Inhalt ist wie unten angegeben.
Es fühlt sich an, als würde man miteinander kommunizieren.
Der Test wurde wie folgt durchgeführt.
Auf diese Weise ist es möglich, eine serielle Kommunikation und Datenanalyse mit Python durchzuführen. Sie können die Funktion mit serial überprüfen und in CSV konvertieren. Es sollte möglich sein, maschinelles Lernen mit seriellen Sensordaten durchzuführen.
Ich habe es unten benutzt. Vielen Dank für die Bereitstellung der wunderbaren Software.
das ist alles.
Recommended Posts