elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Arreglado, de nuevo, el registro del warzone (wargame) de EHN


  Mostrar Mensajes
Páginas: [1] 2
1  Foros Generales / Dudas Generales / Re: Automatizando puerta.... Algo falla.... en: 29 Noviembre 2023, 08:48 am
En tu esquema, estás empleando el bloque B003 para establecer un ciclo infinito. Para iniciar el ciclo cuando lo desees, es necesario conectar la salida del bloque Set/Reset a la entrada de B002 mediante una puerta NOT en serie.
2  Programación / .NET (C#, VB.NET, ASP) / Re: Recibir dos tramas por RS232 diferentes. 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.
3  Programación / .NET (C#, VB.NET, ASP) / Re: Recibir dos tramas por RS232 diferentes. 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.
4  Foros Generales / Foro Libre / Re: ¿qué sucederá? en: 24 Noviembre 2023, 16:17 pm
En muchos casos, la resistencia de un material es el esfuerzo en un punto de ruptura de un material bajo carga. Ahora bien, consideremos una moneda estándar, puramente de latón, con diámetro 20 mm y grosor 1.5 mm (que obviamos para simplificar el cálculo).

Primero calculemos el área transveral de la moneda: At = d^2 x pi /4 = 0.314mm2

Dado que la resistencia a la tracción del latón oscila entre los 300-600 MPa, consideremos su valor más alto.

La fuerza que debes hacer para romper la moneda se define como:

F = E x St

F = 600 MPa x 0.314 mm2 = 188.4N

Así que puedes poner estos cálculos en práctica poniendo la moneda encima de la vía de un tren, y puede pasar: a) se rompe, b) se deforma, c) descarrila el tren.
5  Foros Generales / Dudas Generales / Re: Automatizando puerta.... Algo falla.... en: 24 Noviembre 2023, 15:08 pm
Discúlpame, ese circuito es erróneo (también lo escribí a mano sin poder simularlo).  :-\
Prueba el siguiente, acabo de simularlo.

6  Programación / .NET (C#, VB.NET, ASP) / Re: Recibir dos tramas por RS232 diferentes. 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.";
            }
        }
    }
}
7  Foros Generales / Dudas Generales / Re: Automatizando puerta.... Algo falla.... en: 23 Noviembre 2023, 21:14 pm
Lo que denominas como "pistón" es, en realidad, un cilindro neumático de simple efecto. El pistón, propiamente dicho, se refiere al eje longitudinal que experimenta movimientos hacia adelante y hacia atrás, también conocido como "vástago".

Nunca he programado un PLC de SMC, sinceramente, ni siquiera sabía de su existencia, pero tras revisar rápidamente el manual, creo que he ideado una solución para tu necesidad. Utilizo dos temporizadores de retardo, B002 y B003, y simultáneamente empleo un biestable, B001, para retener la señal del pulsador.

Es necesario contar con un pulsador de parada adicional en este circuito. Intenté diseñar un telerruptor para activar y desactivar el automatismo con el mismo pulsador I8, pero requiero de una memoria auxiliar, algo similar a una marca; y según lo que he observado en la documentación, no he encontrado registros de marcas disponibles.

El programa...




8  Foros Generales / Dudas Generales / Re: Automatizando puerta.... Algo falla.... en: 23 Noviembre 2023, 18:51 pm
¿Podrías compartir la tabla de símbolos?

¿Programas el autómata directamente desde la consola o utilizas un entorno específico? Si es lo segundo, ¿podrías compartir una captura de pantalla del código?

En mi experiencia, evito el uso de temporizadores en serie debido a posibles condiciones de carrera o interrupciones en el ciclo de trabajo, especialmente si carecen de memoria.

En principio, no necesitarías retroalimentación, ya que la ejecución del programa es cíclica. A menos que desees mantener un bucle continuo después de completar el primer ciclo. En este caso, deberías utilizar algún tipo de memoria para la realimentación del sistema, o usar un latch  con alguna condición de set y de reset.
9  Foros Generales / Dudas Generales / Re: espectro electromagnetico en: 23 Noviembre 2023, 13:34 pm
En ámbitos como la electrónica o las comunicaciones, resulta más práctico referirse a la frecuencia de una onda por varias razones fundamentales:

    Diseño intrínseco: Los dispositivos electrónicos se configuran para operar dentro de rangos de frecuencia específicos. Las especificaciones de diseño y los cálculos están generalmente más vinculados a la frecuencia que a la longitud de onda.

    Ancho de banda y modulación: La transmisión de información implica cambios en las propiedades de la onda portadora, expresados principalmente en términos de frecuencia. Conceptos esenciales, como el ancho de banda de un canal de comunicación, se definen en función de la frecuencia. Además, las técnicas de modulación, cruciales para la transmisión de datos, manipulan la frecuencia de la onda portadora.

    Transmisión y propagación: La propagación de ondas electromagnéticas, como las de radio o microondas, puede variar según la frecuencia al atravesar la atmósfera. La consideración de estos factores en el diseño de sistemas de comunicación se facilita al trabajar con frecuencias.

    Compatibilidad e interferencias: En entornos electromagnéticos compartidos por múltiples dispositivos o sistemas, la asignación cuidadosa de frecuencias es esencial para prevenir interferencias perjudiciales. Esto permite que diferentes servicios coexistan sin afectarse mutuamente.

