Código simple de conversión ADC de 12 bits que no funciona como se esperaba

0

Hace unos días publiqué un par de funciones que escribí para hacer ADC de 10 bits. El problema es que no pude averiguar qué estaba mal con mi código, así que escribí una función simple mucho más simple que realiza una conversión de 12 bits para una solución de problemas más sencilla del código original. Así que mi código ahora funciona en su mayor parte, pero tengo un pequeño problema que no puedo resolver por mi cuenta. Configuré 2 leds para que se iluminen cuando el voltaje de entrada es superior a 2.5 voltios y solo uno se enciende cuando está por debajo. El problema es que cuando el voltaje está por debajo de 1v, los dos leds siguen encendidos. pero además de que todo funciona como se esperaba, tan pronto como supere 1 v, el único LED se encenderá. Cuando suba por encima de los 2,5 voltios, los otros 2 LED se encenderán como se esperaba. Realmente agradecería cualquier sugerencia Gracias por su ayuda. Estoy usando PIC16f1788

  #include <xc.h>

 // Config word
#define _XTAL_FREQ   2000000 // set it to match internal oscillator

/*config1 and config2 settings*/
// CONFIG1
#pragma config FOSC = INTOSC // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF // Watchdog Timer Enable (WDT enabled)
#pragma config PWRTE = ON // Power-up Timer Enable (PWRT disabled) (turned on!)
#pragma config MCLRE = OFF // MCLR Pin Function Select (MCLR/VPP pin function is MCLR) (turned off)
#pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = ON // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = ON // Internal/External Switchover (Internal/External Switchover mode is enabled)
#pragma config FCMEN = ON // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)

// CONFIG2
#pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off)
#pragma config VCAPEN = OFF // Voltage Regulator Capacitor Enable bit (Vcap functionality is disabled on RA6.)
#pragma config PLLEN = ON // PLL Enable (4x PLL enabled)
#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LPBOR = OFF // Low Power Brown-Out Reset Enable Bit (Low power brown-out is disabled)
#pragma config LVP = OFF // Low-Voltage Programming Enable (Low-voltage programming enabled) (turned off)


unsigned int analog_reading;
unsigned int i;
unsigned int bit_val;

void main(void)
 {
    //SET UP
ADCON1= 0b00000000; //format setup see page 182 of datasheet
TRISA= 0b11111111; //sets PORTA as all inputs
TRISC= 0b00000000; //sets PORTB as all outputs
PORTC= 0b00000000; //sets all outputs of PORTB off to begin with
ADCON0 =0b00000101;
               // bit0: ADC enabled
               //bit6-2: AN1 enabled for analog input
               //bit7: set for a 12-bit result
               //


while (1)
{
__delay_ms(10);
ADCON0bits.GO_nDONE=1; //do A/D measurement
while(ADCON0bits.GO_nDONE==1); 
bit_val= ADRESH; // store upper 8 bits in a 16bit variable
analog_reading = ((bit_val << 4) | ADRESL); //shift it up by 4 bits then store      ADRESL in the bottom 4bits
                                        // According to page 184 of datasheet   when ADFM=0 ADRESH has the
                                        // upper 8 bits of 12bit conversion results and the lower 4 bits are in ADRESL



 if(analog_reading>512){    // when the voltage is passed 2.5 volts these two  LEDS should come on.
            /*Turn these 2 LED on*/
            PORTCbits.RC2 = 1;
            PORTCbits.RC3 = 1;
            PORTCbits.RC4 = 0;
            }
else{
            /*turn one LED on*/
            PORTCbits.RC2 = 0;
            PORTCbits.RC3 = 0;
            PORTCbits.RC4 = 1;
            }
  }
  }
    
pregunta sam brosteain

1 respuesta

3
  

ADCON1 = 0b00000000; // configuración del formato ver página 182 de la hoja de datos

Para empezar, creo que no está bien. Ese registro controla más que solo el formato. Los bits 0-2 controlan las referencias de voltaje (000 está bien para eso - VDD y VSS). El bit 7 controla el formato. Pero, los bits 4-6 controlan el reloj de conversión.

Los configura en 000, lo que equivale a \ $ F_ {OSC} / 2 \ $. Esa es una fuente de reloj interno de 16MHz dividida por 2 (a juzgar por sus ajustes de configuración). Así que un reloj de conversión de 8MHz. Eso es faaaast. Si nos fijamos en la Tabla 17-1:

Unrelojde16MHz,con\$F_{OSC}/2\$esunperíododerelojde125ns,conunpunteroalanota2,queindica:

  

EstosvaloresviolaneltiempomínimorequeridodeTAD.

Entoncesestásviolandotu\$T_{AD}\$tiempo,¿eh?Entonces,¿quizáselADCnoseacapazdedevolverresultadossignificativos?

TalvezdeberíaintentarreducirlavelocidaddelADCparaquefuncionedentrodelasespecificaciones,talveza\$F_{OSC}/16\$comolaconfiguraciónválidamásrápidaparaunafuentederelojde16MHz.

Esoequivaldríaaunaconfiguraciónde0b101,loqueharíaquelalíneadecódigo:

ADCON1=0b01010000;//formatsetupseepage182ofdatasheet

Otroproblemaconeseregistroessuformato.Tieneelbit7establecidoen0.Esoequivalealresultadode"Signo y magnitud". Es mejor trabajar con el resultado del complemento de 2, ya que eso es matemática "normal" en un microcontrolador. Puede ver la diferencia en la Tabla 17-2:

Enelmomentoenelqueestácambiandosuvaloralto,deje4bitsyluegoOREDconlos8bitsmásbajos.Con"Sign and Magnitude" terminas con, por ejemplo, hay +2355:

ADRESH = 10010011
ADRESL = 00110000

ADRESH << 4 = 100100110000
OR ADRESL = 100100110000

Suponiendo que incluso mantiene los 4 bits más altos y no los trunca (no estoy seguro de qué va a hacer).

El resultado es obviamente incorrecto ya que los 4 bits inferiores de ADRESH sobrescriben los 4 bits superiores de ADRESL.

Usando el modo de complemento de 2, y cambiando 8 bits no 4 resultados en:

ADRESH = 00001001
ADRESL = 00110011

ADRESH << 8 = 0000100100000000
OR ADRESL = 0000100100110011

Y esos son tus 12 bits completos.

Por lo tanto, primero debes configurar ese séptimo bit de tu configuración en 1, por lo que finalmente es:

ADCON1= 0b11010000; //format setup see page 182 of datasheet

Y luego necesitas arreglar tu cambio de bits:

analog_reading = ((bit_val << 8) | ADRESL); //shift it up by 8 bits then
                                            //store ADRESL in the bottom 8 bits
    
respondido por el Majenko

Lea otras preguntas en las etiquetas