Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Otros entornos y lenguajes > ASM y Microcontroladores
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 15-08-2017
REHome REHome is offline
Miembro
 
Registrado: jul 2003
Ubicación: España
Posts: 472
Poder: 22
REHome Va por buen camino
[TUTORIAL] Arduino Consola y puerto serie



Tutorial Arduino Consola y puerto serie. Interfaz creado con diversos lenguajes como C#, C++ CLR y VB .net bajo Visual Studio Community que puedes controlar el puerto serie a Arduino encendiendo y apagando un Led, manejar el LCD y recibes mensajes hacia el ordenador o PC.



En este apartado mostramos el código fuente en C#, en el PDF se encuentra C#, C++ CLR y VB .net.

Código C#:
Código:
using System;
using System.IO.Ports;
using System.Text;

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

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

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

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

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

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

            Puerto_serie.Open(); // Abrir puerto.

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

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

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

                    case ConsoleKey.D2:
                    case ConsoleKey.NumPad2:
                        byte[] miBuffer2 = Encoding.ASCII.GetBytes("Luz_OFF");
                        Puerto_serie.Write(miBuffer2, 0, miBuffer2.Length);
                        Console.WriteLine("Comando \"Luz_OFF\" enviado.");
                        break;

                    default:
                        Console.WriteLine("Tecla el 1, el 2 y Escape para salir.");
                        break;
                }
            } while (tecla != ConsoleKey.Escape); // Pulsa Escape para salir del menú.

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

        // Detecta cualquier dato entrante.
        private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
        {
            SerialPort sp = (SerialPort)sender;
            string entradaDatos = sp.ReadExisting(); // Almacena los datos recibidos en la variable tipo string.
            Console.WriteLine("Dato recibido desde Arduino: " + entradaDatos); // Muestra en pantalla los datos recibidos.
        }
    }
}
Código C# Avanzado:
Código:
using System;
using System.IO;
using System.IO.Ports;
using System.Text;
using System.Speech.Recognition; // No olvidar. Micro.
using System.Speech.Synthesis; // No olvidar. Altavoz.

