Arduino + Comunicación serial + C#

Iniciado por Mr.Blue, 4 Marzo 2016, 03:21 AM

0 Miembros y 2 Visitantes están viendo este tema.

Mr.Blue

Buenas,

Consulta estoy testeando la comunicación serial en mi arduino, arme el código y lo subí al ATMEGA, al utilizar monitor serie de del IDE de arduino puedo prender y apagar 2 leds. Es decir que el código funciona OK.
El problema surge cuando quiero realizar la comunicación con C#. Cuando veo el arduino  apretó algún botón para prender o apagar un led desde la aplicación en C# enciende el led RX del arduino como si estuviera recibiendo la orden pero no enciende el led.

¿Alguna idea de que puede ser?
Una observación: No tengo fuente externa, es decir alimento con USB. Para un par de leds no creo que afecte.

Por las dudas dejo el código pero no tiene nada raro es bastante sencillo.

Código (csharp) [Seleccionar]
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;

namespace SerialArduino
{
    public partial class Form1 : Form
    {
        SerialPort mySerial;
       
        public Form1()
        {
            InitializeComponent();
            init();
        }
        private void init()
        {
            try
            {
  //              if (mySerial.IsOpen == false)
  //              {
                    mySerial = new SerialPort();
                    mySerial.BaudRate = 9600;
                    mySerial.PortName = "COM3";
                    mySerial.Open();
  //              }
            }
            catch (Exception)
            {
                MessageBox.Show("Error");
            }

            button1.Enabled = true;
            button2.Enabled = false;
            button3.Enabled = true;
            button4.Enabled = false;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                mySerial.Write("led1");
                mySerial.Write("on");

                button1.Enabled = false;
                button2.Enabled = true;
               
            }
            catch (Exception)
            {
                MessageBox.Show("Error");
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            try
            {
                mySerial.Write("led1");
                mySerial.Write("off");
               
                button1.Enabled = true;
                button2.Enabled = false;
            }
            catch (Exception)
            {
                MessageBox.Show("Error");
            }

        }

        private void button3_Click(object sender, EventArgs e)
        {
            try
            {
                mySerial.Write("led2");
                mySerial.Write("on");
                string var = mySerial.ReadLine();
                MessageBox.Show(var);

                button3.Enabled = false;
                button4.Enabled = true;
            }
            catch (Exception)
            {
                MessageBox.Show("Error");
            }
        }

        private void button4_Click(object sender, EventArgs e)
        {
            try
            {
                mySerial.Write("led2");
                mySerial.Write("off");

                button3.Enabled = true;
                button4.Enabled = false;
            }
            catch (Exception)
            {
                MessageBox.Show("Error");
            }
        }
    }
}


El código de arduino
int led1 = 2;
int led2 = 3;
//int led3 = 4;
String selectedLed;
String selectedStatus;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
//  pinMode(led3, OUTPUT);
}

void loop() {
  selectedLed = "";
  selectedStatus = "";
  // put your main code here, to run repeatedly:
  while(Serial.available()==0){
  }
  selectedLed = Serial.readString();

  while(Serial.available()==0){
  }
  selectedStatus = Serial.readString();

  Serial.println(selectedLed);
  Serial.print(selectedStatus);
  if (selectedLed == "led1")
  {
    if (selectedStatus == "on")
    {
      digitalWrite(led1,HIGH);
    }
    else
    {
      if(selectedStatus == "off")
      {
        digitalWrite(led1,LOW);
      }
    }
  }
  else
  {
    if(selectedLed == "led2")
    {
      if (selectedStatus == "on")
      {
        digitalWrite(led2,HIGH);
      }
      else
      {
        if(selectedStatus == "off")
        {
          digitalWrite(led2,LOW);
        }
      }
    }
  }
}


Meta

#1
Hola:

Te dejo mis documentos que hice sobre encender y apagar un Led Arduino con C# y otros lenguajes de Visual Studio. También otro documento a la hora de recibir datos desde Arduino y C#.

[youtube=640,360]https://www.youtube.com/watch?v=Ra2PBfLFuHk[/youtube]

Prueba este código de Arduino y compruebas si te funciona.


int led1 =  2;   // Declaramos la variable pin del Led 1.
int led2 =  3;   // Lo mismo para el Led 2.
char caracter;
String comando;

void setup()
{
 Serial.begin(9600);
}

void loop()
{
 pinMode(led1, OUTPUT);  // Inicializa el pin del Led 1 como salida.
 pinMode(led2, OUTPUT);
 /* Voy leyendo carácter a carácter lo que se recibe por el canal
  *  serie (mientras llegue algún dato allí), y los voy concatenando
  *  uno tras otro en una cadena. En la práctica, si usamos el
  *  "Serial monitor" el bucle while acabará cuando pulsemos Enter.
  *  El delay es conveniente para no saturar el canal serie y que la
  *  concatenación se haga de forma ordenada.
  */
 while (Serial.available() > 0)
 {
   caracter= Serial.read();
   comando.concat(caracter);
   delay(10);
 }

 /* Unavez ya tengo la cadena "acabada", compruebo su valor y hago
  * que la placa Arduino reaccione según sea este. Aquí podríamos
  * hacer lo que quiesiéramos: si el comando es "tal", enciende
  * un Led, si es cual, mueve un motor... y así.
  */

  // Led 1.
 if (comando.equals("on1") == true)
 {
       digitalWrite(led1, HIGH); // Enciende el Led.
       Serial.println("Led 1 encendido.");
 }
       
 if (comando.equals("off1") == true) // Led_OFF.
 {
       digitalWrite(led1, LOW); // Apaga el Led.
       Serial.println("Led 1 apagado.");
 }
 
 // Led 2.
 if (comando.equals("on2") == true)
 {
       digitalWrite(led2, HIGH); // Enciende el Led.
       Serial.println("Led 2 encendido.");
 }
       
 if (comando.equals("off2") == true) // Led_OFF.
 {
       digitalWrite(led2, LOW); // Apaga el Led.
       Serial.println("Led 2 apagado.");
 }
 // Limpiamos la cadena para volver a recibir el siguiente comando.
 comando="";
}


