Mostrar variables en cero cuando no hay dato

Hola tengo una duda y no se como resolverlas, en freq y duty cuando no hay dato en el pin 7 me tendrían que quedar en 0 pero me quedan mostrando valores aleatorios, como lo soluciono?

#include <LiquidCrystal.h>

LiquidCrystal lcd(8, 9, 10, 11, 12, 13);
#define pulse_ip 7
int ontime, offtime, duty;
float period;
int freq ;

float voltaje_entrada;
float voltaje_final;
float resistencia1 = 100000; //Resistencia de 100K
float resistencia2 = 10000; //Resistencia de 10k

float lectura = 5.00;


void setup()
{
  pinMode(pulse_ip, INPUT);

  lcd.begin(16, 2);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Hz:");
  lcd.setCursor(8, 0);
  lcd.print("Duty:");
  lcd.setCursor(0, 1);
  lcd.print("volt:");
  lcd.setCursor(11, 1);
  lcd.print("A:");

}
void loop()
{

  voltaje_entrada = (analogRead(A0) * 4.95) / 1024;  //Lee el voltaje de entrada
  voltaje_final = voltaje_entrada / (resistencia2 / (resistencia1 + resistencia2));  //Fórmula del divisor resistivo para el voltaje final

  lectura = analogRead(A3) * ( 5 / 1023.0) ;
  lectura = lectura * 1.0;

  ontime = pulseIn(pulse_ip, HIGH);
  offtime = pulseIn(pulse_ip, LOW);
  period = ontime + offtime;
  freq = 1000000.0 / period;
  duty = (ontime / period) * 100;

  lcd.setCursor(5, 1);
  lcd.print(voltaje_final, 1);

  lcd.setCursor(3, 0);
  lcd.print(freq);

  lcd.setCursor(13, 0);
  lcd.print(duty);
  lcd.print('%');

  lcd.setCursor(13, 1);
  lcd.print(lectura, 1);
  delay(500);

}
if (digitalRead(pulse_ip) == HIGH) { // asumiendo que el pulso es LOW - HIGH - LOW
  ... // haga el cálculo aquí
}
while (digitalRead(pulse_ip) == HIGH) ; // esperar hasta el final del pulso si es necesario 

no, no funciona cuando quito los pulsos muestras valores raros,

if (digitalRead(pulse_ip) == LOW) {
  ... // haga el cálculo aquí
}
while (digitalRead(pulse_ip) == HIGH) ;

Asi se ponen en cero , pero deja de restos de numeros en el display, como 2 %% y varios numeros en el Hz es raro no limpia el lcd.

Aclara que significa:

Tal y como lo dices, significa que no conectas nada a ese pin y en tu código declaras:

pinMode(pulse_ip, INPUT);

Eso significa que la señal al aire está flotando y cuando se lee da valores aleatorios, tanto ceros como unos, de hay que en el display se muestren valores aleatorios.

Una posible solución sería usar la resistencia interna de PULL_UP usando:

pinMode(pulse_ip, INPUT_PULLUP);

Con eso el valor de la entrada no fluctuará, sino que siempre será HIGH. Esto implica que debes tener en cuenta eso a la hora de usar pulseIn y leer tanto la frecuencia como el ciclo de trabajo.

Si conecto una resistencia pero cuando detengo los pulsos queda resto del dato en el lcd, el lcd arranca Hz: 0 duty:0 % después de la medición se pone en cero pero queda así, supongamos que midió una frecuencia de 110hz HZ:010 duty: 0%% y no puedo lograr que queden como el comienzo!

La pantalla LCD debe limpiarse correctamente
por ejemplo, si escribe "100 Hz" y luego "1 Hz", verá "1 HzHz"
➜ el "Hz" de la primera escritura permanece en la pantalla

estoy probando otras formas de acerlo .

#include <LiquidCrystal.h>

LiquidCrystal lcd(8, 9, 10, 11, 12, 13);




volatile unsigned long ta=0;
volatile unsigned long tb=0;
volatile unsigned long delta=0;