namespace Arduino_Consola_Color_Voz_cs
{
    class Program
    {
        static void Main(string[] args)
        {
            string COM = "";

            // Título de la ventana.
            Console.Title = "Arduino Consola color y voz C#";

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

            SerialPort Puerto_serie;

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

            // Configuración.
            Console.Write(@"
Introduzca un número para seleccionar puerto COM.
Por ejemplo el 4, sería COM4.

Puerto: ");
            COM = Console.ReadLine(); // Escribir el número del puerto.
            Console.Clear();

            Puerto_serie.PortName = "COM" + COM; // Número del puerto serie.


            Puerto_serie.BaudRate = 115200; // Baudios.
            Puerto_serie.Parity = Parity.None; // Paridad.
            Puerto_serie.DataBits = 8; // Bits de datos.
            Puerto_serie.StopBits = StopBits.Two; // Bits de parada.
            Puerto_serie.Handshake = Handshake.None; // Control de flujo.

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

            try
            {
                Puerto_serie.Open(); // Abrir el puerto serie.
            }

            catch (IOException)
            {
                Console.ForegroundColor = ConsoleColor.Red; // Texto en rojo.
                Console.CursorVisible = false;
                Console.SetCursorPosition(16, 6);
                Console.WriteLine(@"El puerto " + Puerto_serie.PortName + @" no existe
                o no lo encuentra.");
                Console.ReadKey();   // Pulse cualquier tecla.
                Environment.Exit(1); // Salir de la aplicación.
            }



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

            ConsoleKey tecla;
            Console.WriteLine("Pulse tecla 1 para encender, 2 para apagar y \n" +
                "Escape para salir. \n" +
                "--------------------------------------------------------------\n");

            do
            {
                tecla = Console.ReadKey(true).Key; // Espera pulsación de teclas.
                                                   // Inicializar una nueva instancia de SpeechSynthesizer.
                using (SpeechSynthesizer altavoz = new SpeechSynthesizer())
                {
                    // Configure la salida de audio.
                    altavoz.SetOutputToDefaultAudioDevice();

                    // Velocidad de la voz.
                    altavoz.Rate = -2; // Valores entre -10 a 10.

                    // Volumen de la voz.
                    altavoz.Volume = 100; // Valores entre 0 y 100.

                    switch (tecla)
                    {
                        case ConsoleKey.D1: // Tecla 1 del teclado estandar.
                        case ConsoleKey.NumPad1: // Tecla 1 del número del pad.
                            byte[] miBuffer1 = Encoding.ASCII.GetBytes("Luz_ON"); // Codificación ASCII y guarda en la variable array tipo byte.
                            Puerto_serie.Write(miBuffer1, 0, miBuffer1.Length); // Envía los datos del buffer todo su contenido.
                            Console.ForegroundColor = ConsoleColor.Gray;
                            Console.Write("Comando"); // Muestra en pantalla comandos enviado.
                            Console.ForegroundColor = ConsoleColor.Green;
                            Console.Write(" \"Luz_ON\" ");
                            Console.ForegroundColor = ConsoleColor.Gray;
                            Console.WriteLine("enviado.");
                            Console.ForegroundColor = ConsoleColor.Gray;
                            altavoz.Speak("Luz encendida.");
                            break;

                        case ConsoleKey.D2:
                        case ConsoleKey.NumPad2:
                            byte[] miBuffer2 = Encoding.ASCII.GetBytes("Luz_OFF");
                            Puerto_serie.Write(miBuffer2, 0, miBuffer2.Length);
                            Console.ForegroundColor = ConsoleColor.Gray;
                            Console.Write("Comando"); // Muestra en pantalla comandos enviado.
                            Console.ForegroundColor = ConsoleColor.Green;
                            Console.Write(" \"Luz_OFF\" ");
                            Console.ForegroundColor = ConsoleColor.Gray;
                            Console.WriteLine("enviado.");
                            Console.ForegroundColor = ConsoleColor.Gray;
                            altavoz.Speak("Luz apagada.");
                            break;

                        case ConsoleKey.Escape:
                            Console.WriteLine("Saliendo...");
                            altavoz.Speak("Saliendo.");
                            break;

                        default:
                            Console.WriteLine("Tecla el 1, el 2 y Escape para salir.");                          
                            break;
                    }
                }
            } while (tecla != ConsoleKey.Escape); // Pulsa Escape para salir del menú.

            Console.ForegroundColor = ConsoleColor.Yellow;

            Console.WriteLine();
            Console.WriteLine("╔═════════════════════════════════════════════════════╗");
            Console.WriteLine("║ Electrónica PIC                 metaconta@gmail.com ║");
            Console.WriteLine("║                                                     ║");
            Console.WriteLine("║               Ángel Acaymo M. G.                    ║");
            Console.WriteLine("╚═════════════════════════════════════════════════════╝");
            Console.WriteLine();

            Console.ForegroundColor = ConsoleColor.Cyan;
            Console.WriteLine("Pulse cualquier tecla para salir...");
            Console.WriteLine();
            Console.ReadKey(); // Espera pulsar una tecla cualquiera.
            Puerto_serie.Close(); // Cierra el puerto serie.
        }

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

        // Maneje el evento SpeechRecognized.
        static void recognizer_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
        {
            Console.WriteLine("Texto reconocido: " + e.Result.Text);

            string palabras = e.Result.Text;
        }
    }
}


Código de Arduino:
Código:
// ----- Electrónica PIC -----
//
// Ejercicio 2.
//
// Encendido y apagado del Led 13 mediante puerto serie con pantalla.
// Es lo mismo que el Ejercicoi 1, pero usando el LCD Keypad Shield.

#include

// Inicializa la librería con sus pines indicados.
// RS, RW, Enable, D4, D5, D6, D7.
LiquidCrystal lcd(8, NULL, 9, 4, 5, 6, 7);
// LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

// Pin 10 para saber que es luz de fondo.
const byte LuzFondo = 10;

const byte Led = 13;   // Declaramos la variable pin del Led.
char caracter;
String comando;

void setup()
{
  pinMode(Led, OUTPUT);  // Inicializa el pin del LED como salida:
  Serial.begin(115200);     // Puerto serie 115200 baudios.
  lcd.begin(16, 2);         // Formato de pantalla.
  lcd.clear();      // Borra la pantalla y su posición superior izquierda.
  lcd.print("    Arduino     ");
  delay(1000);
}

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

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

