# Voltímetro con el ADC del PIC



## psm2n3055 (Dic 27, 2010)

Buenas gente.. estaba buscando algo simple de hacer con un pic.. para hacer un voltimeto digital..

por la web encontre este que es muy sencillo y muestra el voltaje.. en un LCD 

http://electronico-etn.blogspot.com/2010/11/voltimetro-con-pic-y-lcd.html

alguien podria darme la formula o que cambio debo realizar en el codigo para en vez de medir de 0 a 5+ volts como lo hace.. que sea de 0 a 6volts????

saludos..


----------



## 1024 (Dic 28, 2010)

Hola, el cambio en código lo tendrías que hacer en esta parte: // p = 5.0 * q / 1024.0;  antes de esto tendrías que realizar un acondicionamiento de la señal de entrada porque en 6V estarías sobrepasando el Vmax de entrada al convertidor AD


----------



## psm2n3055 (Dic 28, 2010)

si si.. de hecho eso es lo que necesito saber como se calcularia :S


----------



## psm2n3055 (Dic 28, 2010)

en realidad.. ncesito armar el circuito para monitorear un pack de baterias AA de 4,8 v per cuando las cargo a full en el tester.. marcan unos 5,6volts.. 

segun lei por ahi.. las pilas AA recargables son de 1,2 v cuando estan cargadas.. llegan a 1,4v y bueno aqui el dilema.. alguna ayuda?


----------



## 1024 (Dic 28, 2010)

Podrías calcular un circuito con amplificadores operacionales para acondicionar la señal de entrada, es una manera simple.


----------



## Americo (Dic 28, 2010)

quieres medir hasta 6 voltios... ??
yo lo haria recontra sencillo, a la entrada del pic realizar un divisor de voltaje por ejemplo a la mitad usando 2 resistencias del mismo valor. ahora bien...en el lcd te dara el valor de 3 voltios cuando midas 6 voltios... esto se soluciona facilmente con modificar el codigo que te dijo el amigo 1024 //p = 5.0 * q / 1024.0;
tambien se lo haria con operacionales.. solo depende del tratamiento que le daras

saludos


----------



## psm2n3055 (Dic 28, 2010)

bien muchas gracias... si he visto que hay alternativas asi.. modificando el codigo.. agregando divisores.. que se yo.. 

el tema es que ese dato 5*q /1024 parte de alguna formula.. y en este caso esta calculado para 5v.. y anda perfecto en proteus.. si yo cambio el 5 por el 6.. mide cualquier cosa.. me podrias decir como es el tema de agregar unas resistencias.. o como sugeris vos?


estoy perdido con esto :S

ya creo q no lo hago con pic y termino armando uno con el lm3914 

jajja porfas

algun esquemita -..


----------



## 1024 (Dic 28, 2010)

La parte de 5*q /1024 tiene que ver con el numero que entrega el convertidor AD(q), que en este caso esta configurado para una conversión de 10bits(0<q<1024) entonces para mostrar el valor de voltaje en el LCD se aplica esa operación


----------



## psm2n3055 (Dic 29, 2010)

gracias por los aportes.. pero alguien me puede decir como es la formula?? como se calcula para 6 volts..?? como agrego resistencias como hago algo? ya se que modificando eso se varia la medida.. pero no se coo buscar info sobre eso :S


----------



## MVB (Dic 29, 2010)

Monta dos resistencias de 10k en serie, asi:
ver imagen adjunta.

y en el codigo cambia la formula quedando asi:

p  = 10.0*q/1024;

Y te voy a explicar de donde sale la forma.
Primero sabemos que el valor que entrega el read_adc(); es un numero entero entre 0 y 1024 dependiendo del valor de voltaje que halla en el pin. Recordar que este voltaje va de 0 a 5 v.

Entonces haciendo una regla de tres simple, donde q es el valor leido del adc.
1024 → 5v
q    → p
asi tenemos que p = 5.0*q/1024