double frecuencia=0;

void setup(){

pinMode(2,INPUT);
attachInterrupt(digitalPinToInterrupt(0), periodo,FALLING);



}
void loop(){
interrupts();
frecuencia= 1000000/delta;

lcd.setCursor(3,0); 
   lcd.print(frecuencia,1);

}
void periodo(){
noInterrupts();
tb=millis();
delta= tb-ta;
tb=ta;


}

No veo para qué es este código ...
frecuencia nunca cambia

¿qué código ha generado esta pantalla?

El primero con que pregunte.

No estas borrando la pantalla.

Algunas ocasiones la frecuencia que te da la operación suele tener mas de 4 digitos (y el punto). Digamos que tu quieres mostrar un valor de la forma XX.XX, si la frecuencia te da por ejemplo 123.45 ese 5 ocupa una posición mas de lo que esperas y hace cosas feas. Ya que usas delay, y te recomiendo que no lo hagas, añade un lcd.clear() antes de escribir nada en el display.

Luego tienes que controlar que el periodo sea válido de alguna forma. Por ejemplo controla que periodo no sea 0, ya que 1/0 es infinito y en la pantalla deberia aparecer NAN.

Sin saber a ciencia cierta que estas intentando medir, te recomiendo el uso de interrupciones.

1 Like

Voy a probar con interrupciones, pulsin me parece que da problemas, frena el código

No puedes en la rutina de interrupción BLOQUEAR las interrupciones.
Eso se hace en el loop, para crear una ventana de lectura si fuera el caso.
pones

noInterrupts()
// lees o calculas y presentas
// vuelvas a habilitar las interrupciones.
interrupts();

Si me permites empieza de nuevo, usa el tutorial de Nick Gammon Timing an interval using the input capture unit para medir frecuencias o períodos con el pin 7 INPUT CAPTURE, te dará resultados muy buenos usando el TIMER. Ve hasta el Reply#12

// Frequency timer using input capture unit
// Author: Nick Gammon
// Date: 31 August 2013

// Input: Pin D8 

volatile boolean first;
volatile boolean triggered;
volatile unsigned long overflowCount;
volatile unsigned long startTime;
volatile unsigned long finishTime;

// timer overflows (every 65536 counts)
ISR (TIMER1_OVF_vect) 
{
  overflowCount++;
}  // end of TIMER1_OVF_vect

ISR (TIMER1_CAPT_vect)
  {
  // grab counter value before it changes any more
  unsigned int timer1CounterValue;
  timer1CounterValue = ICR1;  // see datasheet, page 117 (accessing 16-bit registers)
  unsigned long overflowCopy = overflowCount;
  
  // if just missed an overflow
  if ((TIFR1 & bit (TOV1)) && timer1CounterValue < 0x7FFF)
    overflowCopy++;
  
  // wait until we noticed last one
  if (triggered)
    return;

  if (first)
    {
    startTime = (overflowCopy << 16) + timer1CounterValue;
    first = false;
    return;  
    }
    
  finishTime = (overflowCopy << 16) + timer1CounterValue;
  triggered = true;
  TIMSK1 = 0;    // no more interrupts for now
  }  // end of TIMER1_CAPT_vect
  
void prepareForInterrupts ()
  {
  noInterrupts ();  // protected code
  first = true;
  triggered = false;  // re-arm for next time
  // reset Timer 1
  TCCR1A = 0;
  TCCR1B = 0;
  
  TIFR1 = bit (ICF1) | bit (TOV1);  // clear flags so we don't get a bogus interrupt
  TCNT1 = 0;          // Counter to zero
  overflowCount = 0;  // Therefore no overflows yet
  
  // Timer 1 - counts clock pulses
  TIMSK1 = bit (TOIE1) | bit (ICIE1);   // interrupt on Timer 1 overflow and input capture
  // start Timer 1, no prescaler
  TCCR1B =  bit (CS10) | bit (ICES1);  // plus Input Capture Edge Select (rising on D8)
  interrupts ();
  }  // end of prepareForInterrupts
  