  // Si los carácteres es recibido y verdadero.
  if (comando.equals("Luz_ON") == true)
  {
    digitalWrite(Led, HIGH); // Enciende el Led 13.
    Serial.write("ON - Led encendido.");    // Envía este mensaje al PC.
    lcd.setCursor(0, 1);
    lcd.print("Luz ON.         "); // Mostrar en el LCD.
  }


  if (comando.equals("Luz_OFF") == true)
  {
    digitalWrite(Led, LOW); // Apaga el Led 13.
    Serial.write("OFF - Led apagado. ");  // Envía este mensaje al PC.
    lcd.setCursor(0, 1);
    lcd.print("Luz OFF.        "); // Mostrar en el LCD.
  }

  // Limpiamos la cadena para volver a recibir el siguiente comando.
  comando = "";
}


Ver vídeo.
https://www.youtube.com/watch?v=erQygRNAPWc

Ver visor.

Ver PDF.

Un cordial saludo.
__________________
http://electronica-pic.blogspot.com....n-arduino.html Manuales de electrónica general, PIC y Arduino.

Última edición por Casimiro Notevi fecha: 15-08-2017 a las 17:53:30.
Responder Con Cita
  #2  
Antiguo 15-08-2017
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.257
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Responder Con Cita
  #3  
Antiguo 07-01-2018
tsk tsk is offline
Miembro
 
Registrado: dic 2017
Posts: 56
Poder: 7
tsk Va por buen camino
Que tal REHome, sólo unos comentarios con respecto al código del Arduino. Ya que como es mi primer post todavía no puedo poner imágenes, por lo cual lo anexo como PDF.

El objetivo es que los lectores tomen conciencia de lo que pueden ocasionar nuestras decisiones de diseño, como la que muestras dentro de la función loop.

Código:
while (Serial.available() > 0)
  {
    caracter = Serial.read();
    comando.concat(caracter);
    delay(10);
  }
Y a partir de ello plantear opciones que nos permitan acercarnos a un mejor diseño.

Aunque sólo sea para enseñar, en mi opinión siempre hay que mostrar las consecuencias, porque si no lo hacemos, corremos el riesgo de diseminar malas prácticas de diseño entre los que nos leen, ya que por lo general somos lo suficientemente perezosos para superar el famoso copiar/pegar al que nos hemos ido acostumbrando.

Saludos cordiales.
Imágenes Adjuntas
Tipo de Archivo: pdf Code.pdf (85,0 KB, 6 visitas)
Responder Con Cita
  #4  
Antiguo 08-01-2018
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.257
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Cita:
Empezado por tsk Ver Mensaje
Que tal
Puedes escribir todo aquí mismo, y poner las imágenes también de varios modos, ejemplo: ww.loquesea.imagen1.jpg
Y luego algún moderador añadirá la w que falta.
Responder Con Cita
  #5  
Antiguo 09-01-2018
tsk tsk is offline
Miembro
 
Registrado: dic 2017
Posts: 56
Poder: 7
tsk Va por buen camino
Gracias por el tip, incluso agregué al final dos vídeos. Saludos
---------------------------------------------------------------------

Hay que tener en cuenta que estas trabajando con el puerto serie a 115200bps

Código:
    Serial.begin(115200);
El significado de esto es que el tiempo de bit será de aproximadamente 8.7us. Si consideramos que el formato es de un bit de inicio, 8 bits de datos más un bit de paro, tendremos un caracter en el buffer del UART del Microcontrolador cada 87us.

Luz_ON equivale a 5.22ms y Luz_OFF a 6.09ms

Código:
    while (Serial.available() > 0)
    {
        caracter = Serial.read();
        comando.concat(caracter);
        delay(10);
    }
Con ese while está bloqueando el sistema hasta que todo el comando sea recibido. No existe absolutamente ningún indicio de cuando tengo un comando válido, además de considerar que todos somos buenos chicos que nunca vamos a enviar datos de forma continua que llene la memoria RAM y/o que pueda ocasionar perdida de datos y que el sistema quede bloqueado hasta que me decida a parar mi ataque DoS ya que la única esperanza para salir de ese bloque es que pare de transmitir.

Luego llegamos a ese delay de 10ms. A pesar de poder recibir un caracter cada 87us tenemos que esperar un total de 60 a 70 ms para recibir toda la cadena que compone un comando. Esto también puede ocasionar perdida de datos y además podemos ocasionar un OverRun en el Hardware U(S)ART.

Reproduje tu código para mostrar a lo que me refiero



Envío 1024 bytes más "\\r\\n" de los cauales se pierden 954 bytes

En cambio, si lo hacemos con

Código:
  if(Serial.available()>0)
  {
    caracter = Serial.read();
    if(caracter == '\n')
    {
      Serial.println(comando.length());
      Serial.println(comando);
      comando = "";
    } else {
      comando.concat(caracter);
    }
  }
[/IMG]

Otro aspecto, envuelve el uso de la función loop. Si metes todo en esa función y si tienes retardos considerables, aun con el código que muestro arriba vas a tener algunos problemas de perdida de datos. Podríamos pensar en usar la función serialEvent, pero no todo es lo que parece. Esta función se llama después de llamar la función loop, así que cualquier retardo dentro de la función loop va a impactar el momento exacto en el que podemos procesar los datos entrantes.

Arduino, internamente maneja una interrupción en la recepción que manda cada caracter recibido a un buffer de 63 bytes, la solución sería definir nosotros esa interrupción, pero si no nos queremos salir de las funciones que arduino nos provee, entonces debemos aprender a trabajar con lo que nos ofrece.

Por lo pronto si en estos momentos le agregara un retardo de 500ms para hacer parpadear un led, enfrentaríamos los mismos problemas de posible perdidas de datos.

Código:
    const uint8_t Led=13;
    String comando;
    boolean stringComplete = false;

