aide communication série entre Arduino et visual c#

Bonne nouvelles,

ta solution fonctionnait mais le moteur tourne par a coup

La deuxième solution est bien plus satisfaisante (utilisant donc le L297). Je lui dis de faire une clock a tel fréquence pendant un laps de temps grace a TimerOne.h :slight_smile:

Me reste plus qu'a comprendre comment envoyer des données de vitesse et déplacement rentré par l'utilisateur sur visual c# et qu'il les envoient correctement à l'arduino :slight_smile:

Si une âme charitable voudrait bien m'expliquer comment envoyer un nombre via le port série pour que l'arduino le mette dans une variable ?

Ce que je veux faire :

L'utilisateur rentre la vitesse (en rpm) dans visual c#
il clic sur ok, a ce moment la c# écrit sur le port ce qui se trouve dans la textBox, donc un string

comment faire comprendre a l'arduino que ce qu'il reçoit est par exemple 60rpm ?

Personne ? :frowning:

regarde atoi() dans la lib-C

Indice: la doc de la lib-C se trouve dans ...\arduino-1.0\hardware\tools\avr\doc\avr-libc\avr-libc-user-manual\index.html

HadesDT:
Personne ? :frowning:

Petit rappel de courtoisie : un forum n'est pas une hot-line. Les gens qui participent le font sur la base du volontariat de l'échange. Ils ont aussi une autre vie à coté, voir ils dorment et ne sont pas forcément là à guetter les questions pour essayer d'y répondre le plus vite possible.
Durant les 12 heures de nuit entre ta question et ta relance, qu'a tu fais de ton coté pour faire avancer ton problème ?
Tu aurais du trouver toi même itoa() avec un peu de recherche Google. C'est une fonction de base de la lib-C.
Merci.

merci de ta réponse,

j'ai essayé avec atoi, mais pas convainquant, il considère qu'il reçoit 0 tout le temps (que je rentre 0 ou 255 rpm)

j'ai fait comme ceci du coté Arduino :

#include <TimerOne.h>
#include <stdio.h>
#include <stdlib.h>

unsigned int Speed = 0;
int Distance = 0;
int val;
int clock = 5;
int dir = 3;
int step_half = 4;
int Enable = 6;
int count_val = 0;
int stop_mot = 0;
int c;
char info, *info2;



void setup()  
{                
  Serial.begin(19254); 
  pinMode(clock,OUTPUT);
  pinMode(Enable,OUTPUT);
  pinMode(dir,OUTPUT);
  pinMode(step_half,OUTPUT);
}


void loop()                    
{
      if(Serial.available()>0)
      {
        c = Serial.read();
        if (c == '0')
          {
            info = Serial.read();
            *info2=info
            Speed = atoi(info2);
          }

         if (c == '4')
          {
                Serial.println(analogRead(A5));
          }
         if (c == '5')
         {
                val = analogRead(A5);            // reads the value of the potentiometer (value between 0 and 1023) 
                Serial.println(val);
                unsigned long int ms = (1/(Speed * 3.33))*10000;
                if (stop_mot == 0)
                {                
                  Timer1.initialize(10000);
                  Timer1.attachInterrupt(count);
                  digitalWrite(Enable,HIGH);
                }
         }
         if (c == '6')
         {
           Timer1.stop();
           digitalWrite(clock,LOW);
           digitalWrite(Enable,LOW);
           digitalWrite(dir,LOW);
           count_val=0;
           stop_mot = 0;
         }
    }
}
void count()
{
    if (++count_val <=200 && val <= 53)
    {
      digitalWrite( clock, digitalRead( clock ) ^ 1 );
      
      if (count_val <=100)
          digitalWrite(dir,HIGH);
        
  
      if (count_val > 100 && count_val < 200)
         digitalWrite(dir,LOW);
    }
    else
    {
      stop_mot = 1;
      digitalWrite(clock,LOW);
      digitalWrite(Enable,LOW);
      digitalWrite(dir,LOW);
    }
}

et ceci du côté VS C@ :

        private void Speed_button_Click(object sender, EventArgs e)
        {
            Port1.Write("0");

            Port1.Write(Speed_TextBox.Text);

            textBox2.Text = Port1.ReadLine();

            MessageBox.Show("Vous avez rentré une vitesse de " + Speed_TextBox.Text + " rpm");
        }

une idée ?

