0
\$\begingroup\$

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.

\$\endgroup\$
1
  • \$\begingroup\$ Maybe you're clearing the ADIF flag in your interrupt handler? In that case, that could be why it doesn't work any more. However, you should be polling the GO bit anyway though, not ADIF. If you have enabled AD interrupt, ADIF must be cleared in interrupt routine and then your AD routine could never possibly work. \$\endgroup\$
    – avl_sweden
    Commented Jul 3, 2015 at 17:26

2 Answers 2

0
\$\begingroup\$

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
}
\$\endgroup\$
2
  • \$\begingroup\$ I made thoose changes but the programm is still blocked. break point on ADCON0bits.go is reached but not the one after the while loop. \$\endgroup\$
    – Nico Balas
    Commented Jul 3, 2015 at 11:36
  • \$\begingroup\$ ok i didn't noticed this page, thanks for the help :) \$\endgroup\$
    – Nico Balas
    Commented Jul 3, 2015 at 13:12
1
\$\begingroup\$

One way I know of acknowledging whether the conversion is complete is reading the GO/DONE bit of ADCON0. The bit goes low once the conversion is complete. So you can use

ADCON0bits.GO=1;
while(ADCON0bits.GO);

If you still want to go with ADIF, you should make sure you have enabled the ADC interrupt. Also check whether the oscillator pins have some voltage on them or whether it is soldered well. The voltage should be around 2.3V to 3V, not exactly but a stable value when measured with DC voltmeter.

Good Luck.

\$\endgroup\$
1
  • \$\begingroup\$ it was like that at first, but i didn't notice any change when I used ADIF... \$\endgroup\$
    – Nico Balas
    Commented Jul 3, 2015 at 11:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.