A/D conversion loop infinitly

adcmplabpic

I'm quit new one PIC microcontroller, and i'm stuck with a new problem.

I was using the A/D converter of my PIC18F46j50 to catch 4 push buttons on 1 PIN (RB2), and it worked well. But since I soldered a 32.768kHz oscillator for Timer1, it doesn't work anymore.

unsigned int HAL_SWITCH_GetValADC(void){
    ADCON0bits.VCFG0 = 0;
    ADCON0bits.VCFG1 = 0;
    ADCON0bits.CHS = 0b1000;
    ADCON1bits.ADFM = 1;        // A/D Result format select bit : right justified
    ADCON1bits.ADCAL = 0;       // A/D Calibration bit
    ADCON1bits.ACQT = 0b111;    // A/D Acquisition Time 12 Tad = 12us
    ADCON1bits.ADCS = 0b001;    //Tad = 1us (Fosc/8)
    ADCON0bits.ADON = 0b01;     // A/D enable

    PIR1bits.ADIF = 0; //make sure A/D Int not set
    ADCON0bits.GO=1; //and begin A/D conv.
    while(!PIR1bits.ADIF);
    NOP();
    return (((unsigned int) ADRESH << 8) | ADRESL);
}

Using breakpoint I determined that the problem come from the while loop, when i debug step by step, it works fine, but the programm never stops if the breakpoint is on NOP();

got error like "No source code lines were found at current PC" + few adress, mostly those of the interupt instructions… I don't know if their is a link.

Also someone told me to change the clock used by the A/D convertor… How can I manage to do so ?

Ask for more code if it can help.

Best Answer

ADCON1bits.ACQT = 0b111 <- that's not 12 Tad, but 20 Tad (according to datasheet), which translates roughly to 20us. Try using 0b101, for the value you are trying to achieve. Try setting bit 6 of ADCON1 register (ADCAL, responsible for automatic calibration) to 1 and running your code again. You have also put semicolon after the while loop, which does not seem like a good idea at the moment. Weren't you going for something more like:

while(!PIR1bits.ADIF) {
NOP(); } return (((unsigned int) ADRESH << 8) | ADRESL);

EDIT: What is nop function exactly? Is it literal use of nop assembly instruction or is it a delay function? Other thing, you should probably put whole A/D routine with saving the result to into a loop, since it's 10-bit A/D converter. PIC18F46J50 datasheet suggests something like this(page 400):

#include "p18cxxx.h"
#define COUNT 500 //@ 8MHz = 125uS.
#define DELAY for(i=0;i<COUNT;i++)
#define RCAL .027 //R value is 4200000 (4.2M)//scaled so that result is in//1/100th of uA
#define ADSCALE 1023 //for unsigned conversion 10 sig bits
#define ADREF 3.3 //Vdd connected to A/D Vr+
int main(void)
{
 int i;
 int j = 0; //index for loop
 unsigned int Vread = 0;
 double VTot = 0;
 float Vavg=0, Vcal=0, CTMUISrc = 0; //float values stored for calcs
//assume CTMU and A/D have been setup correctly
//see Example 25-1 for CTMU & A/D setup
setup();
CTMUCONHbits.CTMUEN = 1; //Enable the CTMU
CTMUCONLbits.EDG1STAT = 0; // Set Edge status bits to zero
CTMUCONLbits.EDG2STAT = 0;
 for(j=0;j<10;j++)
 {
 CTMUCONHbits.IDISSEN = 1; //drain charge on the circuit
 DELAY; //wait 125us
 CTMUCONHbits.IDISSEN = 0; //end drain of circuit

 CTMUCONLbits.EDG1STAT = 1; //Begin charging the circuit
 //using CTMU current source
 DELAY; //wait for 125us
 CTMUCONLbits.EDG1STAT = 0; //Stop charging circuit

 PIR1bits.ADIF = 0; //make sure A/D Int not set
 ADCON0bits.GO=1; //and begin A/D conv.
 while(!PIR1bits.ADIF); //Wait for A/D convert complete

 Vread = ADRES; //Get the value from the A/D
 PIR1bits.ADIF = 0; //Clear A/D Interrupt Flag
 VTot += Vread; //Add the reading to the total
 }

 Vavg = (float)(VTot/10.000); //Average of 10 readings
 Vcal = (float)(Vavg/ADSCALE*ADREF);
 CTMUISrc = Vcal/RCAL; //CTMUISrc is in 1/100ths of uA
}