VuMetro con LCD

Una forma muy habitual de representar un valor numérico de forma visible, es mediante barras o bien gráficos de barra, ya que por ejemplo si tenemos un amperimetro y donde pasamos de leer de 1A a 9A de forma numérica como en el ejemplo, no vamos a notar un cambio si no estamos prestando atención directamente el numero en cuestión, pero si en cambio tenemos un gráfico de barra donde el fondo de escala es 10A, entonces pasara de "#" a "#########" donde claramente se puede observar el incremento de la barra proporcional al valor medido.
Este método se utiliza tanto en instrumentos de medición de energía como también en termómetros y en el audio con el nombre de VuMetro (Medición de Unidades de Volumen).
En este caso yo lo he realizado para Audio ya que me pareció una opción muy común pero como mencionaba antes, podríamos hacer un termostato donde nos muestra el valor numérico y en barra (aprovechando los dos renglones del LCD) u otro dispositivo.
En este caso al tratarse de un VuMetro de audio, estamos usando los dos renglones del LCD para poner un canal en cada uno y se esta realizando una actualización del valor de la barra cada un poco mas de 20us que es el tiempo que demora en leer los dos canales ADC (mas algo de tiempo de instrucción).
El programa es relativamente sencillo y no requiere de funciones especiales, en este caso he implementado la función MAP que la pueden encontrar en el siguiente LINK, que se encarga de adaptar el valor del ADC al valor necesario, en este caso de 0 a 16, ya que es la cantidad de caracteres que tenemos en el LCD.
Luego Leemos los ADC (uno por cada canal) y pasamos su valor por la función MAP, lo redimencionamos y lo guardamos en Salida1 y Salida2. 
Una vez echo esto borramos el LCD y procedemos al incremento de caracteres (bloque negro 0xFF) que sera nuestro segmento por cada uno de los 16 niveles. 
Para el incremento se utiliza un lazo de iteracion for, donde contamos de 1 a 16 y vamos incrementando el carácter con la función gotoxy(), donde imprimimos el valor 0xFF con la función lcd_putc().
Luego repetimos este for para el otro canal cambiando el renglon y el ciclo se repite indefinidamente.
Notase que el LCD se borra cada vez que el ciclo se repite, esto es porque el audio cambia constantemente, y los lazos for solo incrementan la cantidad.
Si utilizamos esta visualización para un termómetro por ejemplo, que la variación es lenta, podríamos actualizar el valor con una frecuencia menor, sin la necesidad de borrar el lcd cada +20us.



En el mapa de caracteres del LCD podemos ver que el carácter que utilizamos corresponde a la fila xxxx1111 y la columna 1111, quedando armado así como 11111111 que en hexadecimal es 0xFF, pero si quieren usar otro símbolo pueden armar el valor de esta misma forma.


El circuito no tiene mucha magia, es algo súper básico y ustedes pueden cambiar los pines a gusto, pero hay que tener en cuenta que la tensión de entrada del ADC es de 0 a 5V, pueden utilizar un acondicionador de señal con algún amplificador de entrada para tener 5V de fondo de escala, o bien pueden modificar por firmware la tensión de referencia superior +Vref a la tensión máxima de audio, por ejemplo 1V o 200mV, dependerá del sistema de sonido.

El Programa.

#include<16f883.h>
#device adc=8
#use delay(int=4000000)
#include<LCD.C> 
double map(float valor, float entradaMin, 
           float entradaMax, float salidaMin, 
           float salidaMax){
   return ((((valor-entradaMin)*
             (salidaMax-salidaMin))/
             (entradaMax-entradaMin))+salidaMin);
}  
void main(){
   setup_adc_ports(sAN0|sAN1|VSS_VDD);
   setup_adc(ADC_CLOCK_DIV_2);
   lcd_init();        
   int8 salida1, salida2, i, j, leeAdc1, leeAdc2;
   while(true){
      set_adc_channel(0);
      delay_us(10);
      leeAdc1 = read_adc();
      salida1 = map(leeADC1, 0, 255, 0, 16);
      set_adc_channel(1);
      delay_us(10);
      leeAdc2 = read_adc();
      salida2 = map(leeADC2, 0, 255, 0, 16);      
      lcd_init();
      for(i=1;i<salida1+1;i++){
         lcd_gotoxy(i,1);
         lcd_putc(0xFF);
      }
      for(j=1;j<salida2+1;j++){
         lcd_gotoxy(j,2);
         lcd_putc(0xFF);
      }      
   }
}


17 comentarios:

  1. hola primero déjame felicitarte por tu blog es el mejor que e visto hasta ahora me ha servido mucho :)
    podrías explicar el programa por favor gracias.

    ResponderEliminar
    Respuestas
    1. Hola, como estas?, Gracias!
      El funcionamiento es bastante simple, todo el proceso se realiza en el lazo For, ya que lo que hacemos es leer el ADC luego le aplicamos la función MAP para convertir el valor del ADC leído (entre 0 y 255) a un valor de salida entre 0 y 16.
      En el for lo que realizamos es caracter que rellena la matriz ascii (el cuadrado relleno) este se logra con el valor 0xFF en el LCD. Por ultimo lo que hacemos es incrementar este valor de 1 a 16, ya que el for toma el valor leido por el hace con el máximo de 16 y por ejemplo si es 10, realizara 10 iteraciones, en cada iteracion imprime un cuadrado y con la instrucción gotoxy se desplaza un espacio a la derecha e imprime el siguiente cuadrado, esto hasta que sea 10, luego saldrá, entonces imprime 10 cuadrados en el LCD, el programa vuelve a reiniciar su ciclo preguntando nuevamente por el ADC y reiniciando el proceso de esta forma podemos ver el efecto en el LCD.
      Saludos!!

      Eliminar
    2. perfecto muchas gracias :)

      Eliminar
  2. disculpa pero me maraca error en el pic c #use delay(int=4000000) y en setup_adc_ports(sAN0|sAN1|VSS_VDD);

    ResponderEliminar
    Respuestas
    1. Hola, que microcontrolador estas usando? porque ese error se suele dar en determinados microcontroladores.
      Saludos!

      Eliminar
  3. estoy utilizando el 16f877a

    ResponderEliminar
    Respuestas
    1. Fíjate si podes cambiar la linea por esta:

      #use delay(clock=4000000)
      setup_adc_ports(all_analog);

      Saludos!

      Eliminar
  4. me da error en #device adc=8 gracias

    ResponderEliminar
    Respuestas
    1. se me olvida el micro es el 16f883

      Eliminar
    2. Hola, es muy raro eso, ya que podes usar ese micro con 8bit, pero por las dudas proba #device adc=10, si compila despues proba de pasarlo a 8, si sigue con error "raro", dejalo en 10bit y en la funcion MAP, cambia de map(leeADC1, 0, 255, 0, 16); a map(leeADC1, 0, 1023, 0, 16);
      Saludos!

      Eliminar
  5. Disculpa sebastian pero no me muestra. Nada en la lcd con el pic 16f877 y le entoy ingresando audio y puse las instruccciones q me diste y el programa ya no me marca errores saludos

    ResponderEliminar
    Respuestas
    1. Hola, déjame que lo pruebe con el 877, porque puede que la configuración sea diferente (el ADC, canales, etc...) respecto a la linea 88X.
      Saludos!

      Eliminar
  6. disculpa sebastian como puedo cambiar de puerto de la lcd si esta en el b como lo paso al d grax saludos

    ResponderEliminar
    Respuestas
    1. Hola, entre la configuración del Clock del micro y el include de la librería del LCD, tenes que poner las macros de pines para el LCD, te quedaría algo así.

      #use delay(clock=4000000)
      #define LCD_ENABLE_PIN PIN_C7
      #define LCD_RS_PIN PIN_C4
      #define LCD_RW_PIN PIN_C5
      #define LCD_DATA4 PIN_C0
      #define LCD_DATA5 PIN_C1
      #define LCD_DATA6 PIN_C2
      #define LCD_DATA7 PIN_C3
      #include

      Podes cambiar el orden de los pines como mejor te quede cómodo.
      Saludos.

      Eliminar
    2. perdon puse #use delay(clock=4000000) y era #use delay(int=4000000), ya que es con oscilador interno.
      Saludos

      Eliminar
  7. disculpa sebastian pero me podrias explicar el codigo linea x linea si no es mucha molesta para entenderle mejor

    ResponderEliminar
    Respuestas
    1. Hola, puedo hacer algo mejor! https://www.youtube.com/watch?v=V_uz_F1iako

      Saludos!

      Eliminar