Serielle Kommunikation mit der Verarbeitung
Die Serial-Klasse
Die Vorgänge zur Verwendung serieller Kommunikation In Bearbeitung werden in der Klasse definiert Serial
.Der erste Vorgang, der ausgeführt werden muss, um sie in einem Programm zu verwenden (Skizze) wird darin bestehen, es in den Code zu integrieren import processing.serial.*;
.
Klasse Serial
Abhängig von den angegebenen Parametern gibt es fünf verschiedene Konstruktoren. Der einzige erforderliche Parameter ist das übergeordnete Objekt (Elternteil), das normalerweise dem Hauptprogramm (z. B. dem Programmfenster) der Klasse entspricht PApplet
. Wie normalerweise ist das übergeordnete Programm das zu schreibende Programm (das Skizze aktuell) wird der Wert dieses ersten obligatorischen Parameters sein this
.
Die anderen fünf Parameter, die an den Konstruktor übergeben werden können, sind ① die Geschwindigkeit, ② der Name des seriellen Ports ③ der Parität ④ die im Protokoll verwendeten Bits, ④ die Datenbits und ⑤ die Stoppbits. Die am häufigsten übergebenen Parameter sind neben dem erforderlichen übergeordneten Objekt der Portname und die Geschwindigkeit.
La Geschwindigkeit der seriellen Kommunikation ist eine ganze Zahl (int
) Das Der Standardwert ist 9600 wenn dieser Parameter nicht an den Konstruktor übergeben wird.
Serielle Schnittstellen verfügbar. Die Listenmethode
El Portname hat die vom System vorgegebene Form, beispielsweise in Linux-Distributionen es wird so etwas sein /dev/ttyS4 / dev / ttyACM3 o /dev/ttyUSB1 (abhängig vom Porttyp), während es unter Windows etwa so aussieht COM12. Sofern ein Port nicht physisch mit einem Gerät verknüpft ist, weiß das Programm normalerweise nicht, welchen Port es verwenden soll. Eine übliche Methode zur Auswahl des Ports besteht darin, eine Liste der verfügbaren Ports abzurufen, sie dem Benutzer anzuzeigen und ihm die Möglichkeit zu geben, den Port auszuwählen, den er verwenden möchte. Die Methode Serial.list()
gibt einen Vektor von Textzeichenfolgen zurück (String
) mit den Namen der auf dem System verfügbaren Ports.
1
2
3
4
5
6
7
8
9
|
// Mostrar los puertos serie disponibles en el sistema
import processing.serial.*;
void setup()
{
noLoop(); // No iterar (no llama a draw periódicamente)
println(Serial.list());
}
|
Der von der Bibliothek standardmäßig verwendete Port Serial
ist der erste, der von der Methode zurückgegeben wird list
(sicherlich COM1 unter Windows oder /dev/ttyS0 en GNU / Linux). Außer in sehr begrenzten Kontexten, in denen die Hardware, mit der gearbeitet wird, genau bekannt ist (z. B. ein System im Kioskmodus), wird sie normalerweise nicht weggelassen und der Zielport wird ausdrücklich angegeben.
Der Screenshot oben zeigt die Ausgabe eines Systems GNU / Linux das über vier serielle Ports verfügt RS-232 (ttyS0 a ttyS3) und fünf Adapter zweier Typen (ttyACM0 a ttyACM1 y ttyUSB0 a ttyUSB2).
Um auf die seriellen Schnittstellen zugreifen zu können, muss der Benutzer normalerweise zu der Gruppe gehören, der das System ihn zuordnet tty o Einwahl. Im Screenshot des Bildes oben können Sie sehen, dass die seriellen Ports mit aufgeführt sind ls /dev/tty[ASU]* -la
gehören zur Gruppe Einwahl die über Lese- und Schreibzugriffsrechte verfügt.
Parameter des seriellen Protokolls
La Parität der seriellen Kommunikation wird ausgedrückt in In Bearbeitung als Charakter (char
), die die Werte annehmen kann: ① N
(keine), um das nicht zu erkennen Parität, ② E
(sogar), um anzuzeigen, dass die Paritätsbit ist gerade, ③ O
(ungerade), um anzuzeigen, dass die Paritätsbit ist ungerade, ④ M
(Kennzeichen), um immer das zu machen Paritätsbit und ⑤ S
(Raum), um immer eines zu machen Paritätsbit. Der Standardwert ist, wenn er nicht als Parameter an den Konstruktor übergeben wird N
(ohne Parität).
Anzahl Daten Bits, standardmäßig acht, gibt die Anzahl der Bits an, aus denen sich die Nettodatennutzlast (Zeichen oder manchmal Wort genannt) zusammensetzt, die in jeder Grundeinheit des Rahmens übertragen wird. Der Parameter, der die Anzahl der Datenbits angibt, wird als Ganzzahl ausgedrückt (int
).
Schließlich gibt der fünfte mögliche Parameter die Dauer der Endnote an, ausgedrückt als Stopp-Bits (Stopp-Bits), die als Zahl dargestellt wird in Gleitkomma (float
), das die Werte annehmen kann 1.0
(der Standardwert, wenn der Parameter nicht an den Konstruktor übergeben wird), 1.5
oder 2.0
.
Konstruktoren der Serial-Klasse
Die folgende Liste zeigt die verschiedenen Kombinationen von Parametern, die an den Klassenkonstruktor übergeben werden können Serial
:
Serial(padre)
Serial(padre,puerto)
Serial(padre,velocidad)
Serial(padre,puerto,velocidad)
Serial(padre,puerto,velocidad,paridad,bits_datos,bits_parada)
Beenden Sie die serielle Kommunikation. Die Stop-Methode.
Zum Freigeben des seriellen Ports, der beim Instanziieren zugewiesen wird Serial
, und dass andere Systemanwendungen es nutzen können, wird die Kommunikation mit der Methode beendet stop
, das keine Parameter empfängt.
1
2
3
4
5
6
7
8
9
10
|
import processing.serial.*;
Serial serie;
void setup()
{
noLoop(); // No iterar
serie=new Serial(this,“/dev/ttyUSB0”,9600); // Usar un puerto USB con un adaptador UART
serie.stop(); // Detiene las comunicaciones serie y libera el puerto ttyUSB0 para otros usos
}
|
Senden Sie Daten über die serielle Schnittstelle. Die write.method
Um Daten zu senden, muss die Klasse Serial
de In Bearbeitung beinhaltet die Methode write
mit dem Sie ① Textzeichenfolgen übertragen können (String
), ② Bytes oder ③ Byte-Vektoren (byte[]
). Es ist interessant, sich daran zu erinnern byte
en In Bearbeitung (At Javac) stellt eine Ganzzahl zwischen -128 und 127 dar und standardmäßig verwenden Zeichenfolgen diese Kodierung UTF-16.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
import processing.serial.*;
Serial serie;
String texto=“Ohm”;
void setup()
{
noLoop();
serie=new Serial(this,“/dev/ttyUSB0”,9600); // Usar un puerto USB con un adaptador UART
serie.write(texto); // Envía el texto “Ohm”
serie.write(10); // Envía un fin de línea \n que corresponde con el ASCII 10
serie.write(200); // Envía el valor -56 ¡Es un byte, va de -128 a 127! (200-256=-56)
serie.stop(); // Detiene las comunicaciones serie y libera el puerto ttyUSB0 para otros usos
}
|
Daten vom seriellen Port lesen
Damit das Programm andere Aufgaben ausführen kann, während Daten über die serielle Schnittstelle empfangen werden, ist es üblich, in einem zu speichern puffern die ankommenden Daten und liest sie gegebenenfalls. Obwohl dies normalerweise nicht sehr effizient ist, können Sie die Anwendung anhalten, um alle verfügbaren Daten zu laden. Am häufigsten wird es jedoch sein, die Informationen zu lesen, sobald sie eintreffen, entweder in jeder Iteration von draw
, wenn eine bestimmte Menge verfügbar ist oder ein spezieller Code eingegangen ist.
Im Puffer verfügbare Datenmenge. Die verfügbare Methode
Um zu wissen, ob Daten angekommen sind puffern Serie, die Methode available
gibt die Anzahl der Bytes zurück, die bereits darin gespeichert wurden puffern. In beiden Fällen können Lesevorgänge einen speziellen Wert zurückgeben (z. B -1
o null
), wenn Sie versuchen, Daten von zu laden puffern Serie, wenn leer.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
import processing.serial.*;
Serial serie;
void setup()
{
frameRate(1); // Llama a draw una vez por segundo
serie=new Serial(this,“/dev/ttyUSB0”,9600);
}
void draw()
{
print(“Hay “);
print(serie.available());
println(” bytes en el buffer serie”);
}
|
Laden Sie jeweils ein Byte. Die Lesemethode
Die wichtigsten Methoden der Klasse Serial
die zum Lesen der von einer seriellen Schnittstelle empfangenen Informationen verwendet werden, sind solche vom Typ „ read
» die sich hauptsächlich durch die Art der Daten unterscheiden, in denen sie die empfangenen Informationen übermitteln.
read
dient dazu, die von der seriellen Schnittstelle empfangenen Bytes als Wert zwischen 0 und 255 auszuliefern. Als Datentyp byte
de In Bearbeitung den Bereich zwischen -128 und 127 und nicht zwischen 0 und 255 darstellt, muss a verwendet werden int
um den von zurückgegebenen Bereich darzustellen read
. Wenn Sie versuchen, mit zu lesen read
und puffern String ist leer, gibt Wert zurück -1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
import processing.serial.*;
Serial serie;
void setup()
{
frameRate(10); // Llama a draw 10 veces por segundo
serie=new Serial(this,“/dev/ttyUSB0”,9600);
}
void draw()
{
if(serie.available()>0)
{
println(serie.read());
}
}
|
Lesen Sie Zeichen von der seriellen Schnittstelle. Die readChar-Methode
Die Methode readChar
es ist ähnlich a read
aber es gibt einen Wert im Format zurück char
anstelle einer int
. Wie intern, die char
en In Bearbeitung (At Javac) werden mit zwei Bytes gespeichert, dem Wert, der beim Lesen zurückgegeben werden soll readChar
ein puffern leere Serie ist 0xFFFF
o -1
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
import processing.serial.*;
Serial serie;
void setup()
{
frameRate(10);
serie=new Serial(this,“/dev/ttyUSB0”,9600);
}
void draw()
{
if(serie.available()>0)
{
print(serie.readChar());
}
}
|
Laden Sie eine Textzeichenfolge. Die Methoden readString und readStringUntil.
Die Methode readString
gibt ein Objekt zurück String
gebildet aus allen in der verfügbaren Daten puffern Serie zum Zeitpunkt der Beratung.
Die Methode readString
Erstellt die Textzeichenfolge unter der Annahme, dass die von der seriellen Schnittstelle empfangenen Bytes im Format vorliegen ASCII Daher kann diese Lesemethode nicht für andere Kodierungen verwendet werden.
Wenn es darum geht, das zu lesen puffern Serie mit readString
Wenn es leer ist, lautet der Rückgabewert null
.
Die Methode readStringUntil
Hinzufügen zu readString
die Fähigkeit, in das geladene Informationen zurückzugeben puffern Serie, die durch ein Sonderzeichen (Code) aufgeteilt wird, das als Parameter übergeben wird. Diese Art des Lesens der empfangenen Informationen ermöglicht es uns, sowohl Trennzeichen als auch Abschlusszeichen zu unterscheiden, die bei der Interpretation der empfangenen Informationen helfen.
Die Methode readStringUntil
zurückbringen null
wenn in der puffern Die Serie findet den im übergebenen Argument angegebenen Code (ein Byte) nicht.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
import processing.serial.*;
Serial serie;
String mensaje;
void setup()
{
frameRate(5);
serie=new Serial(this,“/dev/ttyUSB0”,9600);
}
void draw()
{
if(serie.available()>1)
{
mensaje=serie.readStringUntil(9); // Lee los datos del buffer hasta encontrar un tabulador
if(mensaje!=null) // Si la respuesta no es null ya ha llegado el tabulador y el mensaje está completo
{
println(“Mensaje recibido: “+mensaje); // Mostrar el mensaje si ha llegado completo
}
}
}
|
Im folgenden Code für Arduino sendet drei Nachrichten über die serielle Schnittstelle. Die ersten beiden enden in einer Registerkarte, sodass sie in der Konsole angezeigt werden. In Bearbeitung, während der dritte, obwohl er über die serielle Schnittstelle gesendet wird, nicht mit gelesen wird readStringUntil(9)
da es nicht in einem Tab endet (mit Code ASCII 9).
1
2
3
4
5
6
7
8
9
10
11
12
|
void setup()
{
Serial.begin(9600);
while(!Serial);
Serial.print(“Primer mensaje\t”);
Serial.print(“Segundo mensaje\t”);
Serial.print(“Tercer mensaje”); // Este mensaje no llega porque no termina en tabulador
}
void loop()
{
}
|
Datenblöcke lesen. Die Methoden readBytes und readBytesUntil.
Die oben gezeigten Methoden werden zum Lesen von Daten mit bestimmten Formaten, zum Lesen von Rohdatenblöcken oder mit einem Format verwendet, das in nicht vorgesehen ist In Bearbeitung Methoden eingesetzt werden readBytes
y readBytesUntil
Die Methode readBytes
Versuchen Sie, die verfügbaren Daten zu lesen puffern Serie. Wenn kein Parameter an die Methode übergeben wird readBytes
Alle verfügbaren Daten werden gelesen und in einem Vektor zurückgegeben (byte[]
). Wird als Parameter eine Ganzzahl übergeben, wird maximal die durch diese Zahl angegebene Anzahl an Bytes gelesen und zusätzlich als Vektor zurückgegeben.
Es gibt eine dritte Verwendungsmöglichkeit readBytes
, effizienter, das als Argument einen Bytevektor verwendet, in den der Inhalt der puffern Serie. Diese Art der Verwendung readBytes
gibt eine Ganzzahl zurück (int
), was die Anzahl der gelesenen Bytes darstellt.
Die Methode readBytesUntil
funktioniert auf ähnliche Weise, enthält jedoch einen ersten Parameter, der den Wert des Bytes darstellt, das, falls es in gefunden wird puffern, zeigt das Ende der Lesung an. Bei dieser Methode ist der Parameter, der die maximale Anzahl der zu lesenden Bytes bestimmt, nicht sinnvoll, da die Menge durch den speziellen Code bestimmt wird.
Um die Funktionsweise der Methode zu testen readBytes
Nehmen wir den folgenden Code an Arduino der einen Text über die serielle Schnittstelle sendet.
1
2
3
4
5
6
7
8
9
10
|
void setup()
{
Serial.begin(9600);
while(!Serial);
Serial.println(“En Viena hay diez muchachas, un hombro donde solloza la muerte y un bosque de palomas disecadas. Hay un fragmento de la mañana en el museo de la escarcha. Hay un salón con mil ventanas.”);
}
void loop()
{
}
|
Das folgende Beispielprogramm für In Bearbeitung liest Text von der seriellen Schnittstelle in 32-Byte-Blöcken (TOTAL_BYTES). Um zu überprüfen, ob es funktioniert, zeigt es es über die Konsole als Zeichen an und erzwingt den Typ der empfangenen Bytes char
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
import processing.serial.*;
Serial serie;
byte bloque_datos[];
static byte TOTAL_BYTES=32;
void setup()
{
frameRate(10);
serie=new Serial(this,“/dev/ttyUSB0”,9600);
bloque_datos=new byte[TOTAL_BYTES];
}
void draw()
{
if(serie.available()>0)
{
bloque_datos=serie.readBytes(TOTAL_BYTES);
if(bloque_datos!=null)
{
for(byte numero_byte=0;numero_byte<bloque_datos.length;numero_byte++)
{
print((char)bloque_datos[numero_byte]);
}
}
}
}
|
Im folgenden Screenshot können Sie sehen, wie diese in der Konsole angezeigt werden In Bearbeitung die geladenen Daten in Blöcken von (maximal) 32 Bytes (TOTAL_BYTES) jedes Mal. Aber es gibt ein Problem, über das bereits gesprochen wurde: Arduino hat die Verse von gesendet Federico García Lorca des Beispiels als Text im Format kodiert UTF-8, was nicht der verwendete ist In Bearbeitung (Javac), was bevorzugen Sie UTF-16 also diejenigen, die nicht dem Rang des entsprechen ASCII printable werden falsch interpretiert.
Um dieses Problem zu lösen, können die Zeichensätze geladen werden (charset) und definieren Sie ein neues Objekt String
Erzwingen, dass es mit Codierung dargestellt wird UTF-8 wie im folgenden Beispielcode gezeigt.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
import processing.serial.*;
import static java.nio.charset.StandardCharsets.*;
Serial serie;
byte bloque_datos[];
static byte TOTAL_BYTES=32;
void setup()
{
frameRate(10);
serie=new Serial(this,“/dev/ttyUSB0”,9600);
bloque_datos=new byte[TOTAL_BYTES];
}
void draw()
{
if(serie.available()>0)
{
bloque_datos=serie.readBytes(TOTAL_BYTES);
if(bloque_datos!=null)
{
print(new String(bloque_datos,UTF_8));
}
}
}
|
Lesen Sie die neuesten empfangenen Daten. Die Methoden last und lastChar.
Während die restlichen Lesemethoden (der „Typ read
») sie laden die Informationen des puffern Serie in der gleichen Reihenfolge, in der sie angekommen ist (FIFO), mit diesen beiden Methoden das letzte Byte, das die erreicht hat puffern Serie. Die Methode last
gibt den Wert des letzten Bytes als a zurück int
y lastChar
gibt den Wert als zurück char
.
Serielle Pufferverwaltung
Obwohl die bisher vorgestellten Methoden vollkommen funktionsfähig sind, stellen sie nicht immer die beste Möglichkeit dar, den Zugriff auf die serielle Schnittstelle auszunutzen. Um die Daten zu laden, müssen sie regelmäßig den Status überprüfen puffern Serie und lesen Sie die in einem sich wiederholenden Teil des Codes verfügbaren Daten. Eine im Allgemeinen effizientere Methode besteht darin, die Daten nur dann zu lesen, wenn Sie wissen, dass sie verfügbar sind.
Lesen Sie den seriellen Port, wenn Daten empfangen werden. Das Serienereignis.
Um auf die zuzugreifen puffern Serial Wenn die Daten empfangen werden, kann das Serial-Ereignis ausgenutzt werden, indem es über die Methodendefinition verwaltet wird serialEvent
. Diese Methode verwendet den seriellen Port, der sie startet, als Argument.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
import processing.serial.*;
Serial serie;
void setup()
{
serie=new Serial(this,“/dev/ttyUSB0”,9600);
}
void draw()
{
}
void serialEvent(Serial comunicaciones)
{
print(comunicaciones.readChar());
}
|
Größe des seriellen Puffers. Die Puffermethode.
Wenn Sie die Anzahl der Bytes kennen, aus denen ein Nutzdatenblock besteht, können Sie diese Art des Datenlesens weiter optimieren. puffern Serie durch serialEvent
. Die Methode buffer
Hier können Sie die Anzahl der Bytes festlegen, die im gespeichert werden puffern bevor Sie eine Serienveranstaltung starten. Als Parameter erwartet die Methode eine Ganzzahl, die die Anzahl der Bytes darstellt.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
import processing.serial.*;
Serial serie;
void setup()
{
//noLoop();
serie=new Serial(this,“/dev/ttyUSB0”,9600);
serie.buffer(32); // Esperar a recibir 32 bytes antes de lanzar el evento Serial
}
void draw()
{
}
void serialEvent(Serial comunicaciones)
{
while(comunicaciones.available()>0)
{
print(comunicaciones.readChar());
}
}
|
Füllen Sie den Puffer, bis ein Wert empfangen wird. Die bufferUntil-Methode.
Anstatt den Methodenaufruf festzulegen serialEvent
für eine Datenmenge in der puffern, Wobei das Verfahren bufferUntil
Sie können konfigurieren, dass Daten gespeichert werden, bis ein spezieller Wert eintrifft, und dann das Serial-Ereignis auslösen. Der an diese Methode übergebene Parameter ist a int
Dies stellt den Wert dar, der durch den Aufruf von erzeugt wird serialEvent
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
import processing.serial.*;
Serial serie;
void setup()
{
serie=new Serial(this,“/dev/ttyUSB0”,9600);
serie.bufferUntil(9); // Espera a recibir un tabulador (ASCII 9) antes de llamar a serialEvent
}
void draw()
{
}
void serialEvent(Serial comunicaciones)
{
println(comunicaciones.readString()); // Imprime en una línea diferente cada valor separado originalmente por tabuladores
}
|
Löschen Sie die im Puffer gespeicherten Daten. Die klare Methode.
mit der Methode clear
Sie können die Daten löschen, die sich derzeit im befinden puffern. Diese Methode kann beispielsweise verwendet werden, um eine neue Datenempfangssitzung zu starten und dabei die von der vorherigen verbleibenden Daten zu ignorieren.
Typische Verarbeitungsanwendung zum Lesen von Daten über die serielle Schnittstelle
Abschließend ist es zweckmäßig, die Operationen des Objekts noch einmal zusammenzufassen Serial
de In Bearbeitung die häufiger verwendet werden, indem wir ein typisches Beispiel für den Empfang von Daten über die serielle Schnittstelle durchgehen, um damit ein Diagramm zu zeichnen, in diesem Fall von gestapelten Bereichen.
Importieren Sie die serielle Bibliothek
1
|
import processing.serial.*;
|
Datenprotokoll festlegen (Trennzeichen)
1
2
|
static final String SEPARADOR=“\t”; // Los datos de cada sensor se separan con un tabulador
static final char TERMINADOR=10; // Cada grupo de datos se termina con un código ASCII 10 → Nueva línea → \n
|
Bestimmen Sie das Objekt der Serial-Klasse
1
|
Serial conexion_sensores;
|
Instanziieren Sie das Serial-Klassenobjekt, indem Sie den verwendeten seriellen Port festlegen
1
|
conexion_sensores=new Serial(this,“/dev/ttyUSB1”,9600);
|
Konfigurieren Sie den Puffer der seriellen Schnittstelle
1
|
conexion_sensores.bufferUntil(TERMINADOR);
|
Implementieren Sie einen Handler für das Serial-Ereignis
1
|
void serialEvent(Serial serie)
|
Seriellen Puffer lesen
1
|
String[] texto_valor=serie.readString().split(SEPARADOR);
|
Konditionieren Sie die empfangenen Daten
1
2
3
4
5
|
float[] valor=new float[texto_valor.length];
for(int numero_valor=0;numero_valor<texto_valor.length;numero_valor++)
{
valor[numero_valor]=parseFloat(texto_valor[numero_valor]);
}
|
Beenden Sie die serielle Kommunikation
1
2
|
conexion_sensores.clear();
conexion_sensores.stop();
|
Der folgende Beispielcode veranschaulicht diese Zusammenfassung mit einer funktionalen (wenn auch sehr einfachen) Anwendung, die ein Flächendiagramm mit den Werten generiert, die über die serielle Schnittstelle empfangen werden, ähnlich wie in der folgenden Animation.
Um sich nicht im Rest des Programms zu verlieren und die Aufmerksamkeit auf die serielle Kommunikation mit zu richten In Bearbeitung, werden die Codezeilen hervorgehoben, die den vorherigen Vorgängen entsprechen.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
|
import processing.serial.*;
static final byte ROJO=0,VERDE=1,AZUL=2,OPACIDAD=3;
static final int CANTIDAD_SENSORES=3;
static final int CANTIDAD_VALORES=20;
static final String NOMBRE_FONDO=“fondo.png”;
static final int[][] COLOR_LINEA={{0x44,0x88,0xCC,0xFF},{0xFF,0xAA,0x00,0xFF},{0xCC,0x44,0xAA,0xFF}};
static final int[][] COLOR_AREA={{0x44,0x88,0xCC,0x88},{0xFF,0xAA,0x00,0x88},{0xCC,0x44,0xAA,0x88}};
static final int[] COLOR_FONDO={0xFF,0xFF,0XFF};
static final float GROSOR_LINEA=2.0;
static final float DIAMETRO_MARCA=8.0;
static final float VALOR_MINIMO=0.0; // Valor mínimo de la suma de todos los componentes
static final float VALOR_MAXIMO=100.0; // Valor máximo de la suma de valores
static final String SEPARADOR=“\t”; // Los datos de cada sensor se separan con un tabulador
static final char TERMINADOR=10; // Cada grupo de datos se termina con un código ASCII 10 → Nueva línea → \n
Serial conexion_sensores;
float[][] valor_sensor=new float[CANTIDAD_SENSORES][CANTIDAD_VALORES];
float coeficiente_valor;
float[] vertical_area=new float[CANTIDAD_VALORES];
float[] vertical_marca=new float[CANTIDAD_VALORES];
PImage fondo;
void setup()
{
size(792,396,P2D); // El tamaño de la ventana no se puede establecer con variables en setup (usar settings)
surface.setResizable(false);
surface.setTitle(“consumo relativo comparado”);
noLoop();
smooth(4);
conexion_sensores=new Serial(this,“/dev/ttyUSB1”,9600);
conexion_sensores.bufferUntil(TERMINADOR);
for(int numero_sensor=0;numero_sensor<CANTIDAD_SENSORES;numero_sensor++)
{
for(int numero_valor=0;numero_valor<CANTIDAD_VALORES;numero_valor++)
{
valor_sensor[numero_sensor][numero_valor]=0.0;
}
}
fondo=loadImage(NOMBRE_FONDO);
coeficiente_valor=height/(VALOR_MAXIMO–VALOR_MINIMO);
//strokeCap(ROUND); // El modo del final de líneas por defecto es redondeado
//ellipseMode(CENTER); // Por defecto el modo de elipse es desde el centro
if(DIAMETRO_MARCA>GROSOR_LINEA) // Si la marca no es visible hay que configurar el tipo de esquina
{
strokeJoin(ROUND); // El modo de esquina por defecto es en ángulo
}
}
void draw()
{
for(int numero_valor=0;numero_valor<valor_sensor[0].length;numero_valor++)
{
vertical_area[numero_valor]=height;
for(int numero_sensor=0;numero_sensor<valor_sensor.length;numero_sensor++)
{
vertical_area[numero_valor]-=(valor_sensor[numero_sensor][numero_valor]–VALOR_MINIMO)*coeficiente_valor;
}
vertical_marca[numero_valor]=vertical_area[numero_valor];
}
if(fondo==null)
{
background(COLOR_FONDO[ROJO],COLOR_FONDO[VERDE],COLOR_FONDO[AZUL]);
}
else
{
image(fondo,0,0);
}
strokeWeight(GROSOR_LINEA);
for(int numero_sensor=0;numero_sensor<valor_sensor.length;numero_sensor++)
{
stroke
(
COLOR_LINEA[numero_sensor][ROJO],
COLOR_LINEA[numero_sensor][VERDE],
COLOR_LINEA[numero_sensor][AZUL],
COLOR_LINEA[numero_sensor][OPACIDAD]
);
fill
(
COLOR_AREA[numero_sensor][ROJO],
COLOR_AREA[numero_sensor][VERDE],
COLOR_AREA[numero_sensor][AZUL],
COLOR_AREA[numero_sensor][OPACIDAD]
);
beginShape();
for(int numero_valor=valor_sensor[numero_sensor].length–1;numero_valor>=0;numero_valor—)
{
vertex(numero_valor*width/(valor_sensor[numero_sensor].length–1),vertical_area[numero_valor]);
}
for(int numero_valor=0;numero_valor<valor_sensor[numero_sensor].length;numero_valor++)
{
vertical_area[numero_valor]+=(valor_sensor[numero_sensor][numero_valor]–VALOR_MINIMO)*coeficiente_valor;
vertex(numero_valor*width/(valor_sensor[numero_sensor].length–1),vertical_area[numero_valor]);
}
endShape(CLOSE);
if(DIAMETRO_MARCA>0)
{
noStroke();
fill
(
COLOR_LINEA[numero_sensor][ROJO],
COLOR_LINEA[numero_sensor][VERDE],
COLOR_LINEA[numero_sensor][AZUL],
COLOR_LINEA[numero_sensor][OPACIDAD]
);
for(int numero_valor=0;numero_valor<valor_sensor[numero_sensor].length;numero_valor++)
{
ellipse
(
numero_valor*width/(valor_sensor[numero_sensor].length–1),
vertical_marca[numero_valor],
DIAMETRO_MARCA,
DIAMETRO_MARCA
);
vertical_marca[numero_valor]=vertical_area[numero_valor];
}
}
}
}
void stop() // Al terminar un Applet. No hay garantía de que se ejecute y, como estas operaciones se realizan al terminar, en realidad no son necesarias y solo se incluyen para recordar el uso de clear y stop
{
conexion_sensores.clear(); // Solo para ilustrar la posibilidad de borrar los datos que queden en el buffer
conexion_sensores.stop(); // Solo para ilustrar la posibilidad de terminar las comunicaciones serie y liberar el puerto que se está usando
}
void serialEvent(Serial serie)
{
String[] texto_valor=serie.readString().split(SEPARADOR);
float[] valor=new float[texto_valor.length];
for(int numero_valor=0;numero_valor<texto_valor.length;numero_valor++)
{
valor[numero_valor]=parseFloat(texto_valor[numero_valor]);
}
nuevo_valor(valor_sensor,valor);
redraw();
}
void nuevo_valor(float[][] valor_sensor, float[] valor)
{
for(int numero_sensor=0;numero_sensor<valor_sensor.length;numero_sensor++)
{
for(int numero_valor=1;numero_valor<valor_sensor[0].length;numero_valor++)
{
valor_sensor[numero_sensor][numero_valor–1]=valor_sensor[numero_sensor][numero_valor];
}
valor_sensor[numero_sensor][valor_sensor[0].length–1]=valor[numero_sensor];
}
}
|
Geben Sie Anmerkung