Oulalalala !

Apparemment il y a du boulot coté langage C!

1ere étape : définir clairement un protocole sur la liaison série.
Tu n'as qu'une valeur a transmettre ? ou dans le future tu en aura d'autre ?
Supposons que dans le futur tu va en avoir d'autre et que celle-ci s'appelle "A". Les autres s'appellerons "B", "C", ...
La définition d'un protocole série en ASCII comprend généralement :

  • Un caractère de début de trame : c'est pratique pour se resynchroniser. Classique prenons '$'
  • Un identifiant de message : on va utiliser une lettre majuscule.
  • Un message utile
  • Un caractère de fin. Puisqu'on est en ASCII, on va prendre le retour chariot '\r' auquel on peut ajouter optionnellement le saut de ligne '\n' ce qui rend le protocole lisible sur un terminal série

Exemple message "A" pour transmettre ta valeur en question :
"$Annn\r\n" ou "nnn" est la valeur en décimal à transmettre.

Coté C# ca devrait donner :

WriteLine( "$A" + valeur.ToString() );

Je préfère convertir le TextBox en valeur puis reconvertir en string pour éviter d'envoyer des caractères non valides.

Coté Arduino, il faut lire le message en se synchronisant sur le 1er caractère et en attendant le dernier :

#define BUFF_LEN   40
char buffer[BUFF_LEN]; // pour le plus long des messages
int buff_index = 0;

