Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: Meta en 16 Marzo 2017, 22:21



Título: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 16 Marzo 2017, 22:21
Buenas:

Tengo un programa aquí que no está bien hecho del todo.

Envía datos al puerto seria, concretamente llega a Arduino. Los datos llegan bien, al recibir, ya no tanto.

Si pulsas la tecla, por ejemplo 5, primero se ve reflejado y luego tengo que pulsar Enter. Lo que quiero lograr es que si pulse el número 5, automáticamente ejecuta la instruacción del case 5 del Switch.

Otra cosa, es que no me llegan los datos desde Arduino cuando le pulso un botón. C++ tiene que ser capaz, desde que le llegue algún dato, reflejarlo en pantalla.

La librería a usar es esta.

https://github.com/Gmatarrubia/LibreriasTutoriales

El código de C++ es:
Código
  1. #include <iostream>
  2. #include <fstream>
  3. #include <Windows.h>
  4. #include "SerialClass.h"
  5. using namespace std;
  6.  
  7. void main()
  8. {
  9. SetConsoleTitle("Control Led 13 de Arduino UNO y saludos.");
  10.  
  11. Serial* Puerto = new Serial("COM4");
  12.  
  13. while (Puerto -> IsConnected())
  14. {
  15.  
  16. // Comandos para Arduino.
  17. char L_ON[] = "Led13_ON";
  18. char L_OFF[] = "Led13_OFF";
  19. char Saludar[] = "Hola Arduino. Saludos desde el PC con C++ bajo  Win32.";
  20. char Luz_ON[] = "Luz_ON";
  21. char Luz_OFF[] = "Luz_OFF";
  22. char lectura[50];
  23.  
  24. int opc;
  25.  
  26. cout << "Introduzca la opcion deseada: ";
  27.  
  28. cin >> opc;
  29.  
  30. switch (opc)
  31. {
  32. case 1:
  33. cout << "caso 1\n";
  34. // Enviar encender Led.
  35. cout << "Enviando: " << L_ON << endl;
  36. Puerto -> WriteData(L_ON, sizeof(L_ON) - 1);
  37. break;
  38.  
  39. case 2:
  40. cout << "caso 2\n";
  41. // Enviar apagar Led.
  42. cout << "Enviando: " << L_OFF << endl;
  43. Puerto -> WriteData(L_OFF, sizeof(L_OFF) - 1);
  44. break;
  45.  
  46. case 3:
  47. cout << "caso 3\n";
  48. // Mensaje saludar.
  49. cout << "Enviando: " << Saludar << endl;
  50. Puerto -> WriteData(Saludar, sizeof(Saludar) - 1);
  51. break;
  52.  
  53. case 4:
  54. cout << "caso 4\n";
  55. // Mensaje saludar.
  56. cout << "Enviando: " << Luz_ON << endl;
  57. Puerto->WriteData(Luz_ON, sizeof(Luz_ON) - 1);
  58. break;
  59.  
  60. case 5:
  61. cout << "caso 5\n";
  62. // Mensaje saludar.
  63. cout << "Enviando: " << Luz_OFF << endl;
  64. Puerto->WriteData(Luz_OFF, sizeof(Luz_OFF) - 1);
  65. break;
  66.  
  67. default:
  68. cout << "Puse del 1 al 5.";
  69. }
  70.  
  71. Puerto -> ReadData(lectura, 50);
  72. cout << "Recibido: " << lectura << endl;
  73.  
  74. cout << "-------------------" << endl;
  75.  
  76. // system("PAUSE");
  77. }
  78. }

¿Alguna ayuda?

Un cordial saludo.

PD: Uso Visual Studio Community 2017, lenguaje C++ bajo Win32.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: ivancea96 en 16 Marzo 2017, 22:45
Utilizando el input normal de la consola no puedes hacer esto que comentas.

