Puerto serie C++. Mejorar el programa.

Iniciado por Meta, 16 Marzo 2017, 22:21 PM

0 Miembros y 1 Visitante están viendo este tema.

Meta

La cosa rara que hace es  no volver a la opción principal si no pones un 1 o un 2, desde que pongas otra cosa, no sale de ahí.

La cuestión es como se hace.

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

ivancea96

En primer lugar, yo separaría estoa  una función:

Código (cpp) [Seleccionar]
while (true) {
int n = Puerto->ReadData(lectura, 49);
if (n > 0) {
lectura[n + 1] = '\0';
break;
}
Sleep(1);
}

Una función que espere a que el Arduino envíe datos, y los retorne.

Lo de esperar datos solo lo vas a hacer si pulsan 1 o 2, así que llamas a esa función en cada case. Es cierto que los 2 case son idénticos salvo por la constante que envías. Podrías poner algo como:
Código (cpp) [Seleccionar]
const char *luz[2] = {"Luz_ON", "Luz_OFF"};

switch(opc){
    case 1:
    case 2:
        cout << "Enviando: " << luz[opc-1] << endl;
        Puerto->WriteData(luz[opc-1], strlen(luz[opc-1]));
        cout << "Respuesta: " << obtenerRespuestaArduino() << endl;
        break;

    default:
        // ...
}


De ese modo, solo esperará entrada del Arduino cuando sea necesario hacerlo. Al terminar el switch, puedes poner, si quieres, para leer datos del Arduino (sin esperar indefinidamente, eso sí, para que vuelva al inicio del bucle while y siga preguntando)

El problema es eso, el cómo está estructurado el código. Lo dicho: si tienes más experiencia en C#, puedes tratar de hacerlo ahí primero.

Meta

#32
Hola:

A pesar de tener más experiencia con C#, con la idea de pasarlo a C++, he hecho esto.

Código C#:
Código (csharp) [Seleccionar]
using System;
using System.Text;
using System.IO.Ports;

namespace Envio_y_recepcion_puerto_serie_cs
{
   class Program
   {
       static void Main(string[] args)
       {
           // Título de la ventana.
           Console.Title = "Recibir datos desde Arduino con C#";

           // Tamaño ventana consola.
           Console.WindowWidth = 55; // X. Ancho.
           Console.WindowHeight = 18; // Y. Alto.

           // Cree un nuevo objeto SerialPort con la configuración predeterminada.
           SerialPort Puerto_serie = new SerialPort("COM4");

           Puerto_serie.BaudRate = 115200;
           Puerto_serie.Parity = Parity.None;
           Puerto_serie.StopBits = StopBits.One;
           Puerto_serie.DataBits = 8;
           Puerto_serie.Handshake = Handshake.None;
           Puerto_serie.RtsEnable = true;

           // Establecer los tiempos de espera de lectura / escritura.
           Puerto_serie.ReadTimeout = 500; // Milisegundos.
           Puerto_serie.WriteTimeout = 500;

           // Detecta cualquier dato recibido.
           Puerto_serie.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);

           Puerto_serie.Open(); // Abrir puerto.

           ConsoleKey tecla;
           Console.WriteLine("Pulse tecla 1 para encender y 2 para apagar:");

           do
           {
               tecla = Console.ReadKey(true).Key; // Espera pulsación de teclas.

               switch (tecla)
               {
                   case ConsoleKey.D1: // Tecla 1 del teclado estandar.
                   case ConsoleKey.NumPad1: // Tecla 1 del número del pad.
                       byte[] miBuffer1 = Encoding.ASCII.GetBytes("Luz_ON"); // Codificación ASCII y guarda en la variable array tipo byte.
                       Puerto_serie.Write(miBuffer1, 0, miBuffer1.Length); // Envía los datos del buffer todo su contenido.
                       Console.WriteLine("Enviado: {0}", miBuffer1); // Muestra en pantala el mensaje enviado, en este caso, Luz_ON.
                       break;

                   case ConsoleKey.D2:
                   case ConsoleKey.NumPad2:
                       byte[] miBuffer2 = Encoding.ASCII.GetBytes("Luz_OFF");
                       Puerto_serie.Write(miBuffer2, 0, miBuffer2.Length);
                       //Console.WriteLine("Enviado: {0}", miBuffer2);
                       break;

                   default:
                       Console.WriteLine("Tecla el 1, el 2 y Escape para salir.");
                       break;
               }
           }