void gere_reception()
{
  char c;
  if ( Serial.available() )
  {
    c = buffer[buff_index] = Serial.Read();
    if ( buff_index == 0 )
    {
      // attente caractère de synchro
      // tant qu'on ne l'a pas reçu on reste à l'index 0
      if (c =='

C'est un exemple rapide torché en quelques minutes.
Il ne respecte pas ma sacro-sainte règle de séparer tout en tâches individuelles élémentaires puisque je traite la commande dans la même tâche que la réception série.
Mais c'est un exemple pour commencer.

)
        ++buff_index;
    }
    else
    {
      // on empile les caractères dans le buffer jusqu'au max
      if ( buff_index < (BUFF_MAX-1) )
        ++buff_index;
      // si le caractère est le marqueur de fin, on a reçu un message entier     
      if ( c == '\r' )
        traite_message();
      // le message a été traité, on repart à 0
      buff_index = 0;
  }
}

void traite_message()
{
  // on sait que le 1er caractère est $, on s'en fout
  // le 2nd caractère est l'ID du message
  switch( buffer[1] )
  {
  case 'A':
    // message A, on lit la valeur numérique qui est derrière
    // si le message était plus complexe avec plusieurs valeurs, on pourrait utiliser strtok()
    int valeur = atoi( &buffer[2] );
    // utiliser la valeur
    .......
    break;
  }
}


C'est un exemple rapide torché en quelques minutes.
Il ne respecte pas ma sacro-sainte règle de séparer tout en tâches individuelles élémentaires puisque je traite la commande dans la même tâche que la réception série. 
Mais c'est un exemple pour commencer.

Wow Oo

je vais essayé d'implémenter ceci dans mon code Oo, ca va pas etre facile :stuck_out_tongue:

barbudor:

HadesDT:
Personne ? :frowning:

Petit rappel de courtoisie : un forum n'est pas une hot-line. Les gens qui participent le font sur la base du volontariat de l'échange. Ils ont aussi une autre vie à coté, voir ils dorment et ne sont pas forcément là à guetter les questions pour essayer d'y répondre le plus vite possible.
Durant les 12 heures de nuit entre ta question et ta relance, qu'a tu fais de ton coté pour faire avancer ton problème ?
Tu aurais du trouver toi même itoa() avec un peu de recherche Google. C'est une fonction de base de la lib-C.
Merci.

Désolé, je voulais offencer personne et ferai + attention la prochaine fois

barbudor:
Oulalalala !
Apparemment il y a du boulot coté langage C!

Pour être plus précis, parce que critiquer dans le vide ca n'apporte rien à personne :

Tu écrit :

char info, *info2;
info = Serial.read();
*info2=info
Speed = atoi(info2);

Il faut d'urgence que tu lises un tuto sur le pointeurs.
Un pointeur est une variable qui indique une adresse en mémoire où aller lire ou écrire.
ptr est l'adresse
*ptr représente la case mémoire qui se situe à l'adresse mémoire qui est dans la variable ptr.
Si tu résonne en adresse postale,

ptr = "55, rue du faubourg Saint-Honoré 75008 Paris"
*ptr = 0;

vient écrire 0 devant le palais de l'Elysée :D.

Dans ton cas

*info2 = info;

Va écrire la valeur du caractère reçu de la liaison série vers ..... en fait on n'en sait rien car info2 n'est pas initialisé.
Donc tu va écrire n'importe où. Probalement là où il n'y a pas de mémoire, voir là où il y a quelque chose d'autre.

La fonction atoi() attend bien un argument du type pointeur sur caractère mais en fait c'est un pointeur sur "le 1er caractère d'une chaine de caractères se terminant par le caractère nul '\0'
Donc déjà tu n'a pas le droit non plus d'écrire ;

char c = '4';
int i = atoi( &c );

&c signifie "addresse de c"
C'est bien un pointeur sur c, c étant un char &c est bien un char*
Mais ce n'est pas une chaîne de caractères se terminant par un '\0'
Avec le code ci-dessus, atoi() va aller chercher en mémoire les caractères qui suivent '4' alors qu'on ne sait pas ce qu'il y a en mémoire après la case de c.
Ce code ci est bon :

char p[] = "123";
int i = atoi( &p[0] );

Ca marche par ce que :

  • p est un tableau de caractères initialisé avec la chaîne "123". C'est un tableau de ..... 4 caractères. En effet ce que tu ne vois pas ici c'est que derrière le 3 il y a un 4eme caractère caché qui est le caractère nul '\0' marquant la fin d'une chaine de caractère.
    p[0] est le 1er caratère du tableau c'est à dire de la chaine et vaut '1'
    p[2] est le 3eme caratère du tableau c'est à dire de la chaine et vaut '3'
    p[4] est le dernier caratère du tableau marquant la fin de la chaine et vaut '\0'
    &p[0] est l'adresse du 1er caractère de la chaine, c'est à dire un pointeur sur la chaine.
    Note qu'on peut simplifier et écrire p tout court qui est équivalent à &p[0]
    (En C le nom d'un tableau est toujours équivalent à un pointeur sur le 1er élément du tableau)
int i = atoi( p );

Tuto sur les pointeurs par Osaka : http://arduino.cc/forum/index.php/topic,101780.0.html

Ensuite, ton erreur est qu'il faut récupérer tous les caractères représentant le nombre dans une même chaîne de caractères avant d'appeller itoa()
Dans mon code, on reconstruit la chaine de caractères "$A123\r\n" dans le tableau buffer.
Ensuite on utilise itoa( &buffer[2] ) pour convertir les caractères après le 'A' en un nombre. itoa() arrête automatiquement la conversion au 1er caractère non numérique qu'elle rencontre.

Merci pour tes explications, en mettant ton code dans mon code, lors du lancement de visual c# il me dit que le port est fermé

plus aucune communication est possible, voila les deux codes

#include <TimerOne.h>

#define BUFF_LEN 40

unsigned int Speed = 0;
int Distance = 0;
int val;
int clock = 5;
int dir = 3;
int step_half = 4;
int Enable = 6;
int count_val = 0;
int stop_mot = 0;
char c;
char buffer[BUFF_LEN];
int buff_index = 0;



void setup()  
{                
  Serial.begin(19254); 
  pinMode(clock,OUTPUT);
  pinMode(Enable,OUTPUT);
  pinMode(dir,OUTPUT);
  pinMode(step_half,OUTPUT);
}


void loop()                    
{
  //Boucle qui traite le message reçu
      if(Serial.available())
      {
        c = buffer[BUFF_LEN]=Serial.read();
        if (buff_index == 0)
        {
      // attente caractère de synchro
      // tant qu'on ne l'a pas reçu on reste à l'index 0
        if (c == '

)
             ++buff_index;
       }
       else
       {
         
     // on empile les caractères dans le buffer jusqu'au max
           if (buff_index < (BUFF_LEN-1))
             ++buff_index;
     // si le caractère est le marqueur de fin, on a reçu un message entier      
           if (c == '\r' )
             traite_message();
     // le message a été traité, on repart à 0
       buff_index = 0;
       }
     }
}
void count()
{
   if (++count_val <=200 && val <= 53)
   {
     digitalWrite( clock, digitalRead( clock ) ^ 1 );
     
     if (count_val <=100)
         digitalWrite(dir,HIGH);
       
 
     if (count_val > 100 && count_val < 200)
        digitalWrite(dir,LOW);
   }

else
   {
     stop_mot = 1;
     digitalWrite(clock,LOW);
     digitalWrite(Enable,LOW);
     digitalWrite(dir,LOW);
   }
}
void traite_message()
{
   // on sait que le 1er caractère est $, on s'en fout
   // le 2nd caractère est l'ID du message
   
   switch( buffer[1])
   {
     case 'A' :
     {
   // message A, on lit la valeur numérique qui est derrière
   // si le message était plus complexe avec plusieurs valeurs, on pourrait utiliser strtok()
         int Speed = atoi ( &buffer[2]);
   //utiliser la valeur
           break;
     }
     case 'B' :
     {
         int Deplacement = atoi ( &buffer[2]);
           break;
     }
     case 'C' :
     {
         Serial.println(analogRead(A5));
           break;
     }
     case 'D' :
     {
          val = analogRead(A5);            
          Serial.println(val);
          //int Deplacement = Distance / 0.005;
          unsigned long int ms = (1/(Speed * 3.33))*10000;

if (stop_mot == 0)
            {                
              Timer1.initialize(ms);
              Timer1.attachInterrupt(count);
              digitalWrite(Enable,HIGH);
            }
             break;
     }
     case 'E' :
        {
          Timer1.stop();
          digitalWrite(clock,LOW);
          digitalWrite(Enable,LOW);
          digitalWrite(dir,LOW);
          count_val=0;
          stop_mot = 0;
      break;  
      }
       
   }
}

cote c# :

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using System.IO;
using Microsoft.Office.Core;
using Excel = Microsoft.Office.Interop.Excel;
using System.Windows.Forms.DataVisualization.Charting;
using Microsoft.Office.Interop.Excel;
using ApplicationForm = System.Windows.Forms.Application;
using System.Globalization;

namespace Acqu_donnee
{
    public partial class Form1 : Form
    {
        SerialPort Port1; //ouverture du port série
        public Form1()
        {
            InitializeComponent();
            for (int i = 1; i <= 50; i++)
            {
                try
                {
                    Port1 = new SerialPort("COM" + i, 19254); //Port1 trouve le port COM du PC
                    Port1.Open(); //Port1 est ouvert
                    Port1.ReadTimeout = 1000; //Delais pour l'écriture
                    Port1.WriteTimeout = 1000; //Délais pour la lecture
                    Port1.Write("$C"); //Ecrit 4 sur le port 1

                    byte[] lus = new byte[8];
                    int nblu = Port1.Read(lus, 0, 8);
                    if (nblu > 0)
                    {
                        return; // port trouvé
                    }
                }
                catch (Exception)
                {
                    Port1.Dispose();
                }

            }
        }

        public void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (Port1.IsOpen) Port1.Close(); //Ferme le port1 à la fermeture du programme
        }

        public void timer1_Tick(object sender, EventArgs e) //Evenement à chaque tick du Timer1
        {
         
            string r = ""; //défini r comme un string vide
            double x = 0; //défini x comme un double vide
            double value = 0; //Défini vélue comme un double vide
            if (but_lect_mes.Enabled==false) //Si Lect_mes est cochée
            {
                Port1.Write("$D"); //on écrit $D sur le port1
            }

            
            try
            {
                r = Port1.ReadLine(); //r = ce qu'il lit sur le port1
                x = Convert.ToDouble(r); //converti un Char en Double
                value = Math.Round((x / 1024 * 5 * 2 * 196.2), 2); //On calcul la pression
                //1024 = 0...1023 échantillons (valeur renvoyée par le port1)
                //5 car on est sur la plage 0...5V
                //196.2 convertion Kg en Newton
                //2, on arrondis à 2 décimales
            }
            catch
            {
                if (listBox1.Items.Count == 0)
                {
                    value = 0;
                }
                else
                {
                    value = double.Parse(listBox1.Items[listBox1.Items.Count - 1].ToString());
                }
            }
            listBox1.Items.Add(value); //Ajoute les valeurs de value dans la ListBox
            listBox1.SelectedIndex = listBox1.Items.Count - 1; //AutoScroll de la ListBox

            double xVal = listBox1.Items.Count * 0.02; //Valeur axe des x
            chart1.Series[0].Points.AddXY(xVal, value); //Ecriture des points sur le graph
            chart1.ChartAreas[0].AxisX.Maximum = xVal; // Maximum de l'axe des x est la dernière valeur de XVal
            if (chart1.Series[0].Points.Count > 250) // Permet d'afficher que 5 secondes sur l'axe des x
            {
                chart1.Series[0].Points.RemoveAt(0);
            }

            chart1.ChartAreas[0].AxisX.Minimum = chart1.Series[0].Points[0].XValue;

        }

        private void timer2_Tick(object sender, EventArgs e)
        {
            string r = ""; //défini r comme un string vide
            double x = 0; //défini x comme un double vide
            double value = 0; //Défini vélue comme un double vide
            if (but_lect_mes.Enabled==false) //Si Lect_mes est cochée
            {
                Port1.Write("$D"); //on écrit 4 sur le port1
            }

            
            try
            {
                r = Port1.ReadLine();
                x = Convert.ToDouble(r); //converti un Char en Double
                value = Math.Round((x / 1023 * 5 * 2 * 196.2), 2); //On calcul la pression
                //1024 = 0...1023 échantillons (valeur renvoyée par le port1)
                //5 car on est sur la plage 0...5V
                //196.2 convertion Kg en Newton
                //2, on arrondis à 2 décimales
            }
            catch
            {
                value = 0;
            }
            textBox1.Text = value.ToString() + ' ' + 'N'; // Rajoute N après la mesure dans la TextBox
        }

        private void but_lect_mes_Click(object sender, EventArgs e)
        {
            if (Speed_TextBox.Text != "" && Depl_TextBox.Text != "")
            {

                timer1.Enabled = true;
                timer2.Enabled = true;
                but_lect_mes.Enabled = false;
                But_Stop.Enabled = true;
            }
            else
                MessageBox.Show("Rentrer la vitesse et le déplacement désiré");
        }



        

        private void But_Stop_Click(object sender, EventArgs e)
        {
            Port1.Write("$E");
            timer1.Enabled = false; //Sinon on coupe les Timers
            timer2.Enabled = false;
            but_lect_mes.Enabled = true;
            But_Stop.Enabled = false;
        }


        public void Del_ListBox_Click(object sender, EventArgs e)
        {
            listBox1.Items.Clear(); //Clear la ListBox
            chart1.Series[0].Points.Clear(); //Clear le Graph
            textBox1.Clear(); //Clear la TextBox
            Speed_TextBox.Clear();
            Depl_TextBox.Clear();
        }

        private void toExcel_Click(object sender, EventArgs e)
        {
            Excel.Application oXL;    //Définition d'une nouvelle application Excel
            Excel.Workbook oWB;       //Définition d'un classeur
            Excel.Worksheet oSheet;   //Définition d'une feuille

            object misValue = System.Reflection.Missing.Value;

            // initialisation feuille excel
            try
            {
                oXL = new Excel.Application(); //myExcelApp est créee par Excel.Application
                oXL.Visible = true;            //Ouvre Excel automatiquement après l'export
                FileInfo fi = new FileInfo(ApplicationForm.ExecutablePath);

                oWB = (Excel.Workbook)(oXL.Workbooks.Open(Path.Combine(fi.DirectoryName, "Acquisition.xls"))); //Ouvre le fichier Acquisition.xls
                oSheet = (Excel.Worksheet)oWB.ActiveSheet;

                Excel.Range oRange = (Excel.Range)oSheet.get_Range("A3", "B30000"); //Ecrit les données de la cellule A3 a B30000
                oRange.Clear();


                //écriture dans feuille excel
                for (int i = 0; i < Math.Min(listBox1.Items.Count - 1, 27997); i++)
                {
                    oXL.Cells[i + 3, 2] = listBox1.Items[i].ToString(); //On inscrit toutes les valeurs de la ListBox les une en dessous des autres à partir de B3
                    if (i == 0)
                    {
                        oXL.Cells[3, 1] = 0; //Permet d'écrire le temps dans A3
                    }
                    else
                    {
                        oXL.Cells[i + 3, 1] = i * 0.02; //Permet d'écrire le temps dans A4 jusque autant de mesure par pas de 0,02 (50hz)
                    }
                }
            }
            catch
            {
                MessageBox.Show("L'exportation n'a pas été effectuée"); //Si exportation Excel plante, message d'erreur
            }
        }

        private void Speed_button_Click(object sender, EventArgs e)
        {
 
            int speed = Convert.ToInt16(Speed_TextBox.Text);
            Port1.WriteLine("$A" + speed.ToString());

            MessageBox.Show("Vous avez rentré une vitesse de " + Speed_TextBox.Text + " rpm");
        }

        private void Depl_button_Click(object sender, EventArgs e)
        {
            if (Speed_TextBox.Text != "")
            {
            int deplacement = Convert.ToInt16(Depl_TextBox.Text);
            Port1.WriteLine("$B" + deplacement.ToString());

            MessageBox.Show("Vous avez rentré un déplacement de " + Depl_TextBox.Text + " mm");
            }
            else
                MessageBox.Show("Rentré d'abord la vitesse de déplacement");
        } 
        
    }

}

une idée ? :frowning:

désolé mais mon niveau de programmation est un peu basique :frowning:

Donc le pb est coté C#

  1. Je comprend pourquoi tu utilises 19254. En gros tu teste chaque port en envoyant la commande "$C". S'il y a une réponse tu considère que c'est le bon port, sans réponse tu passe au suivant.
    Je ne considère pas le choix de 19254 comme utile car il n'est pas assez éloigné de 19200. Si tu as un autre équipement à 19200, il est possible qu'il reçoive "$C" et qu'il envoie une réponse.
    Plutot que d'utiliser un debit non standard, je resterait sur 19200 mais j'implémente une commande d'indentification.
    Par exemple "$?" avec une réponse donnant le nom du produit/programme, un numero de version... telle que "HadesDuino,1.0"

  2. Tu envoie "$C" avec Write() et non pas avec WriteLine(). Sans le retour chariot final, mon code ne va pas détecter la commande

  3. Tes réponses sont en brutes. Je te suggère de considérer d'utiliser le protocole aussi pour les réponses.
    Par exemple la réponse à "$C" pourrait être "#Cxxxxx"
    Comme précédemment çà rend le protocole lisible aussi à un humain, pratique pour debugger et pour tester avec un terminal indépendamment de ton code C#

Maintenant, je ne comprend pas où tu as exactement le message d'erreur de C#
A l'exécution ?
Si le point 2) est exact, tu sort de la boucle sans avoir trouvé le bon port donc quand tu arrive au moment d’émettre Port1 n'est pas ouvert.