Lo que sí puedes hacer, es utilizar funciones de WinAPI para obtener las teclas pulsadas, como GetAsyncKeyState (https://msdn.microsoft.com/en-us/library/windows/desktop/ms646293(v=vs.85).aspx). Entonces ya tendrás total control de la consola sin bloqueos para entrada del usuario. Incluso multi-thread si lo necesitases.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 16 Marzo 2017, 23:16
Hola:

Muchas gracias. Si te digo la verdad, no entiendo ni papa. Jajaajjajajaja. Soy de C# y este C de Win32 (https://msdn.microsoft.com/es-es/library/cc438773%28v=vs.71%29.aspx?f=255&MSPPError=-2147217396) o en WinAPI (https://es.wikipedia.org/wiki/API_de_Windows).

Lo que tiene que hacer el programa es enviar este comando que lo hace bien.
Código
  1. cout << "Enviando: " << L_ON << endl;
  2. Puerto -> WriteData(L_ON, sizeof(L_ON) - 1);

Arduino lo detecta.

Luego recibir este comando que no se si lo hace bien. Cuando Arduino le envía mensajes a C++ del PC.
Código
  1. Puerto -> ReadData(lectura, 50);
  2. cout << "Recibido: " << lectura << endl;

Para los que me respondieron en privado lo pongo en público.
Citar
Si hay que usar el Dev C++.
(https://a.fsdn.com/allura/p/orwelldevcpp/icon?1480458710)

Pues a suarlo.
https://sourceforge.net/projects/orwelldevcpp/

Otros con el Code Blocks (http://www.codeblocks.org/), que no se ponen de acuerdo. Para mi solo son IDE y me quedo con Visual studio 2017 que me gusta más. ;)

¿Alguna ayuda?

Saludos.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: ivancea96 en 17 Marzo 2017, 00:21
"No sabes si lo hace bien"? Pues yo menos ._.

En cualquier caso, mi respuesta iba orientada a:

Si pulsas la tecla, por ejemplo 5, primero se ve reflejado y luego tengo que pulsar Enter. Lo que quiero lograr es que si pulse el número 5, automáticamente ejecuta la instruacción del case 5 del Switch.
Para lo cual, puedes usar la función GetAsyncKeyState (https://msdn.microsoft.com/es-es/library/windows/desktop/ms646293(v=vs.85).aspx) de WinAPI.
En al documentación explica su retorno:
Citar
If the function succeeds, the return value specifies whether the key was pressed since the last call to GetAsyncKeyState, and whether the key is currently up or down. If the most significant bit is set, the key is down

Por tanto, comprobamos el bit:
Código
  1. if(GetAsyncKeyState(tecla) & 0x8000){
  2.    // Tecla pulsada
  3. }

El código de la tecla es un VirtualKey Code: https://msdn.microsoft.com/es-es/library/windows/desktop/dd375731(v=vs.85).aspx (https://msdn.microsoft.com/es-es/library/windows/desktop/dd375731(v=vs.85).aspx). En cualquier caso, decirte que los codigos de las letras coinciden con los caracteres de las letras mayúsculas:

Código
  1. if(GetAsyncKeyState('A') & 0x8000){
  2.    // Tecla 'A' pulsada
  3. }


Y con respecto a lo del IDE que comentaste, no sé de qué hablabais, pero por supuesto que no importa el IDE.

y bueno, lo dicho:
Citar
Luego recibir este comando que no se si lo hace bien.
Describe qué es lo que no sabes si hace bien y por qué.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 17 Marzo 2017, 02:57
Hola Señor:

He hecho el proyecto desde el principio. Como me lía en C++ de Win32, jajajajajja. Y eso que me lo recomendaron mucha gente para aprenerlo, ni viniendo de C#. ;) A lo que íabmos.

La parte donde pone if (GetAsyncKeyState('A') & 0x8000) , precisamente 0x8000 no lo entiendo y no lo pone aquí (https://msdn.microsoft.com/es-es/library/windows/desktop/dd375731%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396).

Con este código me aparece el mensaje en pantalla pero no es capaz de enviar algo a Arduino o datos al puerto serie.
Código
  1. #include <iostream>
  2. #include <fstream>
  3. #include <Windows.h>
  4. #include "SerialClass.h"
  5. using namespace std;
  6.  
  7. void main()
  8. {
  9. // Título de la ventana.
  10. SetConsoleTitle("Control Led 13 de Arduino UNO y saludos.");
  11.  
  12. // Nombre del puerto selecconado.
  13. Serial* Puerto = new Serial("COM4");
  14.  
  15. // Variables. Comandos para enviar a Arduino por puerto serie.
  16. char L_ON[] = "Led13_ON";
  17. char L_OFF[] = "Led13_OFF";
  18. char Saludar[] = "Hola Arduino. Saludos desde el PC con C++ bajo  Win32.";
  19. char Luz_ON[] = "Luz_ON";
  20. char Luz_OFF[] = "Luz_OFF";
  21.  
  22. // Para almacenar datos desde el puerto serie.
  23. char lectura[50];
  24.  
  25. // Mostrar texto en pantalla.
  26. cout << "Pulse letra 'A' para endender Led y 'B' para apagar: " << endl;
  27.  
  28. while (Puerto->IsConnected())
  29. {
  30. // Tecla 'A' pulsada
  31. if (GetAsyncKeyState('A') & 0x8000)
  32. {
  33. cout << "Enviando: " << Luz_ON << endl;
  34. Puerto->WriteData(Luz_ON, sizeof(Luz_ON) - 1);
  35. }
  36.  
  37. // Tecla 'B' pulsada
  38. if (GetAsyncKeyState('B') & 0x8000)
  39. {
  40. cout << "Enviando: " << Luz_OFF << endl;
  41. Puerto->WriteData(Luz_OFF, sizeof(Luz_OFF) - 1);
  42. }
  43. }
  44.  
  45. system("PAUSE");
  46. }

Parece ser que ignora esta instrucción.
Código
  1. Puerto->WriteData(Luz_OFF, sizeof(Luz_OFF) - 1);

Aquí una captura cuando pulsa solo la B o la A. Se repite muchas veces. (Si es posible hacer el tamaño de la ventana (https://codepad.co/snippet/5c70c0) en la programación de C++, mejor que mejor).
(http://www.subeimagenes.com/img/sin-titulo-2-1717415.gif)

Lo de recibir comandos desde el peurto serie o Arduino es este el que me refería:
Código
  1. Puerto -> ReadData(lectura, 50);
  2. cout << "Recibido: " << lectura << endl;

Que este programa al mismo tiempo que envía comandos, también los puede recibir. Si el programa C++ no le hago nada, solo lo dejo arrancado, desde el puerto serie puede venir cualquier dato y C++ debe leerlo sin problemas.

Saludos.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: MAFUS en 17 Marzo 2017, 10:37
Y de parte del arduino cómo lo tienes?
Funciona con hypeterminal?


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: ivancea96 en 17 Marzo 2017, 13:10
La parte donde pone if (GetAsyncKeyState('A') & 0x8000) , precisamente 0x8000 no lo entiendo y no lo pone aquí (https://msdn.microsoft.com/es-es/library/windows/desktop/dd375731%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396).
No, no lo pone ahí. Lo pone aquí: https://msdn.microsoft.com/es-es/library/windows/desktop/ms646293(v=vs.85).aspx (https://msdn.microsoft.com/es-es/library/windows/desktop/ms646293(v=vs.85).aspx)
Citar
If the function succeeds, the return value specifies whether the key was pressed since the last call to GetAsyncKeyState, and whether the key is currently up or down. If the most significant bit is set, the key is down
El bit más significativo en un short es, digamos, ""el de la izquierda"". 0x8000 en binario es 0b1000_0000_0000_0000. Haciendo un and (&), sacamos si ese bit está activo o no. Si está activo, el resultado será diferente de 0, así que se ejecutará el contenido del if. Si no está pulsada, el bit estará a 0, y el AND retornará 0. El if, en ese caso, no se ejecutará.

Parece ser que ignora esta instrucción.
Código
  1. Puerto->WriteData(Luz_OFF, sizeof(Luz_OFF) - 1);

Aquí una captura cuando pulsa solo la B o la A. Se repite muchas veces. (Si es posible hacer el tamaño de la ventana (https://codepad.co/snippet/5c70c0) en la programación de C++, mejor que mejor).
(http://www.subeimagenes.com/img/sin-titulo-2-1717415.gif)
Sobre el tema de que se repita muchas veces es porque el GetAsyncKeyState te dice que está pulsada, no si ha sido pulsada. Por tanto, si mantienes la tecla,  entrará muchas veces. Tendrías que controlar si ha sido pulsada ahora o si ya estaba pulsada.

Lo de recibir comandos desde el peurto serie o Arduino es este el que me refería:
Código
  1. Puerto -> ReadData(lectura, 50);
  2. cout << "Recibido: " << lectura << endl;

Que este programa al mismo tiempo que envía comandos, también los puede recibir. Si el programa C++ no le hago nada, solo lo dejo arrancado, desde el puerto serie puede venir cualquier dato y C++ debe leerlo sin problemas.

Como dice MAFUS, esto es un protocolo con 2 programas. Conocemos el de Windows, pero no conocemos el de Arduino. ¿No podría ser problema del programa del Arduino?


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 17 Marzo 2017, 14:41
Buenos días Señor:

Estuve haciendo pruenas a mi manera, la de poner un número y luego pulsa Enter. Hace cosas raras todavía. Lo raro que hace es almacenar información que viene de Arduino. Lo ideal sería, que si viene algo desde Arduino, se muestre en pantalla de C++, luego se borre, preparado para que llegue otro nuevo mensaje. El truco de las teclas, todavía no me sale.
Código
  1. #include <iostream>
  2. #include <fstream>
  3. #include <Windows.h>
  4. #include "SerialClass.h"
  5. using namespace std;
  6.  
  7. void main()
  8. {
  9. SetConsoleTitle("Control Led 13 de Arduino UNO y saludos.");
  10.  
  11. Serial* Puerto = new Serial("COM4");
  12.  
  13. while (Puerto -> IsConnected())
  14. {
  15.  
  16. // Comandos para Arduino.
  17. char L_ON[] = "Led13_ON";
  18. char L_OFF[] = "Led13_OFF";
  19. char Saludar[] = "Hola";
  20. char Luz_ON[] = "Luz_ON";
  21. char Luz_OFF[] = "Luz_OFF";
  22. char lectura[50] = "\0";
  23.  
  24. int opc;
  25.  
  26. cout << endl;
  27. cout << "Introduzca la opcion deseada: " << endl << endl;
  28.  
  29. cin >> opc;
  30.  
  31. switch (opc)
  32. {
  33. case 1:
  34. cout << "caso 1\n";
  35. // Enviar encender Led.
  36. cout << "Enviando: " << L_ON << endl;
  37. Puerto -> WriteData(L_ON, sizeof(L_ON) - 1);
  38. break;
  39.  
  40. case 2:
  41. cout << "caso 2\n";
  42. // Enviar apagar Led.
  43. cout << "Enviando: " << L_OFF << endl;
  44. Puerto -> WriteData(L_OFF, sizeof(L_OFF) - 1);
  45. break;
  46.  
  47. case 3:
  48. cout << "caso 3\n";
  49. // Mensaje saludar.
  50. cout << "Enviando: " << Saludar << endl;
  51. Puerto -> WriteData(Saludar, sizeof(Saludar) - 1);
  52. break;
  53.  
  54. case 4:
  55. cout << "caso 4\n";
  56. // Mensaje saludar.
  57. cout << "Enviando: " << Luz_ON << endl;
  58. Puerto->WriteData(Luz_ON, sizeof(Luz_ON) - 1);
  59. break;
  60.  
  61. case 5:
  62. cout << "caso 5\n";
  63. // Mensaje saludar.
  64. cout << "Enviando: " << Luz_OFF << endl;
  65. Puerto->WriteData(Luz_OFF, sizeof(Luz_OFF) - 1);
  66. break;
  67.  
  68. default:
  69. cout << "Puse del 1 al 5.";
  70. }
  71.  
  72. cout << endl;
  73. Puerto->ReadData(lectura, 50);
  74. cout << "Recibido: " << lectura << endl;
  75. lectura[0] = 0; // Limpiar.
  76. cout << "-------------------" << endl;
  77.  
  78. //system("PAUSE");
  79. }
  80. }

Código de Arduino perfectamente funcional con su LCD Keypad Shield (http://www.web-robotica.com/wp-content/uploads/2015/10/arduino-lcdkeypad.jpg) incluido.
Código
  1. #include <LiquidCrystal.h>
  2.  
  3. // Inicializa la librería con sus pines indicados.
  4. // RS, RW, Enable, D4, D5, D6, D7.
  5. LiquidCrystal lcd(8, NULL, 9, 4, 5, 6, 7);
  6.  
  7. // Pin 10 para saber que es luz de fondo.
  8. const byte LuzFondo = 10;
  9.  
  10. bool estadoActual = false, estadoUltimo = false, contador = false;
  11. const byte pinLed = 13;   // Declaramos la variable pin del Led.
  12. const byte boton = 2;
  13. char caracter;
  14. String comando;
  15.  
  16. void setup()
  17. {
  18.  pinMode(pinLed, OUTPUT);  // Inicializa el pin del LED como salida:
  19.  pinMode(boton, INPUT);    // Pulsador del pin 2.
  20.  Serial.begin(115200);     // Puerto serie 115200 baudios.
  21.  lcd.begin(16, 2);         // Formato de pantalla.
  22.  //digitalWrite(LuzFondo, HIGH);
  23.  lcd.setCursor(0, 0);      // Posición en la pantalla.
  24.  lcd.print("    Arduino     ");
  25.  delay(1000);
  26. }
  27.  
  28. void loop()
  29. {
  30.  /* Leyendo carácter a carácter lo que se resive por el canal del puerto serie
  31.     y los voy concatenando uno tras otro en una cedena. */
  32.  while (Serial.available() > 0)
  33.  {
  34.    caracter = Serial.read();
  35.    comando.concat(caracter);
  36.    delay(10);
  37.  }
  38.  
  39.  estadoActual = digitalRead(boton); // Guarda el estado del pulsador.
  40.  delay(50); // Retardo de 50 mili segundos par evitar antirebotes.
  41.  
  42.  // ¿Pulsador y estadoActual y negación del estadoUltimo es verdadero?
  43.  if (estadoActual && !estadoUltimo)
  44.  {
  45.    contador = !contador;   // Cambio el estado tipo boleano.
  46.  
  47.    if (contador)
  48.    {
  49.      digitalWrite(LuzFondo, HIGH);
  50.      Serial.write("ON");
  51.      lcd.setCursor(15, 0);
  52.      lcd.print("1");
  53.    }
  54.    else
  55.    {
  56.      digitalWrite(LuzFondo, LOW);
  57.      Serial.write("OFF");
  58.      lcd.setCursor(15, 0);
  59.      lcd.print("0");
  60.    }
  61.  }
  62.  
  63.  // Pasa del estadoActual a estadoUltimo.
  64.  estadoUltimo = estadoActual;
  65.  
  66.  // Si los carácteres es recibido y verdadero.
  67.  if (comando.equals("Led13_ON") == true)
  68.  {
  69.    digitalWrite(pinLed, HIGH); // Enciende el Led.
  70.    Serial.write("Led 13 encendido.");
  71.    lcd.setCursor(0, 1);
  72.    lcd.print("Led 13 encendido");
  73.  }
  74.  
  75.  // Si los carácteres es recibido y verdadero.
  76.  if (comando.equals("Led13_OFF") == true)
  77.  {
  78.    digitalWrite(pinLed, LOW); // Apaga el Led.
  79.    Serial.write("Led 13 apagado  ");
  80.    lcd.setCursor(0, 1);
  81.    lcd.print("Led 13 apagado. ");
  82.  }
  83.  
  84.  // Mensaje de saludo.
  85.  if (comando.equals("Hola") == true)
  86.  {
  87.    Serial.write("Hola C++ de Win32. Saludos desde Arduino.");
  88.    lcd.setCursor(0, 1);
  89.    lcd.print("Hola C++ de Win32. Saludos desde Arduino.");
  90.  }
  91.  
  92.  if (comando.equals("Luz_ON") == true)
  93.  {
  94.    digitalWrite(LuzFondo, HIGH); // Apaga el Led.
  95.    Serial.write("Luz ON.");
  96.    lcd.setCursor(0, 1);
  97.    lcd.print("Luz ON.         ");
  98.  }
  99.  
  100.  
  101.  if (comando.equals("Luz_OFF") == true)
  102.  {
  103.    digitalWrite(LuzFondo, LOW); // Apaga el Led.
  104.    Serial.write("Luz OFF.");
  105.    lcd.setCursor(0, 1);
  106.    lcd.print("Luz OFF.        ");
  107.  }
  108.  
  109.  // Limpiamos la cadena para volver a recibir el siguiente comando.
  110.  comando = "";
  111. }
  112.  

Si tengo la ventana de C++, pulso el botón desde Arduino, me tiene que llegar un mensaje, solo llega un ON o un OFF. No muestra nada en C#, solo se acumula en la variable lenguaje, que si envío algo, se suma el ON o OFF más otros mensajes.

Si no entiendes a lo que hablo, me lo dices y lo explico de otra manera.

Saludos.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: ivancea96 en 17 Marzo 2017, 15:15
El "truco" d elas teclas, es lo mismo que el digitalRead que tienes ahí. Puedes guardar su estado anterior, no más.

Citar
No muestra nada en C#, solo se acumula en la variable lenguaje
¿C#? ¿Variable lenguaje?

En cualquier caso. ¿Tu problema es que no recibes datos del Arduino? Entonces comenta el switch y testealo por separado.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 18 Marzo 2017, 00:08
Buenas:

Quiero decir C++. ;)

Empecé otro proyecto más sencillo, primero corregir lo de recepción del puerto.
Código
  1. // Para crear conexión con los puertos COM1 - COM9.
  2. // Serial* Arduino = new Serial("COM7");
  3.  
  4. // Para crear conexión con los puertos COM10 en adelante.
  5. // Serial* Arduino = new Serial("\\\\.\\COM10");
  6.  
  7. #include <iostream>
  8. #include <fstream>
  9. #include <Windows.h>
  10. #include "SerialClass.h"
  11. using namespace std;
  12.  
  13. void main()
  14. {
  15. // Título de la ventana
  16. SetConsoleTitle("Control Led Arduino.");
  17.  
  18. // Puerto serie.
  19. Serial* Puerto = new Serial("COM4");
  20.  
  21. while (Puerto->IsConnected())
  22. {
  23.  
  24. // Comandos para Arduino.
  25. char Luz_ON[] = "Luz_ON"; // Envía "Luz_ON" al puerto serie.
  26. char Luz_OFF[] = "Luz_OFF";
  27. char lectura[50]; // Guardan datos de entrada del puerto.
  28. int opc; // Guarda un 1 o 2 tipo entero queintroduces desde la consola.
  29.  
  30. cout << endl; // Dejamos un retorno.
  31. cout << "Introduzca la opcion deseada: " << endl << endl; // Muestra texto en pantalla.
  32.  
  33. cin >> opc; // Aquí introduces un número, el 1 o el 2.
  34.  
  35. switch (opc) // Espera recibir un 1 o un 2.
  36. {
  37. case 1:
  38. // Mensaje saludar.
  39. cout << "Enviando: " << Luz_ON << endl; // Muestra en pantalla textos.
  40. Puerto->WriteData(Luz_ON, sizeof(Luz_ON) - 1); // Envía al puerto el texto "Luz_ON".
  41. break;
  42.  
  43.                case 2:
  44. // Mensaje saludar.
  45. cout << "Enviando: " << Luz_OFF << endl;
  46. Puerto->WriteData(Luz_OFF, sizeof(Luz_OFF) - 1);
  47. break;
  48.  
  49. default: // Si haz pulsado otro número distinto del 1 y 2, muestra
  50. cout << "Puse del 1 al 2."; // este mensaje.
  51. }
  52.  
  53. cout << endl; // Dejamos un retorno.
  54. Puerto->ReadData(lectura, 50); // Recibe datos desde el puerto y lo almacena en la variable "lectura".
  55. cout << "Recibido: " << lectura << endl; // Muestra en pantalla el texto o datos almacenado en la variable "lectura".
  56. cout << "-------------------" << endl;
  57. }
  58. }
  59.  

Lo ejecuto y muestra exactamente esto:
(http://www.subeimagenes.com/img/sin-titulo-2-1717702.gif)

¿Por qué en recibido aparece esos caracteres raros?

La manera para que no me salga es esto, cambiando de esta manera la variable lectura, colocarle un \0.
Código
  1. // Comandos para Arduino.
  2. char Luz_ON[] = "Luz_ON"; // Envía "Luz_ON" al puerto serie.
  3. char Luz_OFF[] = "Luz_OFF";
  4. char lectura[50] = "\0"; // Guardan datos de entrada del puerto.
  5. int opc; // Guarda un 1 o 2 tipo entero queintroduces desde la consola.
  6.  

Quiero ir por partes, resolver cada problema. Ahora, no se si lo que hice arriba es lo más indicado. Creo que no, porque si pulso 1 me muestra este resultado:
(http://www.subeimagenes.com/img/sin-titulo-2-1717712.gif)

Si vuelvo a pulsar 1, ya me muestra el Recibido: bien como indica abajo:
(http://www.subeimagenes.com/img/sin-titulo-2-1717713.gif)

Tiene que funcionar todo a la primera. Antes de hacer lo de las teclas, primero resolver este acertijo.  ;)

Saludos.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: ivancea96 en 18 Marzo 2017, 01:24
Para empezar, es interesante saber qué hace exactamente ReadData: Retorna el número de caracteres leídos (y -1 si hubo un error o si leyó 0 caracteres). Dicho esto, ten en cuenta que las cadenas en C++ no son como en C#. De esos 50 caracteres, si solo lees 10, quedarán 40 como basura. Para evitar leerlos, basta poner un '\0' en el undécimo caracter:

Código
  1. int n = Puerto->ReadData(lectura, 49);
  2. lectura[n + 1] = '\0';

Eso en primer lugar. Luego, si el retorno de ReadData es -1, no deberías mostrar el Recibido (deberías esperar primero a que haya bytes para leer, pues no tienen por qué trabajar a la vez el Arduino y el PC (viene siendo como sincronizar varios threads, vaya))

Y bueno, hecho eso, a ver qué problemas te da.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 18 Marzo 2017, 01:47
Hola:

Enviar me envia todo bien, Arduino lo lee.

Recibir, seguí tu consejo, creo que no lo seguí como debería. C++ no lee nada. Seguro que hice algo pero muy mal.
Código
  1. #include <iostream>
  2. #include <fstream>
  3. #include <Windows.h>
  4. #include "SerialClass.h"
  5. using namespace std;
  6.  
  7. void main()
  8. {
  9. // Título de la ventana
  10. SetConsoleTitle("Control Led Arduino.");
  11.  
  12. // Puerto serie.
  13. Serial* Puerto = new Serial("COM4");
  14.  
  15. // Comandos para Arduino.
  16. char Luz_ON[] = "Luz_ON"; // Envía "Luz_ON" al puerto serie.
  17. char Luz_OFF[] = "Luz_OFF";
  18. char lectura[50] = "\0"; // Guardan datos de entrada del puerto.
  19.  
  20. int opc; // Guarda un 1 o 2 tipo entero queintroduces desde la consola.
  21.  
  22. while (Puerto->IsConnected())
  23. {
  24. cout << endl; // Dejamos un retorno.
  25. cout << "Introduzca la opcion deseada: " << endl << endl; // Muestra texto en pantalla.
  26.  
  27. cin >> opc; // Aquí introduces un número, el 1 o el 2.
  28.  
  29. switch (opc) // Espera recibir un 1 o un 2.
  30. {
  31. case 1:
  32. // Mensaje saludar.
  33. cout << "Enviando: " << Luz_ON << endl; // Muestra en pantalla textos.
  34. Puerto->WriteData(Luz_ON, sizeof(Luz_ON) - 1); // Envía al puerto el texto "Luz_ON".
  35. break;
  36.  
  37. case 2:
  38. // Mensaje saludar.
  39. cout << "Enviando: " << Luz_OFF << endl;
  40. Puerto->WriteData(Luz_OFF, sizeof(Luz_OFF) - 1);
  41. break;
  42.  
  43. default: // Si haz pulsado otro número distinto del 1 y 2, muestra
  44. cout << "Puse del 1 al 2."; // este mensaje.
  45. }
  46.  
  47. cout << endl; // Dejamos un retorno.
  48. int n = Puerto->ReadData(lectura, 49); // Recibe datos desde el puerto y lo almacena en la variable "lectura".
  49. lectura[n + 1] = '\0';
  50. cout << "Recibido: " << lectura << endl; // Muestra en pantalla el texto o datos almacenado en la variable "lectura".
  51. cout << "-------------------" << endl;
  52. }
  53. }

Lo que hace es, que si pulso uno, no lee nada. Si vuelvo a pulsar el 1, lee y lo indica bien. Eso si, por segunda vez.

Reinicio la aplicación. Pulso 1, no lee nada, ahora pulso el 2, me lee como si hubiera pulsado el 1.

Tiene que verse Luz OFF cuando pulso el 2.

(http://www.subeimagenes.com/img/sin-titulo-2-1717779.gif)

:)


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: ivancea96 en 18 Marzo 2017, 02:16
Pero, lo dicho. Desde que pulsas enter y escribes al arduino hasta que lees del arduino... ¿Crees que le da tiempo al Arduino a procesar y responder?
Vamos a comprobar que no sea eso. Coloca un Sleep(100); antes del ReadData.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 18 Marzo 2017, 03:07
Va, me olvidé lo del Sleep. Jajajajjaaja.

Por cierto. No me funciona en 100, si en 500.
Código
  1. cout << endl; // Dejamos un retorno.
  2. Sleep(500);
  3. int n = Puerto->ReadData(lectura, 49); // Recibe datos desde el puerto y lo almacena en la variable "lectura".
  4. lectura[n + 1] = '\0';
  5. cout << "Recibido: " << lectura << endl; // Muestra en pantalla el texto o datos almacenado en la variable "lectura".
  6. cout << "-------------------" << endl;
El Sleep a 150 funciona bien. Aunque hay gente que lo dejan a 500 pero se ve un poco lento. ;)

Código
  1. #include <iostream>
  2. #include <fstream>
  3. #include <Windows.h>
  4. #include "SerialClass.h"
  5. using namespace std;
  6.  
  7. void main()
  8. {
  9. // Título de la ventana
  10. SetConsoleTitle("Control Led Arduino.");
  11.  
  12. // Puerto serie.
  13. Serial* Puerto = new Serial("COM4");
  14.  
  15. // Comandos para Arduino.
  16. char Luz_ON[] = "Luz_ON"; // Envía "Luz_ON" al puerto serie.
  17. char Luz_OFF[] = "Luz_OFF";
  18. char lectura[50] = "\0"; // Guardan datos de entrada del puerto.
  19.  
  20. int opc; // Guarda un 1 o 2 tipo entero queintroduces desde la consola.
  21.  
  22. while (Puerto->IsConnected())
  23. {
  24. cout << endl; // Dejamos un retorno.
  25. cout << "Introduzca la opcion deseada: " << endl << endl; // Muestra texto en pantalla.
  26.  
  27. cin >> opc; // Aquí introduces un número, el 1 o el 2.
  28.  
  29. switch (opc) // Espera recibir un 1 o un 2.
  30. {
  31. case 1:
  32. // Mensaje saludar.
  33. cout << "Enviando: " << Luz_ON << endl; // Muestra en pantalla textos.
  34. Puerto->WriteData(Luz_ON, sizeof(Luz_ON) - 1); // Envía al puerto el texto "Luz_ON".
  35. break;
  36.  
  37. case 2:
  38. // Mensaje saludar.
  39. cout << "Enviando: " << Luz_OFF << endl;
  40. Puerto->WriteData(Luz_OFF, sizeof(Luz_OFF) - 1);
  41. break;
  42.  
  43. default: // Si haz pulsado otro número distinto del 1 y 2, muestra
  44. cout << "Puse del 1 al 2."; // este mensaje.
  45. }
  46.  
  47. cout << endl; // Dejamos un retorno.
  48. Sleep(150);
  49. int n = Puerto->ReadData(lectura, 49); // Recibe datos desde el puerto y lo almacena en la variable "lectura".
  50. lectura[n + 1] = '\0';
  51. cout << "Recibido: " << lectura << endl; // Muestra en pantalla el texto o datos almacenado en la variable "lectura".
  52. cout << "-------------------" << endl;
  53. }
  54. }

Por lo que se ve, ahora toca lo del botón. He hace esto y no devuelve nada.
(http://www.subeimagenes.com/img/sin-titulo-2-1717794.gif)

Código de ahora C++:
Código
  1. #include <iostream>
  2. #include <fstream>
  3. #include <Windows.h>
  4. #include "SerialClass.h"
  5. using namespace std;
  6.  
  7. void main()
  8. {
  9. // Título de la ventana.
  10. SetConsoleTitle("Control Led 13 de Arduino UNO y saludos.");
  11.  
  12. // Nombre del puerto selecconado.
  13. Serial* Puerto = new Serial("COM4");
  14.  
  15. // Comandos para Arduino.
  16. char Luz_ON[] = "Luz_ON"; // Envía "Luz_ON" al puerto serie.
  17. char Luz_OFF[] = "Luz_OFF";
  18. char lectura[50] = "\0"; // Guardan datos de entrada del puerto.
  19.  
  20. // Mostrar texto en pantalla.
  21. cout << "Pulse letra 'A' para endender Led y 'B' para apagar: " << endl;
  22.  
  23. while (Puerto->IsConnected())
  24. {
  25. // Tecla 'A' pulsada
  26. if (GetAsyncKeyState('A') & 0x8000)
  27. {
  28. // Encener luz.
  29. cout << "Enviando: " << Luz_ON << endl; // Muestra en pantalla textos.
  30. Puerto->WriteData(Luz_ON, sizeof(Luz_ON) - 1); // Envía al puerto el texto "Luz_ON".
  31. }
  32.  
  33. // Tecla 'B' pulsada
  34. if (GetAsyncKeyState('B') & 0x8000)
  35. {
  36. // Apagar luz.
  37. cout << "Enviando: " << Luz_OFF << endl;
  38. Puerto->WriteData(Luz_OFF, sizeof(Luz_OFF) - 1);
  39. }
  40. }
  41.  
  42. cout << endl; // Dejamos un retorno.
  43. Sleep(500); // Funciona a 150 para asegurarme en estas pruebas lo dejo a 500 por ahora.
  44. int n = Puerto->ReadData(lectura, 49); // Recibe datos desde el puerto y lo almacena en la variable "lectura".
  45. lectura[n + 1] = '\0';
  46. cout << "Recibido: " << lectura << endl; // Muestra en pantalla el texto o datos almacenado en la variable "lectura".
  47. cout << "-------------------" << endl;
  48. }

Saludos.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: ivancea96 en 18 Marzo 2017, 13:01
Bien. De todos modos, un Sleep es un parche para testear, pero no es correcto. Lo que quieres no es esperar 500 milisegundos; lo que quieres es esperar hasta que el Arduino te contexte (o si tarda mucho, poner un timeout, pero esto ya más adelante).
Podrías hacer un while hasta recibir la respuesta completa del Arduino. Un while con un Sleep(1) si tal, para no sobrecargar. Y en el while, pues eso, leer hasta recibirlo todo.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 18 Marzo 2017, 17:58
Buenas:

Sleep(1) como que no. ;)

Código
  1. #include <iostream>
  2. #include <fstream>
  3. #include <Windows.h>
  4. #include "SerialClass.h"
  5. using namespace std;
  6.  
  7. void main()
  8. {
  9. // Título de la ventana
  10. SetConsoleTitle("Control Led Arduino.");
  11.  
  12. // Puerto serie.
  13. Serial* Puerto = new Serial("COM4");
  14.  
  15. // Comandos para Arduino.
  16. char Luz_ON[] = "Luz_ON"; // Envía "Luz_ON" al puerto serie.
  17. char Luz_OFF[] = "Luz_OFF";
  18. char lectura[50] = "\0"; // Guardan datos de entrada del puerto.
  19.  
  20. int opc; // Guarda un 1 o 2 tipo entero queintroduces desde la consola.
  21. while (1)
  22. {
  23. while (Puerto->IsConnected())
  24. {
  25. cout << endl; // Dejamos un retorno.
  26. cout << "Introduzca la opcion deseada: " << endl << endl; // Muestra texto en pantalla.
  27.  
  28. cin >> opc; // Aquí introduces un número, el 1 o el 2.
  29.  
  30. switch (opc) // Espera recibir un 1 o un 2.
  31. {
  32. case 1:
  33. // Encener luz.
  34. cout << "Enviando: " << Luz_ON << endl; // Muestra en pantalla textos.
  35. Puerto->WriteData(Luz_ON, sizeof(Luz_ON) - 1); // Envía al puerto el texto "Luz_ON".
  36. break;
  37.  
  38. case 2:
  39. // Apagar luz.
  40. cout << "Enviando: " << Luz_OFF << endl;
  41. Puerto->WriteData(Luz_OFF, sizeof(Luz_OFF) - 1);
  42. break;
  43.  
  44. default: // Si haz pulsado otro número distinto del 1 y 2, muestra
  45. cout << "Puse del 1 al 2."; // este mensaje.
  46. }
  47.  
  48.  
  49. cout << endl; // Dejamos un retorno.
  50. Sleep(500);
  51. int n = Puerto->ReadData(lectura, 49); // Recibe datos desde el puerto y lo almacena en la variable "lectura".
  52. lectura[n + 1] = '\0';
  53. cout << "Recibido: " << lectura << endl; // Muestra en pantalla el texto o datos almacenado en la variable "lectura".
  54. cout << "-------------------" << endl;
  55. }
  56. }
  57. }

Acordarse que Arduino tiene un botón, si lo pulso, envía un ON o un OFF. Por ahora no me aparece en pantalla. C++ lo ignora. Pero nos estamos centrando en que si envío un 1 o un 2, responde Arduino también.

;)


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: ivancea96 en 18 Marzo 2017, 18:17
No. Hablo de un while a la hora de recibir datos. No sirve solo "enviar y luego recibir". En un protocolo, hay que asegurarse de que se completa la comunicación. Si tratas de leer datos del puerto y no recibes nada, hay un problema. El Arduino no es instantáneo, probablemente trabajará mucho más lento que tu PC. Hay que esperar los datos:

Código
  1. while(true){
  2.    int n = Puerto->ReadData(lectura, 49);
  3.    if(n > 0){
  4.        lectura[n + 1] = '\0';
  5.        break;
  6.    }
  7.    Sleep(1);
  8. }
  9. cout << "Recibido: " << lectura << endl;
  10. cout << "-------------------" << endl;
  11.  

Por ejemplo.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 18 Marzo 2017, 18:35
Funciona bien mientras ocurre una cosa rara.
Código
  1. #include <iostream>
  2. #include <fstream>
  3. #include <Windows.h>
  4. #include "SerialClass.h"
  5. using namespace std;
  6.  
  7. void main()
  8. {
  9. // Título de la ventana
  10. SetConsoleTitle("Control Led Arduino.");
  11.  
  12. // Puerto serie.
  13. Serial* Puerto = new Serial("COM4");
  14.  
  15. // Comandos para Arduino.
  16. char Luz_ON[] = "Luz_ON"; // Envía "Luz_ON" al puerto serie.
  17. char Luz_OFF[] = "Luz_OFF";
  18. char lectura[50] = "\0"; // Guardan datos de entrada del puerto.
  19.  
  20. int opc; // Guarda un 1 o 2 tipo entero queintroduces desde la consola.
  21.  
  22. while (Puerto->IsConnected())
  23. {
  24. cout << endl; // Dejamos un retorno.
  25. cout << "Introduzca la opcion deseada: " << endl << endl; // Muestra texto en pantalla.
  26.  
  27. cin >> opc; // Aquí introduces un número, el 1 o el 2.
  28.  
  29. switch (opc) // Espera recibir un 1 o un 2.
  30. {
  31. case 1:
  32. // Encener luz.
  33. cout << "Enviando: " << Luz_ON << endl; // Muestra en pantalla textos.
  34. Puerto->WriteData(Luz_ON, sizeof(Luz_ON) - 1); // Envía al puerto el texto "Luz_ON".
  35. break;
  36.  
  37. case 2:
  38. // Apagar luz.
  39. cout << "Enviando: " << Luz_OFF << endl;
  40. Puerto->WriteData(Luz_OFF, sizeof(Luz_OFF) - 1);
  41. break;
  42.  
  43. default: // Si haz pulsado otro número distinto del 1 y 2, muestra
  44. cout << "Puse del 1 al 2."; // este mensaje.
  45. }
  46.  
  47.  
  48. while (true) {
  49. int n = Puerto->ReadData(lectura, 49);
  50. if (n > 0) {
  51. lectura[n + 1] = '\0';
  52. break;
  53. }
  54. Sleep(1);
  55. }
  56. cout << "Recibido: " << lectura << endl;
  57. cout << "-------------------" << endl;
  58. }
  59.  
  60. }

Si pulso una tecla que no está en el Switch, se queda el programa bloqueado. Hablando de pulsar números, porque si pulsas letras se vuelve loco, ya que la variable de entrada es tipo entero, pero esto, ya es otra historia.

;)


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: ivancea96 en 18 Marzo 2017, 21:09
¡Desde luego!
Si no envías nada al Arduino, intuyo que el Arduino, en principio, no le envía nada al PC. por tanto, se va a quedar esperando.
Everything as expected
Tendrás que cambiar el flujo del programa si quieres que eso no ocurra. Además, imagínate que agregas una opción que envía datos al Arduino pero no los recibe. ¿Para qué esperar la salida del Arduino?
En fin, eso ya no es un error, solo un flujo incorrecto. Depende de cómo quieras ampliar el programa, modifícalo como más te convenga.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 19 Marzo 2017, 01:01
Hola:

El programa que quiero es:

1. Si pulso un número 1 o un 2 en C++, envía un mensaje a Aduino, luego Arduino le devuelve un mensaje.

2. Si pulso otro número que no está en el Switch Case, te salta elmensaje Default inficando que solo hay dos opciones para pulsar, tecla 1 y 2.

3. Si no se pulsa nada desde C++, Arduino tiene un botón, que al pulsarlo, envía mensajes llamado, ON o un OFF, C++ debe leer.

Por eso en C++ Win32 me cuesta mucho, en .net de C++ del CLI no cuesta tanto, más fácil pero no tiene ejecutable nativo, el Win32 si. Hay ventajas enuno y en la otra. ;)

Saludos.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: ivancea96 en 19 Marzo 2017, 14:23
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.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: MAFUS en 19 Marzo 2017, 22:06
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.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: ivancea96 en 19 Marzo 2017, 22:23
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


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: MAFUS en 19 Marzo 2017, 23:21
Si fuera puerto serie puro se podrían usar las líneas CTS y RTS, pero al ser emulado no sé si existen.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: ivancea96 en 19 Marzo 2017, 23:29
O directamente, poniendole un "header" a los mensjaes:
Código:
~~ Arduino -> PC

<msg_type:1 byte>

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


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 20 Marzo 2017, 05:29
Hola:

Probando con C# se funciona la recepción de datos, en C++ con Win32 no tengo idea como se hace. ;)
Código
  1. using System;
  2. using System.IO.Ports;
  3.  
  4. namespace Envio_y_recepcion_puerto_serie_cs
  5. {
  6.    class Program
  7.    {
  8.        static void Main(string[] args)
  9.        {
  10.            // Título de la ventana.
  11.            Console.Title = "Recibir datos desde Arduino con C#";
  12.  
  13.            // Cree un nuevo objeto SerialPort con la configuración predeterminada.
  14.            SerialPort Puerto_serie = new SerialPort("COM4");
  15.  
  16.            Puerto_serie.BaudRate = 115200;
  17.            Puerto_serie.Parity = Parity.None;
  18.            Puerto_serie.StopBits = StopBits.One;
  19.            Puerto_serie.DataBits = 8;
  20.            Puerto_serie.Handshake = Handshake.None;
  21.            Puerto_serie.RtsEnable = true;
  22.  
  23.            // Detecta cualquier dato recibido.
  24.            Puerto_serie.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
  25.  
  26.            Puerto_serie.Open(); // Abrir puerto.
  27.  
  28.            Console.WriteLine("Presione cualquier tecla para continuar...");
  29.            Console.WriteLine();
  30.            Console.ReadKey(); // Espera pulsar una tecla cualquiera.
  31.            Puerto_serie.Close(); // Cierra el puerto serie.
  32.        }
  33.  
  34.        private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
  35.        {
  36.            SerialPort sp = (SerialPort)sender;
  37.            string indata = sp.ReadExisting(); // Almacena los datos recibidos en la variable tipo string.
  38.            Console.WriteLine("Dato recibido desde Arduino: " + indata); // Muestra en pantalla los datos recibidos.
  39.        }
  40.    }
  41. }

(http://www.subeimagenes.com/img/sin-titulo-2-1718400.gif)

Para enviar datos si el puerto en C# es así:
Código
  1. byte[] mBuffer = Encoding.ASCII.GetBytes("Hola mundo");
  2.    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...


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: ivancea96 en 20 Marzo 2017, 12:43
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.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: MAFUS en 20 Marzo 2017, 13:27
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.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 23 Marzo 2017, 06:45
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
  1. // Para crear conexión con los puertos COM1 - COM9.
  2. // Serial* Arduino = new Serial("COM7");
  3.  
  4. // Para crear conexión con los puertos COM10 en adelante.
  5. // Serial* Arduino = new Serial("\\\\.\\COM10");
  6.  
  7. #include <iostream>
  8. #include <fstream>
  9. #include <Windows.h>
  10. #include "SerialClass.h"
  11. using namespace std;
  12.  
  13. void main()
  14. {
  15. // Título de la ventana
  16. SetConsoleTitle("Control Led Arduino.");
  17.  
  18. // Puerto serie.
  19. Serial* Puerto = new Serial("COM4");
  20.  
  21. // Comandos para Arduino.
  22. char Luz_ON[] = "Luz_ON"; // Envía "Luz_ON" al puerto serie.
  23. char Luz_OFF[] = "Luz_OFF";
  24. char lectura[50] = "\0"; // Guardan datos de entrada del puerto.
  25.  
  26. int opc; // Guarda un 1 o 2 tipo entero queintroduces desde la consola.
  27.  
  28. while (Puerto->IsConnected())
  29. {
  30. cout << endl; // Dejamos un retorno.
  31. cout << "Introduzca la opcion deseada: " << endl << endl; // Muestra texto en pantalla.
  32.  
  33. cin >> opc; // Aquí introduces un número, el 1 o el 2.
  34.  
  35. switch (opc) // Espera recibir un 1 o un 2.
  36. {
  37. case 1:
  38. // Encener luz.
  39. cout << "Enviando: " << Luz_ON << endl; // Muestra en pantalla textos.
  40. Puerto->WriteData(Luz_ON, sizeof(Luz_ON) - 1); // Envía al puerto el texto "Luz_ON".
  41. break;
  42.  
  43. case 2:
  44. // Apagar luz.
  45. cout << "Enviando: " << Luz_OFF << endl;
  46. Puerto->WriteData(Luz_OFF, sizeof(Luz_OFF) - 1);
  47. break;
  48.  
  49. default: // Si haz pulsado otro número distinto del 1 y 2, muestra
  50. cout << "Puse del 1 al 2."; // este mensaje.
  51. }
  52.  
  53.  
  54. while (true) {
  55. int n = Puerto->ReadData(lectura, 49);
  56. if (n > 0) {
  57. lectura[n + 1] = '\0';
  58. break;
  59. }
  60. Sleep(1);
  61. }
  62. cout << "Recibido: " << lectura << endl;
  63. cout << "-------------------" << endl;
  64. }
  65. }

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

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.

;)


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: ivancea96 en 23 Marzo 2017, 18:14
Citar
Pero 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.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 23 Marzo 2017, 22:37
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...


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: ivancea96 en 23 Marzo 2017, 23:54
En primer lugar, yo separaría estoa  una función:

Código
  1. while (true) {
  2. int n = Puerto->ReadData(lectura, 49);
  3. if (n > 0) {
  4. lectura[n + 1] = '\0';
  5. break;
  6. }
  7. Sleep(1);
  8. }
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
  1. const char *luz[2] = {"Luz_ON", "Luz_OFF"};
  2.  
  3. switch(opc){
  4.    case 1:
  5.    case 2:
  6.        cout << "Enviando: " << luz[opc-1] << endl;
  7.        Puerto->WriteData(luz[opc-1], strlen(luz[opc-1]));
  8.        cout << "Respuesta: " << obtenerRespuestaArduino() << endl;
  9.        break;
  10.  
  11.    default:
  12.        // ...
  13. }

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.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 24 Marzo 2017, 07:19
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
  1. using System;
  2. using System.Text;
  3. using System.IO.Ports;
  4.  
  5. namespace Envio_y_recepcion_puerto_serie_cs
  6. {
  7.    class Program
  8.    {
  9.        static void Main(string[] args)
  10.        {
  11.            // Título de la ventana.
  12.            Console.Title = "Recibir datos desde Arduino con C#";
  13.  
  14.            // Tamaño ventana consola.
  15.            Console.WindowWidth = 55; // X. Ancho.
  16.            Console.WindowHeight = 18; // Y. Alto.
  17.  
  18.            // Cree un nuevo objeto SerialPort con la configuración predeterminada.
  19.            SerialPort Puerto_serie = new SerialPort("COM4");
  20.  
  21.            Puerto_serie.BaudRate = 115200;
  22.            Puerto_serie.Parity = Parity.None;
  23.            Puerto_serie.StopBits = StopBits.One;
  24.            Puerto_serie.DataBits = 8;
  25.            Puerto_serie.Handshake = Handshake.None;
  26.            Puerto_serie.RtsEnable = true;
  27.  
  28.            // Establecer los tiempos de espera de lectura / escritura.
  29.            Puerto_serie.ReadTimeout = 500; // Milisegundos.
  30.            Puerto_serie.WriteTimeout = 500;
  31.  
  32.            // Detecta cualquier dato recibido.
  33.            Puerto_serie.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
  34.  
  35.            Puerto_serie.Open(); // Abrir puerto.
  36.  
  37.            ConsoleKey tecla;
  38.            Console.WriteLine("Pulse tecla 1 para encender y 2 para apagar:");
  39.  
  40.            do
  41.            {
  42.                tecla = Console.ReadKey(true).Key; // Espera pulsación de teclas.
  43.  
  44.                switch (tecla)
  45.                {
  46.                    case ConsoleKey.D1: // Tecla 1 del teclado estandar.
  47.                    case ConsoleKey.NumPad1: // Tecla 1 del número del pad.
  48.                        byte[] miBuffer1 = Encoding.ASCII.GetBytes("Luz_ON"); // Codificación ASCII y guarda en la variable array tipo byte.
  49.                        Puerto_serie.Write(miBuffer1, 0, miBuffer1.Length); // Envía los datos del buffer todo su contenido.
  50.                        Console.WriteLine("Enviado: {0}", miBuffer1); // Muestra en pantala el mensaje enviado, en este caso, Luz_ON.
  51.                        break;
  52.  
  53.                    case ConsoleKey.D2:
  54.                    case ConsoleKey.NumPad2:
  55.                        byte[] miBuffer2 = Encoding.ASCII.GetBytes("Luz_OFF");
  56.                        Puerto_serie.Write(miBuffer2, 0, miBuffer2.Length);
  57.                        //Console.WriteLine("Enviado: {0}", miBuffer2);
  58.                        break;
  59.  
  60.                    default:
  61.                        Console.WriteLine("Tecla el 1, el 2 y Escape para salir.");
  62.                        break;
  63.                }
  64.            }
  65.  
  66.            // Pulsa Escape para salir del menú.
  67.            while (tecla != ConsoleKey.Escape);
  68.  
  69.            Console.WriteLine("Presione cualquier tecla para continuar...");
  70.            Console.WriteLine();
  71.            Console.ReadKey(); // Espera pulsar una tecla cualquiera.
  72.            Puerto_serie.Close(); // Cierra el puerto serie.
  73.        }
  74.  
  75.    // Detecta cualquier dato entrante.
  76.    private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
  77.        {
  78.            SerialPort sp = (SerialPort)sender;
  79.            string entradaDatos = sp.ReadExisting(); // Almacena los datos recibidos en la variable tipo string.
  80.            Console.WriteLine("Dato recibido desde Arduino: " + entradaDatos); // Muestra en pantalla los datos recibidos.
  81.        }
  82.    }
  83. }
  84.  

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
  1. Console.WriteLine("Enviado: {0}", miBuffer1);

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

¿Pero qué es esto?

Concretamente aquí:
Código
  1.                    case ConsoleKey.D1:
  2.                    case ConsoleKey.NumPad1:
  3.                        byte[] miBuffer1 = Encoding.ASCII.GetBytes("Luz_ON");
  4.                        Puerto_serie.Write(miBuffer1, 0, miBuffer1.Length);
  5.                        Console.WriteLine("Enviado: {0}", miBuffer1);
  6.                        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. ;)
(https://social.msdn.microsoft.com/Forums/getfile/1030701)
Código
  1. 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 (https://code0x66.blogspot.com.es/), no sabía que eres un profesional de C++.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: ivancea96 en 24 Marzo 2017, 13:37
Prueba con:
Código
  1. Encoding.ASCII.GetString(miBuffer1);


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 24 Marzo 2017, 13:51
Buenas:

Lo había probado, da este error:
Citar
no 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:
MRiBUpgn-Z0



Saludos.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: ivancea96 en 24 Marzo 2017, 14:41
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 (https://msdn.microsoft.com/es-es/library/744y86tc(v=vs.110).aspx)


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 24 Marzo 2017, 17:51
Lo más parecido que he hecho es esto.
Código
  1. #include <iostream>
  2. #include <fstream>
  3. #include <Windows.h>
  4. #include <stdio.h>
  5. #include "SerialClass.h"
  6. using namespace std;
  7.  
  8. void main()
  9. {
  10. // Título de la ventana
  11. SetConsoleTitle("Control Led Arduino.");
  12.  
  13. // Puerto serie.
  14. Serial* Puerto = new Serial("COM4");
  15.  
  16. // Comandos para Arduino.
  17. char Luz_ON[] = "Luz_ON"; // Envía "Luz_ON" al puerto serie.
  18. char Luz_OFF[] = "Luz_OFF";
  19. char lectura[50] = "\0"; // Guardan datos de entrada del puerto.
  20. int tecla; // Guarda las teclas pulsadas.
  21.  
  22. cout << "Introduzca la opcion deseada: " << endl << endl;
  23. cin >> tecla; // Aquí introduces un número, el 1 o el 2.
  24.  
  25. do
  26. {
  27. while (tecla)
  28. {
  29. case 1:
  30. // Encener luz.
  31. cout << "Enviando: " << Luz_ON << endl; // Muestra en pantalla textos.
  32. Puerto->WriteData(Luz_ON, sizeof(Luz_ON) - 1); // Envía al puerto el texto "Luz_ON".
  33. break;
  34.  
  35. case 2:
  36. // Apagar luz.
  37. cout << "Enviando: " << Luz_OFF << endl;
  38. Puerto->WriteData(Luz_OFF, sizeof(Luz_OFF) - 1);
  39. break;
  40.  
  41. default: // Si haz pulsado otro número distinto del 1 y 2, muestra
  42. cout << "Puse del 1 al 2."; // este mensaje.
  43. }
  44.  
  45. } while (tecla != 0);
  46. }
  47.  
  48.     while (true) {
  49.     int n = Puerto->ReadData(lectura, 49);
  50.     if (n > 0) {
  51.     lectura[n + 1] = '\0';
  52.     break;
  53.     }
  54.     Sleep(1);
  55.     }
  56.  


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: ivancea96 en 24 Marzo 2017, 18:11
Parecido sí, pero de forma incorrecta:
En C# tienes esto:
Código
  1.            do
  2.            {
  3.                tecla = Console.ReadKey(true).Key; // Espera pulsación de teclas.

En C++ tienes esto otro:
Código
  1. cin >> tecla; // Aquí introduces un número, el 1 o el 2.
  2.  
  3. do
  4. {
La diferencia entre uno y otro es que el C++ va a quedarse en un bucle infinito.

Y pusiste:
Código
  1. while (tecla)
  2. {
  3. case 1:
._.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 24 Marzo 2017, 18:46
Buenas:

Código
  1. #include <iostream>
  2. #include <fstream>
  3. #include <Windows.h>
  4. #include <stdio.h>
  5. #include "SerialClass.h"
  6. using namespace std;
  7.  
  8. void main()
  9. {
  10. // Título de la ventana
  11. SetConsoleTitle("Control Led Arduino.");
  12.  
  13. // Puerto serie.
  14. Serial* Puerto = new Serial("COM4");
  15.  
  16. // Comandos para Arduino.
  17. char Luz_ON[] = "Luz_ON"; // Envía "Luz_ON" al puerto serie.
  18. char Luz_OFF[] = "Luz_OFF";
  19. char lectura[50] = "\0"; // Guardan datos de entrada del puerto.
  20. int tecla; // Guarda las teclas pulsadas.
  21.  
  22. cout << "Introduzca la opcion deseada: " << endl << endl;
  23.  
  24.  
  25. do
  26. {
  27. cin >> tecla; // Aquí introduces un número, el 1 o el 2.
  28.  
  29. while (tecla)
  30. {
  31. case 1:
  32. // Encener luz.
  33. cout << "Enviando: " << Luz_ON << endl; // Muestra en pantalla textos.
  34. Puerto->WriteData(Luz_ON, sizeof(Luz_ON) - 1); // Envía al puerto el texto "Luz_ON".
  35. break;
  36.  
  37. case 2:
  38. // Apagar luz.
  39. cout << "Enviando: " << Luz_OFF << endl;
  40. Puerto->WriteData(Luz_OFF, sizeof(Luz_OFF) - 1);
  41. break;
  42.  
  43. default: // Si haz pulsado otro número distinto del 1 y 2, muestra
  44. cout << "Puse del 1 al 2."; // este mensaje.
  45. }
  46.  
  47. } while (tecla != 0);
  48.  
  49. while (true) {
  50. int n = Puerto->ReadData(lectura, 49);
  51. if (n > 0) {
  52. lectura[n + 1] = '\0';
  53. break;
  54. }
  55. Sleep(1);
  56. }
  57. }

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.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: ivancea96 en 24 Marzo 2017, 19:42
Parecido sí, pero de forma incorrecta:
En C# tienes esto:
Código
  1.            do
  2.            {
  3.                tecla = Console.ReadKey(true).Key; // Espera pulsación de teclas.

En C++ tienes esto otro:
Código
  1. cin >> tecla; // Aquí introduces un número, el 1 o el 2.
  2.  
  3. do
  4. {
La diferencia entre uno y otro es que el C++ va a quedarse en un bucle infinito.

Y pusiste:
Código
  1. while (tecla)
  2. {
  3. case 1:
._.
Línea 29.
Código
  1. while (tecla)
No es while, es switch.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: MAFUS en 24 Marzo 2017, 20:02
Vaya, el programa está mal planteado.

El bucle principal,  ese while(true), no capta el teclado. Lo único que hace es leer del arduino.



Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 24 Marzo 2017, 20:17
Vaya, que fallo, no me he dado cuenta en todo el día con el while ahí.

Código
  1. #include <iostream>
  2. #include <fstream>
  3. #include <Windows.h>
  4. #include <stdio.h>
  5. #include "SerialClass.h"
  6. using namespace std;
  7.  
  8. void main()
  9. {
  10. // Título de la ventana
  11. SetConsoleTitle("Control Led Arduino.");
  12.  
  13. // Puerto serie.
  14. Serial* Puerto = new Serial("COM4");
  15.  
  16. // Comandos para Arduino.
  17. char Luz_ON[] = "Luz_ON"; // Envía "Luz_ON" al puerto serie.
  18. char Luz_OFF[] = "Luz_OFF";
  19. char lectura[50] = "\0"; // Guardan datos de entrada del puerto.
  20. int tecla; // Guarda las teclas pulsadas.
  21.  
  22. Puerto->IsConnected(); // Puerto abierto.
  23.  
  24. cout << "Introduzca la opcion deseada: " << endl << endl;
  25.  
  26.  
  27. do
  28. {
  29. cin >> tecla; // Aquí introduces un número, el 1 o el 2.
  30.  
  31. switch (tecla)
  32. {
  33.  
  34. case 1:
  35. // Encener luz.
  36. cout << "Enviando: " << Luz_ON << endl; // Muestra en pantalla textos.
  37. Puerto->WriteData(Luz_ON, sizeof(Luz_ON) - 1); // Envía al puerto el texto "Luz_ON".
  38. break;
  39.  
  40. case 2:
  41. // Apagar luz.
  42. cout << "Enviando: " << Luz_OFF << endl;
  43. Puerto->WriteData(Luz_OFF, sizeof(Luz_OFF) - 1);
  44. break;
  45.  
  46. default: // Si haz pulsado otro número distinto del 1 y 2, muestra
  47. cout << "Puse del 1 al 2."; // este mensaje.
  48. }
  49.  
  50. } while (tecla != 0);
  51.  
  52. while (true)
  53. {
  54. int n = Puerto->ReadData(lectura, 49);
  55. if (n > 0) {
  56. lectura[n + 1] = '\0';
  57. break;
  58. }
  59. Sleep(500); // Lo dejo en 500 ms por si acaso.
  60. }
  61. }

Dice enviado pero no se si envia algo en realidad, nunca responde.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: ivancea96 en 24 Marzo 2017, 21:02
Más que no responder, será que no lees del Arduino:
Código
  1. } while (tecla != 0);
Ya dije antes. Tienes que leer después de enviar. En un mensaje anterior hablé sobre hacer una función.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 24 Marzo 2017, 22:01
¿Qué esperas de ahí?
Código
  1. while ((tecla == 1) || (tecla == 2));

No se me ocurre nada.

Código
  1.            // Pulsa Escape para salir del menú.
  2.            while (tecla != ConsoleKey.Escape);

Lo pondría igual que C#, pero  ya sabes, de C++ se muy más bien tirando a nada.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: ivancea96 en 24 Marzo 2017, 22:03
Pues por eso te digo. Hazlo primero completamente funcional en C#, y ya luego, en C++. Sinó, estás acarreando 2 problemas en vez de 1.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 24 Marzo 2017, 22:33
En C# está hecho el programa por completo,funciona como debe ser y en C++ me da la tabarra.

Código
  1. using System;
  2. using System.Text;
  3. using System.IO.Ports;
  4.  
  5. namespace Envio_y_recepcion_puerto_serie_cs
  6. {
  7.    class Program
  8.    {
  9.        static void Main(string[] args)
  10.        {
  11.            // Título de la ventana.
  12.            Console.Title = "Recibir datos desde Arduino con C#";
  13.  
  14.            // Tamaño ventana consola.
  15.            Console.WindowWidth = 55; // X. Ancho.
  16.            Console.WindowHeight = 18; // Y. Alto.
  17.  
  18.            // Cree un nuevo objeto SerialPort con la configuración predeterminada.
  19.            SerialPort Puerto_serie = new SerialPort("COM4");
  20.  
  21.            Puerto_serie.BaudRate = 115200;
  22.            Puerto_serie.Parity = Parity.None;
  23.            Puerto_serie.StopBits = StopBits.One;
  24.            Puerto_serie.DataBits = 8;
  25.            Puerto_serie.Handshake = Handshake.None;
  26.            Puerto_serie.RtsEnable = true;
  27.  
  28.            // Establecer los tiempos de espera de lectura / escritura.
  29.            Puerto_serie.ReadTimeout = 500; // Milisegundos.
  30.            Puerto_serie.WriteTimeout = 500;
  31.  
  32.            // Detecta cualquier dato recibido.
  33.            Puerto_serie.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
  34.  
  35.            Puerto_serie.Open(); // Abrir puerto.
  36.  
  37.            ConsoleKey tecla;
  38.            Console.WriteLine("Pulse tecla 1 para encender y 2 para apagar:");
  39.  
  40.            do
  41.            {
  42.                tecla = Console.ReadKey(true).Key; // Espera pulsación de teclas.
  43.  
  44.                switch (tecla)
  45.                {
  46.                    case ConsoleKey.D1: // Tecla 1 del teclado estandar.
  47.                    case ConsoleKey.NumPad1: // Tecla 1 del número del pad.
  48.                        byte[] miBuffer1 = Encoding.ASCII.GetBytes("Luz_ON"); // Codificación ASCII y guarda en la variable array tipo byte.
  49.                        Puerto_serie.Write(miBuffer1, 0, miBuffer1.Length); // Envía los datos del buffer todo su contenido.
  50.                        break;
  51.  
  52.                    case ConsoleKey.D2:
  53.                    case ConsoleKey.NumPad2:
  54.                        byte[] miBuffer2 = Encoding.ASCII.GetBytes("Luz_OFF");
  55.                        Puerto_serie.Write(miBuffer2, 0, miBuffer2.Length);
  56.                        break;
  57.  
  58.                    default:
  59.                        Console.WriteLine("Tecla el 1, el 2 y Escape para salir.");
  60.                        break;
  61.                }
  62.            }
  63.  
  64.            // Pulsa Escape para salir del menú.
  65.            while (tecla != ConsoleKey.Escape);
  66.  
  67.            Console.WriteLine("Presione cualquier tecla para terminar...");
  68.            Console.WriteLine();
  69.            Console.ReadKey(); // Espera pulsar una tecla cualquiera.
  70.            Puerto_serie.Close(); // Cierra el puerto serie.
  71.        }
  72.  
  73.    // Detecta cualquier dato entrante.
  74.    private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
  75.        {
  76.            SerialPort sp = (SerialPort)sender;
  77.            string entradaDatos = sp.ReadExisting(); // Almacena los datos recibidos en la variable tipo string.
  78.            Console.WriteLine("Dato recibido desde Arduino: " + entradaDatos); // Muestra en pantalla los datos recibidos.
  79.        }
  80.    }
  81. }


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: ivancea96 en 25 Marzo 2017, 00:02
El problema es que en C# te funciona porque lo estás utilizando "orientado a eventos", con los handlers. Son por lo menos 2 threads funcionando. Sin embargo, en C++ solo estás utilizando 1 thread.

Tendrás que elegir: o utilizar 2 threads en C++, o pasar el código de C# a 1 solo thread controlando tú el flujo del programa (completo).


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 25 Marzo 2017, 06:00
Sea como sea, que funcione de una vez, así me paso hacer en versión de Visual C++ MFC. Quiero tanto en consola como en formulario.

He estado buscando y que va.
https://sites.google.com/site/fernandoagomezf/programacion-en-c/tips-de-programador-c/win32-api/leer-y-escribir-datos-en-puertos-seriales

La otra historia que tengo, es como dije, también hacer el MFC C++ que también tengo mis dudas y creo que peores, porque nunca lo he hecho arrancar.

###################################################################################################
Siguiendo este tutorial (https://es.slideshare.net/Metaconta2/formulario-windows-con-visual-c-2017) desde la página 36 he creado el formulario MFC tal como indica ahí y tal como lo quiero.

Quiero enviar y recibir datos al puerto serie. Las librerías del puerto serie las puedes descargar aquí (https://github.com/Gmatarrubia/LibreriasTutoriales). He cargado las librerías dentro del proyecto y se muestra como indica en la imagen.
(https://social.msdn.microsoft.com/Forums/getfile/1030762)

He Añadido dos botones al formulario y lo he llamado ON y el otro OFF como puedes ver en la imagen.
(https://social.msdn.microsoft.com/Forums/getfile/1030765)

En Exploradores de Soluciones, abre el archivo llamado MFC_Arduino.cpp para ver el código fuente. Arriba, en la barra de herramientas o en los menús, pulsa, Proyecto --> Propiedades MFC_Arduino... y deja la opción tal como indica en la imagen de abajo.
(https://social.msdn.microsoft.com/Forums/getfile/1030776)

Librerías agregadas en el Explorador de soluciones.
(https://social.msdn.microsoft.com/Forums/getfile/1030764)

Dejando todo tal como está y las librerías cargada, intento ejecutar y compilar el programa vacío. Me produce un error que es este:
Citar
Gravedad    Código    Descripción    Proyecto    Archivo    Línea    Estado suprimido
Error    C1010    final de archivo inesperado al buscar la directiva de encabezado precompilado. Compruebe si olvidó agregar '#include "stdafx.h"' al código fuente?    MFC_Arduino    c:\users\usuario\documents\visual studio 2017\projects\mfc_arduino\mfc_arduino\serialclass.cpp    140  
 

Se que la librería está bien. Puede que las librerías o archivos cargados de forma predeterminada con Visual Studio C++ 2017 Win32 no sea el adecuado y hay que borrarlas, o hacer alguna modificación.
###################################################################################################

El MFC es otra historia que ya haré más adelante. Por cierto, a nadie le interesa los MFC ni Win32 de C++ hoy en día, exeptuando a los que se lo obligan hacer en universidades o por pura curiosidad como yo, JEjejejejejjejejeje.

A seguir con el modo consola de C++ aunque cueste, y mira que cuesta, sea como sea, que funcione. Y mira que pensé comprar la versión del libro pequeño de C++ del 2008 y este del 2014 actualizado.

(http://www.anayamultimedia.es/jpg_g/multimedia/MU00375701.jpg)
http://anayamultimedia.es/libro.php?id=3607608

Como curiosidad.
¿Que lenguaje de programación debería saber para el 2017? (https://es.quora.com/Que-lenguaje-de-programaci%C3%B3n-deber%C3%ADa-saber-para-el-2017)

Si sabes hacer el programa, adelante, no me tengas 4 años en C++ que no lo domin. ;)

Saludos.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 25 Marzo 2017, 23:05
Hola de nuevo:

Empezando desde 0 y más básico. En C++ envía datos al puerto serie y recibe. Si pulso 1 o un 2, me envía datos y Arduino le devuelve a C++. Es capaz de encender y apagar un Led del pin 13 que viene incorporado en la placa de Arduino. El problema está cuando pulse otra tecla que no sea 1 o un 2, se queda atascado C++ y no hace nada.

Código de Arduino:
Código
  1. const byte pinLed = 13;   // Declaramos la variable pin del Led.
  2. char caracter;
  3. String comando;
  4.  
  5. void setup()
  6. {
  7.  pinMode(pinLed, OUTPUT);  // Inicializa el pin del LED como salida:
  8.  Serial.begin(115200);     // Puerto serie 115200 baudios.
  9. }
  10.  
  11. void loop()
  12. {
  13.  /*
  14.     Voy leyendo carácter a carácter lo que se recibe por el canal serie
  15.     (mientras llegue algún dato allí), y los voy concatenando uno tras otro
  16.     en una cadena. En la práctica, si usamos el "Serial monitor" el bucle while
  17.     acabará cuando pulsamos Enter. El delay es conveniente para no saturar el
  18.     canal serie y que la concatenación se haga de forma ordenada.
  19.   */
  20.  while (Serial.available() > 0)
  21.  {
  22.    caracter = Serial.read();
  23.    comando.concat(caracter);
  24.    delay(10);
  25.  }
  26.  
  27.  /*
  28.     Una vez ya tengo la cadena "acabada", compruebo su valor y hago que
  29.     la placa Arduino reacciones según sea este. Aquí podríamos hacer lo
  30.     que quisiéramos: si el comando es "tal", enciende un Led, si es cual,
  31.     mueve un motor... y así.
  32.   */
  33.  
  34.  // Si le llega el mensaje Luz_ON, se ejecuta este if.
  35.  if (comando.equals("Luz_ON") == true)
  36.  {
  37.    digitalWrite(pinLed, HIGH); // Enciende el Led 13.
  38.    Serial.write("Luz ON.");    // Envía este mensaje a C++.
  39.  }
  40.  
  41.  // Si le llega el mensaje Luz_ON, se ejecuta este if.
  42.  if (comando.equals("Luz_OFF") == true)
  43.  {
  44.    digitalWrite(pinLed, LOW); // Apaga el Led 13.
  45.    Serial.write("Luz OFF.");  // Envía este mensaje a C++.
  46.  }
  47.  
  48.  // Limpiamos la cadena para volver a recibir el siguiente comando.
  49.  comando = "";
  50. }

Código en C++:
Código
  1. // Para crear conexión con los puertos COM1 - COM9.
  2. // Serial* Arduino = new Serial("COM7");
  3.  
  4. // Para crear conexión con los puertos COM10 en adelante.
  5. // Serial* Arduino = new Serial("\\\\.\\COM10");
  6.  
  7. #include <iostream>
  8. #include <fstream>
  9. #include <Windows.h>
  10. #include "SerialClass.h"
  11. using namespace std;
  12.  
  13. void main()
  14. {
  15. // Título de la ventana
  16. SetConsoleTitle("Control Led Arduino.");
  17.  
  18. // Puerto serie.
  19. Serial* Puerto = new Serial("COM4");
  20.  
  21. // Comandos para Arduino.
  22. char Luz_ON[] = "Luz_ON"; // Envía "Luz_ON" al puerto serie.
  23. char Luz_OFF[] = "Luz_OFF";
  24. char lectura[50] = "\0"; // Guardan datos de entrada del puerto.
  25.  
  26. int opc; // Guarda un 1 o 2 tipo entero queintroduces desde la consola.
  27.  
  28. while (Puerto->IsConnected())
  29. {
  30. cout << endl; // Dejamos un retorno.
  31. cout << "Introduzca la opcion deseada: " << endl << endl; // Muestra texto en pantalla.
  32.  
  33. cin >> opc; // Aquí introduces un número, el 1 o el 2.
  34.  
  35. switch (opc) // Espera recibir un 1 o un 2.
  36. {
  37. case 1:
  38. // Encener luz.
  39. cout << "Enviando: " << Luz_ON << endl; // Muestra en pantalla textos.
  40. Puerto->WriteData(Luz_ON, sizeof(Luz_ON) - 1); // Envía al puerto el texto "Luz_ON".
  41. break;
  42.  
  43. case 2:
  44. // Apagar luz.
  45. cout << "Enviando: " << Luz_OFF << endl;
  46. Puerto->WriteData(Luz_OFF, sizeof(Luz_OFF) - 1);
  47. break;
  48.  
  49. default: // Si haz pulsado otro número distinto del 1 y 2, muestra
  50. cout << "Puse del 1 al 2."; // este mensaje.
  51. }
  52.  
  53.  
  54. while (true) {
  55. int n = Puerto->ReadData(lectura, 49);
  56. if (n > 0) {
  57. lectura[n + 1] = '\0';
  58. break;
  59. }
  60. Sleep(500);
  61. }
  62. cout << "Recibido: " << lectura << endl;
  63. cout << "-------------------" << endl;
  64. }
  65. }

Por ahora resolver ese problema que no me sale.

Saludos.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: ivancea96 en 25 Marzo 2017, 23:19
Es el mismo problema de antes. Si pulsas un número que no sea ni 1 ni 2, se va al default. Al salir del switch, espera infinitamente hasta que el Arduino responda algo (y, como no le enviaste nada, no va a responder).
Solo debes esperar respuesta del Arduino en caso de que haya puesto 1 o 2.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 25 Marzo 2017, 23:24
¿Y cómo se resuelve est e problema?

¿Enviando algo a Arduino que no sea 1 o el 2? ;)

Así no me va, jajajaja. Mejor que C++ controle la situación y estoy que arde de no lograrlo.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: MAFUS en 25 Marzo 2017, 23:53
Cambia todo el while(true) por:
Código
  1. Sleep(500);
  2. int n = Puerto->ReadData(lectura, 49);
  3. if (n > 0) {
  4.    lectura[n + 1] = '\0';
  5.    cout << "Recibido: " << lectura << endl;
  6.    cout << "-------------------" << endl;
  7. }


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: ivancea96 en 26 Marzo 2017, 00:20
En primer lugar, yo separaría estoa  una función:

Código
  1. while (true) {
  2. int n = Puerto->ReadData(lectura, 49);
  3. if (n > 0) {
  4. lectura[n + 1] = '\0';
  5. break;
  6. }
  7. Sleep(1);
  8. }
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
  1. const char *luz[2] = {"Luz_ON", "Luz_OFF"};
  2.  
  3. switch(opc){
  4.    case 1:
  5.    case 2:
  6.        cout << "Enviando: " << luz[opc-1] << endl;
  7.        Puerto->WriteData(luz[opc-1], strlen(luz[opc-1]));
  8.        cout << "Respuesta: " << obtenerRespuestaArduino() << endl;
  9.        break;
  10.  
  11.    default:
  12.        // ...
  13. }

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.

Ya ahí te respondiera el cómo solucionarlo -.-'


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 26 Marzo 2017, 08:39
Por fiiiiiiiiiiiiiiiiiiiiiiiiiiiinnnnnnnnnnnnnnn.

Código
  1. // Para crear conexión con los puertos COM1 - COM9.
  2. // Serial* Arduino = new Serial("COM7");
  3.  
  4. // Para crear conexión con los puertos COM10 en adelante.
  5. // Serial* Arduino = new Serial("\\\\.\\COM10");
  6.  
  7. #include <iostream>
  8. #include <fstream>
  9. #include <Windows.h>
  10. #include "SerialClass.h"
  11. using namespace std;
  12.  
  13. void main()
  14. {
  15. // Título de la ventana
  16. SetConsoleTitle("Control Led Arduino.");
  17.  
  18. // Puerto serie.
  19. Serial* Puerto = new Serial("COM4");
  20.  
  21. // Comandos para Arduino.
  22. char Luz_ON[] = "Luz_ON"; // Envía "Luz_ON" al puerto serie.
  23. char Luz_OFF[] = "Luz_OFF";
  24. char lectura[50] = "\0"; // Guardan datos de entrada del puerto.
  25.  
  26. int opc; // Guarda un 1 o 2 tipo entero queintroduces desde la consola.
  27.  
  28. while (Puerto->IsConnected())
  29. {
  30. cout << endl; // Dejamos un retorno.
  31. cout << "Introduzca la opcion deseada: " << endl << endl; // Muestra texto en pantalla.
  32.  
  33. cin >> opc; // Aquí introduces un número, el 1 o el 2.
  34.  
  35. switch (opc) // Espera recibir un 1 o un 2.
  36. {
  37. case 1:
  38. // Encener luz.
  39. cout << "Enviando: " << Luz_ON << endl; // Muestra en pantalla textos.
  40. Puerto->WriteData(Luz_ON, sizeof(Luz_ON) - 1); // Envía al puerto el texto "Luz_ON".
  41. break;
  42.  
  43. case 2:
  44. // Apagar luz.
  45. cout << "Enviando: " << Luz_OFF << endl;
  46. Puerto->WriteData(Luz_OFF, sizeof(Luz_OFF) - 1);
  47. break;
  48.  
  49. default: // Si haz pulsado otro número distinto del 1 y 2, muestra
  50. cout << "Puse del 1 al 2."; // este mensaje.
  51. }
  52.  
  53.  
  54. Sleep(500);
  55. int n = Puerto->ReadData(lectura, 49);
  56. if (n > 0)
  57. {
  58. lectura[n + 1] = '\0';
  59. cout << "Recibido: " << lectura << endl;
  60. cout << "-------------------" << endl;
  61. }
  62. }
  63. }

A pesar de que funciona bien en apariencia, hay que seguir mejorando ya que si pulso una letra, sale un bucle repetitivo en default, no sale de ahí ni loco.

@ ivancea96 :
La abreviación que hiciste para ahorrar código está muy curioso, antes debo resolver problemas indicado arriba, a parte de eso, lo de pulsar una tecla y automáticamente ejecuta el envio. ;)

¿Cómo resolvemos el bucle este si pulso letras?

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

Saludos.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: MAFUS en 26 Marzo 2017, 09:59
Vacía el buffer cin después de obtener el dato.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 26 Marzo 2017, 10:22
Hola:

Lo he intentado así:
Código
  1. default: // Si haz pulsado otro número distinto del 1 y 2, muestra
  2. cout << "Puse del 1 al 2."; // este mensaje.
  3. }
  4.  
  5.  
  6. Sleep(500);
  7. int n = Puerto->ReadData(lectura, 49);
  8. if (n > 0)
  9. {
  10. lectura[n + 1] = '\0';
  11. cout << "Recibido: " << lectura << endl;
  12. cout << "-------------------" << endl;
  13. }
  14.  
  15. opc = NULL; // Vaciar el buffer.
  16. }
  17. }

Actúa de la misma manera.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: MAFUS en 26 Marzo 2017, 12:32
Pásate por aquí.  Miestra varias formas de vaciar cin.
http://www.cplusplus.com/forum/general/11070/


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 26 Marzo 2017, 13:25
Hola:

Voy a probar, mientras hay que entretenerse actualizarse del futuro C++ 17 y C++ 20.
wGYY90vq2VU

Usé esto:
Código
  1. Sleep(250);
  2. int n = Puerto->ReadData(lectura, 49);
  3. if (n > 0)
  4. {
  5. lectura[n + 1] = '\0';
  6. cout << "Recibido: " << lectura << endl;
  7. cout << "-------------------" << endl;
  8. }
  9.  
  10. cin.sync(); // Limpiar.
  11. }
  12. }

Ese no es el problema, todo funciona bien menos una cosa.

Si escribo letras, se vuelve loco. Si escribo cualquier número, funciona de maravilla.
Saludos.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: ivancea96 en 26 Marzo 2017, 17:53
La abreviación que hiciste para ahorrar código está muy curioso, antes debo resolver problemas indicado arriba, a parte de eso, lo de pulsar una tecla y automáticamente ejecuta el envio. ;)

No era una abreviación, era la forma de corregir el flujo del programa :/


Si escribo letras, se vuelve loco. Si escribo cualquier número, funciona de maravilla.

Al usar el operator>> de istream (cin), le estás pasando una variable numérica. Si no recibe una entrada válida, pone activa alguna de sus flags internas: http://www.cplusplus.com/reference/istream/istream/operator%3E%3E/ (http://www.cplusplus.com/reference/istream/istream/operator%3E%3E/)
Para ver si está la flag de error (la que te interesa en este caso), tienes el método fail(). Si quieres ver si hay errores de cualquier tipo, tienes el operator bool de la clase ios.

Usando el operator bool:
Código
  1. #include <iostream>
  2.  
  3. using namespace std;
  4.  
  5. int main(){
  6. while(true){
  7. int n;
  8. cin >> n;
  9. if(!cin){
  10. cout << "Error" << endl;
  11. cin.clear();
  12. cin.sync();
  13. }else{
  14. cout << "Ok: " << n << endl;
  15. }
  16. }
  17. }


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 26 Marzo 2017, 18:23
Entendido. Muy buena explicación.

Fíjate que fuí a probar el código en CODE::BLOCKS (https://sourceforge.net/projects/codeblocks/files/Binaries/16.01/Windows/codeblocks-16.01mingw-setup.exe/download) para saber como se comporta, más bien creyendo que funconaría igual y me da errores por todas partes.

Citar
||=== Build: Debug in Arduino_Led (compiler: GNU GCC Compiler) ===|
C:\Users\Meta\Documents\Code Blocks\Arduino_Led\Arduino_Led\main.cpp|13|error: '::main' must return 'int'|
C:\Users\Meta\Documents\Code Blocks\Arduino_Led\Arduino_Led\main.cpp||In function 'int main()':|
C:\Users\Meta\Documents\Code Blocks\Arduino_Led\Arduino_Led\main.cpp|19|warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]|
||=== Build failed: 1 error(s), 1 warning(s) (0 minute(s), 0 second(s)) ===|

(http://www.subeimagenes.com/img/sdfsd-1720457.png)

En Visual Studio 2017 funciona muy bien.



Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: ivancea96 en 26 Marzo 2017, 18:32
El error es totalmente explicativo.
Citar
error: '::main' must return 'int'|

El main es int main() o int main(int, char**).


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 26 Marzo 2017, 19:12
Hola:

Eso hice pero no le puse nada dentro del main. Hasta solo con int main(int) ya me basta. Aún así, ahora el código si lo ejecuta pero no recibe nada del puerto serie con CODE::BLOCKS, encima con Visual Studio C++ si lo hace a pesar que el código es el mismo, excaptuando en que VS C++ es void main () y code::blocks es int main(int).

Código
  1. #include <iostream>
  2. #include <fstream>
  3. #include <Windows.h>
  4. #include "SerialClass.h"
  5. using namespace std;
  6.  
  7. int main(int, char**)
  8. {
  9. // Título de la ventana
  10. SetConsoleTitle("Control Led Arduino - C++ Code::Blocks 16.1");
  11.  
  12. // Puerto serie.
  13. Serial* Puerto = new Serial("COM4");
  14.  
  15. // Comandos para Arduino.
  16. char Luz_ON[] = "Luz_ON"; // Envía "Luz_ON" al puerto serie.
  17. char Luz_OFF[] = "Luz_OFF";
  18. char lectura[50] = "\0"; // Guardan datos de entrada del puerto.
  19.  
  20. int opc; // Guarda un 1 o 2 tipo entero queintroduces desde la consola.
  21.  
  22. while (Puerto->IsConnected())
  23. {
  24. cout << endl; // Dejamos un retorno.
  25. cout << "Introduzca la opcion deseada: " << endl << endl; // Muestra texto en pantalla.
  26.  
  27. cin >> opc; // Aquí introduces un número, el 1 o el 2.
  28.  
  29. switch (opc) // Espera recibir un 1 o un 2.
  30. {
  31. case 1:
  32. // Encener luz.
  33. cout << "Enviando: " << Luz_ON << endl; // Muestra en pantalla textos.
  34. Puerto->WriteData(Luz_ON, sizeof(Luz_ON) - 1); // Envía al puerto el texto "Luz_ON".
  35. break;
  36.  
  37. case 2:
  38. // Apagar luz.
  39. cout << "Enviando: " << Luz_OFF << endl;
  40. Puerto->WriteData(Luz_OFF, sizeof(Luz_OFF) - 1);
  41. break;
  42.  
  43. default: // Si haz pulsado otro número distinto del 1 y 2, muestra
  44. cout << "Puse del 1 al 2."; // este mensaje.
  45. }
  46.  
  47.  
  48. Sleep(250);
  49. int n = Puerto->ReadData(lectura, 49);
  50. if (n > 0)
  51. {
  52. lectura[n + 1] = '\0';
  53. cout << "Recibido: " << lectura << endl;
  54. cout << "-------------------" << endl;
  55. }
  56.  
  57. cin.ignore(256, '\n'); // Limpiar buffer del teclado.
  58. }
  59. }
  60.  

(http://www.subeimagenes.com/img/sdfsd-1720473.png)

(http://www.subeimagenes.com/img/sdfsd-1720479.png)

Lo que no se que en code::blocks el ejecutable pesa 1.01 MB y en VS 2017 pesa el mismo programa a 53 KB. ¿Esto es normal?

Impresionante, no salgo de mi asombro, y eso que más adelante voy a probarlo con C++ Builder, otro IDE.

Saludos.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: ivancea96 en 26 Marzo 2017, 19:26
Una cosa es el DIE y otra el compilador. VC++ utiliza su compilador, Code::Blocks utilizará el que le hayas puesto, o con el que viene por defecto en algunas instalaciones (MinGW-GCC).

En cualquier caso, esa e suna forma muy inexacta de hacerlo. Después de enviar datos al arduino (caso 1 y 2), se supone que tienes que esperar la respuesta. Poner un sleep y luego leer 1 vez no es la forma ideal.

Trata de poner nuevamente el bucle while al leer del arduino (y nuevamente, solo lee del Arduino cuando le hayas enviado datos, no siempre).


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 26 Marzo 2017, 19:44
Lo de cambiar de compilador ya lo había hecho y pesa lo mismo, también se comporta igual.

(http://www.subeimagenes.com/img/sdfsd-1720482.png)

Si sabes hacer el código, hazlo todo a la primera.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: ivancea96 en 26 Marzo 2017, 19:55
Si sabes hacer el código, hazlo todo a la primera.
._.

Ya te he dicho qué hacer, pero ignoraste el mensaje.



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

Código
  1. while (true) {
  2. int n = Puerto->ReadData(lectura, 49);
  3. if (n > 0) {
  4. lectura[n + 1] = '\0';
  5. break;
  6. }
  7. Sleep(1);
  8. }
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
  1. const char *luz[2] = {"Luz_ON", "Luz_OFF"};
  2.  
  3. switch(opc){
  4.    case 1:
  5.    case 2:
  6.        cout << "Enviando: " << luz[opc-1] << endl;
  7.        Puerto->WriteData(luz[opc-1], strlen(luz[opc-1]));
  8.        cout << "Respuesta: " << obtenerRespuestaArduino() << endl;
  9.        break;
  10.  
  11.    default:
  12.        // ...
  13. }

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.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 26 Marzo 2017, 20:37
No tira, algo no hago bien.

Código
  1. #include <iostream>
  2. #include <fstream>
  3. #include <Windows.h>
  4. #include "SerialClass.h"
  5. using namespace std;
  6.  
  7. void main()
  8. {
  9. // Título de la ventana
  10. SetConsoleTitle("Control Led Arduino - Visual Studio C++ 2017");
  11.  
  12. // Puerto serie.
  13. Serial* Puerto = new Serial("COM4");
  14.  
  15. // Comandos para Arduino.
  16. char lectura[50] = "\0"; // Guardan datos de entrada del puerto.
  17. const char *luz[2] = { "Luz_ON", "Luz_OFF" };
  18.  
  19. int opc; // Guarda un 1 o 2 tipo entero queintroduces desde la consola.
  20.  
  21. while (Puerto->IsConnected())
  22. {
  23. cout << endl; // Dejamos un retorno.
  24. cout << "Introduzca la opcion deseada: " << endl << endl; // Muestra texto en pantalla.
  25.  
  26. cin >> opc; // Aquí introduces un número, el 1 o el 2.
  27.  
  28. switch (opc)
  29. {
  30. case 1:
  31. case 2:
  32. cout << "Enviando: " << luz[opc - 1] << endl;
  33. Puerto->WriteData(luz[opc - 1], strlen(luz[opc - 1]));
  34. cout << "Respuesta: " << obtenerRespuestaArduino() << endl;
  35. break;
  36.  
  37. default:
  38. cout << "Puse del 1 al 2."; // este mensaje.
  39. }
  40.  
  41. void obtenerRespuestaArduino()
  42. {
  43. while (true)
  44. {
  45. int n = Puerto->ReadData(lectura, 49);
  46. if (n > 0) {
  47. lectura[n + 1] = '\0';
  48. break;
  49. }
  50. Sleep(1);
  51. }
  52. }
  53.  
  54. cin.ignore(256, '\n'); // Limpiar buffer del teclado.
  55. }
  56. }


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: ivancea96 en 26 Marzo 2017, 20:57
La función obtenerRespuestaArduino no existe... Tienes que hacerla tú.
En el otro mensaje te lo indiqué también.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 26 Marzo 2017, 21:22
Lo hice pero no funciona. ;)


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: ivancea96 en 26 Marzo 2017, 21:22
No veo la función creada.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 27 Marzo 2017, 20:09
A veces, mejor no ver. Gracias de todas formas, lo dejaré así ya funcionando algo, que si no me pego hasta el 2020. ;)


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: ivancea96 en 27 Marzo 2017, 21:11
Aja...
Código
  1. void obtenerRespuestaArduino()
  2. {
  3. while (true)
  4. {
  5. int n = Puerto->ReadData(lectura, 49);
  6. if (n > 0) {
  7. lectura[n + 1] = '\0';
  8. break;
  9. }
  10. Sleep(1);
  11. }
  12. }

En C++, no se ponen funciones dentro de funciones.

Y bueno, la idea de esa función es que la modifiques para que retorne la respuesta del Arduino.
Pero bueno, como veas.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 27 Marzo 2017, 21:20
No se como se hace, en C++ ni idea, me he vuelto loco. Ahora estoy intentando como funciona en CODE::BLOCKS, luego lo paso a C++ Bulder Starter y te cuento.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: ivancea96 en 27 Marzo 2017, 21:28
Pues, por eso te digo. Hazlo en C# sin eventos/handles. Luego pasarlo es casi directo.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 27 Marzo 2017, 22:10
Hola:

Ya me funciona en Visual Studio 2017, Code::Blocks y C++ Builder Started. ;)

Era la librería que lo tenía 9600 buadios en el Code:Blocks y demás. ;)

El código y librería es el mismo.
Código
  1. #include <iostream>
  2. #include <fstream>
  3. #include <Windows.h>
  4. #include "SerialClass.h"
  5. using namespace std;
  6.  
  7. int main()
  8. {
  9. // Título de la ventana
  10. SetConsoleTitle("Control Led Arduino - Visual Studio C++ 2017");
  11.  
  12. // Puerto serie.
  13. Serial* Puerto = new Serial("COM4");
  14.  
  15. // Comandos para Arduino.
  16. char Luz_ON[] = "Luz_ON"; // Envía "Luz_ON" al puerto serie.
  17. char Luz_OFF[] = "Luz_OFF";
  18. char lectura[50] = "\0"; // Guardan datos de entrada del puerto.
  19.  
  20. int opc; // Guarda un 1 o 2 tipo entero queintroduces desde la consola.
  21.  
  22. while (Puerto->IsConnected())
  23. {
  24. cout << endl; // Dejamos un retorno.
  25. cout << "Introduzca la opcion deseada: " << endl << endl; // Muestra texto en pantalla.
  26.  
  27. cin >> opc; // Aquí introduces un número, el 1 o el 2.
  28.  
  29. switch (opc) // Espera recibir un 1 o un 2.
  30. {
  31. case 1:
  32. // Encener luz.
  33. cout << "Enviando: " << Luz_ON << endl; // Muestra en pantalla textos.
  34. Puerto->WriteData(Luz_ON, sizeof(Luz_ON) - 1); // Envía al puerto el texto "Luz_ON".
  35. break;
  36.  
  37. case 2:
  38. // Apagar luz.
  39. cout << "Enviando: " << Luz_OFF << endl;
  40. Puerto->WriteData(Luz_OFF, sizeof(Luz_OFF) - 1);
  41. break;
  42.  
  43. default: // Si haz pulsado otro número distinto del 1 y 2, muestra
  44. cout << "Puse del 1 al 2."; // este mensaje.
  45. }
  46.  
  47.  
  48. Sleep(250);
  49. int n = Puerto->ReadData(lectura, 49);
  50. if (n > 0)
  51. {
  52. lectura[n + 1] = '\0';
  53. cout << "Recibido: " << lectura << endl;
  54. cout << "-------------------" << endl;
  55. }
  56.  
  57. cin.ignore(256, '\n'); // Limpiar buffer del teclado.
  58. }
  59. }

Quité el void main() y le puse en int a todos. El void solo funciona en el Visual studio y C++ Builder, en Code.blocks, solo int. Esto para saber.

Gracias por todo.


Título: Re: Puerto serie C++. Mejorar el programa.
Publicado por: Meta en 31 Marzo 2017, 02:31
Hola:

Tutorial ya hecho, como me agotó solo hacer la maquetación y diseño que el propio contenido.

Ver tutorial (https://foro.elhacker.net/electronica/tutorial_arduino_c_y_puerto_serie-t467313.0.html).

Saludos.