    void setup() {
        // put your setup code here, to run once:

        pinMode(Led, OUTPUT);
        Serial.begin(115200);
    }

    void loop() {
      // put your main code here, to run repeatedly:
        digitalWrite(Led,!digitalRead(Led));
        delay(500);
        if(stringComplete)
        {
            Serial.println(comando.length());
            Serial.println(comando);
            comando = "";
            stringComplete = false;
        }
    }

    void serialEvent(){
        while(Serial.available())
        {
            char c = Serial.read();
            comando.concat(c);
            if(c == '\n'){
                stringComplete = true;
            }
        }
    }
Incluso podemos terminar con un sistema que no responde en periodos más largos de los 500ms, previstos, cuando usamos cadenas largas.



En esta última imagen se percibe que hay perdida de datos ya que los últimos debería de recibir los 1026 bytes, pero las perdidas pueden ser variables, además de que el U(S)ART deja de responder si el tamaño de la cadena que le llega es mayor a los 63 bytes del buffer de recepción. De este estado sale cuando introducimos una cadena que sea menor a 63 bytes, pero nos enfrentamos a la penosa perdida de datos.

Aunque todo no esta perdido, ya que podemos hacer uso de la función micros de la siguiente forma para poder tener nuestro retardo de 500ms (aproximadamente)

Código:
    const uint8_t Led=13;
    String comando;
    boolean stringComplete = false;
    unsigned long c_time = 0;
    unsigned long t_delay = 500000;
    void setup() {
        // put your setup code here, to run once:

        pinMode(Led, OUTPUT);
        Serial.begin(115200);
        c_time = micros();
    }

    void loop() {
        // put your main code here, to run repeatedly:
        if(micros() - c_time >= t_delay)
        {
            digitalWrite(Led,!digitalRead(Led));
            c_time = micros();
        }
        if(stringComplete)
        {
            Serial.println(comando.length());
            Serial.println(comando);
            comando = "";
            stringComplete = false;
        }
    }