J'ai modifié l'histoire comme ceci et la le port s'ouvre, etc

#include <TimerOne.h>

#define BUFF_LEN 40

unsigned int Speed = 0;
int Distance = 0;
int val;
int clock = 5;
int dir = 3;
int step_half = 4;
int Enable = 6;
int count_val = 0;
int stop_mot = 0;
char c;
char buffer[BUFF_LEN];
int buff_index = 0;



void setup()  
{                
  Serial.begin(21000); 
  pinMode(clock,OUTPUT);
  pinMode(Enable,OUTPUT);
  pinMode(dir,OUTPUT);
  pinMode(step_half,OUTPUT);
}


void loop()                    
{
  //Boucle qui traite le message reçu
      if(Serial.available() > 0)
      {
        c = Serial.read();
        
        if (c == '

Mais...

int speed ne prends pas une bonne valeur, je m'explique

quand j'obtiens Speed j'effectue un calcul pour le remettre en période d'oscillation en µs.

donc unsigned long int µs : (1/Speed*3.33)*10000

et ensuite j'appelle µs dans Timer1.initialize(µs);

Mais au moment ou le moteur doit se lancer, ça foire, il considère que la vitesse est de 1.000.000 µs soit 1 seconde, et l'acquisition se fait toutes les seconde aussi, donc il reste coincé dans une boucle qui l'empêche de travailler assez vite)
        gere_reception();
       
        else
       
        switch (c)
        {
          case '4' :
      {
          Serial.println(analogRead(A5));
            break;
      }
          case '5' :
      {
          val = analogRead(A5);           
          Serial.println(val);
          //int Deplacement = Distance / 0.005;
          //int ms = (1/(Speed * 3.33))*10000;

if (stop_mot == 0)
            {               
              Timer1.initialize(10000);
              Timer1.attachInterrupt(count);
              digitalWrite(Enable,HIGH);
            }
          break;
      }
            case '6' :
      {
          Timer1.stop();
          digitalWrite(clock,LOW);
          digitalWrite(Enable,LOW);
          digitalWrite(dir,LOW);
          count_val=0;
          stop_mot = 0;
        break; 
      }
        }
      }
}
void count()
{
    if (++count_val <=200 && val <= 53)
    {
      digitalWrite( clock, digitalRead( clock ) ^ 1 );
     
      if (count_val <=100)
          digitalWrite(dir,HIGH);
       
 
      if (count_val > 100 && count_val < 200)
        digitalWrite(dir,LOW);
    }

else
    {
      stop_mot = 1;
      digitalWrite(clock,LOW);
      digitalWrite(Enable,LOW);
      digitalWrite(dir,LOW);
    }
}

