Saludos! Abro este hilo por si a alguien le puede servir de ayuda, estaba haciendo un programa que envia por el puerto serie el valor del adc cada vez que le enviamos un caracter, esto es mas que nada para poder comprobar valores sin que el monitor serie se nos llene de datos como podria pasar si enviamos el valor cada segundo por ejemplo.
En este caso usaba el adc con 8 bits de definicion, era solo una prueba y es una forma de disminuir los efectos del ruido. El pic usado es el 18f2550.
Pues bien, el programa iba bastante mal: los datos oscilaban sin modificar el potenciometro, a veces eran oscilaciones demasiado grandes, y lo mas raro venia cuando estaba al maximo voltaje en lugar de 255 o un valor cercano, me marcaba 15, a veces 31 y alguna suelta 63; curioso que los datos sean igual a multiplicar el anterior por 2 y sumar uno.
La solución la he encontrado al modificar el tiempo de adquisición para el conversor, el conversor en los pic18f no es igual a la serie pic16f, en la serie 18f nos permite por "hardware" establecer un tiempo de espera para que se estabilice el conversor, y ese tiempo es el tiempo de adquisicion de datos.
Este tiempo se puede configurar mediante los bits ACQT2:ACQT0 que se encuentran en el registro ADCON2, en el datasheet se puede observar en la pagina 257.
ACQT2:ACQT0: A/D Acquisition Time Select bits
111 = 20 TAD
110 = 16 TAD
101 = 12 TAD
100 = 8 TAD
011 = 6 TAD
010 = 4 TAD
001 = 2 TAD
000 = 0 TAD
El "problema" es que no hay una forma directa de establecer este tiempo con el CCS, o yo no la conozco. La solucíon ha sido definir el registro usando la directiva:
#byte ADCON2=0xFC0
Y posteriormente aplicando mascaras para poner a 1 o a 0, los bits que deseamos del registro. En mi caso uso un tiempo de 20 Tad, con lo que hay que poner a 1 los tres bits:
ADCON2= ADCON2 | 0b00111000;
Si se deseara caragar en los bits el valor "101" por ejemplo, posteriormente habria que hacer una and para poner a 0 los bits deseados:
ADCON2= ADCON2 | 0b00101000;
ADCON2= ADCON2 & 0b11101111;
Consiste en aplicar mascaras de forma que modifiquen los bits que deseamos:
- Para poner a 1, se usa la operacion "or" (|)con una mascara que contengan con bits a 1 aquellos que deseamos setear(poner a 1) y los demas a 0 para no modificar el resto del registro.
- Para poner a 0, se usa la operacion "and"(&) con una mascara que contengan con bits a 0 aquellos que deseamos limpiar(poner a 0) y los demas a 1 para no modificar el resto del registro.
#include <18F2550.h>
#device ADC = 8
#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL3,CPUDIV1,VREGEN
#use delay(clock=48000000)
//Configura comunicacion serie
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
//#byte nombre=direccion
//se define byte control adcon2, controla t.adquisicion, justificacion y reloj
#byte ADCON2=0xFC0
char Keypress=' ';
int8 valor;
#int_rda
void serial_isr() {
Keypress=0x00;
if(kbhit())
{
if(Keypress!=0x00)
{
valor=read_adc(ADC_START_AND_READ);//Inicia conversion y lee, hara espera automatica
delay_ms(1);
printf("\n\rEl valor del adc es : %u",valor
);//muestra dato mayor }
}
}
void main()
{ //Establecer a como entrada
set_tris_a(0x01); //Entrada an0
//Se define entradas analogicas y valores referencia
setup_adc (adc_clock_div_64); //Enciende ADC, pongo 64 en lugar 32 a ver si mejora
//se configura t.adquisicion sin modificar demas, se usa operacion or
//se usara tadq de 20 tad, bits acqt2..0 todos a 1
//para poner a 0 se utilizaria and con 0 en bit a modificar y demas a 1
ADCON2= ADCON2 | 0b00111000;
setup_adc_ports (AN0_ANALOG); //Elige entrada analogica
set_adc_channel (0); //Elige canal a medir
//Habilita interrupcion rda
enable_interrupts(global);
enable_interrupts(int_rda);
printf("\r\n\ Conectado \r\n");
do {
} while (TRUE);
}
No sé si a alguien mas le ha dado problemas, a mi bastantes por lo que he puesto aqui la solución por si a alguien mas le puede servir.