    void serialEvent(){
        while(Serial.available())
        {
            char c = Serial.read();
            comando.concat(c);
            if(c == '\n'){
                stringComplete = true;
            }
        }
    }


No soluciona todo ya que ahora nos enfrentamos al overflow de la variable que almacena los micro segundos que han pasado desde que el Arduino fue encendido, pero el código de arriba no bloquea el funcionamiento de otras secciones del sistema.

A partir de esto ya se pude vislumbrar una mejor forma de desarrollar un sistema embebido que sea más confiable ya que tomamos conciencia de lo que puede ocasionar nuestras decisiones de diseño.

Anexo dos vídeos donde se puede percibir de forma clara el problema que se ocasiona. Para las pruebas estoy enviando 40000 bytes al inicio con 0 ms entre byte y después 1 ms entre byte. En el primer vídeo vemos como el parpadeo del led se detiene mientras espera a que termine de enviar los datos y además se puede apreciar perdida de datos.



En este segundo vídeo, la perdida de datos es debida a que no existe más RAM, pero no bloquea el parpadeo del led, así que ya tenemos la ventaja que el sistema no se va a bloquear mientras espera que todos los datos sean recibidos.



Cabe aclarar que siempre hay mejores formas, pero con esto ya podemos ir un paso adelante.

Última edición por Casimiro Notevi fecha: 09-01-2018 a las 11:11:21.
Responder Con Cita
  #6  
Antiguo 15-03-2021
REHome REHome is offline
Miembro
 
Registrado: jul 2003
Ubicación: España
Posts: 472
Poder: 22
REHome Va por buen camino
@tsk

Buenas:

No te había leído. Tendré que hacer otra vez el tutorial, ya que tengo intención de hacer lo mismo pero con entradas analógicas ya para Delphi 10.4.

Lo que no me deja ahora mismo cargar el proyecto. Me da este error.

Desde que pulse File--->Open Proyect para cargar un archivo me sale este error y no se el motivo.

https://www.clubdelphi.com/foros/att...1&d=1615844858

Desinstalé Delphi 10.2 y luego instalé el Delphi 10.4.

¿Tiene algo que ver?

Sobre el tutorial de arriba con el código de ARduino. Que es este.

Código:
#include

// Inicializa la librería con sus pines indicados.
// RS, RW, Enable, D4, D5, D6, D7.
LiquidCrystal lcd(8, NULL, 9, 4, 5, 6, 7);
// LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

// Pin 10 para saber que es luz de fondo.
const byte LuzFondo = 10;

const byte Led = 13;   // Declaramos la variable pin del Led.
char caracter;
String comando;

void setup()
{
  pinMode(Led, OUTPUT);  // Inicializa el pin del LED como salida:
  Serial.begin(115200);     // Puerto serie 115200 baudios.
  lcd.begin(16, 2);         // Formato de pantalla.
  lcd.clear();      // Borra la pantalla y su posición superior izquierda.
  lcd.print("    Arduino     ");
  delay(1000);
}

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

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

  // Si los carácteres es recibido y verdadero.
  if (comando.equals("Luz_ON") == true)
  {
    digitalWrite(Led, HIGH); // Enciende el Led 13.
    Serial.write("ON - Led encendido.");    // Envía este mensaje al PC.
    lcd.setCursor(0, 1);
    lcd.print("Luz ON.         "); // Mostrar en el LCD.
  }


  if (comando.equals("Luz_OFF") == true)
  {
    digitalWrite(Led, LOW); // Apaga el Led 13.
    Serial.write("OFF - Led apagado. ");  // Envía este mensaje al PC.
    lcd.setCursor(0, 1);
    lcd.print("Luz OFF.        "); // Mostrar en el LCD.
  }

  // Limpiamos la cadena para volver a recibir el siguiente comando.
  comando = "";
}
Siguiendo lo que haz contado, pero no tiene Led que parpadea.

¿Cómo harías el código sustituyendo a este?

Lo comento para hacerlo de nuevo.

A parte que voy hacer el de entradas y salidas analógicas.

Quiero hacer coas con Delphi y Arduino.