void gere_reception()
{
  if (buff_index == 0)
        {
      // attente caractère de synchro
      // tant qu'on ne l'a pas reçu on reste à l'index 0
        if (c == '


Mais...

int speed ne prends pas une bonne valeur, je m'explique

quand j'obtiens Speed j'effectue un calcul pour le remettre en période d'oscillation en µs.

donc unsigned long int µs : (1/Speed*3.33)*10000

et ensuite j'appelle µs dans Timer1.initialize(µs);

Mais au moment ou le moteur doit se lancer, ça foire, il considère que la vitesse est de 1.000.000 µs soit 1 seconde, et l'acquisition se fait toutes les seconde aussi, donc il reste coincé dans une boucle qui l'empêche de travailler assez vite)
              ++buff_index;
        }
        else
        {
          
      // on empile les caractères dans le buffer jusqu'au max
            if (buff_index < (BUFF_LEN - 1))
              ++buff_index;
      // si le caractère est le marqueur de fin, on a reçu un message entier      
            if (c == '\r' )
              traite_message();
      // le message a été traité, on repart à 0
        buff_index = 0;
        }
}

void traite_message()
{
    // on sait que le 1er caractère est $, on s'en fout
    // le 2nd caractère est l'ID du message
    
    switch( buffer[1])
    {
      case 'A' :
      {
    // message A, on lit la valeur numérique qui est derrière
    // si le message était plus complexe avec plusieurs valeurs, on pourrait utiliser strtok()
          int Speed = atoi ( &buffer[2]);
    //utiliser la valeur
            break;
      }
      case 'B' :
      {
          int Deplacement = atoi ( &buffer[2]);
            break;
      }
      
    }
}

