Lorsqu'il s'agit d'incorporer, il est souvent débogué par communication série. Si vous créez votre propre appareil IoT, il n'y a pas de shell, donc un simple moniteur série entre en jeu.
Dans ce cas, la norme serait TeraTerm? Les macros sont également importantes.
Cependant, quand je veux traiter le résultat en série ou convertir le résultat en csv, je veux utiliser Python ou quelque chose (dans mon cas, c'est juste une question de familiarité, pas lequel est le meilleur). Je pense que l'utilisation de pyserial est probablement la voie royale.
Mais,
C'est étrange d'être pris en Java (quoi?). Dans un autre cas, je jouais avec python et le langage C, donc j'ai essayé de réaliser cette fois une communication série en l'appliquant. Créez la partie de communication série avec DLL et accédez-y à partir de ctypes. Cela suffit pour un échange de messages lent tel que intégré.
J'espère qu'il vous sera utile de savoir comment utiliser les contrôles spécifiques à Windows de Python.
Vérifiez ci-dessous. Puisqu'il s'agit d'un prototype, je voudrais vous pardonner.
--Confirmé sous Windows10 (64 bits) et Windows7 (64 bits). --Python est la série 2.7 32 bits, et DLL est également construit et utilisé avec x86.
Le tutoriel est ci-dessous http://starship.python.net/crew/theller/ctypes/tutorial.html
Je pense que les DLL utilisant Visual C ++ peuvent être codées de manière normale. D'un autre côté, le côté python a besoin d'une certaine ingéniosité, et il est nécessaire de définir des fonctions à l'aide de ctypes. Cependant, je pense qu'il est plus rapide de regarder le didacticiel ci-dessus et le code réel, je vais donc exposer le code immédiatement.
Vous trouverez ci-dessous le code côté DLL.
#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);
}
Les quatre fonctions suivantes sont préparées. C'est extrêmement simple.
//Port ouvert, port="COMxx", Baud est bps. La valeur de retour est 0 pour le succès et négative pour l'échec
INT32 SERIAL_open(char *port, INT32 baud)
//Lisez les données. Lorsqu'il est appelé, len contient le nombre d'octets lus et char contient les données reçues.
//Avec un timeout de 500 msec*len=Cela peut être 0.
char * SERIAL_read(void *len)
//Écriture de données. La chaîne de texte est de len octets (comme vous pouvez le voir dans le code, le maximum est de 1024 octets)
INT32 SERIAL_write(char *text, INT32 len)
//Port fermé
void SERIAL_close(void)
Générez ce code en tant que DLL dans Visual Studio. Les points à noter dans ce cas sont les suivants.
Le code réel est censé être une communication série écrite selon le manuel utilisant l'API Win32 (plutôt, je suis désolé, c'est une version dégradée). .. Si vous construisez avec, vous pouvez créer une dll normalement. J'écrirai le côté Python comme si j'utilisais uniquement cette DLL.
Les sites suivants ont été très utiles lors de la création du programme. http://www.geocities.co.jp/SiliconValley-SanJose/5309/serial.html http://www.ys-labo.com/BCB/2007/070512%20RS232C%20zenpan.html
C'est du côté Python. Le code de la classe qui effectue la communication série à l'aide de la DLL ci-dessus est indiqué ci-dessous. Au fait, c'est le code lorsque le nom de fichier de la DLL est serial_if.dll.
#!/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();
Décrivez les fonctions de la DLL série. Le commentaire contient la description de la gestion de la DLL.
Cette fois, nous avons adopté la description qui utilise DLL en utilisant windll. À ce moment, définissez d'abord le nom de la DLL à utiliser comme suit.
dll = windll.serial_if
# windll.(Nom du fichier DLL)Spécifiez la DLL correspondante avec. L'exemple ci-dessus est en série_if.Signifie dll
Ensuite, définissez les arguments et la valeur de retour de chaque fonction exportée par la DLL à l'aide de la description de ctypes. Je vais l'écrire en comparaison avec la fonction C ci-dessous.
# 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);
#Aucune définition requise s'il n'y a pas d'arguments ou de valeurs de retour
Si vous êtes une personne qui a fait à la fois C et Python, vous pouvez comprendre la méthode d'écriture de base en comparant ce qui précède. Tutoriel sera utile pour traiter les types détaillés.
Après cela, vous pouvez appeler la fonction définie normalement. Veuillez noter ce qui suit. Soyez particulièrement prudent lorsque vous obtenez une valeur de C avec un pointeur.
La classe SerialDriver ci-dessus appelle une fonction DLL pour effectuer une communication série. Ceux qui utilisent cette classe sont implémentés de manière à ne pas avoir besoin de connaître les ctypes.
En ce qui concerne la valeur, le site suivant de stackoverflow a été utile. http://stackoverflow.com/questions/2330587/how-to-convert-ctypes-c-long-to-pythons-int
Voici un programme qui utilise la classe SerialDriver pour effectuer une communication série réelle et enregistre les données reçues en série. En passant, cela est basé sur l'hypothèse que la classe SerialDriver a été écrite avec le nom de fichier serial_lib.py (comme vous pouvez le voir en important le code ci-dessous).
#!/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
De plus, j'ai écrit ce fichier en tant que serial_test.py. Telle est la prémisse de l'explication suivante.
Comme vous pouvez le voir dans le code, il comprend les fonctions suivantes.
Traitement principal --serial_test --serial_read Traitement de la réception série
Comme vous pouvez le voir à partir du code DLL, le résultat de la réception peut être de 0 octet car il expire dans 500 ms. Par conséquent, le processus de poursuite de la lecture jusqu'à ce qu'un mot-clé spécifique soit reçu est effectué ici (le mécanisme est donc tel qu'il ne peut pas être supprimé à moins que ce mot-clé ne vienne. Aucune contre-mesure n'a été prise pour ce w)
Le processus principal (fonction serial_test) est traité selon le flux suivant.
En passant, s'il s'agit de COM10 ou supérieur, il est inutile dans ce qui précède et vous devez le décrire comme \\. \ COM10 "(spécifications de type MS comme ci-dessous) https://support.microsoft.com/ja-jp/help/115831/howto-specify-serial-ports-larger-than-com9
L'autre partie de la fonction serial_test ci-dessus a été réalisée expérimentalement avec la macro TeraTerm suivante.
timeout=30
sendln 'teraterm command1'
wait 'python response1'
sendln 'teraterm command2'
Le contenu est comme indiqué ci-dessous.
On a l'impression de communiquer les uns avec les autres.
Le test a été exécuté comme suit.
--Mettez la DLL, la classe SerialDeriver et l'application de test qui l'utilise (serial_test.py dans l'exemple d'environnement de l'auteur) dans le même dossier.
En appliquant cela, il est possible d'effectuer une communication série et une analyse de données avec Python. Vous pourrez vérifier la fonction en utilisant la série et la convertir en CSV. Il devrait être possible de prendre en charge l'apprentissage automatique avec des données de capteur en série.
Je l'ai utilisé ci-dessous. Merci d'avoir fourni le merveilleux logiciel.
c'est tout.
Recommended Posts