           // Pulsa Escape para salir del menú.
           while (tecla != ConsoleKey.Escape);

           Console.WriteLine("Presione cualquier tecla para continuar...");
           Console.WriteLine();
           Console.ReadKey(); // Espera pulsar una tecla cualquiera.
           Puerto_serie.Close(); // Cierra el puerto serie.
       }

   // Detecta cualquier dato entrante.
   private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
       {
           SerialPort sp = (SerialPort)sender;
           string entradaDatos = sp.ReadExisting(); // Almacena los datos recibidos en la variable tipo string.
           Console.WriteLine("Dato recibido desde Arduino: " + entradaDatos); // Muestra en pantalla los datos recibidos.
       }
   }
}


Es este último código que me funciona mejor, también he intentado que me muestre el valor enviado y me diga en pantalla:

Enviado: Luz_ON


He usado esto para que muestre lo que envía:
Código (csharp) [Seleccionar]
Console.WriteLine("Enviado: {0}", miBuffer1);

Su resultado fue este:
Enviado: system.Byte[]

¿Pero qué es esto?

Concretamente aquí:
Código (csharp,5) [Seleccionar]
                   case ConsoleKey.D1:
                   case ConsoleKey.NumPad1:
                       byte[] miBuffer1 = Encoding.ASCII.GetBytes("Luz_ON");
                       Puerto_serie.Write(miBuffer1, 0, miBuffer1.Length);
                       Console.WriteLine("Enviado: {0}", miBuffer1);
                       break;


Lo bueno que también ya recibo el ON y OFF si pulso el pulsador dede Arduino directamente. Funciona todo menos lo indicado justo arriba.

Debe aparecer de esta manera: Luz_ON

Aparece en hexadecimales. ;)

Código (csharp) [Seleccionar]
Console.WriteLine("Enviado: {0}", BitConverter.ToString(miBuffer1));
Cuando esté listo todo C#, ya se podrá hacer el C++ de una vez por todas, jaaaj ajajajja. Eso espero y se las debo a todos. ;)

PD: No me había dado cuenta que tienes un blog, no sabía que eres un profesional de C++.
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/

ivancea96

Prueba con:
Código (csharp) [Seleccionar]
Encoding.ASCII.GetString(miBuffer1);

Meta

#34
Buenas:

Lo había probado, da este error:
Citarno se puede convertir de 'byte[]' a 'char[]'

Bueno, como no es importante, pues lo que tenemos arriba con C# ya se puede hacer una idea de como se puede hacer en C++. Mira que da guerra el C++ de las narices, no me extraña que Java junto con C# desbanque a C++ Win32 como lenguaje principal para un informático.

Empezando otra vez con las grandes aventuras con el C++ de Win32, ;)
Como se puede ver en el código de C# arriba, hay que usar un do while.
https://msdn.microsoft.com/es-es/library/b0kk5few.aspx

Tutorial:
[youtube=640,360]https://www.youtube.com/watch?v=MRiBUpgn-Z0[/youtube]



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

ivancea96