Mais...

int speed ne prends pas une bonne valeur, je m'explique

quand j'obtiens Speed j'effectue un calcul pour le remettre en période d'oscillation en µs.

donc unsigned long int µs : (1/Speed*3.33)*10000

et ensuite j'appelle µs dans Timer1.initialize(µs);

Mais au moment ou le moteur doit se lancer, ça foire, il considère que la vitesse est de 1.000.000 µs soit 1 seconde, et l'acquisition se fait toutes les seconde aussi, donc il reste coincé dans une boucle qui l'empêche de travailler assez vite

Pourquoi as tu mélangé ton ancien code et mon code qui gère le protocole ?
Mon code a pour but de traiter l'intégralité d'une commande, de la réception du marqueur de débit $ au retour chariot final.
Là tu continue a tout exploser et tour mélanger.
Si je l'ai écrit d'une certaine façon c'est qu'il y a une raison. Essaye de comprendre où justifie qu'il y a quelque chose de faux.

car au démarre du programme c# écrire

Port1.WriteLine("$C")

ne fonctionne pas, j'ai l'impression que l'arduino ne comprends pas. Il me dit qu!l a pas eu de réponse car le délais est dépassé. et le port est donc pas ouvert

Si je met

Port1.WriteLine("4")

il est ok et ouvre le port

