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.

ivancea96

El caso es que, este mismo código en C#, también dará problema. No es cosa del lenguaje, sinó de la lógica. Si tu switch va por el default, le estás obligando igualmente a leer datos del Arduino (que no tiene por qué haber).

Si lo que quieres es enviarle datos y leerlos a la vez, necesitarás threads.

MAFUS

Con hilos se complica un poco. Debes estar seguro de no recibir y emitir al mismo tiempo.

Pero si el arduino solo contesta a los comandos que recibe en el mismo case se emite el comando y se espera la respuesta.

Otra forma sería emulando la forma de trabajar de un PLC: se mira si hay algo de comunicación externa; se controlan las entradas; se calcula lo que se deba, se escriben las salidas; se escriben las comunicaciones externas.

ivancea96

Cita de: MAFUS en 19 Marzo 2017, 22:06 PM
Con hilos se complica un poco. Debes estar seguro de no recibir y emitir al mismo tiempo.

Pero si el arduino solo contesta a los comandos que recibe en el mismo case se emite el comando y se espera la respuesta.

Otra forma sería emulando la forma de trabajar de un PLC: se mira si hay algo de comunicación externa; se controlan las entradas; se calcula lo que se deba, se escriben las salidas; se escriben las comunicaciones externas.

Uy uy, que catastrofista  >:D
Realmente, utilizando GetAsyncKeyState() y 2 mutex (uno para la salida por consola y otro para el Serial), está sincronizado.
O al menos lo estaría si el protocolo PC-Arduino fuera más preciso, vaya. Porque como escriba el PC al Arduino y el Arduino al PC a la vez, el PC se tomará lo del Arduino como respuesta xD

MAFUS

Si fuera puerto serie puro se podrían usar las líneas CTS y RTS, pero al ser emulado no sé si existen.

ivancea96

O directamente, poniendole un "header" a los mensjaes:
~~ Arduino -> PC

<msg_type:1 byte>

(msg_type=1){
    ~~ Botón pulsado
    <datos:string>
}
(msg_type=2){
    ~~ Respuesta al PC
    <datos:string>
}

Meta

Hola:

Probando con C# se funciona la recepción de datos, en C++ con Win32 no tengo idea como se hace. ;)
Código (csharp) [Seleccionar]
using System;
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#";

            // 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;

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

            Puerto_serie.Open(); // Abrir puerto.

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

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




Para enviar datos si el puerto en C# es así:
Código (csharp) [Seleccionar]
byte[] mBuffer = Encoding.ASCII.GetBytes("Hola mundo");
    serialPort1.Write(mBuffer, 0, mBuffer.Length)


En C# lo hago rápido, deja acabarlo por completo y luego haber si es posible traducirlo al C++. ;)

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

ivancea96

El problema es la estructura del programa. Si te es más cómodo, hazlo en C#, y ya luego traduces.

De todos modos, trata de no usar handles. Maneja tú el flujo del programa. Sinó luego, al pasarlo a C++, va a ser más complicado.

MAFUS

Claro que el evento te controla el puerto pero eso lo debes hacer a mano.
Podrías crear un hilo que vaya monitorizando si el puerto ha recibido algo y te disparara una función, ese sería tu evento.

Meta

Hola:

Viendo lo visto, no he digo capaz, al menos por ahora, hacer un menú con fundamento para que me salga en C#, sigo con ello en paralelo ha este por si acaso. Me centraré en que si pulsas una tecla, directamente envía datos al puerto serie.

Código (cpp) [Seleccionar]
// Para crear conexión con los puertos COM1 - COM9.
// Serial* Arduino = new Serial("COM7");

// Para crear conexión con los puertos COM10 en adelante.
// Serial* Arduino = new Serial("\\\\.\\COM10");

#include <iostream>
#include <fstream>
#include <Windows.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 opc; // Guarda un 1 o 2 tipo entero queintroduces desde la consola.

while (Puerto->IsConnected())
{
cout << endl; // Dejamos un retorno.
cout << "Introduzca la opcion deseada: " << endl << endl; // Muestra texto en pantalla.

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

switch (opc) // Espera recibir un 1 o un 2.
{
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 (true) {
int n = Puerto->ReadData(lectura, 49);
if (n > 0) {
lectura[n + 1] = '\0';
break;
}
Sleep(1);
}
cout << "Recibido: " << lectura << endl;
cout << "-------------------" << endl;
}
}


Habías comentado algo así:
Código (cpp) [Seleccionar]
// Tecla 'B' pulsada
if (GetAsyncKeyState('B') & 0x8000)
{
// Apagar luz.
cout << "Enviando: " << Luz_OFF << endl;
Puerto->WriteData(Luz_OFF, sizeof(Luz_OFF) - 1);
}


Pero no funcionaba, daba cosas raras.

Me conformo lo de enviar datos al puerto serie y acto seguido responde desde Arduino, hasta ahí bien, solo falta pulsar una tecla, desde que detecta la tecla, a enviar datos, no que primero pulse una tecla, luego Enter para enviar datos como hasta ahora.

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

ivancea96

CitarPero no funcionaba, daba cosas raras.
"Cosas raras" xD
El problema de ponerlo directamente así, es que si pulsas una letra, mientras la tengas pulsada, va a ser true ese if, con lo que entrará muchas veces seguidas.