Foro de elhacker.net

Programación => .NET (C#, VB.NET, ASP) => Mensaje iniciado por: Meta en 24 Noviembre 2023, 06:49 am



Título: Recibir dos tramas por RS232 diferentes.
Publicado por: Meta en 24 Noviembre 2023, 06:49 am
Hola:

Puedo recibir tramas de bytes por el puerto serie, una es esta si envía este comando:
Código:
serialPort1.Write("B\r");

#I230.3O230.0L007B100V25.7F50.2H50.2R0080S„€ˆ„À

y la otra es esta si envías este otro comando diferente:
Código:
serialPort1.Write("X72\r");

#2000,1400,230,45.0,55.0,8.6

En la primera tengo el código hecho en Windows Form y funciona.
Código:
using System;
using System.IO.Ports;
using System.Threading;
using System.Windows.Forms;

namespace Termite_SAI_04
{
    public partial class Form1 : Form
    {
        private delegate void DelegadoAcceso(String accion);
        public Form1()
        {
            InitializeComponent();
        }

        private void button_Ver_datos_Click(object sender, EventArgs e)
        {
            serialPort1.Write("B\r");
        }

        private void button_Ver_Tabla_Click(object sender, EventArgs e)
        {
            serialPort1.Write("X72\r");
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            try
            {
                serialPort1 = new SerialPort("COM3", 2400, Parity.None, 8, StopBits.One);
                serialPort1.Handshake = Handshake.None;
                serialPort1.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
                serialPort1.ReadTimeout = 500;
                serialPort1.WriteTimeout = 500;
                serialPort1.Open();
                serialPort1.Write("B\r");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            if (this.Enabled == true)
            {
                Thread.Sleep(500);
                string entrada = serialPort1.ReadExisting();
                this.BeginInvoke(new DelegadoAcceso(si_DataReceived), new object[] { entrada });
                //serialPort1.Write("B\r"); // Envía comando.
            }
        }

        private void si_DataReceived(string accion)
        {
            try
            {
                char[] separadores = { '#', 'I', 'O', 'L', 'B', 'V', 'F', 'H', 'R', 'S' };

                string[] salida = accion.Split(separadores, StringSplitOptions.RemoveEmptyEntries);

                label_I.Text = salida[0] + " Vac";
                label_O.Text = salida[1] + " Vac";
                label_L.Text = salida[2].TrimStart('0') + " %"; // Quita los ceros de la izquierda.
                label_B.Text = salida[3] + " %";
                label_V.Text = salida[4] + " Vdc";
                label_F.Text = salida[5].PadRight(5, '0') + " Hz"; // Añade ceros a la derecha.
                label_H.Text = salida[6].PadRight(5, '0') + " Hz";

                // Convertir variable tipo string a tipo int, es decir, la variable tipo string "salida[7]"
                // se convierte en tipo int "resultadoSalida7".
                int resultadoSalida7 = Int32.Parse(salida[7]);

                // ¿Es igual a 1 minuto?
                if ((resultadoSalida7 % 60) == 1)
                {
                    label_R.Text = resultadoSalida7 / 60 + " hora y " + resultadoSalida7 % 60 + " minuto.";
                }

                // ¿Es mayor a 60 segundos o 1 minuto?
                if ((resultadoSalida7 % 60) > 1)
                {
                    label_R.Text = resultadoSalida7 / 60 + " hora y " + resultadoSalida7 % 60 + " minutos.";
                }

                // ¿Es igual a 60 segundos o 1 minuto?
                if ((resultadoSalida7 % 60) == 0)
                {
                    label_R.Text = resultadoSalida7 / 60 + " hora y " + resultadoSalida7 % 60 + " minutos.";
                }
            }

            catch (IndexOutOfRangeException ex)
            {
                Console.Write("Índice fuera de los límites de la matriz.");
                MessageBox.Show(ex.Message);
            }

            catch (FormatException ex)
            {
                Console.Write("La cadena de entrada no tiene el formato correcto.");
                MessageBox.Show(ex.Message, "Error");
            }
        }
    }
}

Aquí abajo es el trozo de códigos para leer esa trama que no se donde ponerlo.
Código:
            char[] separadores2 = { '#', ',' };

            string[] salida2 = entrada2.Split(separadores2, StringSplitOptions.RemoveEmptyEntries);

            label_Resultado_valores_nonimales_de_alimentacion.Text = salida2[0] + " VA / " + salida2[1] + " W";
            label_Resultado_voltaje_nominal.Text = salida2[2] + " Vac";
            label_Resultado_corriente_nominal.Text = salida2[5] + " A";
            label_Resultado_valores_nominales_de_frecuencia.Text = salida2[3] + " ~ " + salida2[4] + " Hz";

¿Alguna ayuda?

Gracias.


Título: Re: Recibir dos tramas por RS232 diferentes.
Publicado por: profinet en 24 Noviembre 2023, 11:21 am
He reorganizado tu código para hacerlo más modular, lo que facilitará futuras implementaciones y tareas de mantenimiento.
También he introducido dos banderas para determinar qué comando se ha utilizado al enviar la solicitud, permitiendo así la llamada a la función correspondiente.

Código:
using System;
using System.IO.Ports;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Termite_SAI_04 {
    public partial class Form1 : Form {

        private SerialPort puertoSerie;
        private bool verDatosFlag = false;
        private bool verTablaFlag = false;
        private readonly string verDatosReq = "B\r";
        private readonly string verTablaReq = "X72\r";

        private void Form1_Load(object sender, EventArgs e) {
        }

        public Form1() {
            InitializeComponent();
            InitSerialPort();
        }

        /* Iniciar y configurar el puerto serie */
        private void InitSerialPort() {
            try {
                puertoSerie = new SerialPort("COM3", 2400,
                    Parity.None, 8, StopBits.One) {
                    Handshake = Handshake.None,
                    ReadTimeout = 500,
                    WriteTimeout = 500,
                };
                // Subscribir el evento Sp_DataReceived cuando lleguen datos
                puertoSerie.DataReceived += Sp_DataReceived;
            } catch (Exception ex) {
                MessageBox.Show(ex.Message);
                puertoSerie.Close(); // Cierra el puerto en caso de error
            }
        }

        /* Evento de botón: Abrir puerto serie y mandar "B" */
        private void Button_Ver_datos_Click(object sender, EventArgs e) {
            if (puertoSerie.IsOpen) {
                verDatosFlag = true;
                puertoSerie.Open();
                puertoSerie.Write(verDatosReq);
            } else {
                Console.Write("Puerto cerrado. " +
                    "No se puede solicitar datos.");
            }
        }

        /* Evento de botón: Abrir puerto serie y mandar "X72" */
        private void Button_Ver_Tabla_Click(object sender, EventArgs e) {
            if (puertoSerie.IsOpen) {
                verTablaFlag = true;
                puertoSerie.Open();
                puertoSerie.Write(verTablaReq);
            } else {
                Console.Write("Puerto cerrado. " +
                    "No se puede enviar datos.");
            }
        }

        /* Evento para leer asíncronamente datos del puerto serie */
        void Sp_DataReceived(object sender, SerialDataReceivedEventArgs e) {
            if (puertoSerie.IsOpen) {
                Task.Run(async () => {
                    try {
                        await Task.Delay(500); // Pausa para recibir datos
                        string str = puertoSerie.ReadExisting();
                        if (!String.IsNullOrEmpty(str)) {
                            if (verDatosFlag) { ProcessVerDatosReq(str); }
                            if (verTablaFlag) { ProcessVerTablaReq(str); }
                        } else {
                            Console.Write("Datos leídos corruptos.");
                        }
                    } catch (IndexOutOfRangeException ex) {
                        Console.Write("Índice fuera de los límites de la matriz.");
                        MessageBox.Show(ex.Message);
                    } catch (FormatException ex) {
                        Console.Write("La cadena de entrada no tiene el formato correcto.");
                        MessageBox.Show(ex.Message, "Error");
                    }
                });
            }
        }

        /* Procesar VerTablaReq */
        private void ProcessVerTablaReq(string str) {
            verTablaFlag = false;
            char[] separadores = { '#', ',' };
            string[] salida = str.Split(separadores, StringSplitOptions.RemoveEmptyEntries);

            // Al manipular controles de Windows Forms desde un hilo diferente al
            // hilo de la interfaz de usuario, es necesario usar Invoke para evitar problemas de concurrencia
            if (InvokeRequired) {
                Invoke(new Action(() => {
                    UpdateUIControlsVerTabla(salida);
                }));
            } else {
                UpdateUIControlsVerTabla(salida);
            }
        }

        /* Procesar VerDatosReq */
        private void ProcessVerDatosReq(string str) {
            verDatosFlag = false;
            char[] separadores = { '#', 'I', 'O', 'L', 'B', 'V', 'F', 'H', 'R', 'S' };
            string[] salida = str.Split(separadores, StringSplitOptions.RemoveEmptyEntries);

            // Al manipular controles de Windows Forms desde un hilo diferente al
            // hilo de la interfaz de usuario, es necesario usar Invoke para evitar problemas de concurrencia
            if (InvokeRequired) {
                Invoke(new Action(() => {
                    UpdateUIControlsVerDatos(salida);
                }));
            } else {
                UpdateUIControlsVerDatos(salida);
            }
        }

        /* Mostrar datos VerTablaReq */
        private void UpdateUIControlsVerTabla(string[] salida) {
            label_Resultado_valores_nonimales_de_alimentacion.Text
               = salida[0] + " VA / " + salida2[1] + " W";
            label_Resultado_voltaje_nominal.Text
                = salida[2] + " Vac";
            label_Resultado_corriente_nominal.Text
                = salida[5] + " A";
            label_Resultado_valores_nominales_de_frecuencia.Text
                = salida[3] + " ~ " + salida2[4] + " Hz";
        }

        /* Mostrar datos VerDatosReq */
        private void UpdateUIControlsVerDatos(string[] salida) {
            label_I.Text
                  = salida[0] + " Vac";
            label_O.Text
                = salida[1] + " Vac";
            label_L.Text
                = salida[2].TrimStart('0') + " %"; // Quita los ceros de la izquierda.
            label_B.Text
                = salida[3] + " %";
            label_V.Text
                = salida[4] + " Vdc";
            label_F.Text
                = salida[5].PadRight(5, '0') + " Hz"; // Añade ceros a la derecha.
            label_H.Text
                = salida[6].PadRight(5, '0') + " Hz";

            // Convertir variable tipo string a tipo int, es decir, la variable tipo string "salida[7]"
            // se convierte en tipo int "resultadoSalida7".
            int resultadoSalida7 = Int32.Parse(salida[7]);

            // ¿Es igual a 1 minuto?
            if ((resultadoSalida7 % 60) == 1) {
                label_R.Text
                    = resultadoSalida7 / 60 + " hora y "
                    + resultadoSalida7 % 60 + " minuto.";
            }

            // ¿Es mayor a 60 segundos o 1 minuto?
            if ((resultadoSalida7 % 60) > 1) {
                label_R.Text
                    = resultadoSalida7 / 60 + " hora y "
                    + resultadoSalida7 % 60 + " minutos.";
            }

            // ¿Es igual a 60 segundos o 1 minuto?
            if ((resultadoSalida7 % 60) == 0) {
                label_R.Text
                    = resultadoSalida7 / 60 + " hora y "
                    + resultadoSalida7 % 60 + " minutos.";
            }
        }
    }
}


Título: Re: Recibir dos tramas por RS232 diferentes.
Publicado por: Meta en 25 Noviembre 2023, 21:11 pm
Buenas:

Lo he probado y no hace nada de nada.  :(

No encuentro el motivo.

Eso si, tiene variables que se llama salida2 y es solo salida en tu código, ya corregido al compilar. Compila ahora todo, no da errores pero tampoco hace nada.


Título: Re: Recibir dos tramas por RS232 diferentes.
Publicado por: Meta en 28 Noviembre 2023, 00:06 am
Hola:

He hecho una interfaz con Windows Form como indica en la captura.

Se trata a la hora de recibir tramas de string o bytes por el puerto serie.

Si envío el comando X72\r, me llega la tramas de Bytes y lo muestra en los labels marcado en rojo.

Si envío otro comando en este caso llamado X72\r muestra los valores en otras etiquetas indicado en el recuardro en verde.
(https://i.postimg.cc/63BSKkgc/SAI-Csharp-copia.jpg)
Ver zoom (https://i.postimg.cc/63BSKkgc/SAI-Csharp-copia.jpg).

El problema como puedes ver en la captura, te muestra cada comando tramas diferentes en el cual quiero guardarlo en su variable para luego poder poner los valores en sus respectivos labels.

Los comandos los puedes ver, sus respuestas y errores si los hay.

Ver comandos PDF (https://www.dropbox.com/s/u9e22w8iwnw240v/Protocolo%20Comandos%20Salicru%20SAI%20UPS.pdf?dl=0).

Código que he hecho hasta ahora solo funciona para el recuerdre verde.
Código:
using System;
using System.IO.Ports;
using System.Threading;
using System.Windows.Forms;

namespace Termite_SAI_04
{
    public partial class Form1 : Form
    {
        private delegate void DelegadoAcceso(String accion);
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            try
            {
                serialPort1 = new SerialPort("COM3", 2400, Parity.None, 8, StopBits.One);
                serialPort1.Handshake = Handshake.None;
                serialPort1.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
                serialPort1.ReadTimeout = 500;
                serialPort1.WriteTimeout = 500;
                serialPort1.DtrEnable = true;
                serialPort1.RtsEnable = true;
                serialPort1.Open();
                ComandoB();
                timer1.Start();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            if (this.Enabled == true)
            {
                Thread.Sleep(500);
                string entrada = serialPort1.ReadExisting();
                this.BeginInvoke(new DelegadoAcceso(si_DataReceived), new object[] { entrada });
                //serialPort1.Write("B\r"); // Envía comando.
            }
        }

        private void si_DataReceived(string accion)
        {
            try
            {
                char[] separadores = { '#', 'I', 'O', 'L', 'B', 'V', 'F', 'H', 'R', 'S', '\r' };

                string[] salida = accion.Split(separadores, StringSplitOptions.RemoveEmptyEntries);

                label_I.Text = salida[0] + " Vac";
                label_O.Text = salida[1] + " Vac";
                label_L.Text = salida[2].TrimStart('0') + " %"; // Quita los ceros de la izquierda.
                label_B.Text = salida[3] + " %";
                label_V.Text = salida[4] + " Vdc";
                label_F.Text = salida[5].PadRight(5, '0') + " Hz"; // Añade ceros a la derecha.
                label_H.Text = salida[6].PadRight(5, '0') + " Hz";

                // Convertir variable tipo string a tipo int, es decir, la variable tipo string "salida[7]"
                // se convierte en tipo int "resultadoSalida7".
                int resultadoSalida7 = Int32.Parse(salida[7]);

                #region Mostrar horas y minutos.
                // Cálculos.
                int horas = resultadoSalida7 / 60;
                int minutos = resultadoSalida7 % 60;

                // ¿0 horas y 1 minuto?
                if ((horas == 0) && (minutos == 1))
                {
                    label_R.Text = $"{minutos} minuto.";
                }

                // ¿0 horas y 0 minuto?
                if ((horas == 0) && (minutos == 0))
                {
                    label_R.Text = $"{minutos} minutos";
                }

                // ¿0 horas y más de 1 minuto?
                if ((horas == 0) && (minutos > 1))
                {
                    label_R.Text = $"{minutos} minutos.";
                }

                // ¿1 hora y 0 minutos?
                if ((horas == 1) && (minutos == 0))
                {
                    label_R.Text = $"{horas} hora.";
                }

                // ¿Más de una hora y 0 minutos?
                if ((horas > 1) && (minutos == 0))
                {
                    label_R.Text = $"{horas} horas.";
                }

                // ¿1 hora y 1 minuto?
                if ((horas == 1) && (minutos == 1))
                {
                    label_R.Text = $"{horas} hora y {minutos} minuto";
                }

                // ¿1 hora y más de 1 minuto?
                if ((horas == 1) && (minutos > 1))
                {
                    label_R.Text = $"{horas} hora y {minutos} minutos.";
                }

                // ¿Más de 1 hora y 1 minuto?
                if ((horas > 1) && (minutos == 1))
                {
                    label_R.Text = $"{horas} horas y {minutos} minuto.";
                }

                // ¿Más de 1 horas y más de 1 minuto?
                if ((horas > 1) && (minutos > 1))
                {
                    label_R.Text = $"{horas} horas y {minutos} minutos.";
                }
                #endregion
            }

            catch (IndexOutOfRangeException ex)
            {
                Console.Write("Índice fuera de los límites de la matriz.");
                MessageBox.Show(ex.Message);
            }

            catch (FormatException ex)
            {
                Console.Write("La cadena de entrada no tiene el formato correcto.");
                MessageBox.Show(ex.Message, "Error");
            }
        }

        private void button_Ver_datos_Click_1(object sender, EventArgs e)
        {
            ComandoB();
        }

        private void button_Ver_Tabla_Click_1(object sender, EventArgs e)
        {
            ComandoX72();
        }

        // Comandos.
        void ComandoB()
        {
            serialPort1.Write("B\r");
        }

        void ComandoX72()
        {
            serialPort1.Write("X72\r");
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            ComandoB();
        }

        // Al cerrar el formulario.
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            timer1.Stop();          // Detiene el temporizador.
            Thread.Sleep(700);      // 0.5 segudos. 500 milisegundos.
            serialPort1.Close();    // Cierra el puerto serie.
        }
    }
}

¿Alguna idea?

Saludos.


Título: Re: Recibir dos tramas por RS232 diferentes.
Publicado por: profinet en 28 Noviembre 2023, 10:15 am
Ah sí, tuve un descuido al copiar y pegar directamente la lógica para editar los labels. Mis disculpas por eso.

En cuanto a la afirmación de que "no hace nada", me parece extraño. Al menos debería arrojar un error al configurar el puerto o indicar "puerto cerrado" al presionar uno de los dos botones.

En tu código, sería útil almacenar el tipo de solicitud realizada ("B" o "X72") en dos variables booleanas para procesar la trama en la función correspondiente. Puedes aprovechar el mismo manejador de eventos para recibir ambos tipos de tramas y luego pasar el array de cadenas (string[]) a la función apropiada.


Título: Re: Recibir dos tramas por RS232 diferentes.
Publicado por: Meta en 28 Noviembre 2023, 14:02 pm
Cuando llegue a mi casa lo pruebo.

Hay algo que se me escapó y no te conté.

Todas las tramas de string o Bytes siempre empieza con # y acaba en \r.

#I230.3O230.0L007B100V25.7F50.2H50.2R0080S„€ˆ„\r

Lo comento por si acaso y los delimitadores se incluye el \r también.


Título: Re: Recibir dos tramas por RS232 diferentes.
Publicado por: Meta en 28 Noviembre 2023, 23:43 pm
Hola de nuevo.

He modificado nombre de las variables y lo he adaptado el Windows Form .net 4.8 al .net 8.0.

Me sale este error: Puerto cerrado.

Código
  1. using System.IO.Ports;
  2.  
  3. namespace Termite_SAI_05_.NET_8._0
  4. {
  5.    public partial class Form1 : Form
  6.    {
  7.        SerialPort puertoSerie;
  8.        bool verComandoBFlag = false;
  9.        bool verComandoX72Flag = false;
  10.        readonly string verComandoBReq = "B\r";
  11.        readonly string verComandoX72Req = "X72\r";
  12.  
  13.        private void Form1_Load(object sender, EventArgs e)
  14.        {
  15.  
  16.        }
  17.  
  18.        public Form1()
  19.        {
  20.            InitializeComponent();
  21.            InitSerialPort();
  22.        }
  23.  
  24.        /* Iniciar y configurar el puerto serie */
  25.        private void InitSerialPort()
  26.        {
  27.            try
  28.            {
  29.                puertoSerie = new SerialPort("COM3", 2400,
  30.                    Parity.None, 8, StopBits.One)
  31.                {
  32.                    Handshake = Handshake.None,
  33.                    ReadTimeout = 500,
  34.                    WriteTimeout = 500,
  35.                    DtrEnable = true,
  36.                    RtsEnable = true
  37.                };
  38.  
  39.                // Subscribir el evento Sp_DataReceived cuando lleguen datos
  40.                puertoSerie.DataReceived += Sp_DataReceived;
  41.            }
  42.            catch (Exception ex)
  43.            {
  44.                MessageBox.Show(ex.Message);
  45.                puertoSerie.Close(); // Cierra el puerto en caso de error
  46.            }
  47.        }
  48.  
  49.        /* Evento para leer asíncronamente datos del puerto serie */
  50.        void Sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
  51.        {
  52.            if (puertoSerie.IsOpen)
  53.            {
  54.                Task.Run(async () =>
  55.                {
  56.                    try
  57.                    {
  58.                        await Task.Delay(500); // Pausa para recibir datos
  59.                        string str = puertoSerie.ReadExisting();
  60.                        if (!String.IsNullOrEmpty(str))
  61.                        {
  62.                            if (verComandoBFlag) { ProcessverComandoBReq(str); }
  63.                            if (verComandoX72Flag) { ProcessverComandoX72Req(str); }
  64.                        }
  65.                        else
  66.                        {
  67.                            Console.Write("Datos leídos corruptos.");
  68.                        }
  69.                    }
  70.                    catch (IndexOutOfRangeException ex)
  71.                    {
  72.                        Console.Write("Índice fuera de los límites de la matriz.");
  73.                        MessageBox.Show(ex.Message);
  74.                    }
  75.                    catch (FormatException ex)
  76.                    {
  77.                        Console.Write("La cadena de entrada no tiene el formato correcto.");
  78.                        MessageBox.Show(ex.Message, "Error");
  79.                    }
  80.                });
  81.            }
  82.        }
  83.  
  84.        /* Procesar verComandoX72Req */
  85.        private void ProcessverComandoX72Req(string str)
  86.        {
  87.            verComandoX72Flag = false;
  88.            char[] separadores = { '#', ',' };
  89.            string[] salida = str.Split(separadores, StringSplitOptions.RemoveEmptyEntries);
  90.  
  91.            // Al manipular controles de Windows Forms desde un hilo diferente al
  92.            // hilo de la interfaz de usuario, es necesario usar Invoke para evitar problemas de concurrencia
  93.            if (InvokeRequired)
  94.            {
  95.                Invoke(new Action(() =>
  96.                {
  97.                    UpdateUIControlsVerTabla(salida);
  98.                }));
  99.            }
  100.            else
  101.            {
  102.                UpdateUIControlsVerTabla(salida);
  103.            }
  104.        }
  105.  
  106.        /* Procesar verComandoBReq */
  107.        private void ProcessverComandoBReq(string str)
  108.        {
  109.            verComandoBFlag = false;
  110.            char[] separadores = { '#', 'I', 'O', 'L', 'B', 'V', 'F', 'H', 'R', 'S', '\r'};
  111.            string[] salida = str.Split(separadores, StringSplitOptions.RemoveEmptyEntries);
  112.  
  113.            // Al manipular controles de Windows Forms desde un hilo diferente al
  114.            // hilo de la interfaz de usuario, es necesario usar Invoke para evitar problemas de concurrencia
  115.            if (InvokeRequired)
  116.            {
  117.                Invoke(new Action(() =>
  118.                {
  119.                    UpdateUIControlsVerDatos(salida);
  120.                }));
  121.            }
  122.            else
  123.            {
  124.                UpdateUIControlsVerDatos(salida);
  125.            }
  126.        }
  127.  
  128.        /* Mostrar datos verComandoX72Req */
  129.        private void UpdateUIControlsVerTabla(string[] salida)
  130.        {
  131.            label_Resultado_valores_nonimales_de_alimentacion.Text
  132.               = salida[0] + " VA / " + salida[1] + " W";
  133.            label_Resultado_voltaje_nominal.Text
  134.                = salida[2] + " Vac";
  135.            label_Resultado_corriente_nominal.Text
  136.                = salida[5] + " A";
  137.            label_Resultado_valores_nominales_de_frecuencia.Text
  138.                = salida[3] + " ~ " + salida[4] + " Hz";
  139.        }
  140.  
  141.        /* Mostrar datos verComandoBReq */
  142.        private void UpdateUIControlsVerDatos(string[] salida)
  143.        {
  144.            label_I.Text
  145.                  = salida[0] + " Vac";
  146.            label_O.Text
  147.                = salida[1] + " Vac";
  148.            label_L.Text
  149.                = salida[2].TrimStart('0') + " %"; // Quita los ceros de la izquierda.
  150.            label_B.Text
  151.                = salida[3] + " %";
  152.            label_V.Text
  153.                = salida[4] + " Vdc";
  154.            label_F.Text
  155.                = salida[5].PadRight(5, '0') + " Hz"; // Añade ceros a la derecha.
  156.            label_H.Text
  157.                = salida[6].PadRight(5, '0') + " Hz";
  158.  
  159.            // Convertir variable tipo string a tipo int, es decir, la variable tipo string "salida[7]"
  160.            // se convierte en tipo int "resultadoSalida7".
  161.            int resultadoSalida7 = Int32.Parse(salida[7]);
  162.  
  163.            #region Horas y minutos.
  164.            // Cálculos.
  165.            int horas = resultadoSalida7 / 60;
  166.            int minutos = resultadoSalida7 % 60;
  167.  
  168.            // ¿0 horas y 1 minuto?
  169.            if ((horas == 0) && (minutos == 1))
  170.            {
  171.                label_R.Text = $"{minutos} minuto.";
  172.            }
  173.  
  174.            // ¿0 horas y 0 minuto?
  175.            if ((horas == 0) && (minutos == 0))
  176.            {
  177.                label_R.Text = $"{minutos} minutos";
  178.            }
  179.  
  180.            // ¿0 horas y más de 1 minuto?
  181.            if ((horas == 0) && (minutos > 1))
  182.            {
  183.                label_R.Text = $"{minutos} minutos.";
  184.            }
  185.  
  186.            // ¿1 hora y 0 minutos?
  187.            if ((horas == 1) && (minutos == 0))
  188.            {
  189.                label_R.Text = $"{horas} hora.";
  190.            }
  191.  
  192.            // ¿Más de una hora y 0 minutos?
  193.            if ((horas > 1) && (minutos == 0))
  194.            {
  195.                label_R.Text = $"{horas} horas.";
  196.            }
  197.  
  198.            // ¿1 hora y 1 minuto?
  199.            if ((horas == 1) && (minutos == 1))
  200.            {
  201.                label_R.Text = $"{horas} hora y {minutos} minuto";
  202.            }
  203.  
  204.            // ¿1 hora y más de 1 minuto?
  205.            if ((horas == 1) && (minutos > 1))
  206.            {
  207.                label_R.Text = $"{horas} hora y {minutos} minutos.";
  208.            }
  209.  
  210.            // ¿Más de 1 hora y 1 minuto?
  211.            if ((horas > 1) && (minutos == 1))
  212.            {
  213.                label_R.Text = $"{horas} horas y {minutos} minuto.";
  214.            }
  215.  
  216.            // ¿Más de 1 horas y más de 1 minuto?
  217.            if ((horas > 1) && (minutos > 1))
  218.            {
  219.                label_R.Text = $"{horas} horas y {minutos} minutos.";
  220.            }
  221.            #endregion
  222.        }
  223.  
  224.        /* Evento de botón: Abrir puerto serie y mandar "B" */
  225.        private void button_Comando_B_Click(object sender, EventArgs e)
  226.        {
  227.            if (puertoSerie.IsOpen)
  228.            {
  229.                verComandoBFlag = true;
  230.                puertoSerie.Open();
  231.                puertoSerie.Write(verComandoBReq);
  232.            }
  233.            else
  234.            {
  235.                MessageBox.Show("Puerto cerrado. " +
  236.                "No se puede solicitar datos.");
  237.  
  238.            }
  239.        }
  240.  
  241.        /* Evento de botón: Abrir puerto serie y mandar "X72" */
  242.        private void button1_Click(object sender, EventArgs e)
  243.        {
  244.            if (puertoSerie.IsOpen)
  245.            {
  246.                verComandoX72Flag = true;
  247.                puertoSerie.Open();
  248.                puertoSerie.Write(verComandoX72Req);
  249.            }
  250.            else
  251.            {
  252.                MessageBox.Show("Puerto cerrado. " +
  253.                    "No se puede enviar datos.");
  254.            }
  255.        }
  256.    }
  257. }
  258.  
  259.  

Algo pasa que no me deja abrir el puerto.


Título: Re: Recibir dos tramas por RS232 diferentes.
Publicado por: Danielㅤ en 29 Noviembre 2023, 00:00 am
Hola, desactiva el Firewall de Windows o cualquier otro Firewall luego prueba a ejecutar ese programa exe con permisos de administrador y nos comentas las novedades.


Saludos


Título: Re: Recibir dos tramas por RS232 diferentes.
Publicado por: Meta en 29 Noviembre 2023, 00:08 am
.


Título: Re: Recibir dos tramas por RS232 diferentes.
Publicado por: Meta en 29 Noviembre 2023, 07:25 am
Buenos días.

El puertoSerie.Open(); se tiene que poner desde el principio, para que quede abierto siempre.

Ahora el programa si funciona.

Lo tendré que pulir después cuando salga de trabajar.

Dejo el código aquí y gracias a tu ayuda ya funciona todo.

A parte de esto, hay más comandos que enviar, espero que tu programa me sirva de ejemplo para que se me ejecuten todos.

Dejar claro que si hay algún error, me por ejemplo, al enviar un comando que no existe me viene con este error:
#-0\r

Si lo has hecho bien, en algunos comando devuelve uno similar pero sin guión en medio -.
#0\r

Otro errores que no se cual es son.
#3\r
#4\r
#10\r

Y no recuerdo más. Son errores que ya pondré en un label.

Código
  1. using System.IO.Ports;
  2.  
  3. namespace Termite_SAI_05_.NET_8._0
  4. {
  5.    public partial class Form1 : Form
  6.    {
  7.        SerialPort puertoSerie;
  8.        bool verComandoBFlag = false;
  9.        bool verComandoX72Flag = false;
  10.        readonly string verComandoBReq = "B\r";
  11.        readonly string verComandoX72Req = "X72\r";
  12.  
  13.        private void Form1_Load(object sender, EventArgs e)
  14.        {
  15.  
  16.        }
  17.  
  18.        public Form1()
  19.        {
  20.            InitializeComponent();
  21.            InitSerialPort();
  22.        }
  23.  
  24.        /* Iniciar y configurar el puerto serie */
  25.        private void InitSerialPort()
  26.        {
  27.            try
  28.            {
  29.                puertoSerie = new SerialPort("COM3", 2400,
  30.                    Parity.None, 8, StopBits.One)
  31.                {
  32.                    Handshake = Handshake.None,
  33.                    ReadTimeout = 500,
  34.                    WriteTimeout = 500,
  35.                    DtrEnable = true,
  36.                    RtsEnable = true,
  37.                    DiscardNull = false,
  38.                    ParityReplace = 63,
  39.                    ReadBufferSize = 4096,
  40.                    WriteBufferSize = 2018,
  41.                    ReceivedBytesThreshold = 1
  42.                };
  43.  
  44.                // Abrir puerto serie.
  45.                puertoSerie.Open();
  46.  
  47.                // Subscribir el evento Sp_DataReceived cuando lleguen datos
  48.                puertoSerie.DataReceived += Sp_DataReceived;
  49.            }
  50.            catch (Exception ex)
  51.            {
  52.                MessageBox.Show(ex.Message);
  53.                puertoSerie.Close(); // Cierra el puerto en caso de error
  54.            }
  55.        }
  56.  
  57.        /* Evento para leer asíncronamente datos del puerto serie */
  58.        void Sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
  59.        {
  60.            if (puertoSerie.IsOpen)
  61.            {
  62.                Task.Run(async () =>
  63.                {
  64.                    try
  65.                    {
  66.                        await Task.Delay(500); // Pausa para recibir datos
  67.                        string str = puertoSerie.ReadExisting();
  68.                        if (!String.IsNullOrEmpty(str))
  69.                        {
  70.                            if (verComandoBFlag) { ProcessverComandoBReq(str); }
  71.                            if (verComandoX72Flag) { ProcessverComandoX72Req(str); }
  72.                        }
  73.                        else
  74.                        {
  75.                            Console.Write("Datos leídos corruptos.");
  76.                        }
  77.                    }
  78.                    catch (IndexOutOfRangeException ex)
  79.                    {
  80.                        Console.Write("Índice fuera de los límites de la matriz.");
  81.                        MessageBox.Show(ex.Message);
  82.                    }
  83.                    catch (FormatException ex)
  84.                    {
  85.                        Console.Write("La cadena de entrada no tiene el formato correcto.");
  86.                        MessageBox.Show(ex.Message, "Error");
  87.                    }
  88.                });
  89.            }
  90.        }
  91.  
  92.        /* Procesar verComandoX72Req */
  93.        private void ProcessverComandoX72Req(string str)
  94.        {
  95.            verComandoX72Flag = false;
  96.            char[] separadores = { '#', ',' };
  97.            string[] salida = str.Split(separadores, StringSplitOptions.RemoveEmptyEntries);
  98.  
  99.            // Al manipular controles de Windows Forms desde un hilo diferente al
  100.            // hilo de la interfaz de usuario, es necesario usar Invoke para evitar problemas de concurrencia
  101.            if (InvokeRequired)
  102.            {
  103.                Invoke(new Action(() =>
  104.                {
  105.                    UpdateUIControlsComandoX72(salida);
  106.                }));
  107.            }
  108.            else
  109.            {
  110.                UpdateUIControlsComandoX72(salida);
  111.            }
  112.        }
  113.  
  114.        /* Procesar verComandoBReq */
  115.        private void ProcessverComandoBReq(string str)
  116.        {
  117.            verComandoBFlag = false;
  118.            char[] separadores = { '#', 'I', 'O', 'L', 'B', 'V', 'F', 'H', 'R', 'S', '\r'};
  119.            string[] salida = str.Split(separadores, StringSplitOptions.RemoveEmptyEntries);
  120.  
  121.            // Al manipular controles de Windows Forms desde un hilo diferente al
  122.            // hilo de la interfaz de usuario, es necesario usar Invoke para evitar problemas de concurrencia
  123.            if (InvokeRequired)
  124.            {
  125.                Invoke(new Action(() =>
  126.                {
  127.                    UpdateUIControlsComandoB(salida);
  128.                }));
  129.            }
  130.            else
  131.            {
  132.                UpdateUIControlsComandoB(salida);
  133.            }
  134.        }
  135.  
  136.        /* Mostrar datos verComandoX72Req */
  137.        private void UpdateUIControlsComandoX72(string[] salida)
  138.        {
  139.            label_Resultado_valores_nonimales_de_alimentacion.Text
  140.               = salida[0] + " VA / " + salida[1] + " W";
  141.            label_Resultado_voltaje_nominal.Text
  142.                = salida[2] + " Vac";
  143.            label_Resultado_corriente_nominal.Text
  144.                = salida[5] + " A";
  145.            label_Resultado_valores_nominales_de_frecuencia.Text
  146.                = salida[3] + " ~ " + salida[4] + " Hz";
  147.        }
  148.  
  149.        /* Mostrar datos verComandoBReq */
  150.        private void UpdateUIControlsComandoB(string[] salida)
  151.        {
  152.            label_I.Text
  153.                  = salida[0] + " Vac";
  154.            label_O.Text
  155.                = salida[1] + " Vac";
  156.            label_L.Text
  157.                = salida[2].TrimStart('0') + " %"; // Quita los ceros de la izquierda.
  158.            label_B.Text
  159.                = salida[3] + " %";
  160.            label_V.Text
  161.                = salida[4] + " Vdc";
  162.            label_F.Text
  163.                = salida[5].PadRight(5, '0') + " Hz"; // Añade ceros a la derecha.
  164.            label_H.Text
  165.                = salida[6].PadRight(5, '0') + " Hz";
  166.  
  167.            // Convertir variable tipo string a tipo int, es decir, la variable tipo string "salida[7]"
  168.            // se convierte en tipo int "resultadoSalida7".
  169.            int resultadoSalida7 = Int32.Parse(salida[7]);
  170.  
  171.            #region Horas y minutos.
  172.            // Cálculos.
  173.            int horas = resultadoSalida7 / 60;
  174.            int minutos = resultadoSalida7 % 60;
  175.  
  176.            // ¿0 horas y 1 minuto?
  177.            if ((horas == 0) && (minutos == 1))
  178.            {
  179.                label_R.Text = $"{minutos} minuto.";
  180.            }
  181.  
  182.            // ¿0 horas y 0 minuto?
  183.            if ((horas == 0) && (minutos == 0))
  184.            {
  185.                label_R.Text = $"{minutos} minutos";
  186.            }
  187.  
  188.            // ¿0 horas y más de 1 minuto?
  189.            if ((horas == 0) && (minutos > 1))
  190.            {
  191.                label_R.Text = $"{minutos} minutos.";
  192.            }
  193.  
  194.            // ¿1 hora y 0 minutos?
  195.            if ((horas == 1) && (minutos == 0))
  196.            {
  197.                label_R.Text = $"{horas} hora.";
  198.            }
  199.  
  200.            // ¿Más de una hora y 0 minutos?
  201.            if ((horas > 1) && (minutos == 0))
  202.            {
  203.                label_R.Text = $"{horas} horas.";
  204.            }
  205.  
  206.            // ¿1 hora y 1 minuto?
  207.            if ((horas == 1) && (minutos == 1))
  208.            {
  209.                label_R.Text = $"{horas} hora y {minutos} minuto";
  210.            }
  211.  
  212.            // ¿1 hora y más de 1 minuto?
  213.            if ((horas == 1) && (minutos > 1))
  214.            {
  215.                label_R.Text = $"{horas} hora y {minutos} minutos.";
  216.            }
  217.  
  218.            // ¿Más de 1 hora y 1 minuto?
  219.            if ((horas > 1) && (minutos == 1))
  220.            {
  221.                label_R.Text = $"{horas} horas y {minutos} minuto.";
  222.            }
  223.  
  224.            // ¿Más de 1 horas y más de 1 minuto?
  225.            if ((horas > 1) && (minutos > 1))
  226.            {
  227.                label_R.Text = $"{horas} horas y {minutos} minutos.";
  228.            }
  229.            #endregion
  230.        }
  231.  
  232.        /* Evento de botón: Abrir puerto serie y mandar "B" */
  233.        private void button_Comando_B_Click(object sender, EventArgs e)
  234.        {
  235.            if (puertoSerie.IsOpen)
  236.            {
  237.                verComandoBFlag = true;
  238.                //puertoSerie.Open();
  239.                puertoSerie.Write(verComandoBReq);
  240.            }
  241.            else
  242.            {
  243.                MessageBox.Show("Puerto cerrado. " +
  244.                "No se puede solicitar datos.");
  245.  
  246.            }
  247.        }
  248.  
  249.        /* Evento de botón: Abrir puerto serie y mandar "X72" */
  250.        private void button1_Click(object sender, EventArgs e)
  251.        {
  252.            if (puertoSerie.IsOpen)
  253.            {
  254.                verComandoX72Flag = true;
  255.                //puertoSerie.Open();
  256.                puertoSerie.Write(verComandoX72Req);
  257.            }
  258.            else
  259.            {
  260.                MessageBox.Show("Puerto cerrado. " +
  261.                    "No se puede enviar datos.");
  262.            }
  263.        }
  264.    }
  265. }

Una cosa muy importante. No sé si se puede corregir con estos código o hay que empezar desde cero.

Para mi s muy buena idea recibir las tramas de Bytes en Bytes y no en string.

¿Es posible hacerlo?


Muchísimas gracias mi muy distinguido amigo.  ;-) ;-) ;-)


Título: Re: Recibir dos tramas por RS232 diferentes.
Publicado por: profinet en 29 Noviembre 2023, 08:35 am
He cometido varios descuidos al escribir ese código, al parecer.  :-\

Me complace que hayas logrado resolverlos y que el código ahora funcione correctamente, espero que te sea útil como ejemplo.

Además, es importante que incluyas los demás caracteres en el mismo arreglo de separadores para procesar todas las tramas. También te recomiendo separar la lógica de la interfaz de usuario de la lógica de gestión del puerto serie mediante la creación de clases distintas.


Título: Re: Recibir dos tramas por RS232 diferentes.
Publicado por: Meta en 29 Noviembre 2023, 09:51 am
Funciona gracias a ti.  ;-)

Eso sí, cambiaré en vez de recoger una cadena tipo string mejor tipo byte ya que en la tabla ASCII (http://) usa las 255 caracteres y muchos no son visuales sino de comportamientos.

https://learn.microsoft.com/es-es/dotnet/api/system.io.ports.serialport.read?view=dotnet-plat-ext-7.0

Haber si puedo cambiarlo sin que afecte su funcionamiento.


Título: Re: Recibir dos tramas por RS232 diferentes.
Publicado por: Meta en 29 Noviembre 2023, 23:41 pm
Hola:

Quiero enviar el comando B cada 3 segundos (3000 milisegundos) y el timer no funciona. Estoy trabajando en el :NET 8.0 y la verdad que falla más que una escopeta de feria, a parte que los textos de ayuda o errores del compilador se quitó el español y está en Inglés, un desastre.

En fin, dejo el código haber si sabes hacerlo o me quedo otra vez con el .Net 4.8.

(https://i.postimg.cc/rFkX8QSp/SAI-con-tercer-comando.jpg)
Ver zoom (https://i.postimg.cc/rFkX8QSp/SAI-con-tercer-comando.jpg).

Código C#:
Código
  1. using System.IO.Ports;
  2. using System.Text;
  3.  
  4. namespace Termite_SAI_05_.NET_8._0
  5. {
  6.    public partial class Form1 : Form
  7.    {
  8.        SerialPort puertoSerie;
  9.        bool verComandoBFlag = false;
  10.        bool verComandoX72Flag = false;
  11.        bool verComandoX5Flag = false;
  12.        public const string COMANDO_B = "B\r";
  13.        const string COMANDO_X72 = "X72\r";
  14.        const string COMANDO_X5 = "X5\r";
  15.  
  16.        public Form1()
  17.        {
  18.            InitializeComponent();
  19.            InitSerialPort();
  20.        }
  21.        private void Form1_Load(object sender, EventArgs e)
  22.        {
  23.            timer1.Start();
  24.        }
  25.        /* Iniciar y configurar el puerto serie */
  26.        private void InitSerialPort()
  27.        {
  28.            try
  29.            {
  30.                //Encoding cp437 = Encoding.GetEncoding(437);
  31.  
  32.                puertoSerie = new SerialPort()
  33.                {
  34.                    // Configuración del puerto serie.
  35.                    PortName = "COM3",           // Nombre del puerto serie.
  36.                    BaudRate = 2400,             // Velocidad en baudios.
  37.                    Parity = Parity.None,        // Esquema para comprobar la paridad de cada byte recibido.
  38.                    StopBits = StopBits.One,     // Número de bits de parada por byte.
  39.                    DataBits = 8,                // Número de bits de datos por byte.
  40.                    Handshake = Handshake.None,  // Protocolo de establecimiento.
  41.                    DtrEnable = true,            // Línea de terminal de datos.
  42.                    RtsEnable = true,            // Línea de solicitud.
  43.  
  44.                    // Establecer los tiempos de espera de lectura / escritura.
  45.                    ReadTimeout = 500,           // Tiempo de espera de escritura en ms.
  46.                    WriteTimeout = 500,          // Tiempo de espera de escritura en ms.
  47.  
  48.                    // Más configuraciones.
  49.                    DiscardNull = false,         // Descartar bytes nulos recibidos.
  50.                    ParityReplace = 63,
  51.                    ReadBufferSize = 4096,
  52.                    WriteBufferSize = 2018,
  53.                    ReceivedBytesThreshold = 1
  54.                };
  55.  
  56.                // Abrir puerto serie.
  57.                puertoSerie.Open();
  58.  
  59.                // Subscribir el evento DatosRecividos cuando lleguen datos.
  60.                puertoSerie.DataReceived += DatosRecividos;
  61.            }
  62.            catch (Exception ex)
  63.            {
  64.                MessageBox.Show(ex.Message);
  65.                puertoSerie.Close(); // Cierra el puerto en caso de error
  66.            }
  67.        }
  68.  
  69.        /* Evento para leer asíncronamente datos del puerto serie */
  70.        void DatosRecividos(object sender, SerialDataReceivedEventArgs e)
  71.        {
  72.            Task.Run(async () =>
  73.            {
  74.                try
  75.                {
  76.                    await Task.Delay(500); // Pausa para recibir datos
  77.                    string cadena = puertoSerie.ReadExisting();
  78.                    if (!string.IsNullOrEmpty(cadena))
  79.                    {
  80.                        if (verComandoBFlag == true) { ProcessCOMANDO_B(cadena); }
  81.                        if (verComandoX72Flag) { ProcessCOMANDO_X72(cadena); }
  82.                        if (verComandoX5Flag) { ProcessCOMANDO_X5(cadena); }
  83.                    }
  84.                    else
  85.                    {
  86.                        Console.Write("Datos leídos corruptos.");
  87.                    }
  88.                }
  89.                catch (IndexOutOfRangeException ex)
  90.                {
  91.                    Console.Write("Índice fuera de los límites de la matriz.");
  92.                    MessageBox.Show(ex.Message);
  93.                }
  94.                catch (FormatException ex)
  95.                {
  96.                    Console.Write("La cadena de entrada no tiene el formato correcto.");
  97.                    MessageBox.Show(ex.Message, "Error");
  98.                }
  99.            });
  100.        }
  101.  
  102.        /* Procesar COMANDO_X5 */
  103.        private void ProcessCOMANDO_X5(string cadena)
  104.        {
  105.            verComandoX5Flag = false;
  106.            char[] separadores = { '#', ',', '\r' };
  107.            string[] salida = cadena.Split(separadores, StringSplitOptions.RemoveEmptyEntries);
  108.  
  109.            // Al manipular controles de Windows Forms desde un hilo diferente al
  110.            // hilo de la interfaz de usuario, es necesario usar Invoke para evitar problemas de concurrencia.
  111.            if (InvokeRequired)
  112.            {
  113.                Invoke(new Action(() =>
  114.                {
  115.                    UpdateUIControlsComandoX5(salida);
  116.                }));
  117.            }
  118.            else
  119.            {
  120.                UpdateUIControlsComandoX5(salida);
  121.            }
  122.        }
  123.  
  124.        /* Procesar COMANDO_X72 */
  125.        private void ProcessCOMANDO_X72(string str)
  126.        {
  127.            verComandoX72Flag = false;
  128.            char[] separadores = { '#', ',', '\r' };
  129.            string[] salida = str.Split(separadores, StringSplitOptions.RemoveEmptyEntries);
  130.  
  131.            // Al manipular controles de Windows Forms desde un hilo diferente al
  132.            // hilo de la interfaz de usuario, es necesario usar Invoke para evitar problemas de concurrencia.
  133.            if (InvokeRequired)
  134.            {
  135.                Invoke(new Action(() =>
  136.                {
  137.                    UpdateUIControlsComandoX72(salida);
  138.                }));
  139.            }
  140.            else
  141.            {
  142.                UpdateUIControlsComandoX72(salida);
  143.            }
  144.        }
  145.  
  146.        /* Procesar COMANDO_B */
  147.        private void ProcessCOMANDO_B(string str)
  148.        {
  149.            verComandoBFlag = false;
  150.            char[] separadores = { '#', 'I', 'O', 'L', 'B', 'V', 'F', 'H', 'R', 'S', '\r' };
  151.            string[] salida = str.Split(separadores, StringSplitOptions.RemoveEmptyEntries);
  152.  
  153.            // Al manipular controles de Windows Forms desde un hilo diferente al
  154.            // hilo de la interfaz de usuario, es necesario usar Invoke para evitar problemas de concurrencia
  155.            if (InvokeRequired)
  156.            {
  157.                Invoke(new Action(() =>
  158.                {
  159.                    UpdateUIControlsComandoB(salida);
  160.                }));
  161.            }
  162.            else
  163.            {
  164.                UpdateUIControlsComandoB(salida);
  165.            }
  166.        }
  167.  
  168.        /* Mostrar datos COMANDO_X5 */
  169.        private void UpdateUIControlsComandoX5(string[] salida)
  170.        {
  171.            label_Resultado_Tension_nominal.Text
  172.                = salida[0] + " V";
  173.            label_Resultado_Cantidad_del_paquete.Text
  174.                = salida[1] + " Baterías";
  175.            label_Resultado_Capacidad_del_paquete.Text
  176.                = salida[2] + " Ah";
  177.            label_Resultado_Cantidad_externa.Text
  178.                = salida[3];
  179.            label_Resultado_Descarga_maxima.Text
  180.                = salida[4] + " Minuto";
  181.  
  182.            // Convertir variable tipo string a tipo uint, es decir, la variable tipo string "salida[5]"
  183.            // se convierte en tipo uint "resultadoSalida5".
  184.            uint resultadoSalida5 = UInt32.Parse(salida[5]);
  185.  
  186.            // Cálculos.
  187.            uint horas = resultadoSalida5 / 60;
  188.            uint minutos = resultadoSalida5 % 60;
  189.  
  190.            label_Resultado_Carga_maxima.Text
  191.                = $"{horas} Horas";
  192.  
  193.        }
  194.        /* Mostrar datos COMANDO_X72 */
  195.        private void UpdateUIControlsComandoX72(string[] salida)
  196.        {
  197.            label_Resultado_valores_nonimales_de_alimentacion.Text
  198.               = salida[0] + " VA / " + salida[1] + " W";
  199.            label_Resultado_voltaje_nominal.Text
  200.                = salida[2] + " Vac";
  201.            label_Resultado_corriente_nominal.Text
  202.                = salida[5] + " A";
  203.            label_Resultado_valores_nominales_de_frecuencia.Text
  204.                = salida[3] + " ~ " + salida[4] + " Hz";
  205.        }
  206.  
  207.        /* Mostrar datos COMANDO_B */
  208.        private void UpdateUIControlsComandoB(string[] salida)
  209.        {
  210.            label_I.Text
  211.                  = salida[0] + " Vac";
  212.            label_O.Text
  213.                = salida[1] + " Vac";
  214.            label_L.Text
  215.                = salida[2].TrimStart('0') + " %"; // Quita los ceros de la izquierda.
  216.            label_B.Text
  217.                = salida[3].TrimStart('0') + " %";
  218.            label_V.Text
  219.                = salida[4] + " Vdc";
  220.            label_F.Text
  221.                = salida[5].PadRight(5, '0') + " Hz"; // Añade ceros a la derecha.
  222.            label_H.Text
  223.                = salida[6].PadRight(5, '0') + " Hz";
  224.  
  225.            // Convertir variable tipo string a tipo uint, es decir, la variable tipo string "salida[7]"
  226.            // se convierte en tipo uint "resultadoSalida7".
  227.            uint resultadoSalida7 = UInt32.Parse(salida[7]);
  228.  
  229.            #region Horas y minutos.
  230.            // Cálculos.
  231.            uint horas = resultadoSalida7 / 60;
  232.            uint minutos = resultadoSalida7 % 60;
  233.  
  234.            // ¿0 horas y 1 minuto?
  235.            if ((horas == 0) && (minutos == 1))
  236.            {
  237.                label_R.Text = $"{minutos} minuto.";
  238.            }
  239.  
  240.            // ¿0 horas y 0 minuto?
  241.            if ((horas == 0) && (minutos == 0))
  242.            {
  243.                label_R.Text = $"{minutos} minutos";
  244.            }
  245.  
  246.            // ¿0 horas y más de 1 minuto?
  247.            if ((horas == 0) && (minutos > 1))
  248.            {
  249.                label_R.Text = $"{minutos} minutos.";
  250.            }
  251.  
  252.            // ¿1 hora y 0 minutos?
  253.            if ((horas == 1) && (minutos == 0))
  254.            {
  255.                label_R.Text = $"{horas} hora.";
  256.            }
  257.  
  258.            // ¿Más de una hora y 0 minutos?
  259.            if ((horas > 1) && (minutos == 0))
  260.            {
  261.                label_R.Text = $"{horas} horas.";
  262.            }
  263.  
  264.            // ¿1 hora y 1 minuto?
  265.            if ((horas == 1) && (minutos == 1))
  266.            {
  267.                label_R.Text = $"{horas} hora y {minutos} minuto";
  268.            }
  269.  
  270.            // ¿1 hora y más de 1 minuto?
  271.            if ((horas == 1) && (minutos > 1))
  272.            {
  273.                label_R.Text = $"{horas} hora y {minutos} minutos.";
  274.            }
  275.  
  276.            // ¿Más de 1 hora y 1 minuto?
  277.            if ((horas > 1) && (minutos == 1))
  278.            {
  279.                label_R.Text = $"{horas} horas y {minutos} minuto.";
  280.            }
  281.  
  282.            // ¿Más de 1 horas y más de 1 minuto?
  283.            if ((horas > 1) && (minutos > 1))
  284.            {
  285.                label_R.Text = $"{horas} horas y {minutos} minutos.";
  286.            }
  287.            #endregion
  288.  
  289.            uint barraProgresoB = UInt32.Parse(salida[3]);
  290.            progressBar_B.Value = (int)barraProgresoB;
  291.        }
  292.  
  293.        /* Evento de botón: Abrir puerto serie y mandar "B" */
  294.        private void button_Comando_B_Click(object sender, EventArgs e)
  295.        {
  296.            verComandoBFlag = true;
  297.            puertoSerie.Write(COMANDO_B);
  298.        }
  299.  
  300.        /* Evento de botón: Abrir puerto serie y mandar "X72" */
  301.        private void button_Comando_X72_Click(object sender, EventArgs e)
  302.        {
  303.            verComandoX72Flag = true;
  304.            puertoSerie.Write(COMANDO_X72);
  305.        }
  306.  
  307.        private void button_Comando_X5_Click(object sender, EventArgs e)
  308.        {
  309.            verComandoX5Flag = true;
  310.            puertoSerie.Write(COMANDO_X5);
  311.        }
  312.        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
  313.        {
  314.            timer1.Stop();          // Detiene el temporizador.
  315.            Thread.Sleep(700);      // 0.5 segundos. 500 milisegundos.
  316.            puertoSerie.Close();    // Cierra el puerto serie.
  317.        }
  318.  
  319.        private void timer1_Tick_1(object sender, EventArgs e)
  320.        {
  321.            // Enviar comando B al puerto serie.
  322.            puertoSerie.Write(COMANDO_B);
  323.        }
  324.    }
  325. }

En resumen, quiero que se active el timer, por mucho que le de estas instrucciones que hace lo mismo, no funciona.

Código
  1. timer1.Enable = true;
  2.  
  3. timer1.Start();

Gracias.
Gracias.