Pero si el único problema que tenías era la estructura (que es lo mismo en C++ como en C#) ._.

Y sobre el error, aseg´ñurate de que usas el método correcto: https://msdn.microsoft.com/es-es/library/744y86tc(v=vs.110).aspx

Meta

Lo más parecido que he hecho es esto.
Código (cpp) [Seleccionar]
#include <iostream>
#include <fstream>
#include <Windows.h>
#include <stdio.h>
#include "SerialClass.h"
using namespace std;

void main()
{
// Título de la ventana
SetConsoleTitle("Control Led Arduino.");

// Puerto serie.
Serial* Puerto = new Serial("COM4");

// Comandos para Arduino.
char Luz_ON[] = "Luz_ON"; // Envía "Luz_ON" al puerto serie.
char Luz_OFF[] = "Luz_OFF";
char lectura[50] = "\0"; // Guardan datos de entrada del puerto.
int tecla; // Guarda las teclas pulsadas.

cout << "Introduzca la opcion deseada: " << endl << endl;
cin >> tecla; // Aquí introduces un número, el 1 o el 2.

do
{
while (tecla)
{
case 1:
// Encener luz.
cout << "Enviando: " << Luz_ON << endl; // Muestra en pantalla textos.
Puerto->WriteData(Luz_ON, sizeof(Luz_ON) - 1); // Envía al puerto el texto "Luz_ON".
break;

case 2:
// Apagar luz.
cout << "Enviando: " << Luz_OFF << endl;
Puerto->WriteData(Luz_OFF, sizeof(Luz_OFF) - 1);
break;

default: // Si haz pulsado otro número distinto del 1 y 2, muestra
cout << "Puse del 1 al 2."; // este mensaje.
}

} while (tecla != 0);
}

    while (true) {
    int n = Puerto->ReadData(lectura, 49);
    if (n > 0) {
    lectura[n + 1] = '\0';
    break;
    }
    Sleep(1);
    }
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/

ivancea96

Parecido sí, pero de forma incorrecta:
En C# tienes esto:
Código (csharp) [Seleccionar]
            do
            {
                tecla = Console.ReadKey(true).Key; // Espera pulsación de teclas.


En C++ tienes esto otro:
Código (cpp) [Seleccionar]
cin >> tecla; // Aquí introduces un número, el 1 o el 2.

do
{

La diferencia entre uno y otro es que el C++ va a quedarse en un bucle infinito.

Y pusiste:
Código (cpp) [Seleccionar]
while (tecla)
{
case 1:

._.

Meta

Buenas:

Código (cpp) [Seleccionar]
#include <iostream>
#include <fstream>
#include <Windows.h>
#include <stdio.h>
#include "SerialClass.h"
using namespace std;

void main()
{
// Título de la ventana
SetConsoleTitle("Control Led Arduino.");

// Puerto serie.
Serial* Puerto = new Serial("COM4");

// Comandos para Arduino.
char Luz_ON[] = "Luz_ON"; // Envía "Luz_ON" al puerto serie.
char Luz_OFF[] = "Luz_OFF";
char lectura[50] = "\0"; // Guardan datos de entrada del puerto.
int tecla; // Guarda las teclas pulsadas.

cout << "Introduzca la opcion deseada: " << endl << endl;


do
{
cin >> tecla; // Aquí introduces un número, el 1 o el 2.

while (tecla)
{
case 1:
// Encener luz.
cout << "Enviando: " << Luz_ON << endl; // Muestra en pantalla textos.
Puerto->WriteData(Luz_ON, sizeof(Luz_ON) - 1); // Envía al puerto el texto "Luz_ON".
break;

case 2:
// Apagar luz.
cout << "Enviando: " << Luz_OFF << endl;
Puerto->WriteData(Luz_OFF, sizeof(Luz_OFF) - 1);
break;

default: // Si haz pulsado otro número distinto del 1 y 2, muestra
cout << "Puse del 1 al 2."; // este mensaje.
}

} while (tecla != 0);

while (true) {
int n = Puerto->ReadData(lectura, 49);
if (n > 0) {
lectura[n + 1] = '\0';
break;
}
Sleep(1);
}
}


Como no se como se llaman las cosas en C++, ya me atasqué. En C# funciona todo bien. ;)

Ahora si necesito ayuda bien ayuda para sacar esto de una vez. A parte que tengo otro proyecto en mente con lo mismo pero en MFC C++. ;)

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

ivancea96

Cita de: ivancea96 en 24 Marzo 2017, 18:11 PM
Parecido sí, pero de forma incorrecta:
En C# tienes esto:
Código (csharp) [Seleccionar]
            do
            {
                tecla = Console.ReadKey(true).Key; // Espera pulsación de teclas.


En C++ tienes esto otro:
Código (cpp) [Seleccionar]
cin >> tecla; // Aquí introduces un número, el 1 o el 2.

do
{

La diferencia entre uno y otro es que el C++ va a quedarse en un bucle infinito.

Y pusiste:
Código (cpp) [Seleccionar]
while (tecla)
{
case 1:

._.
Línea 29.
Código (cpp) [Seleccionar]
while (tecla)
No es while, es switch.