Tendrás que modificar cosas de C#, como los comandos a enviar que son on1, off1, on2 y off2.

Fíjate en los enlaces arriba, si lo quieres en PDF directo pues te dejo uno aquí y otro aquí.

En C#, procura enviar datos en tramas de bytes o al menos codificado, ejemplo, haz puesto esto:
Código (csharp) [Seleccionar]
mySerial.Write("led1");
               mySerial.Write("off");


Prueba co ntu mismo código C# usando esto entre medio, así no se trunca.
Código (csharp) [Seleccionar]
mySerial.Write("led1");
Thread.Sleep(2000);
               mySerial.Write("off");

No olvidar el using llamado:
Código (csharp) [Seleccionar]
using System.Threading;

Más información aquí.
https://msdn.microsoft.com/es-es/library/d00bd51t%28v=vs.110%29.aspx

Lo sustituye por este otro.
Código (csharp) [Seleccionar]
           byte[] mBuffer = Encoding.ASCII.GetBytes("on1"); // Envía comando ACTUALIZAR por el puerto.
           mySerial.Write(mBuffer, 0, mBuffer.Length);


Además, veo que envías led1 y acto seguido off, claro que no te funciona, lo envías todo junto y sin haber espacios por medio al menos con un tiempo.

No olvide que en los PDF te puede descargar proyecto completo de Visual C# para qu ehagas pruebas con Arduino.

Saludos.
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/

Mr.Blue

#2
Gracias Meta, justo luego de postear vi que habías publicado un tutorial relacionado. Probando el código que me pasas anda 10 puntos.

Ya se me había cruzado por la cabeza que el problema debía estar al mandar la escritura al puerto sin ningún tipo de delay.

Código (csharp) [Seleccionar]
mySerial.Write("led1");
mySerial.Write("off");


Aun así usando el mismo código Arduino que publique mas el Sleep que sugerís para darle tiempo a ejecutar el comando y no se trunque, sigue sin funcionar.
Código (csharp) [Seleccionar]
mySerial.Write("led1");
Thread.Sleep(2000);
mySerial.Write("off");


Viendo el código arduino que me pasaste haces uso de un único IMPUT. El cual evalúa si es: on1, off1, on2, off2.
El punto es, que pasa si en mi comunicación serial necesito ingresar mas de una comando?.

Ahí revisando un poco mas pude hacer que funcione con el mismo código arduino que pase.
Lo único que agregue en C#, fue lo que me dijiste.
Código (csharp) [Seleccionar]
mBuffer = Encoding.ASCII.GetBytes("led2"); // Envía comando ACTUALIZAR por el puerto.
mySerial.Write(mBuffer, 0, mBuffer.Length);
Thread.Sleep(2000);
mBuffer = Encoding.ASCII.GetBytes("on"); // Envía comando ACTUALIZAR por el puerto.
mySerial.Write(mBuffer, 0, mBuffer.Length);

Por lo visto, no le gusto el serial.Write crudo jaja.

Gracias por la mano!!
Saludos

Meta

Hola:

Me alegro que te funcione. En cuanto a la pregunta sobre que pasa si envías más de un comando. Simplemente envías comandos en una cadena desde Arduino y usa delimitadores en C# para separar esos comandos de una cadena para luego interpretarlo.

También puedes hacerlo como hiciste usando varias veces el mySerial pero la manera como te he presentado. Lo hicieste.
Código (csharp) [Seleccionar]
mBuffer = Encoding.ASCII.GetBytes("led2"); // Envía comando ACTUALIZAR por el puerto.
mySerial.Write(mBuffer, 0, mBuffer.Length);
Thread.Sleep(2000);
mBuffer = Encoding.ASCII.GetBytes("on"); // Envía comando ACTUALIZAR por el puerto.
mySerial.Write(mBuffer, 0, mBuffer.Length);


En caso que tuvieras problemas con los Enconding, lo haces que funcione seguro por tramas de bytes de esta manera y funciona al 100 %.
Código (csharp) [Seleccionar]
private void button_t_Click(object sender, EventArgs e)
{
    byte[] mBuffer = new byte[5];
    mBuffer[0] = 0x74;
    mBuffer[1] = 0x75;
    mBuffer[2] = 0x89;
    mBuffer[3] = 0x20;
    mBuffer[4] = 0x6C;
    serialPort1.Write(mBuffer, 0, mBuffer.Length);
}


Eso si, tienes que mirar la tabla ASCII.


Esto lo publiqué aquí hace tiempo.
http://www.codeproject.com/Articles/46603/A-PicRS-control-with-a-PIC-microcontroller-seri

Saludos.
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/