Un cordial saludos y muy buena explicación.
Imágenes Adjuntas
Tipo de Archivo: png Captura.PNG (7,2 KB, 22 visitas)
__________________
http://electronica-pic.blogspot.com....n-arduino.html Manuales de electrónica general, PIC y Arduino.
Responder Con Cita
  #7  
Antiguo 20-03-2021
tsk tsk is offline
Miembro
 
Registrado: dic 2017
Posts: 56
Poder: 7
tsk Va por buen camino
Es exactamente lo que que puse, lo que cambiaría es que eliminas la parte que hace parpadear el LED y dentro de la condición que se pregunta por stringComplet ahí procesas los comandos.

Aunque yo lo que haría es hacer un separación de los componentes del sistema para que te sea más fácil desarrollar. Por lo general siempre sigo una estrategia similar a la siguiente, aunque cada aplicación es su propio mundo, por lo que a veces no es posible generalizar.

Defino una estructura donde coloco la información de cada comando, incluso lo que debe de ejecutar.

Código PHP:
typedef struct {
  
char *cmdName;
  
uint8_t cmdLen;
  
void (*query)(Message_t *msg);
  
void (*setCmd)(char *paramsMessage_t *msg);
  
void (*execCmd)(Message_t *msg);
Cmd_t
Le puedes agregar lo que se te ocurra, incluso un timeout, para indicarle cuanto tiempo debe de esperar para recibir respuesta del sistema principal.

Después se crear un arreglo donde se colocan los comandos de la siguiente forma.

Código PHP:
Cmd_t cmd_table[CMD_N] = {
  {
NULL,0,NULL,NULL,cmdNull},
  {
"+PLAY",5,cmdDanceQuery,cmdDanceSet,NULL},
  {
"+BTONE",6,NULL,cmdBendToneSet,NULL},
  {
"+SHAKEL",7,NULL,cmdMoveShakeLegs,NULL},
  {
"+WALK",5,NULL,cmdMoveWalk,NULL},
  {
"+TURN",5,NULL,cmdMoveTurn,NULL},
  {
"+UPDOWN",7,NULL,cmdMoveUpdown,NULL},
  {
"+SWING",6,NULL,cmdMoveSwing,NULL},
  {
"+TTSWING",8,NULL,cmdMoveTiptoeSwing,NULL},
  {
"+JITTER",7,NULL,cmdMoveJitter,NULL},
  {
"+ASCTURN",8,NULL,cmdMoveAscendingTurn,NULL},
  {
"+MOONWLK",8,NULL,cmdMoveMoonWalker,NULL},
  {
"+CRUSAITO",9,NULL,cmdMoveCrusaito,NULL},
  {
"+FLAPPING",9,NULL,cmdMoveFlapping,NULL},
  {
"+HOME",5,NULL,NULL,cmdMoveHome},
  {
"+JUMP",5,NULL,cmdMoveJump,NULL},
  {
"+BEND",5,NULL,cmdMoveBend,NULL},
  {
"+STOP",5,NULL,cmdStop,NULL},
  {
"+GDST",5,NULL,NULL,cmdGetDistance},
}; 
Y se definen las funciones para manejar esos comandos, como por ejemplo los siguientes

Código PHP:
Cmd_Status_t cmdProcess(Cli_t *meint8_t cmd_idxchar *pRcvDataMessage_t *msg);
int8_t cmdLen(char *pCmd);
int8_t cmdSearch(Cli_t *meuint8_t lenchar *pCmd);
int8_t p_parse(char *pParams_t *params); 

Por ejemplo cmdSearch busca en el arreglo el índice del comando, si es que existe, en caso de existir regresa el índice, de lo contrario un -1.

Con esa información cmdProcess se encargar de ejecutar el comando y decidir si el formato es de un query, un set o una ejecución

Así es mucho más sencillo añadir comandos y que lleves un buen control.

En tu ejemplo, tienes un Luz_ON, Luz_OFF, pero si quieres añadir más, o incluso preguntar el estado, le vas a tener que agregar más y más IFs, en cambio si lo planteas de esta forma, con un sólo comando podrías manejar todas las opciones

{"+LUZ",4,getState,setState,NULL},

Entonces puedes definir un formato de comando, por ejemplo

AT+LUZ <- Te regresa el estado de todas las luces que tengas definidas
AT+LUZ?1 <- Te regresa el estado de la Luz 1
AT+LUZ==1,0 <- Pone la Luz 1 en estado bajo
AT+LUZ==2,1 <- Pone la Luz 2 en estado alto

De la misma forma, podrías aplicar el mismo concepto a la lectura de los sensores, y en lugar de actuar directamente sobre el sistema, este le enviaría un comando, por ejemplo:

Código PHP:
typedef struct sensor{
  
char *name_;
  
uint32_t period_us;
  
uint16_t th;
  
void (*init)();
  
Status_t (*execute)(struct sensor *me,uint32_t c_timechar *message);
  
char *cmd;
sensor_t
period_us contendrá cada cuando queremos acceder observar el estado del sensor y en el caso de niveles lógicos el valor de th no tendría mucho sentido de colocarlo, pero, para un valor de un ADC o que pueda variar dentro de un rango, este valor tiene sentido, por ejemplo

Código PHP:
sensor_t sensor_table[n_sensors] = {
  {
"Eyes",200000,10,&init_us_sensor,&us_sensor,"OT+STOP:0\r\n"},
  {
"Mic",50000,1,&init_mic_sensor,&mic_sensor,"OT+STOP:1\r\n"},
  {
"Touch Head",200000,1,&init_touch_sensor_head,&touch_sensor_head,"OT+DANCE=3,3\r\n"},
}; 
Código PHP:
Status_t us_sensor(struct sensor *meuint32_t c_time,char *message)
{
  static 
uint32_t t_time 0;
  
int32_t duration;
  
  if(
c_time t_time >= me->period_us)
  {
    
digitalWrite(TRIG_PIN,LOW);
    
delayMicroseconds(2);
    
digitalWrite(TRIG_PIN,HIGH);
    
delayMicroseconds(10);
    
digitalWrite(TRIG_PIN,LOW);

    
duration pulseIn(ECHO_PINHIGH);

    
otto.distance duration*0.034/2;
    
t_time c_time;
    if(
otto.distance me->th)
    {
      
sprintf(message"%s"me->cmd);
      return 
OK;
    }
    
  }
  return 
NOP;

Entonces, si la distancia del sensor es menor a valor que tenemos en th, va a guardar en message el comando que definimos en cmd. Después este mensaje se pasa al sistema principal a través de una función que se encarga de manejar los comandos de sistema. Por lo tanto, si observas, en este momento, los comandos pueden venir del puerto serial o de los sensores, y como separaste el sistema de los estímulos que se le pueden aplicar al sistema, es fácil agregar más sensores sin tener que alterar el sistema principal.

Por ejemplo, ahorita sólo tienes un sólo LED y el comando AT+LUZ==1,1 te arrojaría un error, pero si decides agregarle una segunda luz, podrías ejecutar el comando AT+LUZ==1,1 modificando una sola parte del sistema sin importar que venga de un comando que se introduzca por el puerto serie o que provenga como respuesta a un estímulo de una entrada, de lo contrario vas a tener que modificar el código en, por lo menos dos partes:

1.- La sección que interpreta los comandos que entran por el puerto serie.
2.- En el código de cada uno de los sensores cuyo efecto se debe de notar en el estado de la salida en particular.
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
[TUTORIAL] Arduino Delphi 10.2 y Puerto serie REHome ASM y Microcontroladores 4 20-07-2017 09:58:32
[TUTORIAL] Arduino C++ y Puerto serie REHome C++ Builder 2 01-04-2017 00:12:21
[TUTORIAL] Interfaz Java, Visual Basic 6 y Arduino REHome ASM y Microcontroladores 0 07-12-2015 05:43:04
Leer Puerto Com escrito por Arduino mariano22 Varios 1 25-08-2015 06:56:33
Puerto serie esquerda21 Varios 2 13-05-2004 00:58:52


La franja horaria es GMT +2. Ahora son las 01:18:14.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi