Mostrar voltaje sin usar ADC

#1
hola necesito ayuda con un problema que no se como resolver , tengo un programa que muestra la tensión , un voltámetro la muestra es por el adc pero cuando pongo una carga se mueve mucho la muestra , como puedo hacer para mostrarla en el lcd que quede fija , por mas que haya pequeñas oscilaciones .

Código:
#include <16f886.h>
#device ADC=10
#use     delay(internal = 8MHz)                           
#define  LCD_DATA_PORT getenv("SFR:PORTC")
#include <flex_lcd.c>

#define LCD_RW_PIN    PIN_C3
//#include <internal_eeprom.c>


int1 flagHayDatos=0;
float const ticks_us = 4.0;          // microsegundos por Tick del Timer 1 @ 8 MHz. (Osc. Interno)
//float const ticks_us = 8.0;          // microsegundos por Tick del Timer 1 @ 8 MHz. (Osc. Cristal)
long int  var2=0;
int8 flancos;
int8 flag_flanco;
int16 periodo1,periodo2,periodo3;
int16 tiempo_alto,tiempo_bajo,tiempo_total;
float us_alto,us_bajo,us_total,valor2,amper, duty;
   int porcentaje, porcentaje2;
   int frecuencia;
  
int16 valor_adc;
   float voltaje;
int8   ciclo_activo=1;
void voltaje(void);
  int16 cont3;   
  
  
#INT_EXT
void sdi_externa_RB0 (void)
{
   flancos++;                          // Incrementar la variable "flancos"
  
   if(!flag_flanco)                    // Si el flanco del pulso es bajo...
   {
      if(flancos == 1)                 // Si el conteo de flancos es 1...
      {
         set_timer1(0);                // Limpiar el Timer 1
         periodo1 = get_timer1();      // "periodo1" tendrá el tiempo del pulso en alto.
      }
      if(flancos == 3)                 // Si el conteo de flancos es 3...
         periodo3 = get_timer1();      // "periodo3" tendrá el tiempo del pulso en alto.
        
         EXT_INT_EDGE(H_TO_L);         // Establecer la interrupción por flanco de bajada.
         flag_flanco = 1;              // Indicar que el próximo flanco será de bajada.
   }
   else                                // Caso contrario. (Pulso en estado alto)...
   {
      periodo2 = get_timer1();         // "periodo2" tendrá el valor del pulso en bajo.
      EXT_INT_EDGE(L_TO_H);            // Establecer la interrupción por flanco de subida.
      flag_flanco = 0;                 // Indicar que el próximo flanco será de subida.
       if(flagHayDatos==0){       // Si los datos anteriores han sido procesados ...
      flagHayDatos=1;          // Indico que ya hay nuevos datos de flancos para calcular
    }
   }

   if(flancos > 2)flancos = 0;         // Si la variable "flancos" llega a 3, ponerla a 0.
}



void establecer_ciclo (int8 ciclo)
{
  
   set_pwm1_duty(ciclo);   // Establecer el ciclo activo
   lcd_gotoxy(10,3);
   // Obtener el porcentaje del ciclo activo.
   porcentaje2 = (ciclo / 24.5) *10;
   // Mostrar el porcentaje del ciclo activo para la carga.            
   printf(lcd_putc,"PWM:%02u%%",porcentaje2,);
        voltaje();
 
    
}
void voltaje (void)
{
int16 valor_adc;
float voltaje;
 set_adc_channel(0); // Establecer la lectura del canal ADC 10
   delay_us(62);
   valor_adc = read_adc(); // Tomar la lectura del voltaje.
   voltaje = ((valor_adc * 18.0) / 1023);
 
  lcd_gotoxy(11,1);
  printf(lcd_putc,"V=%4.1fV ",voltaje);
    
delay_ms(30);
} 

void pulsadores()
{   
   if (input(PIN_A4)==0)
   {
    while(!input(pin_a4)){
      ciclo_activo ++;  // Incrementar el ciclo activo.
      if (ciclo_activo > 249) ciclo_activo = 249;   // No permitir que el ciclo activo suba de 249
      delay_ms(10);
      establecer_ciclo(ciclo_activo);
      
   }
   }
   if (input(PIN_A5)==0)
   {
    while(!input(pin_a5)){
      ciclo_activo --;  // Disminuir el ciclo activo.
      delay_ms(10);
       if (ciclo_activo <= 1) ciclo_activo = 2;  // No permitir que el ciclo activo baje de 1
      establecer_ciclo(ciclo_activo);
      
   }
  
}
}
void energia()   
{
// set_adc_channel(11);
 //  delay_us(50);
 //  ene = read_adc();
 // if(ene<200)
if(input(pin_B4)==0){
cont3++;
delay_ms(1);
if (cont3 >10) {
write_eeprom(03,ciclo_activo );
delay_ms(50);
cont3 = 0;             
               }
                  }
}

void main()
{
  
 ciclo_activo =read_eeprom(03);                   
    establecer_ciclo(ciclo_activo);   
    
 setup_ccp1(CCP_PWM);
   setup_timer_2(T2_DIV_BY_4,249,1);   // 1000 Hz. @ 4 MHz.
   set_pwm1_duty(1);                   // Ciclo activo al mínimo
  
   setup_adc_ports(sAN1|san3|san11);
   setup_adc(ADC_CLOCK_INTERNAL);
  
   setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);
   enable_interrupts(int_ext);
   ext_int_edge(0,L_TO_H);
   enable_interrupts(global);
 
   #ZERO_RAM   // Limpiar RAM. (Variables en 0)
   lcd_init();
    establecer_ciclo(ciclo_activo);
    
   while (true)
   {
 
    if(flagHayDatos==1){
  
      if((periodo3 > periodo2) && (periodo2 > periodo1))
      {
         tiempo_alto = periodo2 - periodo1;                 // Obtener el periodo del pulso en estado alto.
         tiempo_bajo = periodo3 - periodo2;                 // Obtener el periodo del pulso en estado bajo.
         tiempo_total = tiempo_alto + tiempo_bajo;          // Obtener el periodo de la frecuencia.
         us_alto = ticks_us * tiempo_alto;                  // Obtener el periodo en microsegundos del pulso en alto.
         us_bajo = ticks_us * tiempo_bajo;                  // Obtener el periodo en microsegundos del pulso en bajo.
         us_total = ticks_us * tiempo_total;                // Obtener los microsegundos en total de la frecuencia.
         frecuencia = 1 / (us_total / 1000000);             // Obtener la frecuencia.
         duty = ((float) tiempo_bajo / (float)(tiempo_bajo + tiempo_alto));
          porcentaje = (duty * 100) + 10; // Físicamente el + 0.5 puede no ser necesario. (Ajusta desviación pero consume ROM)       
      }
       flagHayDatos=0;
    }
      lcd_gotoxy(1,1);
      printf(lcd_putc,"Hz:%03u ",frecuencia);
       if(porcentaje < 3)porcentaje = 0;
      if(porcentaje > 95)porcentaje = 99;
    
      lcd_gotoxy(1,2);
      printf(lcd_putc,"Duty:%02u%% ",porcentaje );
    
      
       flagHayDatos=0;
      
      delay_ms(100); // Retardo para disminuir parpadeos en la pantalla. (No afecta interrupción externa.)
      if(flagHayDatos==0){
      frecuencia = 0;
      porcentaje=0;
  
    
      }
      
    pulsadores();
 
   voltaje();
energia();
 
 
  set_adc_channel(1);
    delay_us(30);
   amper=0;
  for(var2=0;var2<50;var2++)
  {
    amper=amper+ read_adc();
    delay_us(62); 
  }

  valor2 = amper / 50;
  valor2 = valor2 * 20 / 1023;

  lcd_gotoxy(11,2);
  printf(lcd_putc,"A=%4.2f",valor2);
  delay_ms(60);
 
   }
 
   }
 
#2
Hola buen dia, el problema es que la fuente tiene poco filtro a la salida, o el capacitor esta en mal estado, podes agregar en la entrada del adc una red r c como 10.000 ohm en serie, y un capacitor de .33 micrifaradios en paralelo a la entrada del adc
 
#3
Si cambio la función de voltaje, la saco y en la función de ciclo activo donde muestro un porcentaje de la carga, saco ese porcentaje y muestro el voltaje de 1 a 18 volt sería mejor, no importaría ahi las oscilaciones porque no se verían en pantalla, ahora como calculo eso ahi estoy trabado!
 
#5
Consulta, el problema es un planteo para solucionar con programación, o queres un indicador estable?
(de que fuente se trata y que tipo de adc usas)? manda foto
 
#7
La fuente funciona muy bien solo oscila la muestra del voltaje en el lcd! Yo quería hacerla fija que con programación se muestre sin oscilaciones, con retardos no funciona te pone lento todo el programa
 
#8
De cuánto hablamos en porcentaje la oscilación que mencionas?
Puede haber un problema de ruido eléctrico en la entrada al ADC. Pero cómo no hay circuito, difícil opinar.
Quizás añadiendo un condensador en la entrada se soluciona el problema.
 
#9
La fuente funciona muy bien solo oscila la muestra del voltaje en el lcd! Yo quería hacerla fija que con programación se muestre sin oscilaciones, con retardos no funciona te pone lento todo el programa
El problema es que usas retardos, que es una cosa que debes dejar de usar a los pocos dias que comenzaste a aprender programacion. Aprende a realizar temporizadores por interrupciones. Los retardos son como usar muletas para aprender a caminar. Si tienes bien las piernas debes arrojar las muletas lo antes posible.
 
#10
La oscilación real de la fuente medida con tester es nada 0.100 pero en la muestra del pic en de 0.500 y se mueve constantemente, ya se puso capacitores se probó de todo, por eso hay que hacerlo por software, voy a sacar el porcentaje y ver si puedo hacer una muestra ahi promediando el ciclo activo y mostrando como si fuera voltaje
set_pwm1_duty(ciclo); // Establecer el ciclo activo
lcd_gotoxy(10,3);

porcentaje2 = (ciclo / 24.5) *10;
El cambio lo haría acá porcentaje 2=(ciclo *24) / 1023;
Esto creo que mostraría algo y sacaría el porcentaje de la muestra lcd

printf(lcd_putc,"PWM:%02u%%",porcentaje2,);
voltaje();
 
Última edición:
#14
Algunas veces se hace lo que dice chclau:
Realiza un refresco de la lectura que se envía al LCD solo si la diferencia con la lectura anterior es mayor a un umbral determinado, o cada tantos segundos.
Se hace así:
1. Se declara una variable auxiliar del mismo tipo de la variable principal en la que guardara la lectura del ADC.
2. Se comprueba que la diferencia absoluta entre la variable principal y la variable auxiliar sea mayor o igual a la máxima tolerancia permitida.
3. Solo si se cumple lo anterior, se muestra el dato de la variable principal en la LCD. Ademas se guarda el dato de la variable principal en la la variable auxiliar, esto se hace antes de salir de la comprobación.

Ejemplo con relación a la función voltaje () de su código:
Código:
void voltaje (void)
{
   int16 valor_adc, valor_adc_auxiliar;
   float voltaje;
   set_adc_channel(0);
   valor_adc = read_adc();
   if ((valor_adc - valor_adc_auxiliar) >= 10 || (valor_adc_auxiliar  - valor_adc) >= 10)) //Tolerancia de 10 unidades digitales
   {
      voltaje = ((valor_adc * 18.0) / 1023);
      lcd_gotoxy(11,1);
      printf(lcd_putc,"V=%2.2f V",voltaje);
      valor_adc_auxiliar = valor_adc;
   }
}
 
#15
lo probe y me funciona peor!
esto es lo que decía pero estoy errado lo estoy calculando mal ya que el pwm va hasta 5 volt

void establecer_ciclo (int8 ciclo)
{
float voltaje;
set_pwm1_duty(ciclo); // Establecer el ciclo activo

voltaje = (ciclo * 24.5) /1023;
lcd_gotoxy(11,1);
printf(lcd_putc,"V=%4.1fV ",voltaje);
}

porque va de la mano con esto
void pulsadores()
{
if (input(PIN_A4)==0)
{
while(!input(pin_a4)){
ciclo_activo ++; // Incrementar el ciclo activo.
if (ciclo_activo > 249) ciclo_activo = 249; // No permitir que el ciclo activo suba de 249
delay_ms(10);
establecer_ciclo(ciclo_activo);

}
}
if (input(PIN_A5)==0)
{
while(!input(pin_a5)){
ciclo_activo --; // Disminuir el ciclo activo.
delay_ms(10);
if (ciclo_activo <= 1) ciclo_activo = 2; // No permitir que el ciclo activo baje de 1
establecer_ciclo(ciclo_activo);

}

}
}
 
Última edición:
#16
Lo voy a probar! Como me dicen pero no afecta cuando con los pulsadores cambio el valor del pwm?
No, no afecta cuando se cambia el valor del ciclo útil desde los pulsadores.

Y tardaría en mostrar el dígito que con el pulsador va cambiando de 0,1 a 0,1
No, no tardaría con el código que se propuso. Recordar que la tolerancia máxima propuesta es de 10 unidades digitales entonces según su código será: 18V*10/1023 = 0.18 V pero esa tolerancia la define usted como diseñador. Podría ser tan solo 1 unidad digital lo que equivale a: 18V*1/1023 = 0.02 V.

El código propuesto podría llegar afectar si se utiliza la variable voltaje en otras funciones pero revisando su código original esta variable solo tiene importancia en la visualización por medio de la LCD. El código prepuesto es solo un "truco" para evitar el parpadeo y/u oscilaciones en la presentación en la LCD.
lo probe y me funciona peor!
Entonces intenta con este código:
Código:
void voltaje (void)
{
   int16 valor_adc, valor_adc_auxiliar;
   float voltaje;
   set_adc_channel(0);
   valor_adc = read_adc();
   voltaje = ((valor_adc * 18.0) / 1023); //Se sacó esta línea de las sentencias del IF
   if ( ( (valor_adc - valor_adc_auxiliar) >= 10) || ( (valor_adc_auxiliar  - valor_adc) >= 10) ) //Tolerancia de 10 unidades digitales
   {
      lcd_gotoxy(11,1);
      printf(lcd_putc,"V=%2.2f V",voltaje);
      valor_adc_auxiliar = valor_adc;
   }
}
Esta linea no la tiene el primer código que usted compartió. :unsure::unsure:
voltaje = (ciclo * 24.5) /1023;
 
Última edición:
#17
La línea voltaje = (ciclo * 24.5) /1023; son las pruebas que empecé hacer para ver si puedo mostrar el voltaje por software sin usar el acd, el voltaje que tengo que mostrar es de 1 a 18, por medio del ciclo activo, quiero ver si funciona, sabiendo que se mueve de 0 a 5 volt el pwm lo multiplicó y divido como el adc, pero no creo que sea así!
 

Arriba