void setup () 
  {
  Serial.begin(115200);       
  Serial.println("Frequency Counter");
  // set up for interrupts
  prepareForInterrupts ();   
  } // end of setup

void loop () 
  {
  // wait till we have a reading
  if (!triggered)
    return;
 
  // period is elapsed time
  unsigned long elapsedTime = finishTime - startTime;
  // frequency is inverse of period, adjusted for clock period
  float freq = F_CPU / float (elapsedTime);  // each tick is 62.5 ns at 16 MHz
  
  Serial.print ("Took: ");
  Serial.print (elapsedTime);
  Serial.print (" counts. ");

  Serial.print ("Frequency: ");
  Serial.print (freq);
  Serial.println (" Hz. ");

  // so we can read it  
  delay (500);

  prepareForInterrupts ();   
}   // end of loop

Ese es el código, pruebalo con el pin7 y no tendrás problema.

Para visualizar los datos en la pantalla lcd te aconsejo que uses sprintf()
Esta función te permite formatear la salida y evita los problemas cuando se muestra
0.1
10.1
100.1
etc, etc

Con esta línea cuanta los pulsos del pin d8 TIMSK1 = bit (TOIE1) | bit (ICIE1);

Cierto, puse Pin 7 y es 8.

// Input: Pin D8 
1 Like

sigo con el mismo problema, los programas funcionan bien use cual use , siempre queda algun dato fantasma en el lcd, cuando no mido se tienen que poner en 0 se pone en 0, pero deja restos de datos:

Opción 1:

lcd.clear();

pero tenes que volver a imprimir toda la pantalla.

Opción 2:
Formatear el número agregando los espacios necesarios como te expliqué más arriba.
Asigna bien la posición del cursor para que imprima donde corresponde.
Lamentablemente borrar los "restos" es un trabajo manual.

Saludos

1 Like

Perdón, me confundí de tema con otro similar, por eso te dije "como te expliqué más arriba". :man_facepalming:t2:

Sacando ese detalle (que no te había explicado nada), lo demás es como te dije.

Saludos

este codigo que puede ser que este mal que solo muestra 3 w en el lcd, gracias por su tiempo


#define F_CPU 16000000l
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 10, 11, 12, 13);

  unsigned int a,b,c,high,period;
  int freq,duty_cycle;
void setup ( )
{

 
  lcd.begin(16,2);
    lcd.clear();
   
  PORTD = 0xFF;   /* Turn ON Pull-UP resistor */
}
  void loop()
  {

    TCCR1A = 0;
    TCNT1=0;

    TIFR1 = (1<<ICF1);       /* clear ICP flag (Input Capture flag) */

    TCCR1B = 0x41;          /* rising edge, No prescaler */
    while ((TIFR1&(1<<ICF1)) == 0);
    a = ICR1;           /* take value of capture register */
    TIFR1 = (1<<ICF1);       /* clear ICP flag (Input Capture flag) */
    
    TCCR1B = 0x01;           /* falling edge, No prescaler */
    while ((TIFR1&(1<<ICF1)) == 0);
    b = ICR1;           /* take value of capture register */
    TIFR1 = (1<<ICF1);       /* clear ICP flag (Input Capture flag) */
    
    TCCR1B = 0x41;          /* rising edge, No prescaler */
    while ((TIFR1&(1<<ICF1)) == 0);
    c = ICR1;           /* take value of capture register */
    TIFR1 = (1<<ICF1);       /* clear ICP flag (Input Capture flag) */

    TCCR1B = 0;               /* stop the timer */
    
    if(a<b && b<c)          /* check for valid condition, to avoide timer overflow reading */
    {
      high=b-a;
      period=c-a;
      
      freq= F_CPU/period;    /* calculate frequency */
      duty_cycle = ((int) high/ (int) period)*100;  /*calculate duty cycle */
       
    }
     lcd.setCursor(3,0); 
   lcd.print(freq);
    
         lcd.setCursor(3,1);
   lcd.print(duty_cycle); 
  delay(50);
    }