Al poner las dos resistencias en serie lo que hacemos es un dividor de tension, (http://es.wikipedia.org/wiki/Divisor_de_tensión), como las dos resistencias que utilizamos son iguales, el valor del voltaje en la pin del pic sera la mitad del valor que se este midiendo.

Asi podemos formar de nuevo nuestra formula.
Cuando se le aplican 10v, tenemos 5 en el pin y el valor del adc sera de 1024.

10v → 1024
p → q

de nuevo tenemos que  p = 10.0*p/1024;

Espero haber sido lo suficientemente claro,

Saludos


----------



## psm2n3055 (Dic 29, 2010)

excelente.. te pasaste.. muchisimas gracias!!! te debo una cerveza loco!
jaja

feliz año para todos


----------



## adiktofer (Ago 20, 2011)

Muchas gracias MVB, io hice el ajuste necesario para hacerme un voltimetro de 0 - 100Vdc.
Les dejo los archivos para Uds del voltimetro, por si acaso qieren hacerle modificaciones o mejor aun implementar ademas un amperimetro.
El extracto contiene:
- Archivo *.bas del programa
- Archivo *.HEX
- Esquematico en ISIS PROTEUS
Nota: el compilador que estoy usando es el PROTON IDE DEVELOPMENT SUITE. Ademas deben tener instalado el MPLAB, por si quieren hacer nuevas modificaciones.
Gracias.


----------



## apocalypsys (Nov 27, 2011)

hola amigos disculpa 

1 tu voltimetro mis respetos 
2 crees q sea capas de soportar la bateria de un auto
dijo por el amperaje o tengo q agregarle otra cosa


saludos


----------



## MVB (Nov 27, 2011)

No importa el amperaje de lo que se mide, siempre y cuando el voltaje este en el rango todo estara bien.
Eso si, a mayor amperaje mas cuidado debes tener pues si hay un corto o algo similar en la medicion las consecuencias pueden ser mayores.

saludos.


----------



## apocalypsys (Nov 27, 2011)

para eso un fusible o me equivoco


----------



## apocalypsys (Nov 28, 2011)

hi amigo adiktofer disculpa  lo tendras en c  es que lo quiero modificar pero mi mplab me marca q todo es error te lo agradeceria


----------



## apocalypsys (Dic 3, 2011)

hola disculpen me podrian ayudar pasar este programa para el pic18f4550  

se los agradeceria  he tratado pero no me funciona 


#include <16f877a.h>
#use delay(clock=16000000)
#fuses xt,put,nowdt,protect,nobrownout,NOLVP,NOCPD
#byte porta = 0x05
#byte portb = 0x06
#byte portc = 0x07
#byte portd = 0x08
#byte porte = 0x09

#include "lcd.c"

char temp;

void main(){

   set_tris_a(0x01);
   set_tris_b(0x00);
   set_tris_c(0x00);
   set_tris_d(0x00);
   set_tris_e(0x00);   
   porta = 0x00;
   portb = 0x00;
   portc = 0x00;
   portd = 0x00;
   porte = 0x00;   

   setup_adc_ports(ALL_ANALOG);
   setup_adc(ADC_CLOCK_INTERNAL);
   set_adc_channel(0);

   lcd_init();   

   for(;{
      temp = read_adc();         
      lcd_putc("\f Pic Termometro ");
      printf(lcd_putc,"\n      %d%cc",temp*2,0xdf);      
      delay_ms(1000);
   }   
}


----------



## biker2k3 (Dic 3, 2011)

Tenes que hacer un divisor resistivo para que cuando entren 6volts te lo deje en 5v que es lo maximo que podes medir con el pic. Despues modificas el codigo asi...   p = 6.0 * q / 1024.0;



apocalypsys dijo:


> hola amigos disculpa
> 
> 1 tu voltimetro mis respetos
> 2 crees q sea capas de soportar la bateria de un auto
> ...



No tiene nada que ver el amperaje si estas idiendo voltaje yo tengo hecho un voltimetro en mi moto con un 16f819 y anda bien. Solo tenes que hacer un divisor resistivo de acuerdo al voltaje que quieras medir, al pic nunka deben llegar mas de 5v


----------



## apocalypsys (Dic 3, 2011)

hol amigo como que  lo compilastes   el del voltimetro


----------



## apocalypsys (Dic 4, 2011)

me podrian ayudar a  cambiar  el puerto de la señal de entrada de este programa en lugar de ra0 sea ra1 por favor me urge  y como pudo unir dos programas para el mismo  pic se los agradeceria 


#include <16f877a.h>
#fuses hs,nowdt,noput,nolvp
#device adc=8
#use delay(clock=20M)
#define LCD_DATA_PORT getenv("SFRORTB")
#define LCD_ENABLE_PIN  PIN_B2
#define LCD_RS_PIN      PIN_B0
#define LCD_RW_PIN      PIN_B1
#include <lcd.c>

int8 q;
double p=0;
//****************** defino funcion ADC ***************
void modulo_adc();

//***************** programa principal ***************

void main(){

 SETUP_ADC_PORTS(AN0);           // defino el pin analogo a usar
  setup_adc(ADC_CLOCK_INTERNAL);      // define el tipo de clock a usar
  lcd_init();                          // inicializo el lcd

  while(true){
      modulo_adc();


      lcd_gotoxy(4,1);
      printf(lcd_putc,"VOLTS:%1.3f",p);



  }
} 
//*********** funcion ADC****************

void modulo_adc()
{  set_adc_channel(0);
  delay_us(20);  // tiempo de conversion
  q= read_adc(); // lectura del valor
  p=50.0*q/127.5; // conversion adc
}


----------



## biker2k3 (Dic 4, 2011)

Proba asi



```
#include <16f877a.h>
 #fuses hs,nowdt,noput,nolvp
 #device adc=8
 #use delay(clock=20M)
 #define LCD_DATA_PORT getenv("SFR:PORTB")
 #define LCD_ENABLE_PIN PIN_B2
 #define LCD_RS_PIN PIN_B0
 #define LCD_RW_PIN PIN_B1
 #include <lcd.c>

 int8 q;
 double p=0;
 //****************** defino funcion ADC ***************
 void modulo_adc();

 //***************** programa principal ***************

 void main(){

 SETUP_ADC_PORTS(AN1); // defino el pin analogo a usar
 setup_adc(ADC_CLOCK_INTERNAL); // define el tipo de clock a usar
 lcd_init(); // inicializo el lcd

 while(true){
 modulo_adc();


 lcd_gotoxy(4,1);
 printf(lcd_putc,"VOLTS:%1.3f",p);



 }
 } 
 //*********** funcion ADC****************

 void modulo_adc()
 { set_adc_channel(1);
 delay_us(20); // tiempo de conversion
 q= read_adc(); // lectura del valor
 p=50.0*q/127.5; // conversion adc
 }
```


----------



## apocalypsys (Dic 5, 2011)

no amigo me marca error en el AN1


----------



## biker2k3 (Dic 5, 2011)

apocalypsys dijo:


> no amigo me marca error en el AN1



Perdona no programo en CSS por eso no puedo ayudarte mucho, proba cambiando esta linea y poniendo asi..

setup_adc_ports( AN0_TO_AN1 );


y sino proba asi

setup_adc_ports(AN0_AN1_AN3);


----------



## apocalypsys (Dic 6, 2011)

gracias amigo me funciono de maravilla 


otra pregunta como puedo poner dos programas en el mismo pic  es decir el programa anterior y otro 


gracias


----------



## biker2k3 (Dic 6, 2011)

apocalypsys dijo:


> gracias amigo me funciono de maravilla
> 
> 
> otra pregunta como puedo poner dos programas en el mismo pic  es decir el programa anterior y otro
> ...



De nada, que bueno que te haya funcionado.. y que otro programa queres agregarle? no podes mexclar 2 programas asi nomas, tenes que hacer uno que haga lo que hacen esos 2 programas.


----------



## dpm9 (Ago 19, 2012)

Una consulta quiero hacer q*ue* el pic muestre hasta 380 v en el lcd acá dejo mi programa para obtener ayuda vuestra

```
#include <16f877.h>
#device  adc=10
#fuses   xt,nowdt
#use  delay(clock=4M)
#define LCD_ENABLE_PIN  PIN_E0
#define LCD_RS_PIN      PIN_E1
#define LCD_RW_PIN      PIN_E2
#define LCD_DATA4       PIN_D4
#define LCD_DATA5       PIN_D5
#define LCD_DATA6       PIN_D6 
#define LCD_DATA7       PIN_D7
#include  <lcd.c>

void main()
{
lcd_init();

int16 a;
float b;

setup_adc(adc_clock_div_8);
setup_adc_ports(an0);

   for(;;)
   {
   set_adc_channel(0);
   delay_us(20);
   a=read_adc();
   b=a*380/1024.0;
   
   printf(lcd_putc,"\fVoltage=%fV",b);
   delay_ms(200);
   
     
      }
   }
```
El problema es q*ue* en el lcd no muestra el avance q*ue* quiero


----------



## erickmarcelo (Oct 9, 2012)

Hola a todos, tengo una duda... programe el pic 16f887 por medio de CCS para que mida tensión por medio de la entrada analógica AN0 . Pero no estoy seguro si solo puede medir la tensión de su propia fuente o si puede medir la tensión de fuentes externas, dado que lo simulo en proteus y corre perfecto... 

 En el caso que solo pueda medir tensión de su propia fuente, como puedo hacer que mida de fuentes externas?


----------



## VEGATRONICA (Oct 9, 2012)

Por supuesto q*ue* puede medir otro tipo de tensiones, pero para eso tienes q*ue* acondicionar la entrada, ya q*ue *como recordaras al ser un circuito digital solo puede trabajar con tensiones de 5V, mas de eso destruirías el PIC, lo mas común es usar un divisor de tensión en la entrada, saludos


----------



## Giru_zgz (Oct 10, 2012)

Como dice Somacruz, claro que es posible realizar esa medición; yo a tensiones superiores de 5 voltios uso amplificadores operacionales para estabilizar la tensión de 0 a 5 voltios.

Un saludo


----------



## 2cool2you (Oct 11, 2012)

Podes leer cualquier tensión siempre y cuando este en el rango de los 5V; por ejemplo, si quisieras medir una tensión máxima de 8V podrías poner un divisor resistivo 10K-10K de modo que la tensión máxima en la pata del pic sea de 4V (se puede mejorar, puse 10K-10K para evitar los cálculos ) y después hacer regla de 3 simple dentro del pic para ver que tensión estas leyendo.

Con respecto a lo de las fuentes externas, como todo circuito para que mida tiene que tener las referencias de 0V (masa) conectadas entre sí.


----------



## erickmarcelo (Oct 13, 2012)

Gracias a todos! ya lo probe y funciona ... hice el divisor de tensión para que llegue al pic y salio perfecto, ya que mi propósito era medir el voltaje de una fuente externa de 12 voltios.


----------



## VEGATRONICA (Oct 18, 2012)

erickmarcelo dijo:


> Gracias a todos! ya lo probe y funciona ... hice el divisor de tensión para que llegue al pic y salio perfecto, ya que mi propósito era medir el voltaje de una fuente externa de 12 voltios.



Erick, que bueno que te funciono, ojala y pudiera compartir tu codigo y esquema y asi sea de utilidad a otros usuarios, saludos


----------



## pablov (Ene 10, 2013)

Hola soy nuevo en este foro, he estado probando un programa de un voltímetro que han colgado en este foro y he hecho algunas modificaciones, lo he simulado en proteus y corre de maravilla, pero al montarlo en el protoboard solo aparece  en la segunda fila unos cuadrados blanco y no registra ningún valor, no se si es el pic,
el programa, o algún error en la programación.
Aquí dejo el código fuente:


```
#include <16f877a.h>
#device adc=10
#fuses NOWDT,BROWNOUT,XT,NOLVP,,NOPROTECT
#use delay (clock=4M)
#define use_portb_lcd TRUE //define portb lcd
#include <lcd.c> 
//
//Programa Principal
//
void main()
{
   unsigned long valor=0;//Declaracion de variables
   float voltaje;        //Variable que contendra el resultado
//
//Se habilita el A/D y se declara el PORT a usar//
//
   setup_adc( ADC_CLOCK_INTERNAL );            
   setup_adc_ports(AN0);
   set_adc_channel(0);
//
//Se inicia la LCD//
//     
   lcd_init();
lcd_gotoxy(4,1);
lcd_putc("Iniciando");
delay_ms(2000);
lcd_gotoxy(3,2);
lcd_putc("PABLO OJEDA");
delay_ms(1000);
lcd_putc("\f" ) ;
lcd_gotoxy(2,1);
lcd_putc("VOLTIMETRO DC");
      
   do
   {
```
Funciona en proteus pero no me arroja ningún resultado armándolo.
Estoy usando el pic16f877a, el cristal es de 4 Mhz y los condensadores de 27pf



Estoy un poco estresado, llevo días probando cual ha sido el error, el pic lo grabo y lo regrabo y no me arroja ningún error al momento de cargar el programa en el pic con el icprog.


----------



## 2cool2you (Ene 10, 2013)

¿Estas usando una resistencia en pull up para el pin MCLR (pin 1 del micro)?
En caso de que la respuesta sea no, agrega una resistencia de 10k entre el pin 1 y Vcc.

En caso contrario, probá con los siguientes FUSES:
#fuses NOWDT,BROWNOUT,XT,NOLVP,NOPROTECT,NOPUT,NODEBUG,NOLVP,NOCPD,NOWRT

Fijate también que el cristal, junto con sus capacitores, esté lo más cerca posible del micro. Para ese micro y ese cristal yo usé capacitores de 15pF, la configuración de fuses que escribí mas arriba, [#use delay(clock=4000000)] y la resistencia en pull up y no tuve ningún problema.


----------



## D@rkbytes (Ene 10, 2013)

pablov dijo:


> Funciona en proteus pero no me arroja ningún resultado armándolo.


Si tu código no tiene ninguna instrucción para leer el ADC ¿Como quieres obtener un resultado?

Adjunto una modificación realizada de rápido para un sencillo voltímetro hasta 50V, con el código que posteaste.

Suerte.


----------



## pablov (Ene 11, 2013)

holas arme el circuito y hice las modificaciones que me dijeron pero no puse la reistencia de 10k en el pin1 del masterclear y ul pulsador mas para reiniciar cambie los condensadores de 27p a 22p pero no obtube algun cambio alguno no se si es el pic que esta danado o otra cosa por que use el codigo hex de D@rkbytes para asegurarme y nada.pero al momento de la grabacion en el pic no me da ningun error
bueno graciasp or la ayuda a una cosa mas al momento de pulsar en le pulsador el lcd no reinicia el programa no hay cambio alguno en la pantalla del lcd,gracias por la ayuda que me pudieran dar


----------



## 2cool2you (Ene 11, 2013)

El pin 1 de este micro, es el pin MCLR (Master Clear), a menos que se lo configure de otra forma, que lo que hace, justamente, es reiniciar el procesador. Al estar en alto activa el procesador y el programa se ejecuta; al estar en bajo detiene el procesador. Por este motivo es necesario ponerlo con una resistencia de 10K a Vcc (+5V). 
Si la resistencia no está puesta, el pin recibe cualquier ruido eléctrico del ambiente, lo que hace que el procesador se active y/o desactive aleatoreamente. 

Cabe recordar que este microcontrolador tiene alimentación de ambos lados, por lo que tenes que fijarte que estén ambas conectadas.


----------



## D@rkbytes (Ene 11, 2013)

2cool2you dijo:


> El pin 1 de este micro, es el pin MCLR (Master Clear), a menos que se lo configure de otra forma, que lo que hace, justamente, es reiniciar el procesador.


Saludos.
En este PIC el pin 1 MCLR/Vpp solamente funciona como reset del microcontrolador.
No se puede configurar de otra forma, incluso no existe el fuse  MCLR ó NOMCLR (_MCLR_OFF/ON)
Aunque el compilador PCWHD permita establecerlos y compilar sin errores (Bug del compilador).
En otros compiladores esto no sucede, y si generan error al encontrar esos fuses declarados.
Existen PICs que si tienen esa posibilidad, y se puede usar ese pin como entrada, con el fuse MCLR en OFF
Si no se desea resetear el PIC, se puede conectar directamente el pin 1 a VDD


pablov dijo:


> hice las modificaciones que me dijeron pero no puse  la reistencia de 10k en el pin1 del masterclear y ul pulsador mas para  reiniciar cambie los condensadores de 27p a 22p pero no obtuve cambio alguno


Probablemente es porque no hiciste todas las modificaciones que se te dijeron.
2cool2you ya te había mencionado en el post #34 que verificaras la conexión del pin 1.

Adjunto el diagrama, y así es como debes hacer las conexiones.

Suerte.


----------



## 2cool2you (Ene 11, 2013)

Acabo de verificar el datasheet y tenes razón, no me había dado cuenta que en ese micro es solamente MCLR o Vpp, perdón por la equivocación.


----------



## pablov (Ene 12, 2013)

ok manes gracias hice las modificaiones que me dijeron, lo arme otra ves desde cero y funciona de maravilla  es el primer trabajo que hago con pic y me lleno de emocion al ver que el pic estaba vivo jajaja
una consulta mas, este programa lo hice con el fin de ponerlo en una fuente simetrica pero no logro que lea el las lecturas de a/d


```
#include <16f877a.h>
#device adc=10
#fuses NOWDT,BROWNOUT,XT,NOLVP,PUT
#use delay (clock=4M)
#define use_portb_lcd TRUE //define portb lcd
#include <lcd.c> 
//
//Programa Principal
//
void main()
      {
//Declaracion de variables
float valor,voltaje,val,volt;        //Variable que contendra el resultado

//Se habilita el A/D y se declara el PORT a usar
   setup_adc( ADC_CLOCK_INTERNAL );            
   setup_adc_ports(AN0);
   set_adc_channel(0);
   set_adc_channel(1);
   
//Se inicia la LCD
   lcd_init();
   lcd_gotoxy(4,1);
   lcd_putc("Iniciando");
   delay_ms(2000);
   lcd_gotoxy(3,2);
   lcd_putc("PABLO OJEDA");
   delay_ms(1000);
   lcd_putc("\f");
   lcd_gotoxy(3,1);
   lcd_putc("VOLTIMETRO DC");
      delay_ms(1000);
   while (true)
   {
   valor = read_adc();
   delay_us(50);
   voltaje=(valor*50/930);
   lcd_gotoxy(3,2);
   printf(lcd_putc,"%04.2f P ",voltaje);
   delay_ms(100);
   val = read_adc();
   delay_us(80);
   voltaje=(valor*50/930);
   lcd_gotoxy(11,2);
   printf(lcd_putc,"%04.2f N ",volt);
   delay_ms(150);
   }
   
}
```

cunado pongo en  setup_adc_ports(RA0_RA1_ANALOG); ESTE APARECE COMO ERROR no lo acepta el compilador y si pongo setup_adc_ports(AN1); el AN1 aparece como indefindo cual podria hacer pra que funcione otra entrada nalogica mas y hacer que en el lcd se muestre dos lecturas del voltaje pra ponerlo en una funete simetrica, gracias por las respectivas respuestas


----------



## 2cool2you (Ene 12, 2013)

RA0_RA1_ANALOG ya no se acepta en el compilador, o si se acepta es solo para compatibilidad.

Adjunto acá las definiciones correctas del propio compilador, encontradas en "16F877A.h", línea 258:

```
#define NO_ANALOGS                           7    // None
#define ALL_ANALOG                           0    // A0 A1 A2 A3 A5 E0 E1 E2 
#define AN0_AN1_AN2_AN4_AN5_AN6_AN7_VSS_VREF 1    // A0 A1 A2 A5 E0 E1 E2 VRefh=A3     
#define AN0_AN1_AN2_AN3_AN4                  2    // A0 A1 A2 A3 A5          
#define AN0_AN1_AN2_AN4_VSS_VREF             3    // A0 A1 A2 A4 VRefh=A3              
#define AN0_AN1_AN3                          4    // A0 A1 A3
#define AN0_AN1_VSS_VREF                     5    // A0 A1 VRefh=A3
#define AN0_AN1_AN4_AN5_AN6_AN7_VREF_VREF 0x08    // A0 A1 A5 E0 E1 E2 VRefh=A3 VRefl=A2     
#define AN0_AN1_AN2_AN3_AN4_AN5           0x09    // A0 A1 A2 A3 A5 E0        
#define AN0_AN1_AN2_AN4_AN5_VSS_VREF      0x0A    // A0 A1 A2 A5 E0 VRefh=A3           
#define AN0_AN1_AN4_AN5_VREF_VREF         0x0B    // A0 A1 A5 E0 VRefh=A3 VRefl=A2           
#define AN0_AN1_AN4_VREF_VREF             0x0C    // A0 A1 A4 VRefh=A3 VRefl=A2              
#define AN0_AN1_VREF_VREF                 0x0D    // A0 A1 VRefh=A3 VRefl=A2
#define AN0                               0x0E    // A0
#define AN0_VREF_VREF                     0x0F    // A0 VRefh=A3 VRefl=A2
```


----------



## pablov (Ene 13, 2013)

ok man gracias pucha que esta informacion es valiosa y es siempre bueno contar con un foro tan buena onda con este.gracias

pero como haria la poner en setup_adc_ports(AN0_AN1);
 set_adc_channel(0);
 set_adc_channel(1);
 i cimo lo hariap ta que pueda reconocer las entradas analogicas


----------



## 2cool2you (Ene 14, 2013)

Este pic permite solamente 1 o 3 entradas al mismo tiempo, así que creo que la que te vendría mejor sería AN0_AN1_AN3, que te va a permitir usar AN0 y AN1, aunque te va a habilitar también AN3.

Con respecto a la lectura, es simple:

setup_adc_ports(); -> Configura el/los puertos análogos a utilizar.
setup_adc(); -> Configura la velocidad de muestreo, en base a la velocidad del cristal elegida.

Estas dos funciones son llamadas, normalmente, una sola vez al principio del código.

Después están las siguientes:

set_adc_channel(); -> Elije el canal análogo a leer; En caso de usar AN0, AN1 y AN3, los canales serían 0, 1 y 3.
read_adc(); -> Lee un valor análogo del canal elegido anteriormente.

Estas últimas dos se usan cada vez que se quiera leer un valor análogo o cambiar el canal a leer; pero hay que tener en cuenta que la lectura análoga o el cambio de canal requiere un tiempo, por lo tanto, si se van a registrar lecturas seguidas se debe poner un delay entre lectura y lectura de unos 20uS, y entre cambio de canal y lectura de unos 100uS (que alguien me corrija si el tiempo que elegí no es correcto).

De modo que si quisiera leer 500 valores del puerto análogo, sería así: 

```
set_adc_channel(0);
   delay_us(100);
   for(i=0;i<500;i++)
   {
      temporal = read_adc();
      delay_us(20);
   }
```


----------



## pablov (Ene 26, 2013)

gracias estuve un poco ocupado estos dias hasta ayer que me desocupe y pude recien revisar mi proyecto hice las modificaciones que indicaste y si logre hacer que funcione mas la otra entrada analogica pra hacer que este voltimetro pueda trabajar en una fuente simetrica y quiesiera hacer hacer mas un amperimetro dc para no desperdiciar la an3.como es que lo hacia tendria que conseguir un trandustor de corriente a a voltaje o hay alguna otra forma de hacer lo posible.

y si no fuese asi tendria que mandar a tierra an3 y no es nesesario gtacias por las respuestas que pudieran dar


----------



## 2cool2you (Ene 26, 2013)

Para el amperímetro tendrías que poner una resistencia de bajo valor (cuanto más bajo mejor), en serie con la salida de la fuente y medir la caída de tensión en esa resistencia, luego con ley de Ohm calculas la corriente que circula por esa resistencia, que, al estar en serie, va a ser igual a la corriente total que circula por el circuito. Tenes que tener en cuenta que si la fuente es de 3A por esa resistencia podrían llegar a circular 3A y si es de 10A, van a circular 10A, por ende, tiene que ser una resistencia de potencia. En cuanto al valor, cuanto más bajo mejor va a ser, una resistencia de 0,1 ohm, o 0,01 ohm va a andar bien, tendrías que ver la caída de tensión generada y la resolución del ADC del pic.
Ejemplo: Si la resistencia es de 0,1 ohm, y la corriente máxima de la fuente es de 3A, tendrías que poner una resistencia de 1W para que no se queme, y tener en cuenta que el PIC tendría que leer una tensión comprendida entre 0 y 0,3V (o poner un amplificador operacional y aumentarla para tener una mejor resolución).


----------



## pablov (Ene 28, 2013)

ok man gracia voy a hacer las cosas que me recomiendas. una cosa mas man al mometo de poner el voltimetro uso eltransformador de la fuente simetrica  todo va vine con la parte positiva pero cuando conecto la parte negativa medir el lcd se pone cono en cuadro y la razon es que estoy poniendo los 2 terminales del voltimetro a tierra como haria para usar solamente el transformador de la fuente simewtrica o nesesariamente tendria que construir transformador solo para el voltimetro gracias por las respuestas que me puieran dar.


----------



## 2cool2you (Ene 28, 2013)

No se si entendí bien, pero, primero que nada, el PIC solamente mide tensiones positivas con respecto a su GND, por lo tanto, si queres medir una tensión negativa, primero vas a tener que hacerla positiva y después medirla con el PIC. Segundo, si medis directamente desde el transformador, vas a tener media señal senoidal, dado que vas a obtener el semiciclo positivo de la señal y el otro lo vas a perder; tendrías que rectificarla antes y con respecto a la alimentación del micro, tienen que ser 5V de corriente continua. Volviendo al primer punto, las mediciones que el PIC haga, van a depender de su GND.

En caso de querer usar una referencia de tensión diferente a <+5V - GND>, tendrías que usar otra configuración del ADC, como por ejemplo: AN0_AN1_AN4_VREF_VREF que configura A0, A1 y A4 como entradas análogas, A3 como referencia de tensión positiva y A2 como referencia de tensión negativa (Ver mensaje #41), y de esta manera podés modificar la resolución o la polaridad del ADC (ver características eléctricas del micro en su datasheet). Te recomiendo no superar la tensión de alimentación en los pines de referencia para no quemar el micro.


----------



## pablov (Feb 5, 2013)

Brother podrías explicarme un poco mas del voltaje de referencia?
creo es lo único  que no me queda, ahora ya que intente usar una fuente externa para alimentar solo el voltímetro y medir la tensión negativa en mi fuente simétrica y no dio buenos resultados. Ah una cosa más, ¿como puedo hacer que la lectura del pic sea mas estable? cuando pongo por ejemplo una batería de 9v el voltímetro oscila de 8.77v a 9.21v, no se queda en un valor fijo, ¿debería de aumentar el tiempo de lectura o que debería de hacer?


----------



## 2cool2you (Feb 12, 2013)

Bueno, primero partamos de una base: El pic puede leer una tensión que oscile entre la tensión de alimentación negativa (0V) y la tensión de alimentación positiva (comúnmente, 5V). Obteniendo como respuesta un valor comprendido entre 0 y 255 para el ADC de 8 bits, y entre 0 y 1023 para el ADC de 10 bits, proporcional a la tensión medida.

El voltaje de referencia sirve para obtener una resolución mayor cuando se lee una tensión que tiene una variación menos brusca que [VCC - GND (comúnmente, 5V)]. Por ejemplo: Si tenemos un sensor que emite una tensión, proporcional a la medición, que está entre los 0,5V y los 2V, se puede bajar la tensión de referencia al mínimo (2,5V según la hoja de datos), para que los "pasos" sean más chicos y el mismo tenga más precisión.

Con respecto a la variación del ADC, es muy probablemente debido al ruido, podrías probar poniendo una resistencia en PULL-DOWN y ver si la medición se estabiliza, o sino realizar un promedio de mediciones; por ejemplo: se toman 100 mediciones en un segundo, se las suma, luego se las divide por 100 y el valor obtenido debe ser la tensión medida.


----------



## pablov (Feb 24, 2013)

Hola manes, no entiendo eso de resistencia PULL-DOWN es distinto de las resistencias PULL-UP y como haría para hacer el promedio que dices



ya hice la modificación a mi proyecto y le puse el amplificador inversor para hacer la medición y funciona pero ahora como hago para que pueda visualizar la medida del amperímetro aquí pongo algunas fotos del proyecto



aquí pongo el código del proyecto y podrían decirme como hago para las tiempos de lectura y cambio de canal en en adc del pic

```
while (true)
   {
   //
   //medida de la entrada positiva
   set_adc_channel(0);
   valor = read_adc();
   delay_us(50);
   voltaje=(valor*50/930);
   lcd_gotoxy(1,1);
   printf(lcd_putc,"%04.2f P ",voltaje);
   delay_ms(100);
   //
   //medida de la entrada negativa
   set_adc_channel(1);
   val = read_adc();
   delay_us(150);
   volt=(val*5/930);
   lcd_gotoxy(8,1);
   printf(lcd_putc,"%04.2f N ",volt);
   delay_ms(100);
   //
   //medica de corriente de entrada positiva
   set_adc_channel(2);
   valor1 = read_adc();
   delay_us(50);
   voltaje1=(valor*50/930);
   amp1=(voltaje1/0.1)
   lcd_gotoxy(1,2);
   printf(lcd_putc,"%04.2f A ",amp1);
   delay_ms(100);
   //
   //medida de corriente de la entrada negativa
   set_adc_channel(3);
   val1 = read_adc();
   delay_us(50);
   volt1=(val1*50/930);
   amp2=(volt1/0.1)
   lcd_gotoxy(8,2);
   printf(lcd_putc,"%04.2f A ",amp2);
   delay_ms(100);
   }
  
}
```

aquí están las imágenes del voltímetro en el proteus



como haría par que me para ver en la pantalla del lcd uA, mA, A seria usando el if y else , como mas o menos lo haría alguna ayuda para eso manes que es lo que tendría que aumentar en las instrucciones del pic



y como hago con los tiempos de lectura del canal y del cambio para el otro canal cuanto tiempo mas de retardo tengo que dar por que en proteus aparece mensajes diciéndome que no le da suficiente tiempo para la lectura y cambio de canal sera por eso que oscila la lectura del lcd cuando mido una batería de 9v  como dije mas arriba



vi en alguna pagina donde hay un voltímetro ,amperímetro y termómetro que además cuando hay corte el lcd parpadea y aparece en la pantalla ¡CORTE¡ hasta que se soluciones el problema como se pude hacer eso alguien tiene una idea


----------



## 2cool2you (Feb 24, 2013)

Entre cambio de canal y lectura tenes que esperar unos 100uS.
Esto:

```
set_adc_channel(3);
val1 = read_adc();
```

Debería cambiarse por esto:

```
set_adc_channel(3);
delay_us(100);
val1 = read_adc();
delay_us(50);
```

Por supuesto que estos cambios deben realizarse para los 3 canales. En tu caso, yo crearía una función [int LeerCanal(int Canal);] que se ocupe de seleccionar el canal y realizar la lectura, para reducir instrucciones en el programa, y para que la escritura de código sea más veloz.


```
int LeerCanal(unsigned int Canal)
{
    if(Canal > 3) //Verificamos que el número de canal sea válido
        return 0;
    set_adc_channel(Canal);
    delay_us(100);
    int a = read_adc();
    delay_us(50);
    return a;
}
```

Con respecto a lo de "Corte", es sencillo, está vinculado directamente al amperímetro. Un corte se detecta cuando una corriente demasiado alta está circulando por el circuito. Por ende, si en la medición del ADC nos devuelve 3A y nuestro circuito no soporta más que eso, lo que se hace normalmente es reducir la tensión o bloquear el circuito, dado que se llegó al máximo de corriente establecida.

Olvidé agregar sobre mA, uA y A: Es algo medio rebuscado de hacer en un PIC, sobre todo en CCS, dado que la presición decimal de los PIC no es de más de 2 decimales (que alguien me corrija si no estoy en lo correcto), y porque CCS, en mi opinión, tiene bastantes fallas en la parte aritmética (entre otras). De todas formas, tenés dos maneras de realizarlo, la primera es usar directamente la medición del ADC, la cual es un entero de 10 bits (aunque se almacene en una variable de 16 bits), e ir verificando con bloques [if] si es menor a tal valor o si está comprendido entre tal y tal valor. 
La segunda opción, es más sencilla de realizar a simple vista, pero está el problema de la precisión. Consiste en pasar el valor a corriente y después realizar la misma verificación con los bloques [if], con la única diferencia que en lugar de verificar un valor que, a simple vista, no parece una corriente, estarías verificando para 1A o menos de 1mA.

* Pull-down: Es una resistencia conectada a masa, cuya función es hacer que la señal nunca quede flotando (alta impedancia), sino que en el caso de que la señal flote, quedaría conectada a masa. En este caso, la resistencia en PULL-DOWN lo que haría es generar una corriente -que circularía desde la fuente de la medición hacia masa- para estabilizar la medición, hay que tener en cuenta que debe ser una resistencia alta para no alterar la medición.
Son iguales que las PULL-UP, solamente que en lugar de estar conectado a VCC van conectadas a GND.


----------



## pablov (Mar 4, 2013)

estube modificando el codigo del programa e hice que a 1.6A en el lcd apareca alto para el canal 2 esta bien trabaj bien pero para el canal 2 oscila de la lectura a a alto como hago para solucionar eso
ademas quisiera una referencia al poner %04.00f este pude cambiar por %d o %s o %LuB como es que se diferencian de estos al momento de los digitos



mas tarde colgare el cosigo y la simulacion en proteus estoy un poco ocupado estunsian pata mi examen


----------



## pablov (Mar 8, 2013)

Aquí pongo el código del programa, y no entiendo porque aparece ese problema en el canal 3
Debiera de ser como el canal 2. Alguien que me saque de la duda que estoy haciendo mal
Se inicia la LCD   


```
lcd_init();
   lcd_gotoxy(4,1);
   lcd_putc("Iniciando");
   delay_ms(2000);
   lcd_gotoxy(3,2);
   lcd_putc("PABLO OJEDA");
   delay_ms(1000);
   lcd_putc("\f");
   lcd_gotoxy(2,1);
   lcd_putc("VOLTIMETRO DC");
   delay_ms(1000);
    lcd_putc("\n");
   lcd_gotoxy(2,2);
   lcd_putc("AMP1      AMP2");
   delay_ms(1000);
   //
   while (true)
   {
   //
   //medida de la entrada positiva
   set_adc_channel(0);
   delay_us(100);
   valor = read_adc();
   delay_us(50);
   voltaje=(valor*50/1024);
   lcd_gotoxy(1,1);
   printf(lcd_putc,"%04.2f P ",voltaje);
   delay_ms(100);
   //
   //medida de la entrada negativa
   set_adc_channel(1);
   delay_us(200);
   val = read_adc();
   delay_us(50);
   volt=(val*50/1024);
   lcd_gotoxy(9,1);
   printf(lcd_putc,"%04.2f N ",volt);
   delay_ms(100);
   //
   //medica de corriente de entrada positiva
   set_adc_channel(2);
   delay_us(300);
   valor1 = read_adc();
   delay_us(50);
   voltaje1=(valor1*5/1024);
   amp1=(voltaje1);
   lcd_gotoxy(2,2);
   if(amp1<=1.6)
   printf(lcd_putc,"%04.2f A ",amp1);
   if(amp1>1.6)
   lcd_gotoxy(1,2);
   printf(lcd_putc," !ALTO! ");
   delay_ms(100);
   //
   //medida de corriente de la entrada negativa
   set_adc_channel(3);
   delay_us(400);
   val1 = read_adc();
   delay_us(50);
   volt1=(val1*5/1024);
   amp2=(volt1);
   lcd_gotoxy(10,2);
   if(amp2<=1.6)
   printf(lcd_putc,"%04.2f A ",amp2);
   if(amp2>1.6)
   lcd_gotoxy(9,2);
   printf(lcd_putc," !ALTO! ");
   delay_ms(100);
}
 }
```
Aquí pongo la simulación en proteus del voltimetro y otra es la simulacio para los opams que configuracion me recomineda la de amplificador inversor o la no inversora.
Busque el amplificador no inversor tiene problemas con las respuestas en frecuencia, pero la frecuencia siempre va a ser de 60 hz. No creo que tenga problemas, o uso el amplificador inversor para desarrollar el proyecto.
Gracias por las respuestas que puedan brindarme



algo mas alguna información sobre como poner o que significa %f,%o3LBU;%s,%d esto para poner en el código al momento de seleccionar escalas en el amperímetro.


----------



## pablov (Mar 25, 2013)

broders por fa quiero una opinion de ustedes para terminar mi proyecto solo nesesito eso y lo armo ah sigue  oscilando la lectura en el lcd a pesar de poner una esistencia en pull dow o sera por que lo tengo armado aun en el protoboard


----------



## 2cool2you (Mar 25, 2013)

Bueno, mirá, yo de electrónica sé poco, puedo ayudarte en el tema de la programación, pero creo que si pones un capacitor de bajo valor a la entrada del ADC (en lugar de la resistencia), quizas puedas estabilizar mejor la medición, aunque creo que podría retrasarse un poco la actualización de la medición. Quizás con uno de 100nF (realmente no sabría que valor decirte). Si la medición tiene variaciones muy bruscas, (se considera una variación leve [+5; -5] puntos del ADC), es probable que estés configurando mal el oscilador o que el pin de entrada esté "al aire". En ese caso, o bien se reconfigura el oscilador (del ADC), o bien se verifica la conexión. Cabe destacar que si está conectado a un amplificador operacional, es necesario usar capacitores de estabilización, sobre todo si el operacional esta amplificando una señal de baja amplitud.


----------



## RulasRR (Mar 29, 2013)

adiktofer dijo:


> Muchas gracias MVB, io hice el ajuste necesario para hacerme un voltimetro de 0 - 100Vdc.
> Les dejo los archivos para Uds del voltimetro, por si acaso qieren hacerle modificaciones o mejor aun implementar ademas un amperimetro.
> El extracto contiene:
> - Archivo *.bas del programa
> ...



una pregunta amigo, como puedo hacer para medir un voltaje negativo con el pic? tu voltimetro está muy bueno, sin embargo necesito mostrar el voltaje que da una fuente de cd que arroja desde -36v a -1.2 v y de 1.2 a 36v
espero haberme explicado, muchas gracias


----------



## pablov (Mar 31, 2013)

el voltimetro que estoy haciendo mide tensiones negativas indirectamente uisando opams, igual qe tu lo pienso poner en una fuente simetrica que estoy haciendo, para medir una tension negativa pones un opam en configuracion de amplificador inversor despues de la salida del divisor de tension, teoricamente tendriamos que hacer que la ganacia sea 1 para no afectar la lectura pero hay una caida de tension en el opam por eso hay que usarse potenciometros para regular la ganancia para eso mas puse una simulacion  en proteus en el mensaje 53 en el archivo rar que dice sim 2 ahi esta las configuraciones  pra las entradas



pero el problema de esto es el ruido que hace variar la lacetura por eso estoy preguntando alguna manera de eliminar esto  ya sea poniendo capacitoe en paralelo en las entradas del adc


----------



## pablov (Sep 10, 2013)

manes creo que la unica solucion que encontre para deje de oscilar el voltimetro es un filtro pasa bajos en la entrada del adc y hacer un promedio de las mediciones el problema es que no se como hacer un promedio de ellas con codigo alguien puede darme una ayudas con esto ya hice el pcb  tiendo en cuenta todos los detalles que me pusieron enlos post


----------



## ByAxel (Sep 10, 2013)

pablov dijo:


> como hacer un promedio de ellas con codigo alguien puede darme una ayudas con esto ya hice el pcb  tiendo en cuenta todos los detalles que me pusieron enlos post



Puedes tomar varios samples (por ejemplo 20) del ADC, sumarlos y al final divides entre 20. El resultado es el promedio. Otra es guardar los samples en una array luego según quieras puedes tomar el de mayor valor o el valor que más se repita, etc.


----------



## 2cool2you (Sep 10, 2013)

Coincido con ByAxel, sino la otra opción es agregar un capacitor de no muy alto valor en la entrada del ADC (.1uF o parecido), para que derive las variaciones de alta frecuencia a masa. De esta manera vas a tener una menor velocidad de respuesta pero también una menor oscilación. De todas formas coincido en que lo mejor en estos casos es hacer un promedio de 15 o 20 muestras para obtener un valor consistente.


----------



## pablov (Sep 14, 2013)

claro eso ya lo se pero el punto es como quiero un ejemplo de como hacer lo no soy tan pro de la programa
cion en c lo que se de pic es gracias a lo que busco por internet y a este foro por eso les pido ayuda a ustedes manes la hice la placa del voltimetro y lo voy a colgar pronto para que ven y comenten si hay algo por mejorar



aqui  les pongo el pcb y el esquematico ayudenme a mejorar este proyecto las primeras pruebas las hice en el protoboard con cables muy largos ya de hecho hay una gran oscilacion no he problado aun en un placa con los componentes ya soldados
 pero antes de llevarme una gran desilucion quiero tomar todas las precausiones


----------



## lucegiar2005 (Sep 14, 2013)

Hola a todos, buenas noches. Estaba leyendo el tema y me parece interesante, por lo que he querido compartir con ustedes y quien lo nececite un diseño mio. La fuente no es el proyecto ya que fue hecha para probar y luego la terminaré. Lo que me ocupé es de que presente tensión, corriente y potencia, además de limitar en tensión y corriente programable cuyo rebasamiento produce un corte momentaneo de la alimentación tras lo cual chequea el estado y de no cesar el problema mantiene el corte, caso contrario habilita nuevamente. Las indicaciones de como opera están en el Isis. No aporto la fuente porque está hecha con Niple, pero si a alguien le iteresa el asm o el npl lo subo. Saludo y gracias por aquellos comentarios que puedan aportar para su mejor realización.


----------



## 2cool2you (Sep 15, 2013)

Un promedio de mediciones en pseudocódigo seria algo así:


```
Inicio
Declarar variable 'i' como entero sin signo 8 bits
Declarar variable 'promedio' como entero sin signo 16 bits
Declarar variable 'resultado' como entero sin signo 16 bits
i = 0
promedio = 0
Mientras i sea menor a 20
{
 promedio = promedio + (Medición del ADC)
 i = i + 1
}

resultado = promedio / 20

Mostrar resultado
```

Por supuesto que este fragmento de código es para que lo implementes en tu programa, utilizando la sintaxis de tu compilador y los registros de tu micro.


----------



## cosmefulanito04 (Sep 15, 2013)

Lo ideal es usar un promedio móvil usando un vector que almacene las últimas "N" muestras.

Entonces, del código que publicó *2cool2you*, si yo lo tuviera que hacer en "C", eso podría ser una función que por argumentos reciba la dirección del vector y la dirección de la variable donde se almacenará el resultado.


----------



## pablov (Sep 16, 2013)

Buen aporte manes pero denme una opinion sobre el pcb


----------



## cosmefulanito04 (Sep 16, 2013)

pablov dijo:


> Buen aporte manes pero denme una opinion sobre el pcb



Si lo subís en un PDF o en imágenes de buena calidad tal vez podamos ayudarte.


----------



## pablov (Sep 17, 2013)

holas aqui les dejo las imagenes del esquematico y del pcb ayuden a mejorar el circuito


----------



## cosmefulanito04 (Sep 17, 2013)

pablov dijo:


> holas aqui les dejo las imagenes del esquematico y del pcb ayuden a mejorar el circuito



No se vé bien.

Tratá de aumentar el tamaño de la imagen y en lo posible, en vez de subir todo el esquemático y el PCB, subí la parte donde tengas dudas, que al parecer es la parte analógica.


----------



## pablov (Sep 18, 2013)

pero esta en la carpeta del mensaje numero 61 ahi esta el esquematico y el pcb en aguila version 6.3.0 bueno pero igual voy a subir un nuevo mensaje donde pondre las parte principales


----------



## cosmefulanito04 (Sep 18, 2013)

No todos tenemos el Eagle, yo uso el Altium.

Por eso te mencioné si el programa podía transformar el proyecto en PDF, ya que en Altium si se puede.


----------



## pablov (Sep 19, 2013)

ok aqui subo las imagenes en una buen calidad de imagen y una pregunta mas broder que tal es el altium para hacer pcb ya que solo conosco el agulila el pcb wizard el ares y no he visto nunca una placa en altium


----------



## cosmefulanito04 (Sep 19, 2013)

No alcanzo a ver los valores de los componentes ni del PIC como tampoco la alimentación que le das a los operacionales (creo ver un +/- 15v), pero de lo que ví destaco esto:

*Esquemático:*

- Ojo con los operacionales, estás trabajando como inversor, asegurate que a la salida obtengas una tensión positiva.

- En cuanto a las protección en las entradas analógicas del PIC parecen estar bien (no veo valores).

- No alcanzo a ver si juntas las masas (GND) que van al "+" de los operacionales con el circuito (es necesario hacerlo, pero en un solo punto).

*En cuanto al PCB:*

- Pistas anchas, si podés ensancha lo máximo que puedas, más allá del consumo, ensanchando matás la inductancia parásita de la pista. Por otro lado también tené en cuenta el consumo (con ese circuito no deberías tener mucho consumo), te recomiendo poner la lupa en las pistas de alimentación.

- El cristal debe estar lo más cerca posible de los pines del uC y con pistas los más cortas y anchas posibles. Por otro lado se aconseja que los dos capacitores estén entre el cristal y el uC.

- Faltan capacitores de desacople bien al lado de la alimentación del PIC, del TL084 y el LCD (100nF o más según recomiende el fabricante).

- Si bien las masas (GND) digitales y analógicas son el mismo potencial, en un PCB las tenés que aislar bien después de un cierto punto (ej. el regulador de tensión) y no juntarlas más. Por lo tanto la masa analógica que va al PIC tiene que estar separada de la masa digital del PIC.

- Evitá lazos con la masa, es decir, separá tu circuito en varias etapas, ejemplo => PIC, LCD y Operacionales. Al pic mandale una masa desde el regulador y desde ahí repartís a todo lo involucrado al PIC menos la parte analógica y el LCD. Al LCD también le mandás una linea de masa desde regulador y lo repartís en todos los pines del LCD que necesiten masa. También operacional y la parte analógica del PIC (GND de los zeners y pin AGND) mandás una linea de masa desde el regulador. Nunca juntes las masas de esas etapas.

- De c/etapa que mencioné antes, haces planos de masas bien separados, es decir no sirve llenar todo el resto del cobre que no usas con cualquier GND, tenés que separarlos bien.

- La referencia de tensión para el ADC del PIC también separala y filtrala bien con capacitores e inductores de choque.

Creo que con eso podés mejorar muchísimo el PCB.


----------



## callecuatro1976 (Dic 29, 2014)

```
while (true)
   {
   set_adc_channel(0);
   delay_us(20);
   for(var1=0;var1<8;var1++)
   {
      volt = read_adc();
      delay_us(20);
   }
   
  var2=var2+volt;
  var1=var1+1;
   valor=volt/8;
   valor=volt*50/1023;
   lcd_gotoxy(2,2);
   printf(lcd_putc,"%04.2f",valor );
   delay_ms(500);
```
  asi estaría bien el código para hacer un promedio de variables


----------



## D@rkbytes (Dic 29, 2014)

callecuatro1976 dijo:


> ```
> while (true)
> {
> set_adc_channel(0);
> ...


Nop. Así sólo estás leyendo 9 veces el canal 0 y eso no produce ninguna lectura promedio.
Tienes que ir sumando la lectura dentro del bucle y al final divides el resultado entre la cantidad de muestras.


----------



## callecuatro1976 (Dic 30, 2014)

```
#include <16f873a.h>
#device adc=10
#fuses NOWDT,BROWNOUT,XT,NOLVP,PUT
#use delay (clock=4m) 
#define use_portb_lcd true
#include <lcd.c>

void main(){
int var1=0;
float valor=0,volt=0,valor2,amper;
//Se habilita el A/D y se declara el PORT a usar
setup_adc_ports(an0_an1_an3);
setup_adc(adc_clock_div_32 ); 


//Se inicia la LCD
lcd_init();
lcd_gotoxy(3,1);
lcd_putc("iniciando");
delay_ms(2000);
lcd_gotoxy(7,2);
lcd_putc("LPK");

delay_ms(500);
lcd_putc("\f");
lcd_gotoxy(2,1);
lcd_putc("Volt Amper");
delay_ms(1000);


while (true){
set_adc_channel(0); 
delay_us(20);
{
for(var1=0;var1<8;var1++)
{
volt=volt+ read_adc();
delay_us(62);


valor = volt / 8;

valor = valor * 50 / 1023;
lcd_gotoxy(2,2);
printf(lcd_putc,"%04.2f",valor);
}

set_adc_channel(3); 
delay_us(20);
amper = read_adc();
delay_us(500);
valor2=amper*18/1023;
lcd_gotoxy(11,2);
printf(lcd_putc,"%04.3f",valor2);
delay_ms(200);

}
}
}
```
 
 Ahora lo modifiqué pero me arranca sin parar cuando toma la medición de voltaje.


----------



## cosmefulanito04 (Dic 30, 2014)

Estás matando al pobre uC con las variables flotantes. 

Acá:


```
while(1)
{
  ...
  for(var1=0;var1<8;var1++)
  {
    volt=volt+ read_adc();
    delay_us(62);
  
    valor = volt / 8;

    valor = valor * 50 / 1023;
    lcd_gotoxy(2,2);
    printf(lcd_putc,"%04.2f",valor);
  }
}
```

Debería quedarte así:


```
while(1)
{
  ...
  volt=0;
  for(var1=0;var1<8;var1++)
  {
    volt=volt+ read_adc();
    delay_us(62);  
  }

  valor = volt / 8;

  valor = valor * 50 / 1023;
  lcd_gotoxy(2,2);
  printf(lcd_putc,"%04.2f",valor);
}
```

Te recomiendo hacer un promedio móvil, para lo cual será necesario usar un vector que contenga las distintas muestras.


----------



## callecuatro1976 (Dic 30, 2014)

como seria necesito un ejemplo  de programa ya que soy medio burro con la programacion



que variables deverian ser flotantes


----------



## cosmefulanito04 (Dic 30, 2014)

Acá tenés algo en AVR, pero como es C, es lo mismo (incluso usé ese mismo código en ARM):
_ https://www.forosdeelectronica.com/posts/911848/ _
En tu caso sería hacer algo así:


```
#define MUESTRAS_MAX 16 // promedio 16 muestras
#typedef unsigned char u8;
#typedef unsigned int u16;

int main(void)
{
  u16 muestras[MUESTRAS_MAX]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; //Vector donde almacenaré las muestras => inicializo las muestras en 0.
  u8 indice_muestras=0; //Indice que irá cambiando a medida que obtenga las muestras => armo una cola circular con el vector "muestras"
  
  u16 promedio_movil=0; // Lo uso como variable que indica el resultado  
  
  float valor_resultante;
  //.... inicialización necesaria, entre ellos el ADC

  while(1)
  { 
    //.... Código de la rutina
    
    muestras[indice_muestras]=read_adc();
      
    indice_muestras++;
    if(indice_muestras==MUESTRAS_MAX) //Condición para hacer una cola circular, llegado a 16 muestras, piso el dato más viejo y lo descarto
      indice_muestras=0;
    
    promediar_datos(muestras,&promedio_movil); //Función previamente definida, acá se obtendrá el promedio móvil
               
    valor_resultante=promedio_movil;
    valor_resultante = valor_resultante * 50 / 1024;   
    lcd_gotoxy(2,2);
    printf(lcd_putc,"%04.2f",valor_resultante);

    delay_us(62); 
  }  
}
```

La función "promediar_datos" te queda igual que la del mensaje. 

De todas formas te recomiendo que un futuro, evites los delays usando timers y como en la rutina que hice en el otro mensaje, evitar el hecho de tener que imprimir el resultado toooodo el tiempo.

El promedio móvil a diferencia del promedio anterior, no descarta todas las muestras en el resultado, es decir:

- En el código anterior tomás 8 muestras y obtenés un promedio. Entre medición y medición, descartaste las 8 mediciones anteriores.

- Con este código, tomás las 8 muestras, obtenés su promedio y en la próxima medición, solo descartás 1 muestra para promediar las últimas 8 muestras.


----------



## callecuatro1976 (Ene 23, 2015)

Les hago una consulta: ¿Cómo sería el circuito si quisiera hacer el voltímetro con displays de 7 segmentos?


----------



## callecuatro1976 (Ene 24, 2015)

me pueden dar una mano con esto que quiero ver como se adapta este programa a este pic , saludos


----------



## callecuatro1976 (Ene 24, 2015)

ahora me pasaron este código pero no me funciona si me pueden dar una mano, gracias


----------



## D@rkbytes (Ene 25, 2015)

Mira este sencillo programa que puede leer hasta 60V usando el PIC16F676 (Sólo dos dígitos y un 74LS47)
Es que con ese PIC es algo complicado usar más dígitos porque cuenta con pocos pines.
Si usaras otro PIC como el PIC16F88 sería más fácil agregar más dígitos.

El código que adjunto es muy sencillo y fácil de entender, lo comenté para que entiendas lo que hace.
Tal vez te sirva o al menos te dará una idea de como hacerlo con displays de 7 segmentos.

Nota:
Los programas que has subido contienen varios errores y el código se me hace muy extenso para el fin que se le va a dar.


----------



## callecuatro1976 (Ene 25, 2015)

ok gracias voy a intentar hacerlo, estoy tratando de aprender y quiero ver distintas opciones , saludos



te consulto ya que no me encienden los display que puede ser estoy usando tu código y ejemplo


----------



## D@rkbytes (Ene 26, 2015)

callecuatro1976 dijo:


> Te consulto; ya que no me encienden los display. ¿Qué puede ser?
> Estoy usando tu código y ejemplo.


Seguramente tienes algo mal conectado.
¿Ya revisaste bien las conexiones y usando los displays correctos? Son con ánodo común.


----------



## callecuatro1976 (Ene 28, 2015)

Como decías, este pic es muy chico. Lo voy intentar hacer con el 16F883  con tres display de 7 segmentos.
Voy a empezar el código basado al que me  pasaste y lo subo. Saludos.

---------- Actualizado ----------

Consulta: ¿Cómo puedo acomodar este código para tener un voltímetro con este pic y los display de 7 segmentos?
Ya intenté de todas formas y no me anda.


----------



## D@rkbytes (Ene 28, 2015)

callecuatro1976 dijo:


> Consulta: ¿Cómo puedo acomodar este código para tener un voltímetro con este pic y los display de 7 segmentos?
> Ya intenté de todas formas y no me anda.


Ya que cambiaste de PIC por uno con más pines, ahora es más sencillo aumentar los dígitos.
Entonces mira ahora este otro ejemplo con 3 displays de 7 segmentos de cátodo común.
Obviamente la lectura ahora puede llegar hasta 999 pero la dejé en 350 para no arriesgarse tanto.
De todas formas, manejar 350V ya es peligroso y ten en cuenta que este ejemplo es tan solo didáctico.

Ahora se controlan los displays directamente y ya no se hace uso del decodificador 74LS47.


----------



## callecuatro1976 (Ene 29, 2015)

voy a ver si le puedo adaptar un display de estos pero no encuentro la hoja de datos , dicen que son igual al display de 7 segmentos


----------



## D@rkbytes (Ene 29, 2015)

callecuatro1976 dijo:


> voy a ver si le puedo adaptar un display de estos pero no encuentro la hoja de datos. Dicen que son igual al display de 7 segmentos


Sin la hoja de datos va a ser algo complicado averiguar cómo funciona esa pantalla.

Por otro lado, la idea era hacerlo con displays LED de 7 segmentos.
De usar un display LCD, pues mejor usar uno estándar 16x2 y hasta el código es más sencillo.
Aparte, con LCD no se verá tan bonito como con displays LED de 7 segmentos. 

En fin, si lo piensas hacer con esa pantalla, ya tienes tarea para rato. 

Suerte.


----------



## callecuatro1976 (Ene 29, 2015)

// Fórmulas de conversión.
      voltaje = valor_adc;
      voltaje *=400 ;               // Voltaje requerido
      voltaje /= 1023;              // División entre los bits del conversor


 modificando y poniendo el punto puedo modificar el voltaje ?
 cambiando el divisor resistivo ,  ahí lo puse para 40 volt con un divisor de 100 k y 10 k estaría bien asi??


----------



## D@rkbytes (Ene 29, 2015)

callecuatro1976 dijo:


> // Fórmulas de conversión.
> voltaje = valor_adc;
> voltaje *=400 ;               // Voltaje requerido
> voltaje /= 1023;              // División entre los bits del conversor
> ¿Modificando y poniendo el punto puedo modificar el voltaje?


Si quieres medir 40 voltios, entonces puedes usar el _ejemplo anterior_.
      Y si es para el ejemplo reciente, puedes usar esta fórmula:
voltaje = (valor_adc * 40 / 1023);
Ya se puede hacer así porque ya no existirá desborde y también puedes cambiar la variable "voltaje" a int16.
Pero te sobrará un dígito y deberás acortar el programa y modificar el diseño para eliminarlo.


callecuatro1976 dijo:


> Cambiando el divisor resistivo,  ahí lo puse para 40 voltios con un divisor de 100 k y 10 k. ¿Estaría bien así?


No. Debes calcular el divisor de tensión para que en su punto medio entregue 5V máximo con 40V de entrada.
Por ejemplo: Cambia R1 por una resistencia de 68K, R2 por 8.2K y RV2 por 3.3K
RV2 lo debes ajustar para obtener una tensión de salida lo más próxima a 5.0 voltios y sin que exceda este valor.
También para eso está el diodo Zener que evita que la tensión supere los 5.1V y así proteger al PIC.

PD: Yo veo 400 

Busca sobre divisores de tensión para que lo entiendas.


----------



## cosmefulanito04 (Ene 29, 2015)

No es dividido 1023, es 1024 que es la cantidad de niveles. 

No confundir con el nivel máximo que si es 1023, pensá que no estás incluyendo el nivel 0.


----------



## D@rkbytes (Ene 29, 2015)

cosmefulanito04 dijo:


> No es dividido 1023, es 1024 que es la cantidad de niveles.
> 
> No confundir con el nivel máximo que si es 1023, pensá que no estás incluyendo el nivel 0.


10 bits = 1111111111 = 1023

Si se realiza la división por 1024, el resultado se altera y ya no es mostrado el valor correcto.


----------



## cosmefulanito04 (Ene 29, 2015)

Insisto, 1023 es el nivel máximo, pero la cantidad de niveles son 1024, 2^10=1024.

0, 1, 2,............, 1023 => total 1024 niveles.


----------



## callecuatro1976 (Ene 29, 2015)

yo quiero medir con decimal osea que mida 14,5 13,4 uso esa formula en el ultimo ejemplo

 voltaje = (valor_adc * 40 / 1023);


----------



## cosmefulanito04 (Ene 29, 2015)

Lo importante es el nivel de cuantificación, no el nivel máximo.

Fijate, esta fórmula la saqué de la hoja de datos de un atmega8 (obviamente es universal):







Si despejás, obtenés que:

[LATEX]V_{in}=\frac{V_{Ref}.Lectura_{ADC}}{1024}[/LATEX]

Entonces si usamos una tensión de referencia de 5V, la máxima lectura que podremos hacer será:

[LATEX]V_{in}=\frac{5v.1023}{1024} \approx 4,99v[/LATEX]

Y la resolución será:

[LATEX]V_{RES}=\frac{V_{Ref}}{1024}=  \frac{5v}{1024} \approx 4,88mV[/LATEX]


----------



## D@rkbytes (Ene 29, 2015)

cosmefulanito04 dijo:


> Lo importante es el nivel de cuantificación, no el nivel máximo.


Comprendo, pero al utilizar la fórmula expuesta con el divisor 1023, se obtiene el valor deseado.
Sé que al usar la división por 1023 se obtiene un rango incompleto, pero no altera el resultado esperado.  
Ahora, me gustaría saber una cosa:
¿Utilizando el factor 1024, qué fórmula se debe usar para mostrar el valor correcto, supongamos VCC = 20V y que el resultado no muestre 1 voltio menos?


----------



## cosmefulanito04 (Ene 29, 2015)

D@rkbytes dijo:


> Comprendo, pero al utilizar la fórmula expuesta con el divisor 1023, se obtiene el valor deseado.



Se obtiene el valor "deseado" mintiendo un poco la escala. 

El ADC es capaz de medir hasta (2^(N)-1)*Vres, siempre el último escalón se le escapa.



D@rkbytes dijo:


> Sé que al usar la división por 1023 se obtiene un rango incompleto, pero no altera el resultado esperado.



En realidad lo alterás un poco modificando la resolución. 

Pero por ej. si pretendés calcular el error de cuantización y agregarle tooodos los errores que tenés en la medición, haciendo eso, estás aumentando el error de cuantización y por ende vas a obtener un equipo que mide peor.



D@rkbytes dijo:


> Ahora, me gustaría saber una cosa:
> ¿Utilizando el factor 1024, qué fórmula se debe usar para mostrar el valor correcto, supongamos VCC = 20V y que el resultado no muestre 1 voltio menos?



No, si por ej. tomamos a 20V como referencia mediante un divisor de tensión a por ej. 5v, la resolución será la siguiente:

[LATEX]V_{RES}=\frac{Att_{divisor}.V_{ref}}{1024}=\frac{4.5v}{1024} \approx 19,53 mV[/LATEX]

Entonces:

[LATEX]V_{in-max}=V_{RES}.V_{Lectura-max}\approx 19,53 mV.1023 = 19,97 V[/LATEX]

En realidad sin redondear dá 19,98...V, es decir justo el valor de la tensión de resolución, como modificaste un poco la escala, esa diferencia de tensión la tapás.


----------



## D@rkbytes (Ene 29, 2015)

OK. También comprendo ese planteamiento, pero lo que se pretende es obtener el valor exacto.
Es decir; si hay 20.0 V a medir, yo quiero obtener esa lectura, o sea, los mismos 20.0V
Entonces, si el ADC a 10 bits me entrega 1023 como máximo:
20 * 1023 = 20460
20460 / 1024 = 19.98046875
Pero: 20460 / 1023 = 20
Y ese error de 0.01953125 al usar 1024 como divisor, es lo que no me agrada.


----------



## Miembro eliminado 356005 (Ene 29, 2015)

La diferencia entre 20/1024 V y 20/1023 V es de 19 millonésimas de V, lo cual es asumible para la mayor parte de aplicaciones.

Entonces, si quieres que te dé 20 V al recibir un valor de 1023, debes partir de un valor de nivel de 20/1023 V.


----------



## cosmefulanito04 (Ene 30, 2015)

Lo que debe quedar claro es que no vas a obtener el valor real en toda la escala y si vas a poder informar sobre esa tension final.

Y empeorás un poco la calidad de la medición aumentando el error de cuantización en una cuenta.

Por ej es como los multímetros y su fondo de escala, los que tienen por decir algo... 2000 cuentas, solo son capaces de medir hasta 1999 antes de pasar a otra escala, es decir a fondo de escala te informa por ej. 1,999 v.

Una cosa que  se me pasó, está mal decir que "esta es la medición correcta" (o real como puse antes) como si fuera la definitiva, en realidad se debería hablar de "la medición más probable".


----------



## D@rkbytes (Ene 30, 2015)

cosmefulanito04 dijo:


> Lo que debe quedar claro es que no vas a obtener el valor real en toda la escala y si vas a poder informar sobre esa tensión final.
> 
> Y empeorás un poco la calidad de la medición aumentando el error de cuantización en una cuenta.
> 
> Por ej es como los multímetros y su fondo de escala, los que tienen por decir algo... 2000 cuentas, solo son capaces de medir hasta 1999 antes de pasar a otra escala, es decir a fondo de escala te informa por ej. 1,999 v.


OK. Ahora si ya me quedó algo más claro lo que mencionas.
Sin embargo, no se nota mucho la variación, sino hasta que se llega al máximo.
Ahí es cuando yo quería ver el mismo voltaje máximo de la lectura.

Realicé unas pruebas en físico y las lecturas obtenidas con el divisor 1024 no fueron cercanas al voltaje de entrada que se estaba midiendo. (Estableciendo un máximo de 10 V.)
Variando el voltaje de entrada, desde 0 a 5 V, el valor más próximo comparando la lectura con un multímetro Fluke, siempre fue con el divisor 1023. 

Anteriormente ya había realizado este tipo de prueba, y por ese motivo siempre me convenció más dividir entre 1023.
Sea o no sea lo adecuado, lo interesante es que el resultado se aproxima más al esperado.

Dejo 4 fotos.


----------



## Miembro eliminado 356005 (Ene 30, 2015)

Si te interesa más obtener el valor límite, puedes modificar el cálculo así:

delta = 20 V / 1024;   // 2^10 bits del ADC

y luego, en la lectura de los valores:

Vadc = delta * (ADC()+1);

Con esto, al llegar ADC() a 1023, y sumarle 1, permitimos que con delta lleguemos a un valor de Vadc igual al máximo.

Pero... el problema se traslada al 0: nos dará que siempre hay un valor de unos mV.

Hay otras formas de hacerlo, pero según la documentación, estos chip tienen un error de 1/2 LSB (el bit menos significativo). Según la función de transferencia, si el valor de paso es *1 LSb = Vref/1024*, el paso a 1023 se produce en el momento que la tensión esté entre el valor de 1023 LSb a 1023.5 LSb.

Eso quiere decir que el valor de 1023, realmente no indica que Vadc ha llegado a Vref, sino al valor anterior. Si Vadc = Vref, sigue mostrando 1023.

Eso quiere decir que el ADC nunca nos dará un valor 1024. Es entonces una convención nuestra el decidir que 1023 realmente indica que hemos llegado a Vref.


----------



## callecuatro1976 (Ene 30, 2015)

callecuatro1976 dijo:


> yo quiero medir con decimal osea que mida 14,5 13,4 uso esa formula en el ultimo ejemplo
> 
> voltaje = (valor_adc * 40 / 1023);



como modifico el código para que mida con coma?


----------



## cosmefulanito04 (Ene 30, 2015)

Lindo multímetro... .

Si entendí bien, mediste en todo el rango y siempre daba más cercano usando el factor de 1023, ¿cómo es la tensión de referencia? (tal vez esté un poco desplazada).



callecuatro1976 dijo:


> como modifico el código para que mida con coma?



¿Cuánto sería el valor máximo que pensas medir?, ¿40V?

Si es así, tenés dos formas:

1- Usar flotantes como venías haciendo y simplemente a la hora de imprimir el resultado se agregan esos dos decimales.

2- Usar "unsigned long int" para trabajar con decimales fijos, entonces solo se modifica esto:


```
voltaje = (valor_adc * 40*100) / 1024;
```

Pero como ahora trabajas con enteros, se puede usar desplazamientos en vez de divisiones y el uC "sufre" menos:


```
voltaje = (valor_adc*40*100);
voltaje=(voltaje>>10);
```

Ese (voltaje>>10) equivale a dividir por 1024, pero al uC le resulta mucho más sencillo hacerlo. Como resultado te quedará un número de este tipo, ej:

valor_adc=100 => voltaje=390 => será equivalente a 3,90v
valor_adc=500 => voltaje=1953 => será equivalente a 19,53v
... etc


----------



## D@rkbytes (Ene 30, 2015)

JoaquinFerrero dijo:


> Si te interesa más obtener el valor límite, puedes modificar el cálculo así:
> 
> delta = 20 V / 1024;   // 2^10 bits del ADC
> 
> ...


Algo similar ocurre con el divisor 1024, también quedan algunos milivoltios en vez del 0.



cosmefulanito04 dijo:


> Si entendí bien, mediste en todo el rango y siempre daba más cercano usando el factor de 1023, ¿cómo es la tensión de referencia? (tal vez esté un poco desplazada).


Utilicé la siguiente configuración:

ADCON1:
Bit 7 ADFM: A/D Conversion Result Format Select bit
1 = Right justified <--- Esta selección.
0 = Left justified

Bit 5 VCFG1: Voltage Reference bit
1 = VREF- pin
0 = VSS <--- Esta selección.

Bit 4 VCFG0: Voltage Reference bit
1 = VREF+ pin
0 = VDD   <--- Esta selección.

Entonces viene quedando como VRef = VSS_VDD (Rango: 0V a 5V)
De esta forma en el PIC, no se usan los pines VRef- y VRef+ utilizando me supongo, una referencia interna y quedan disponibles éstos pines como otras entradas análogas.


cosmefulanito04 dijo:


> Lindo multímetro...


Gracias.


----------



## callecuatro1976 (Ene 30, 2015)

esto es mas difícil de lo que pensé la verdad que la tienen clara! estoy tratando de medir con coma con los 3 dígitos pero no se que pasa!


----------



## cosmefulanito04 (Ene 30, 2015)

D@rkbytes dijo:


> Utilicé la siguiente configuración:
> 
> ADCON1:
> Bit 7 ADFM: A/D Conversion Result Format Select bit
> ...



Es decir, usás referencia interna que suele ser muy mala en todos los uC (para aclarar), o por lo menos en los AVR dejan mucho que desear.

¿La tensión en Vdd es 5,01v?


----------



## D@rkbytes (Ene 30, 2015)

cosmefulanito04 dijo:


> Es decir, usás referencia interna que suele ser muy mala en todos los uC (para aclarar), o por lo menos en los AVR dejan mucho que desear.


Así es. También utilicé referencia externa, pero el resultado fue el mismo porque la fórmula toma como base 10.0V.
Entonces vRef lo tenía que poner en 5V para que realizara la lectura correctamente sin que me diera el resultado máximo antes de llegar a 10V en la entrada.


cosmefulanito04 dijo:


> ¿La tensión en Vdd es 5,01v?


Si. El microcontrolador tiene un regulador 7805 y el multímetro mide 5.01V.
Para el voltaje a medir, usé una fuente variable.


----------



## Miembro eliminado 356005 (Ene 30, 2015)

callecuatro1976 dijo:


> esto es mas difícil de lo que pensé la verdad que la tienen clara! estoy tratando de medir con coma con los 3 dígitos pero no se que pasa!


En la línea 40 tienes

```
voltaje *= 350;               // Voltaje requerido
```
Si voltaje (que contiene al principio el valor del ADC), tiene un valor, por ejemplo, de 1023, quedaría

voltaje = 1023 * 350 = 358 050

y esa cifra... no cabe en 16 bits, que es como lo que tienes definida la variable voltaje.

Yo lo haría así:

```
unsigned int16 voltaje;

        ....

    voltaje   = read_adc();    // leer valor del ADC
    voltaje  *= 35;        // escalado según Vref
    voltaje >>=  8;        // ajuste
    voltaje  *=  5;
    voltaje >>=  1;
```


----------



## cosmefulanito04 (Ene 30, 2015)

D@rkbytes dijo:


> Así es. También utilicé referencia externa, pero el resultado fue el mismo porque la fórmula toma como base 10.0V.
> Entonces vRef lo tenía que poner en 5V para que realizara la lectura correctamente sin que me diera el resultado máximo antes de llegar a 10V en la entrada.
> 
> Si. El microcontrolador tiene un regulador 7805 y el multímetro mide 5.01V.
> Para el voltaje a medir, usé una fuente variable.



Perfecto, entonces si usamos las mediciones como referencia, en realidad está mal usar 5v como Vref y deberías usar 5,01v, como consecuencia de eso, el valor arrojado en la medición de 2,506v usando 1024 es más cercano que el valor arrojado por 1023.

Es decir, para aislarnos de las cuentas sería más útil conocer el nivel que lee el ADC, de no equivocarme debe ser cercano a 513 cuentas.

En base a eso:

[LATEX]V_{in}=\frac{5,01v.513cuentas}{1024cuentas}=2,509...v[/LATEX]

[LATEX]V_{in}=\frac{5,01v.513cuentas}{1023cuentas}=2,512...v[/LATEX]

Si me baso en tus resultados, la lectura del ADC pareciera que dá 509, ¿podrías confirmar eso?


----------



## callecuatro1976 (Ene 30, 2015)

me da un error de adc 0x00a8


----------



## Miembro eliminado 356005 (Ene 30, 2015)

Ese error no me dice nada... ¿Es un error de compilación o en ejecución?


----------



## callecuatro1976 (Ene 30, 2015)

cuando lo ejecuto en el proteus me manda como 2000 mensajes de error de adc y no para de mandar mensajes


----------



## Miembro eliminado 356005 (Ene 30, 2015)

Pues hemos metido la pata en algún sitio.

Puedes intentar ejecutarlo paso a paso, o ir comentando líneas hasta averiguar cuál es la que hace provocar el fallo.


----------



## D@rkbytes (Ene 30, 2015)

cosmefulanito04 dijo:


> Perfecto, entonces si usamos las mediciones como referencia, en realidad está mal usar 5v como Vref y deberías usar 5,01v, como consecuencia de eso, el valor arrojado en la medición de 2,506v usando 1024 es más cercano que el valor arrojado por 1023.
> 
> Es decir, para aislarnos de las cuentas sería más útil conocer el nivel que lee el ADC, de no equivocarme debe ser cercano a 513 cuentas.
> 
> ...


OK. Bueno, la tensión de referencia al ser interna, entonces ya queda en 5.01V.
Ahora tomando como base una lectura de 5V máximo, la fórmula la realicé así:
voltaje = (5.01 * valor_adc / 1024);

El resultado para 2.5V fue: ADC = 511 y V = 2.500
Y para 5.0V fue: ADC = 1022 y V = 5.000

De esta forma ahora los resultados si fueron certeros.
¿Entonces está bien sumar el 0.01 en la fórmula? Pues así fue como funcionó bien.
Así también se obtuvo 0 en la lectura con 0V en la entrada.


----------



## cosmefulanito04 (Ene 30, 2015)

D@rkbytes dijo:


> ¿Entonces está bien sumar el 0.01 en la fórmula? Pues así fue como funcionó bien.



Si, pensá que el ADC no distingue la tensión que le metés, él solo compara la tensión de entrada contra la Vref/1024. Claro que uno nunca se toma ese trabajo de calibrar esa tensión con un buen instrumento y en realidad lo que si debería hacer es propagar los errores del 7805 y los del ADC en la medición final, de esta forma te cubrís.

Sobre el 0v, deberías haberlo obtenido en las dos mediciones previas independientemente del factor que uses (ya sea 1024, 1023 o 5v, 5,01v), es posbile que el nivel del ADC no llegara a la cuenta 0 y por eso te arrojaba un valor mayor. Hay que tener en cuenta que no siempre las mediciones son repetibles.


----------



## D@rkbytes (Ene 30, 2015)

cosmefulanito04 dijo:


> Si, pensá que el ADC no distingue la tensión que le metés, él solo compara la tensión de entrada contra la Vref/1024. Claro que uno nunca se toma ese trabajo de calibrar esa tensión con un buen instrumento y en realidad lo que si debería hacer es propagar los errores del 7805 y los del ADC en la medición final, de esta forma te cubrís.








Don Cosme, pues muchas gracias por la explicación, igualmente a Joaquín.
Ahora con esta información ya tendré en cuenta este importante detalle.

Saludos.​


----------



## callecuatro1976 (Ene 31, 2015)

(pic16adc)pc=0x00a8.adc conversión started before "wait"time has expired following previus conversión or cannel change

 este es el mensaje que me tira


----------



## Miembro eliminado 356005 (Ene 31, 2015)

O sea... que estás intentando leer el ADC sin haber esperado el tiempo suficiente a que terminara de hacer la conversión...

Debes hacer una espera, mirando por el bit que indica final de conversión.


----------



## callecuatro1976 (Ene 31, 2015)

delay_us(50);

 solución después de la medición


----------



## Miembro eliminado 356005 (Ene 31, 2015)

Yo lo pondría *antes* de la medición. 

De esa manera presento inmediatamente el resultado de la conversión (aunque... también es cierto que 50 µs es muy poco tiempo de espera para el usuario).


----------



## callecuatro1976 (Feb 3, 2015)

anda muy bien con los led de 7seg ahora consulta  como puedo hacer para que la medición sea mas lenta y no se mueva tanto el ultimo digito.


----------



## Miembro eliminado 356005 (Feb 3, 2015)

Bucles de espera... por ejemplo.


----------



## cosmefulanito04 (Feb 3, 2015)

callecuatro1976 dijo:


> anda muy bien con los led de 7seg ahora consulta  como puedo hacer para que la medición sea mas lenta y no se mueva tanto el ultimo digito.



Usá la función de promedio móvil que te pasé y aumentale la cantidad de muestras hasta alcanzar la óptima.


----------



## callecuatro1976 (Feb 4, 2015)

Puse así el ejemplo. ¿Está bien así?
Me quedan parpadeando los dos últimos números.


----------



## Miembro eliminado 356005 (Feb 4, 2015)

Pero... ¿esto qué es?

```
valor_adc=0; 
for(var1=0;var1<500;var1++) 
{ 
    valor_adc=valor_adc+ read_adc(); 
    delay_us(62);   
}
```
Esto solo sirve para perder el tiempo. El valor almacenado en valor_adc no se usa en el resto del bucle. El único efecto que veo es que hay una espera de 500 * 62 µs = 31 ms. Si a esa espera le sumamos el resto de retrasos, nos sale que los _display_ se repintan unas 30~31 veces por segundo, así que es normal ver que parpadean.

Otra cosa... yo haría la extracción de los dígitos de otra manera:


```
// Obtener el valor para cada dígito a partir de la tabla para 7 segmentos.
	centenas = voltaje / 100;
	voltaje  = voltaje % 100;
	decenas  = voltaje / 10;
	voltaje  = voltaje % 10;
	unidades = voltaje;

	unidades = tabla_7segs[unidades];
	decenas  = tabla_7segs[decenas ];
	centenas = tabla_7segs[centenas];

	// Multiplexar los displays. 
	output_b(1);            // Activar display 1 y desactivar display 2 y 3 
	output_c(unidades);     // Mostrar unidades. 
	delay_ms(2);            // Retardo para mostrar las unidades. 
	output_b(2);            // Activar display 2 y desactivar Display 1 y 3 
	output_c(decenas);      // Mostrar decenas. 
	delay_ms(2);            // Retardo para mostrar las decenas. 
	output_b(4);            // Activar display 3 y desactivar Display 1 y 2 
	output_c(centenas);     // Mostrar las centenas. 
	delay_ms(2);            // Retardo para mostrar las centenas.
```


----------



## D@rkbytes (Feb 6, 2015)

Logré separar el número para mostrar el valor en 4 displays de 7 segmentos de una forma sencilla.

```
void entero_a_bcd(int16 valor, int8 digitos_menos_1)
{
int8 i;
   // Limpiar variables del arreglo "display[]".
   for(i=0;i<=digitos_menos_1;i++)
   {
      display[i] = 0;
   }

   i = digitos_menos_1;
   // Separar los números.
   while (valor > 0)
   {
      display[i--] = (valor % 10);
      valor /= 10;
   }
}
```
Se utiliza un arreglo global para almacenar el valor separado de cada dígito y el formato mostrado es con 2 decimales.

El programa funciona perfectamente durante simulación, pero no lo probé físicamente.
También lo realicé usando una referencia externa de 2.5V con un TL431, modificando el divisor de entrada y la fórmula.
El resultado también fue satisfactorio y al parecer mejor que usando la referencia interna.

Adjunto el proyecto como un aporte, agradeciendo a Cosme y a Joaquín por la colaboración al tema.

Notas:


En el programa adjunto se está usando la referencia interna del CAD por simplicidad y es una base que puede servir para realizar programas de este tipo.


El programa puede medir hasta 99V y se ha dejado en los 40V que se han venido tratando en este tema.
Es muy sencillo cambiar el rango. Solo se debe especificar el voltaje (<99.00) y modificar el divisor.


El programa está comentado y basado en un PIC16F887, pero se pueden usar otros, p.e, un PIC16F88.


----------



## callecuatro1976 (Feb 21, 2015)

hola, que habría que cambiar para hacerlo con display de ánodo común, saludos


----------



## D@rkbytes (Feb 21, 2015)

Los valores de la tabla para displays de 7 segmentos e invertir los bits de activación de cada display. (Incluyendo el punto)


----------



## callecuatro1976 (Feb 22, 2015)

es bastante lio yo porque tenia un par de display de ánodo común y quería ver como usarlos , saludos


----------



## Lord Chango (Feb 22, 2015)

callecuatro1976 dijo:


> es bastante lio yo porque tenia un par de display de ánodo común y quería ver como usarlos , saludos



Calculo que solamente complementando las variables seria suficiente, pero cambiar un par de valores no parece tanto lio...


----------



## D@rkbytes (Feb 23, 2015)

callecuatro1976 dijo:


> Es bastante lio, porque tenía un par de display de ánodo común y quería ver como usarlos.


No es ningún problema. El programa tiene una tabla con los valores del 0 al 9 para displays de cátodo común.
O sea, esta: *{0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};*
El primer número en hexadecimal: 3F es el 0, el 06 es el 1, el 5B es el 2, etc.
Necesitas cambiarlos por los que serían para ánodo común:
El 0 sería: 0xC0, el 1 sería: 0x9F, el 2 sería: 0xA4, etc.

Y también se necesita invertir la activación de los displays.
Si para cátodo común, el bit 0 corresponde al display 4 (LSB) activado por 1 lógico que después de usar un transistor NPN se obtendrá un 0 por colector para el cátodo.
Entonces invirtiendo este bit, tendríamos que el puerto B tendría la siguiente secuencia (LSB a MSB):
Display unidades = 0b11111110 "0xFE"
Display decenas = 0b11111101 "0xFD"
Display centenas = 0b11111011  "0xFB"
Etcétera.

Y lo haces con output_b(valor); Por ejemplo: output_b(0xFE);
Así se obtendrá un 0 como bit de activación para un transistor PNP por display de ánodo común.
Éste deberá dar un 1 por colector, ya que el emisor deberá estar hacia VCC.
Y también se debe invertir la activación y desactivación del punto.

Lo ves. No es ningún lio.


----------



## callecuatro1976 (Feb 23, 2015)

Ok. Empiezo a ver que puedo hacer y pido ayuda. Gracias.


¿Dónde encuentro la tabla hex con los valores para ánodo común?

 Encuentro para cátodo común por todos lados.


----------



## ricbevi (Feb 23, 2015)

callecuatro1976 dijo:
			
		

> donde encuentro la tabla hex con los valores para anodo común?
> 
> encuentro catodo común por todos lados



Hola...Lo tienes que hacer como te explico correctamente D@rkbytes en _esta_ respuesta.
Saludos.

Ric,


----------



## callecuatro1976 (Feb 23, 2015)

0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x98 anodo común seria asi 

0b11000000, 0b11111001, 0b10100100, 0b10110000, 0b10011001, 0b10010010, 0b10000010, 0b11111000, 0b10000000, 0b10011000


----------



## D@rkbytes (Feb 23, 2015)

Los bits para el número nueve están mal. Es: "10010000" = 0x90
Se vería mejor de esa forma:

Mira por aquí: *PIC To 7 Segments*

Con ese programa puedes generar fácilmente los bits para la tabla de displays de 7 segmentos.


----------



## juanc08 (Mar 1, 2015)

Buen día, amigo D@rkbytes.
Hace tiempo monté este circuito del amigo Jorge Ansuini, doy crédito porque no es de mi autoría el circuito y funciona muy bien.
Ahora me gustaría saber si se puede hacer que este voltímetro mida el voltaje de su propia fuente para medir el voltaje de la batería de mi carro sin alimentar el pic con otra funte.
Te agradezco la luz que me puedas brindar.


----------



## D@rkbytes (Mar 2, 2015)

Tendrías que poner un divisor de tensión y modificar algo el programa.
El divisor debe entregar 5 voltios cuando se tenga el máximo voltaje de entrada.

En ese programa se usa una suma para obtener un valor final y luego se separa para obtener cada dígito.
Ahí es donde tendrías que usar otro método para leer por ejemplo, 20 voltios máximo.

¿Por qué no usas el proyecto del _post #127_ y lo adaptas?
Es más sencillo que modificar el programa que adjuntas y aparte muestra los decimales separados por punto.


----------



## juanc08 (Mar 2, 2015)

D@rkbytes dijo:


> Tendrías que poner un divisor de tensión y modificar algo el programa.
> El divisor debe entregar 5 voltios cuando se tenga el máximo voltaje de entrada.
> 
> En ese programa se usa una suma para obtener un valor final y luego se separa para obtener cada dígito.
> ...



muchas gracias por tu respuesta


----------



## callecuatro1976 (Abr 11, 2015)

hola foristas ando con un pequeño problema que me enrede y no se como seguir quiero modificar el programa de d@rkbyte de catodo común a anodo común y me quede aca no me funciona bien , que es lo que estoy haciendo mal , saludos


----------



## D@rkbytes (Abr 11, 2015)

callecuatro1976 dijo:


> Quiero modificar el programa de D@rkbytes de cátodo común a ánodo común y me quedé acá. No me funciona bien. ¿Qué es lo que estoy haciendo mal?


Cambia la rutina para multiplexar los displays por esta otra:

```
output_b(0xFE);   // Activar display 1 y desactivar display 2 y 3
      output_c(tabla_7segs[display[3]]);  // Mostrar unidades.
      delay_ms(1);   // Retardo para mostrar las unidades.
      output_b(0xFD);   // Activar display 2 y desactivar Display 1 y 3
      output_c(tabla_7segs[display[2]]);  // Mostrar decenas.
      delay_ms(1);   // Retardo para mostrar las decenas.
      output_b(0xFB);   // Activar display 3 y desactivar Display 1 y 2
      output_c(tabla_7segs[display[1]]);  // Mostrar las centenas.
      output_low(punto);  // Apagar el punto.
      delay_ms(1);   // Retardo para mostrar las centenas.
      output_b(0xF7);
      output_c(tabla_7segs[display[0]]);  // Mostrar los millares.
      output_high(punto);   // Encender el punto.
      delay_ms(1);
```
PD:
Ya encontré la forma para mejorar la transición de los decimales.


----------



## callecuatro1976 (Abr 12, 2015)

¿Los transistores coloco PNP y el resto lo dejo igual que en la simulación?

Consulta: ¿Cómo controlo por PWM un mosfet para hacer una fuente?


----------



## D@rkbytes (Abr 12, 2015)

Si. Pero recuerda que ahora debes colocar los emisores hacia positivo y los colectores hacia los ánodos de los displays.

La segunda pregunta no la entendí. ¿Podrías explicarlo mejor?


----------



## callecuatro1976 (Abr 12, 2015)

Estoy haciendo una fuente pequeña le voy a colocar el voltimetro con display de 7 segmentos y queria controlar con el pic un transistor para hacer la fuente y subir y bajar el voltaje con dos pulsadores no se si se puede. Saludos


----------



## D@rkbytes (Abr 12, 2015)

Para lo que quieres hacer se necesita algo más complejo, porque el voltaje a la salida del transistor será pulsante y no te servirá como fuente de corriente continua.
Mira este enlace en donde se muestra como hacer una fuente de poder digital.


----------



## callecuatro1976 (Abr 13, 2015)

ok si es pulsante podría poner un mosfet, también pienso como llegar a los 18 volt ya que con el pic solo saldría 5 volt como máximo tendría que amplificar con un operacional mmmm bastante complicado para mi , saludos


----------



## callecuatro1976 (Abr 16, 2015)

hola me regalaron un lcd gdm12864h un lcd grafico es muy difícil pasar el programa del voltimetro con lcd a este lcd y hacerlo con caracteres grandes , saludos


----------



## callecuatro1976 (Abr 17, 2015)

hola quería si pueden darme una mano con este voltimetro que no se como poner el adc para el display 128x64


----------



## MrCarlos (Abr 17, 2015)

Hola callecuatro1976

En el Código hay algo por mejorar. Se trata del nombre que le das a una variable.
Aunque esto parece no solucionar el problema pero en el Display ya se ve algo.

saludos
a sus ordenes


----------



## callecuatro1976 (Abr 19, 2015)

Ya lo mejoré un poco. Pude tomar las dos mediciones, pero me parpadea la pantalla. ¿Qué puede ser?


----------



## D@rkbytes (Abr 19, 2015)

D@rkbytes dijo:


> Ya encontré la forma para mejorar la transición de los decimales.


Aquí adjunto el programa con los cambios para lograr una lectura más estable.

Mejoras realizadas:


ADC a 16 Bits.
Uso del Timer 1 para realizar la lectura del conversor.
Voltaje de referencia externo en 2.5 V. con un C.I. TL431.
Notas:
Proyecto probado y funcionando físicamente con 4 displays de cátodo común.
Si se desea usar displays de ánodo común, en posts anteriores de ha dicho como realizar el cambio.


----------



## MrCarlos (Abr 19, 2015)

Hola callecuatro1976

Tal vez parpadea la pantalla porque el código le faltan algunas mejoras.
Viste los Avisos que se generan al correr la simulación ??

Hice algunos cambios en tu código y reacomodé todo en la simulación de ISIS de Proteus.
Yo no se mucho de programación pero Tú, de alguna manera, debes modificar tu código para que no se borren los letreros *Volts* y *Ampers* en el Display. Tan solo borra las lecturas anteriores e imprime las nuevas, no importa que tengan el mismo valor.

Te adjunto tu código y el archivo de ISIS de Proteus Modificados.

saludos
a sus ordenes


----------



## callecuatro1976 (Abr 30, 2015)

Una consulta arme el voltimetro lcd y funciona bien uso el lcd gdm1602a y anda perfecto ahora quiero usar el gdm1602s de caracteres grande y solo me muestra una línea y todos los cuadraditos y nada mas que puede ser


----------



## ricbevi (Abr 30, 2015)

callecuatro1976 dijo:


> Una consulta arme el voltimetro lcd y funciona bien uso el lcd gdm1602a y anda perfecto ahora quiero usar el gdm1602s de caracteres grande y solo me muestra una línea y todos los cuadraditos y nada mas que puede ser



Hola...Generalmente eso indica una falta de conexión con el micro-controlador. Puede ser por error de conexiones o por incompatibilidad de algún tipo. Aparentemente son similares.
Saludos.

Ric.


----------



## AleSergi (Abr 30, 2015)

D@rkbytes dijo:


> Aquí adjunto el programa con los cambios para lograr una lectura más estable.
> 
> Mejoras realizadas:
> 
> ...



el 16F887, ¿no tiene un ADC de 10bits de máxima resolución?


----------



## D@rkbytes (May 1, 2015)

Si. Obtener una lectura de 16 bits es una característica del PIC C Compiler.


----------



## callecuatro1976 (May 11, 2015)

consulta estoy pasando el voltímetro a un lcd de 1 línea y me escribe solo la mitad 8 caracteres??? porque es eso


----------



## ricbevi (May 11, 2015)

callecuatro1976 dijo:


> consulta estoy pasando el voltímetro a un lcd de 1 línea y me escribe solo la mitad 8 caracteres??? porque es eso



Hola...Puede ser problema de compatibilidad de como trata el compilador la linea y el LCD que estas usando...alguna ves tuve ese tipo de problemas y lo considere como si fuera de dos lineas de 8 caracteres cada una y funciono.
Saludos.

Ric.


----------



## callecuatro1976 (May 11, 2015)

si es asi hay que hacerlo como si fuera de dos líneas, el que no puedo hacer andar el el de carácter grande no le encuentro la vuelta es un gdm1602s de xiamen ocular. saludos


----------



## callecuatro1976 (May 30, 2015)

consulta estoy armando el voltímetro de 7 segmentos ánodo común con la rutina de darkbytes y en el simulador me funciona pero cuando armo en la placa se ven todos 8888 y muy rápido como muestro mas lenta la lectura, gracias por el tiempo


----------



## D@rkbytes (May 30, 2015)

callecuatro1976 dijo:


> Estoy armando el voltímetro de 7 segmentos ánodo común con la rutina de D@rkbytes


¿Cuál rutina?


callecuatro1976 dijo:


> En el simulador me funciona, pero cuando armo en la placa se ven todos 8888 y muy rápido.


Deberías dar más información, porque no podemos ver tu circuito.
Adjunta algunas fotos y un esquema de las conexiones que estás realizando.


callecuatro1976 dijo:


> ¿Cómo muestro más lenta la lectura?


Ya adjunté un programa sobre como lograr eso en el _post #151_



D@rkbytes dijo:


> Notas:
> Proyecto probado y funcionando físicamente con 4 displays de cátodo común.
> Si se desea usar displays de ánodo común, en posts anteriores se ha dicho como realizar el cambio.


----------



## mauroposada (Ene 11, 2016)

disculpa la ignorancia, estoy en aprendisaje  viendo bastantes videos de programacion quiero armar un voltimetro de tres digitos con un pic 18f2550 , que debo de cambiar en el programa para este pic gracias saludos.


----------



## D@rkbytes (Ene 11, 2016)

Debes quitar las variables y rutinas que hacen referencia al cuarto display o dígito.
Y ver que tipo de oscilador usarás para el 18F2550 para configurar los fuses.


----------



## mauroposada (Ene 11, 2016)

¿Para quitar el cuarto dígito tendría q*ue* borrar.   output_c(tabla_7segs[display[0]]);  // Mostrar los  millares.?

Pido de  tu gran ayuda .

```
#include <18f2550.h>
#device  adc = 10
#fuses   nowdt,hs, put
#use     delay(crystal = 20MHz)
#use     fast_io(d)

#define  punto pin_c7

// Arreglo para las variables de los dígitos.
int8 display[3] = {0,0,0};
float valor_adc;

void entero_a_bcd(int16 valor,int8 digitos_menos_1);


// Tabla para displays de 7 segmentos cátodo común.
int8 const tabla_7segs[10] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};

#INT_TIMER1
// Servicio de interrupción por desborde del Timer 1
void sdi_timer1 (void)
{
   // Realizar la lectura del conversor análogo a digital.
   valor_adc = ((40.0 * read_adc()) / 65536);
   set_timer1(0xBDC);               // Recargar el Timer 1
}

void main (void)
{
   int16 voltaje;

   set_tris_d(0b11110000);
   
   enable_interrupts(INT_TIMER1);
   setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);
   set_timer1(0xBDC); // Cargar el timer1 con 3036 (500Ms. Aprox. 0.001% Error)
   enable_interrupts(GLOBAL);
   setup_adc_ports(sAN0|VREF_VREF); // Seleccionar canal 0 y usar VRef = 2.5V
   setup_adc(ADC_CLOCK_INTERNAL);   // Reloj ADC = interno
   set_adc_channel(0);              // Establecer el canal 0
   delay_us(50);
      
   while (true)
   {  
      // Multiplicar por 100 el valor de "valor_adc"
      voltaje = (valor_adc * 100);
      // Obtener el valor para cada dígito, separando el número
      // y convirtiéndolo con la tabla para displays de 7 segmentos.
      entero_a_bcd(voltaje,3);
      
      // Multiplexar los displays. (Con 4 ms se consiguió menor transición en las unidades)
      output_d(1);   // Activar display 1 y desactivar display 2 y 3
      output_c(tabla_7segs[display[3]]);  // Mostrar unidades.
      delay_ms(2);   // Retardo para mostrar las unidades.
      output_d(2);   // Activar display 2 y desactivar Display 1 y 3
      output_c(tabla_7segs[display[2]]);  // Mostrar decenas.
      delay_ms(2);   // Retardo para mostrar las decenas.
      output_d(4);   // Activar display 3 y desactivar Display 1 y 2
      output_c(tabla_7segs[display[1]]);  // Mostrar las centenas.
      output_high(punto);  // Apagar el punto.
      delay_ms(2);   // Retardo para mostrar las centenas.
      output_d(8);
      output_c(tabla_7segs[display[0]]);  // Mostrar los millares.
      output_low(punto);   // Encender el punto.
      delay_us(700);
   }
}

// Subrutina para separar el número.
void entero_a_bcd(int16 valor, int8 digitos_menos_1)
{
int8 i;
   // Limpiar variables del arreglo "display[]".
   for(i=0;i<=digitos_menos_1;i++)
   {
      display[i] = 0;
   }

   i = digitos_menos_1;
   // Separar los números.
   while (valor > 0)
   {
      display[i--] = (valor % 10);
      valor /= 10;
   }
}
```
Intenté con este PIC pero hay algo malo, no funciona bien.
¿Me pueden colaborar?

Gracias. Saludos.


----------



## D@rkbytes (Ene 12, 2016)

mauroposada dijo:


> ¿Para quitar el cuarto dígito tendría q*ue* borrar.   output_c(tabla_7segs[display[0]]);  // Mostrar los  millares.?


Son más cosas las que se tienen que modificar, pero sin conocimientos de programación, te resultará complicado.

Adjunto el programa en C (PIC C Compiler) y simulación (Proteus v7.10) con los cambios necesarios.

Suerte.


----------



## mauroposada (Ene 12, 2016)

*H*ombre, de ante mano muchas gracias por su gran colaboración.
*E*stoy luchando para eso*,* para tener conocimiento*,* y estoy empezando.
*M*e dedico a la eléctricidad automotriz.

*U*na pregunta*.* *¿*Para su experiencia*,* q*ué* debo de seguir variando para un buen funcionamiento en físico*?
Y*o lo seguiré acondicionando*.* *S*aludos.

*E*n la simulación trabaja muy bien, sólo faltan milésimas en algunas ten*s*iones,  pero lo veo muy bien*.

*


----------



## D@rkbytes (Ene 12, 2016)

Un buen plano de tierra en el circuito impreso.
Fuente de alimentación estable a 5V y bien filtrada.
Componentes de calidad, sobre todo en el divisor de tensión y voltaje de referencia.

Como son tres dígitos, no se puede obtener más resolución.


----------



## mauroposada (Ene 12, 2016)

A ok, muchas gracias saludos.


----------



## analexacastillovazquez (Abr 1, 2016)

Buenas. No sé si ya han hablado de esto.
Aunque estuve viendo la conversación, no leí las nueve páginas porque al parecer hablan de programar el PIC en C, y yo tengo muchos problemas.

Es con ensamblador y no sé si me pueden ayudar.
Es que no soy muy ducha con ese lenguaje, por el momento no sé cómo conectar un LCD al propio conversor con la utilización de ASCII, puesto que no tengo ni idea de como llevar los resultados del mismo a este código.

Esto es lo que tengo por el momento:

```
List        p=16f887    ; list directive to define processor
    #include    <p16f887.inc>    ; processor specific variable definitions

    __CONFIG    _CONFIG1, _LVP_OFF & _FCMEN_ON & _IESO_OFF & _BOR_OFF & _CPD_OFF & _CP_OFF & _MCLRE_ON & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT
    __CONFIG    _CONFIG2, _WRT_OFF & _BOR21V
 ;    __CONFIG _CONFIG1, 2007h; LAS PALABRAS DE CONFIGURACION DE ARRIBA EN HEXA
    ;__CONFIG _CONFIG2,  2008h


    CBLOCK 20H
       RESULTHI, RESULTLO, DATO, DATO1        ;variables del conversor
    ENDC
    
    CONT1    EQU 0x20        ;variables del lcd
    CONT2    EQU 0x21
    
       
    
    ORG 0X00    ;INICIO

       BANKSEL OSCCON
    MOVLW    b'11101000'        ; Oscilador interno estable a 8MHz.
        MOVWF    OSCCON
    
    
    
   ;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    ;%%%%%%%%%%%%%%%%CONVERSOR ANALOGICO A DIGITAL%%%%%%%%%%%%%%%%%%
  ;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

     ;///////////ASIGNACION DE VOLTAJES DE REFERENCIA////////////////
    BANKSEL ADCON1        ; SELECCIONAR BANCO DONDE SE ENCUENTRA ADCON1
    MOVLW B'10000000'   ;
    MOVWF ADCON1    ; ESTABLECER BITS JUSTIFICADO A LA DERECHA


    ;//////////CONFIGURAR MODULO ADC//////////////
    BANKSEL ADCON0        ; SELECCIONAR BANCO
    MOVLW B'10000000'
    MOVWF ADCON0    ; ESTABLECER BITS DE CONFIGURACION DE RELOJ 4uS FOSC/32



    BANKSEL ANSEL
    BSF ANSEL,0    ; ESTABLECER PUERTO RA0 COMO ANALOGICO
    BANKSEL TRISA
    BSF TRISA,0    ; ESTABLECER PUERTO RA0 COMO ENTRADA
    
    
    BANKSEL ADCON0
    BSF ADCON0,0    ;HABILITAR EL CONVERTIDOR

    CALL RETARDO

    BSF ADCON0,1 ;COMIENZA CONVERSION (HABILITA GO/DONE)
CHEKEAR    BTFSC ADCON0,1 ;CHEKEA SI EL BIT GO SE APAGO SI APAGA SALTA
    GOTO CHEKEAR

    CALL RETARDO

    BANKSEL ADRESH
    MOVFW ADRESH       ; MOVER EL VALOR PICO POSITIVO DE LA CONVERSION A W
    MOVWF RESULTHI        ; GUARDAR EL VALOR EN LA VARIABLE
    BANKSEL ADRESL
    MOVFW ADRESL    ;MOVER AL W EL VALOR PICO MINIMO
    MOVWF RESULTLO    ; MOVER A LA VARIABLE ESE VALOR


    
    
    
    
    
    
    ;MOVF RESULTHI,PORTB
    ;MOVF RESULTHI,PORTA
    ;MOVF RESULTLO,PORTC



    
    
    
;%%%%%%%%%%%%%%%%RETARDO%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    ;/////////20mS
RETARDO
    MOVLW D'39' ;INICIALIZAR DATOS
    MOVWF DATO1
SEGUNDO
        MOVLW D'255'
        MOVWF DATO
PRIMERO
        NOP;PERDER TIEMPO
        DECFSZ DATO; DECREMENTO Y SALTA SI IGUAL 0
        GOTO PRIMERO
    DECFSZ DATO1; DECREMENTO Y SALTA SI IGUAL 0
       GOTO SEGUNDO

    RETURN
    
    
    
    
    
END
```
Les agradecería enormemente su ayuda


----------



## seve sainz (Abr 26, 2016)

hola a todos, hice un voltimetro igual en pic c con el micro 16f887 y en simulacion me corre bien, pero al momento de hacerlo en fisico el voltaje de referencia de 2v se sube a 4.8 jaja no tengo idea del porque, espero que me puedan ayudar por favor 

agrego el rar con el codigo y la simulación

Ver el archivo adjunto Voltimetro.rar


----------



## D@rkbytes (Abr 26, 2016)

¿Y físicamente de dónde tomas el voltaje de referencia?
En tu esquema únicamente colocaste un voltaje de 2.0V
Si no lo indicas, ¿cómo podemos saber por qué sube a 4.8 V?

Detalles aparte:
Elimina las instrucciones #use fast_io(x) porque no son necesarias.
Aparte, la instrucción set_tris_a(0x01); no está bien configurada así.
Recuerda que usas el pin Vref- (RA2) y ese pin debe ser entrada.
Al estar configurado el pin RA2 como salida, tendrás una contención lógica porque ese pin lo estás conectando hacia negativo.


----------



## seve sainz (Abr 26, 2016)

set_tris_a(0x01) como debe de ser configurado?
y estoy usando esos voltajes de una fuente digital con voltajes independientes.
entonces en código que le tengo que cambiar?


----------



## D@rkbytes (Abr 26, 2016)

El registro TRISX se usa más que nada para determinar que pines serán salidas, ya que por defecto todos los puertos al iniciar, en el POR (Power On Reset) se configuran como entradas.
Entonces, si no vas a usar ningún pin como salida en el puerto A, elimina esa instrucción.

Y tampoco tiene problema su uso.
Un 1 en cada bit seleccionado, configura al pin correspondiente como entrada, y un 0 como salida.

Es mejor que uses un circuito integrado para obtener el voltaje de referencia, por ejemplo; un *TL431*.
Algo así como el diseño del _*post #151*_


----------

