Je poste un exemple modifié de ce que j'utilise. Par curiosité j'ai fait le code C# (en mono sous GNU/Linux). Désolé s'il ne répond pas aux standards (je ne développe pas en C#). Tu devras adapter pour Windows le nom du port série.
Ce code est adapté, je pense, à ton problème (ligne au format "val1 val2" pour les valeurs des 2 moteurs).
Je sécurise par un CRC8 (plus léger pour l'arduino) et un accusé de réception indiquant l'éventuel problème.
A la vitesse de 115200 bauds le programme est capable d'émettre (et de recevoir l’acquittement) de 500 couples de valeurs (lignes) par seconde.
Le programme C# :
using System;
using System.IO.Ports;
using System.Threading;
/*
Émission en boucle (1000) de lignes contenant 2 entiers.
Un CRC8 est ajouté en début de ligne pour validation par le récepteur.
Le récepteur renvoie :
* "0" : ok
* "1" : mauvais format de ligne.
* "2" : mauvais CRC
Arrêt du programme si erreur détectée.
*/
public class TestUsb {
// from pololu.com (https://www.pololu.com/docs/0J44/6.7.6)
static byte GetCRC(String message) {
byte j, crc = 0;
const byte CRC7_POLY = 0x91;
int i;
int length=message.Length;
for (i = 0; i < length; i++)
{
crc ^= (byte) message[i];
for (j = 0; j < 8; j++)
{
if ((crc & 1) == 1)
crc ^= CRC7_POLY;
crc >>= 1;
}
}
return crc;
}
static public void Main ()
{
Random rnd = new Random();
SerialPort serial;
serial = new SerialPort();
serial.PortName = "/dev/ttyUSB0";
serial.Parity = Parity.None;
serial.BaudRate = 115200;
serial.DataBits = 8;
serial.StopBits = StopBits.One;
serial.Open ();
// Pour laisser le temps à la carte arduino de rebooter
Console.WriteLine ("Wait arduino reboot (2s) ...");
Thread.Sleep(2000);
// On émet (à fond) 1000 couples (m1 m2)
for(int i=0; i<1000; ++i) {
int m1=rnd.Next(0,255);
int m2=rnd.Next(0,255);
string msg=m1+" "+m2;
// Calcul du CRC 8
byte crc=GetCRC(msg);
// falsifie le CRC pour test détection mauvais crc
// crc++;
// falsifie le message pour détection mauvais format
//msg="123 bad";
// CRC en hexa sur 2 octets (simplification du code coté arduino)
string crcHex = crc.ToString("X");
if(crcHex.Length==1) crcHex="0"+crcHex;
// Ajout du CRC en début de message
msg=crcHex+" "+msg;
Console.WriteLine ("Envoi : \""+msg+"\"");
// envoi
serial.WriteLine(msg);
// attente de la réponse (on retire '\n' final).
string response=serial.ReadLine().TrimEnd();
// Affichage de la réponse
Console.WriteLine ("Recu ("+i+") : \""+response+"\"");
if(response != "0") {
Console.WriteLine ("Erreur !");
Environment.Exit(1);
}
// pour une attente entre les messages
//Thread.Sleep(500);
}
serial.Close ();
}
}
Le programme Arduino :
/*
Lecture en boucle sur le port série de lignes ASCII au format :
CRC8 VAL1 VAL2
* CRC8 la représentation ASCII en hexadécimal sur 2 caractères du CRC 8
de "VAL1 VAL2".
* VALn la représentation ASCII d'un entier.
A l'issue d'une lecture, un code de retour est émis sur le port série :
* "0" : ok
* "1" : mauvais format de ligne.
* "2" : mauvais CRC
*/
const int maxChars=20; // nombre de caractères maxi d'une ligne
// CRC8 from pololu.com (https://www.pololu.com/docs/0J44/6.7.6)
const unsigned char CRC7_POLY = 0x91;
unsigned char getCRC(char *message, int length)
{
unsigned char i, j, crc = 0;
for (i = 0; i < length; i++)
{
crc ^= message[i];
for (j = 0; j < 8; j++)
{
if (crc & 1)
crc ^= CRC7_POLY;
crc >>= 1;
}
}
return crc;
}
// Fonction fgets inspirée de la version POSIX.
// Évite de manipuler des String (fragmentation du tas).
char *fgets(char *s, int size, Stream &stream) {
int cpt=0;
char c;
while(1) {
if(stream.available()) {
c = stream.read();
if(c=='\r') continue; // skip Windows \r
if(cpt<size-1) s[cpt++]=c;
if(c=='\n') break ;
}
}
s[cpt]=0;
return s;
}
// Initialisation du port série
void setup() {
Serial.begin(115200);
while (!Serial);
}
// lecture en boucle des lignes
void loop() {
char line[maxChars]; // espace pour stocker la ligne lue
int val1, val2, crc, crc2;
// Lecture (bloquante) d'une ligne en provenance du port série
fgets(line, maxChars, Serial);
// retire l'\n' final
line[strlen(line)-1]=0;
// décodage de la ligne reçue
if(sscanf(line, "%x %d %d", &crc, &val1, &val2) !=3) {
// renvoie "1" : ligne au format invalide
Serial.println("1");
return;
}
else {
// vérification du CRC (+3 car le CRC ne s'applique qu'aux données
// utiles)
crc2=getCRC(line+3, strlen(line+3));
if(crc!=crc2) {
// renvoie "2" : mauvais CRC
Serial.println(2);
return;
}
else {
// renvoie "0" : tout est ok
Serial.println(0);
}
}
// arrivé à ce point du programme il y a une forte probabilité que
// val1 et val2 soient valides.
// ...
}
Tu en fait ce que tu veux, mais méfie toi, je ne garanti pas qu'il est exempt d'erreurs de codage.
Sinon oui, sous GNU/Linux la carte reboot aussi à l'ouverture du port série par défaut en C#. J'évite cela sous GNU/Linux en C en fixant des valeurs précises de configuration via la commande stty. Si cela te dérange il faudra que tu te renseignes pour C# sous Windows.
PS 1 : désolé pour l'indentation qui disparaît a la moindre édition du post...?!?
PS 2 : je n'ai pas testé sous Windows (mais ai pris en compte, normalement, la terminaison de ligne différente par rapport à GNU/Linux).
A+