bon ok XD

tu mettais

if (c == '\r' )
              traite_message();

et c'est

if (c == '\n' )
              traite_message();

:slight_smile:

donc voila mon code (ou devrais-je dire TON code :D) que tu dois donc préfèrer comme ca :stuck_out_tongue:

#include <TimerOne.h>

#define BUFF_LEN 40

unsigned int Speed = 0;
int Distance = 0;
int val;
int clock = 5;
int dir = 3;
int step_half = 4;
int Enable = 6;
int count_val = 0;
int stop_mot = 0;
int c;
char buffer[BUFF_LEN];
int buff_index = 0;



void setup()  
{                
  Serial.begin(21000); 
  pinMode(clock,OUTPUT);
  pinMode(Enable,OUTPUT);
  pinMode(dir,OUTPUT);
  pinMode(step_half,OUTPUT);
}


void loop()                    
{
  //Boucle qui traite le message reçu
      if(Serial.available())
      {
        c = buffer[buff_index] = Serial.read();
      // attente caractère de synchro
      // tant qu'on ne l'a pas reçu on reste à l'index 0
        if (c == '

Mais ... hé oui encore :stuck_out_tongue:

toujours pas réglé le probleme de Speed qui n'est pas pris en compte comme il le faudrait :()
              ++buff_index;
        else
          {
      // on empile les caractères dans le buffer jusqu'au max
            if (buff_index < (BUFF_LEN-1))
              ++buff_index;
      // si le caractère est le marqueur de fin, on a reçu un message entier     
            if (c == '\n' )
              traite_message();
      // le message a été traité, on repart à 0
        buff_index = 0;
          } 
      }
}
void count()
{
    if (++count_val <=200 && val <= 53)
    {
      digitalWrite( clock, digitalRead( clock ) ^ 1 );
     
      if (count_val <=100)
          digitalWrite(dir,HIGH);
       
 
      if (count_val > 100 && count_val < 200)
        digitalWrite(dir,LOW);
    }

else
    {
      stop_mot = 1;
      digitalWrite(clock,LOW);
      digitalWrite(Enable,LOW);
      digitalWrite(dir,LOW);
    }
}
void traite_message()
{
    // on sait que le 1er caractère est $, on s'en fout
    // le 2nd caractère est l'ID du message
   
    switch( buffer[1])
    {
      case 'A' :
      {
    // message A, on lit la valeur numérique qui est derrière
    // si le message était plus complexe avec plusieurs valeurs, on pourrait utiliser strtok()
          int Speed = atoi ( &buffer[2]);
    //utiliser la valeur
            break;
      }
      case 'B' :
      {
          int Deplacement = atoi ( &buffer[2]);
            break;
      }
      case 'C' :
      {
          Serial.println(analogRead(A5));
            break;
      }
      case 'D' :
      {
          val = analogRead(A5);           
          Serial.println(val);
          //int Deplacement = Distance / 0.005;
          unsigned long int ms = (1/(Speed * 3.33))*10000;

if (stop_mot == 0)
            {               
              Timer1.initialize(ms);
              Timer1.attachInterrupt(count);
              digitalWrite(Enable,HIGH);
            }
              break;
      }
      case 'E' :
        {
          Timer1.stop();
          digitalWrite(clock,LOW);
          digitalWrite(Enable,LOW);
          digitalWrite(dir,LOW);
          count_val=0;
          stop_mot = 0;
      break; 
      }
       
    }
}


Mais ... hé oui encore :p

toujours pas réglé le probleme de Speed qui n'est pas pris en compte comme il le faudrait :(

C'est pas ce que voulais dire.
Mais la je suis au ciné avec les gamins :slight_smile:
A plus tard

Bon ciné alors :slight_smile:

De retour de Palombie, je n'ai pas pu rapporter de Marsupilami mais je pense avoir trouver MON bug :smiley:
Il manque des accolades :

if (c == '$')
++buff_index;
else
{
// on empile les caractères dans le buffer jusqu'au max
if (buff_index < (BUFF_LEN-1))
++buff_index;
// si le caractère est le marqueur de fin, on a reçu un message entier
if ( (c == '\n') || (c == '\r') )
{
traite_message();
// le message a été traité, on repart à 0
buff_index = 0;
}
}

Il ne faut remettre buff_index à 0 qu'après avoir traité le message.
Sans les accolades, jamais on ne remplit le buffer donc jamais on a le message entier a traiter.

Sinon je te propose de tester '\n' ou '\r' pour la fin de commande.
Cela permet de tester le protocole avec un simple terminal qui envoi '\r' quand tu appuies sur "Entrée".

En dernier, je constate que tu as simplifié mon code probablement sans chercher à le comprendre.
Relit mon code original (le test sur buff_index) et essaye de comprendre sa raison.

Je suis entrain d'écrire un tuto sur le sujet car je pense que ca sera utile à de nombreuses personnes.