En contraste, en contextos como la óptica y la física de las ondas electromagnéticas, especialmente al abordar fenómenos como la difracción o la interferencia, puede resultar más conveniente trabajar con longitudes de onda. Sin embargo, en el contexto de la electrónica y las comunicaciones, la frecuencia emerge como el parámetro más relevante y práctico.
10  Programación / Programación General / Re: Generar lista evitando ", " al inicio sin repetir code. en: 23 Noviembre 2023, 13:17 pm
Si he comprendido correctamente, estás indagando sobre la manera más eficiente de ejecutar código. En ese caso, si prefieres evitar el uso de una estructura if-else, la opción más eficiente, especialmente para operaciones simples, sería emplear un operador ternario.

No son, como mencionaste, "casi lo mismo". Permíteme demostrarte la diferencia.

He escrito los siguientes códigos de pruebas:

# Código 1

Código:
void hal_entry(void) {

volatile uint32_t seed, randNumm;
volatile bool isGreater;
SysTick_Config(SystemCoreClock / 960);

while (true) {
seed = (_ulTickCount * 1664525 + 1013904223) % 4294967296;
randNumm = seed % (10 - 2 + 1) + 2;

if (randNumm >= 5) {
isGreater = true;
} else {
isGreater = false;
}
}
}

Este código realiza las siguientes operaciones:

    - Inicializa el contador de pulsos de un microcontrolador basado en ARM Cortex-M.
    - Genera un número aleatorio acotado entre 2 y 10.
    - Comprueba si el número obtenido es mayor o igual a 5 y actualiza una flag en consecuencia.

Al examinar el desensamblado de la instrucción condicional, se revela lo siguiente:

Código:
115       if (randNumm >= 5) {
00001084:   ldr     r3, [sp, #12]     ; Load the value of randNumm from the stack into register r3
00001086:   cmp     r3, #4            ; Compare the value in r3 (randNumm) with 4
116       isGreater = true;    ; Set isGreater to true if the condition is met
00001088:   ite     hi                ; Conditional (IT) block, executing based on "If Higher" logic
0000108a:   strbhi.w        r4, [sp, #7]  ; Store 1 in memory at [sp + #7] if the condition is true (hi)
118       isGreater = false;   ; Set isGreater to false if the condition is not met
0000108e:   strbls.w        r5, [sp, #7]  ; Store 0 in memory at [sp + #7] if the condition is false (ls)
00001092:   b.n     0x106a <hal_entry()+58> ; Branch to the specified address (conditional, not taken if the condition is false)

    - Se extrae el valor de randNumm del stack y se almacena en el registro r3.
    - Se realiza una comparación para verificar si el valor en r3 es mayor que 4:
        - Si la afirmación es verdadera, se guarda el valor de r4 (1) en [sp +#7].
        - En caso contrario, se guarda el valor de r5 (0) en [sp +#7].
    - Se realiza un salto a la dirección de memoria 0x106a si el resultado de la comparación es verdadero.


# Código 2

Código:
void hal_entry(void) {

volatile uint32_t seed, randNumm;
volatile bool isGreater;
SysTick_Config(SystemCoreClock / 960);

while (true) {
seed = (_ulTickCount * 1664525 + 1013904223) % 4294967296;
randNumm = seed % (10 - 2 + 1) + 2;
isGreater = (randNumm >= 5) ? true : false;
}
}

Este ejecuta la misma lógica que el código 1, pero usando un operador ternario.

Si nos vamos a su código ensamblador, vemos que:

Código:
113       isGreater = (randNumm >= 5) ? true : false;
00001080:   ldr     r3, [sp, #12]     ; Load the value of randNumm from the stack into register r3
00001082:   cmp     r3, #4            ; Compare the value in r3 (randNumm) with 4
00001084:   ite     ls                 ; Conditional IT block, executing based on "If Lower or Same" logic
00001086:   movls   r3, #0            ; If less than or equal to 4 (ls condition), set r3 to 0
00001088:   movhi   r3, #1            ; If greater than 4 (hi condition), set r3 to 1
0000108a:   strb.w  r3, [sp, #7]      ; Store the result in the memory at [sp + #7]

    - Se recupera el valor de randNumm desde el stack y se almacena en el registro r3.
    - Se compara el valor de r3 con 4:
        - Si es menor o igual, se asigna 0 a r3.
        - Si es mayor, se asigna 1 a r3.
    - Se guarda el valor actualizado de r3 en la posición de memoria [sp, #7].
 
En términos de eficiencia, el segundo bloque de código sobresale por varias razones:

    - Simplicidad: En el segundo bloque, el valor de isGreater se asigna directamente, simplificando la lógica del código.

    - Menor número de saltos: Mientras que el primer bloque utiliza dos instrucciones de salto condicional (ite, strbhi.w, y strbls.w), el segundo bloque se limita a una sola instrucción (it y strb.w), reduciendo la complejidad y el consumo de recursos.

    - Eliminación de redundancia: En el segundo bloque, se utiliza el mismo registro r3 de manera consistente, a diferencia del primer bloque que emplea los registros r3, r4 y r5. Esto elimina la necesidad de instrucciones adicionales para cambiar el valor de isGreater después de la comparación, como se evidencia en el primer bloque.

No obstante, es importante señalar que las optimizaciones del compilador pueden atenuar las diferencias prácticas entre ambas implementaciones.
De modo que declaré las variables como volátiles para evitar estas optimizaciones, permitiendo una evaluación más precisa del rendimiento.
Páginas: [1] 2
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines