No concigo resolver el código de error

Iniciado por Meta, 20 Abril 2021, 18:35 PM

0 Miembros y 1 Visitante están viendo este tema.

Meta

Hola:

Al ejecutar el programa me sale este error.
System.OverflowException: 'Valor demasiado grande o demasiado pequeño para Int32.'

Con cretamente aquí.
int Variar_este_valor = Convert.ToInt32(Recibidos);

Código del programa.
Código (csharp,101) [Seleccionar]
using System;
using System.IO.Ports; // No olvidar.
using System.IO;

namespace Porcentaje_Barra_Puerto_Serie_Consola_03
{
    class Program
    {
        public static string recibidos = "";
        public static double Resultado_Porcentaje = 0;
        public static double Resultado_Voltios = 0;
        public static double Mitad_barra = 0;
        public static int Contador = 1;


        static void Main(string[] args)
        {
            #region Configuración ventana.
            // Título de la ventana.
            Console.Title = "Puerto serie C# - 2019";

            // Tamaño de la ventana, x, y.
            Console.SetWindowSize(100, 35);

            // Color de fondo.
            Console.BackgroundColor = ConsoleColor.DarkBlue;

            // Color de las letras.
            Console.ForegroundColor = ConsoleColor.Yellow;

            // Limpiar pantalla y dejarlo todo en color de fondo.
            Console.Clear();

            // Visible el cursor.
            Console.CursorVisible = true;
            #endregion
            string COM = "";

            // Crear un nuevo objeto SerialPort con la configuración predeterminada.
            SerialPort serialPort1 = 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();

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

            // Crear un nuevo objeto SerialPort con la configuración predeterminada.

            // Configuración del puerto serie.
            serialPort1.BaudRate = 9600;            // Baudios o velocidad. 115200
            serialPort1.Parity = Parity.None;       // Sin paridad.
            serialPort1.DataBits = 8;               // 8 Bits de datos.
            serialPort1.StopBits = StopBits.Two;    // Bits de parada.
            serialPort1.Handshake = Handshake.None; // Control de flujo.
            serialPort1.ReadBufferSize = 4096;      // Tamaño del Búffer de lectura en Bytes.
            serialPort1.WriteBufferSize = 2048;     // Tamaño del Búffer de escritura en Bytes.
            serialPort1.ReadTimeout = 500;          // Establecer lectura de espera.
            serialPort1.WriteTimeout = 500;         // Establecer escritura de espera.
            serialPort1.DtrEnable = false;
            serialPort1.RtsEnable = false;


            try
            {
                serialPort1.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 " + serialPort1.PortName + @" no existe
            o no lo encuentra.");
            }

            serialPort1.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);

            Console.Read();
            serialPort1.Close(); // Cerrar puerto.
        }

        private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)

        {

            try
            {
                SerialPort sp = (SerialPort)sender;
                recibidos = sp.ReadExisting();
                //Console.Clear();

                recibidos = recibidos.Replace("\n\r", "");

                int Variar_este_valor = Convert.ToInt32(recibidos);

                Resultado_Porcentaje = Variar_este_valor * (100.00 / 1023.00);
                Resultado_Voltios = Variar_este_valor * (5.00 / 1023.00);


                Console.SetCursorPosition(0, 1);
                Console.Write("Datos recibidos: ");
                Console.SetCursorPosition(17, 1);
                Console.Write("    ");
                Console.SetCursorPosition(17, 1);
                Console.Write(recibidos);

                // Dibujamos la barra del portentaje.
                Console.SetCursorPosition(0, 3);
                Console.Write("0 %                     50 %                   100 %");
                Console.SetCursorPosition(0, 4);
                Console.Write("┌────────────────────────┬───────────────────────┐");
                Console.Write("                                                  ");
                Console.ForegroundColor = ConsoleColor.Yellow;

                // Se dibide por dos la barra del porcentaje para que quepa decuadamente en la pantalla.
                Mitad_barra = Resultado_Porcentaje / 2;

                if (Mitad_barra > 50)
                {
                    Mitad_barra = 50;
                }

                // Console.SetCursorPosition(0, 5);
                ClearCurrentConsoleLine();
                // Barra de progreso.
                for (int i = 1; i <= Mitad_barra; i++)
                {
                    Console.Write("█"); // Muestra ASCII 219 Dec y DB en Hex.
                                        // Console.Write((char)219);
                                        // Console.Write(Encoding.ASCII.GetBytes((char)219));
                }

                // Si sobre pasa 100, muestra # al final de la barra del porcentaje de color rojo.
                if (Resultado_Porcentaje >= 100)
                {
                    Console.SetCursorPosition(50, 5);
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.Write("#");
                }

                Console.ForegroundColor = ConsoleColor.Gray; // Vuelve al color gris.

                // Línea 7.
                Console.SetCursorPosition(0, 7);
                Console.Write("Porcentaje: ");
                Console.SetCursorPosition(12, 7);
                Console.Write("            ");
                Console.SetCursorPosition(12, 7);
                Console.Write(Resultado_Porcentaje.ToString("N0") + " %.");

                // Línea 8.
                Console.SetCursorPosition(0, 8);
                Console.Write("Voltios: ");
                Console.SetCursorPosition(12, 8);
                Console.Write("            ");
                Console.SetCursorPosition(12, 8);
                Console.Write(Resultado_Voltios.ToString("N2") + " V.");

            }

            catch (FormatException)
            {
                // Console.WriteLine("La cadena de entrada no tiene el formato correcto.");
                Console.SetCursorPosition(0, 10);
                Console.Write("                 ");
                Console.SetCursorPosition(0, 10);
                Console.Write("Contador: " + Contador++);
                // return;
            }

        }

        public static void ClearCurrentConsoleLine()
        {
            int currentLineCursor = Console.CursorTop;
            Console.SetCursorPosition(0, Console.CursorTop);
            Console.Write(new string(' ', Console.WindowWidth));
            Console.SetCursorPosition(0, currentLineCursor);
        }
    }
}


Rara vez el programa se ejecuta pero tiene otro comportamiento parpadeante en la pantalla pero muestra los datos un poco incómodo. Voy por partes.

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

Serapis

Creo que está bien claro.

Si el error que marca es 'overflow', implica que el string que quieres convertir a entero de 4 bytes, tiene más bytes que los caben en un int32... No hay solucion, más que quitar bytes hasta que no marque overflow, o directamente tomar solo 4 de ellos de la posición que interese, o bien utilizar un int64 (tendrás el mismo problemas si el string supera los 8 bytes).

Antes de preguntar, por que no haces un 'trace' del error?. Con un simple messagebox.show(recibidos) podrías llegar a ver el contenido de dicho string (si tiene caracteres no imprimibles, presenta el valor de los bytes. Es más ejecutando paso a paso, párate en el string 'recibidos', posiciona el cursor y espera un instante, el 'intellisense', mostrará el valor del string.

Para los errores léxicos o sintácticos, tienes que recurrir al lenguaje. Esto es pulsa F2, y localizas el objeto y método que marca el error (en este caso int 32, o mejor Convert), en la descricpión del mismo aparecerán los posibles errores que pueden darse y la causa del problema. En cualquier caso todos esos errores, debiera uno resolverlos con el IDE o la ayuda en linea (si no está instalada localmente en el equipo), de la pagina de Mocosoft... O bien con libros que explican bien.

Las preguntas que cabe hacer son las semánticas... esto es, cuando quieres hacer una cosa y 'te sale' otra o no te sale nada... o uno no tiene idea de por dondede tirar, o uno tiene demasiadas ideas por donde tirar, pero no tiene claro cual sería preferible. Este tipo de problemas no suelen resolverse con consultas a la ayuda (aunque algún código de ejemplo puede que sí ayude, si se llega a dar con el adecuado que coincida exactamente con tu caso) o al manual del programador...

Meta

Lo cambié por
Código (csharp) [Seleccionar]
long Variar_este_valor = Convert.ToInt64(recibidos);

Resulta que si ejecuto el programa lo hace. Si le doy a cerrar y luego ejecutar vuelve aparecer el mismo error.

Tengo que quitar el cable, colocarlo al P y luego ejecutar el programa y se ejecuta. Así no sale el error a pesar que puse también en modo long.

Una vez funcionando. Lo que no entiendo como que parpadea mucho la pantalla, es decir, si me muestra un valor que le llega por cada 100 ms desde el puerto serie, por ejemplo, el valor 454, tiene que verse este valor a:


Luego se pasa a este valor de abajo.


Se va alternando así cada rato. Tiene que estar fijo la pantalla, parece que hace refrezco de imagen cada cierto tiempo. Solo tiene que cambiar de imagen fluido si desde el puerto serie cambia de valor tanto los números como la barra de progreso.

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

Serapis

#3
Esto parece un problema de sincronización.
Hay dos tipos de sincronización. La que refiere al período de refresco, esto es cada vez que el puerto serie manda datos y a la interpretación de datos.
Si sucede que el puerto manda un dato que tu esperas (pongamos 450) y luego lo alterna con el envío de otro dato distinto (pongamos una señal de 'listo', con valor 0) y tu derivas ambos valores tratados como el mismo tienes ese resultado.

Sucede algo parecido cuando tu solicitas datos al puerto serie en vez de dejar que sea el puerto serie quien te los envíe. supongamos que el puerto serie envía una señal cada 200 ms. y tu pones un evento de actualización cada 100 ms. pués una de dos veces obtendrás el valor real y en la otra podrías obtener un valor temporal, si sucede que el dato no está listo, pero el dispositivo sigue funcionando con otros datos.

Es dífícil de determinar el problema exacto, pues requiere documentación del dispositivo y realizar pruebas específicas para determinar que tu programa cumple lo que la documentación señala y que el propio dispositivo también cumple  lo que la propia documentación señala (a veces puede haber un bug en la documentación o se hicieron cambios de última hora que no se refleja en la documentación).

Una de las cosas que puedes hacer es bajar la velocidad de refresco (por ejemplo de 100 a 200ms), y ver si se soluciona ese parpadeo, o por lo menos mejora.
Otra es interponer una propiedad que verifique diferencias entre el valor actual (recibido y el previo) y descartar el cambio si está por encima de cierto umbral... digamos que el dispositivo tiene flucturaciones que no están estabilizadas...

El siguiente pseudocódifgo trata de paliar ese efecto, naturalmente es un punto de partida, tendrás que afinarlo hasta que veas que resulta satisfactorio.
La idea es la siguiente. Partamos del hecho de que un voltaje es x (2'2 por ejemplo) y que la transicion entre ese valor y 0 precisare de 1sg. si resulta que el refresco es cada 100ms. podríamos establecer que la tasa de cambio por refrsco no debería ser mayor (nota que solo es una aproximación teórica) a tc = 2'2 / (1000/10). Es decir en cada refresco el valor no debería cambiar más de 0'22v. respecto del actual...


flotante f_Valor, f_Previo, umbral

Escribe propiedad Voltaje(flotante valor)
   Si (valor <> p_valor)
       flotante tasaCambio = (f_valor/ (1000ms. / intervalorefresco))

       umbral = (valorAbsoluto(f_valor - valor)
        si (umbral <= tasaCambio)         // aceptar el cambio
            f_previo = 0
           f_Valor = valor
           llamada a redibujar
        sino
            // descomentar esta parte si lo previo funciona más o menos bien, pero tiene algunos 'incidentes' desajustados.
            //si (f_previo + umbral) >= tasacambio)   // segundo intento.
            //    f_previo = 0
           //     f_Valor = valor
           //     llamada a redibujar
           // sino
           //     p_previo += umbral
            //fin si       
       fin si
   Si no
       // no cambia nada, para qué redibujar?      
   fin si
fin propiedad

Y eso debería como mímino limitar los picos de transicion entre estados...

Nota que 'tasaCambio' es un valor de umbral que dentro del mismo acepta el cambio y alejado del mismo rechaza el cambio... en el siguiente evento, si la tendencia continúa, señala que es indicador de que el cambio recibido antes puede ser real... entonces se puede añadir una segunda oportunidad de cambio... ojo, te la comento, de entrada, si no funciona bien del todo, entonces descomenta ese código y habría que ponderarlo...

Es más que probable que deba ser afinado, tasaCambio podría ser ponderdado por un factor constante... (mayor o menos que 1) por ejemplo:

   ...
   flotante tasaCambio = ...
   tasaCambio  = (tasaCambio * 1'3)  // <---- conviene ponerlo como constante

Igualmente el intervalo de refresco y el plazo tomado (son válidos si el sistema es fijo, no es válido si no hay eventos a intervalos fijos, en ese caso debe tomarse una media de eventos por minuto (por ejemplo).
Que funcione del todo bien, va a depender de cuanto se aproxime al funcionamiento del dispositivo.

Meta

Buenas:

El dispositivo es Arduino UNO r3 y este es su código.
Código (cpp) [Seleccionar]
// Include el código de la librería.
#include <LiquidCrystal.h>

unsigned int valorPot1 = 0;

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

void setup()
{

  Serial.begin(9600); // 115200
  // La pantalla es de 16 caracteres y 2 filas.
  lcd.begin(16, 2);

  // Indicar luz de fondo como salida.
  // pinMode(LuzFondo, OUTPUT);

  pinMode(A1, INPUT);
}

void loop()
{
  valorPot1 = analogRead(A1);
  lcd.setCursor(0, 0);
  lcd.print(F("Pot. A1: "));
  lcd.setCursor(9, 0);
  lcd.print(F("    "));
  lcd.setCursor(9, 0);
  lcd.print(valorPot1);
  Serial.print(valorPot1);
  delay(100); // 1000 mili segundos o 1 segundo.
}


Me da que el código C# en vez de actualizar solo números y por supuesto, la barra de progreso. Refrezca todo la pantalla en completo, por eso hace cosas raras.

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

Serapis

Relee, he editado el mensaje mientras por lo visto respondías.

Sí, un problema de la consola es que el dibujado es a nivel de toda la pantalla. Esa es una de las razones por las que operar con forms es más eficiente, solo se actualiza la parte del gráfico que cambia.
Por otro lado la pantalla tiene dos barridos vertical y horizontal uno es miles de veces por segundo el otro es entre decenas y pocas centenas de veces por segundo (típicamente entre 24 y 120 por sg.).  Pués bien, si eres capaz de redibujar todo el gráfico en ese tiempo, no aparece ningún parpadeo.

Otro modo en que se palia ese efecto, es cuando el sistema dispone de un backbuffer (una memoria adicional donde vas dibujando, tarde lo que tarde, y cuando está listo se dibuja de un plumazo entero)... el peor caso es cuando se va dibujando en tiempo real, pixel a pixel, que es muy lento...
Lo cierto es que incluso aquellos antiguos monitores CRT en BN o 256 colores solían tener entre 2 y 8 páginas de vídeo, que uno podía dibujar antes de presentarla, no entiendo porqué Mocosoft, no ha provisto al menos un backbuffer adicional para la consola que luego con un simple Console.Flush o Console.Draw realizara el intercambio entre ambas páginas, incluso con un Raster Op. para dibujar (incorporar al dibujo) solo los cambios (por ejemplo).

Serapis

Cuando sucede que las fluctuaciones de un sistema son elevadas y esto es normal (es decir la causa no es debida a ruido generado en alguna etapa), entonces es más adecuado usar un control tipo búmetro, con escalas verticales (preferible a las horizontales), incluso coloreando distintamente cada bloque o celda en la columna...

Un ejemplo de este caso, son las notas de la música, donde en un instante dado un valor vale 400hz. y al instante siguiente 4000hz.
En casos así, es adecuado 'recordar' el pico, durante un tiempo mayor que el que dura el intervalo del refresco...
Una imagen de ejemplo (aunque aquí se presentan varias columnas):


Dado un valor se cuantiza dentro del bloque supuesto en una serie de divisiones.
En vez de borrar y redibujar el gráfico entero, es preferible dibujar solo lo que cambia.
Por ejemplo imagina que hay una sola columna (es extensible a más columnas como muestra la imagen, pero para explicaciones es más fácil atenerse a solo una).

Para darle cierta concrección al código, considera estos datos: el rango de valores 0-255, 8 bloques en la columna, el valor actual 203 y el previo 85

entero bloque, bloqueprevio, pico, veces, duracion = 6
// Unidades por bloque (se calcula una vez solo cuando cambien en numero de bloques por columna o el rango de valores:
flotante UnidadesXBloque = ((RangoMax - RangoMin) / NumBloques)

funcion Actualizar(entero valor)
// primero cuantizamos en que bloque cae el valor:
bloque = int(Valor / UnidadesXBloque )

// Solo hay que redibujar si el valor ha cambiado...
Si (bloque <> bloquePrevio)
    si (bloqueprevio < bloque)  // solo hay que dibujar los bloques de más...
         bucle para b desde bloqueprevio+1 hasta bloque
             activarbloque(b)   // enciende el bloque 'b' de la columna
         siguiente
    sino       // solo hay que apagar los bloques que ahora 'sobran'.
        si (bloqueprevio  = pico) bloqueprevio -=1
        bucle para b desde bloque+1 hasta bloqueprevio
            desactivarBloque(b)   // apaga el bloque 'b' de la columna
        siguiente
    fin si

    bloqueprevio = bloque // recordamos este valor para la siguiente ocasion.
fin si

// aqui se recuerda x tiempo (6 ciclos) el pico máximo ocurrido en ese intervalo.
veces +=1
si (veces > duracion)   // caduco el tiempo del pico.
    veces = 0               // contador a 0.
    si (pico > bloque)  desactivarBloque(b)   // se borra
    pico = bloque         //  y recuerda como pico, el valor actual.
sino
    si (bloque > pico)   // comprobar si el nuevo valor es superior al pico previo
        pico = bloque    // no hay que borrar el pico previo,
                               //    porque el valor actual al ser mayor ya lo ha redibujado.
        veces = 0        // un nuevo pico exige un reinicio de cuenta.
    fin si
fin si

Meta

El redibujado de una barra lo que se suele hacer al menos en las LCD para microcontroladores es que si funciona hasta aquí que son 10 veces █. "Alt + 219" en ASCII.

██████████

Si luego quiero poner 5 █, no se borra, tienes que borrarlo todo con 10 espacios y redibujar luego hasta cinco veces █.

En cada parte la pantalla de la consola, si solo se actualiza números, letras o dibujos como estos █, solo se tiene que modificar en esas áreas ya indicando las coordenadas de la pantalla a redeibujar o modificar valores.

Parece ser que se refrezca la pantalla completa.

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

Serapis

Citarhasta aquí que son 10 veces █. "Alt + 219" en ASCII.
██████████
Si luego quiero poner 5 █, no se borra, tienes que borrarlo todo con 10 espacios y redibujar luego hasta cinco veces █.
Creo que tendrías el mismo resultado si escribes cinco veces █ y a continuación 5 espacios.
De hecho si puedes posicionar el cursor para dibujar solo esos 5 espacios finales, estarías haciendo lo que te decía más arriba... una funcion: Desactivar(fila, columna, xCantidad)

Meta

Cita de: Serapis en 24 Abril 2021, 19:31 PM
Creo que tendrías el mismo resultado si escribes cinco veces █ y a continuación 5 espacios.
De hecho si puedes posicionar el cursor para dibujar solo esos 5 espacios finales, estarías haciendo lo que te decía más arriba... una funcion: Desactivar(fila, columna, xCantidad)


Mejor tu método para la barra.

El problema que es en toda la pantalla.
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/