0
votes

I am using a PIC24 to read data using 3 analog inputs but am only getting 1 to show the right result. I looked everywhere on the internet and am still not able to get the code to work.

I am trying to read 3 analog input signals and am only able to read in AN0.

I am using an accelerometer to obtain the data and show it on the LCD screen for now. I was able to implement 3 different ways to take the data and display it but only an0 works and an1 is not the right value.

void InitADC(int amask) {
    AD1PCFG = 0xFFF8; // select AN0, AN1, AN2 as analog inputs
    AD1CON1 = 0x00E0; // auto convert @ end of sampling, Integer Data out.
    // see Text pg. 179 & Sec. 17 on AD1CON1.
    //AD1CON2bits.CSCNA = 1;
    AD1CON3 = 0x1F01; // Tad = 2xTcy = 125ns. 31*Tad for conversion time.
    //AD1CSSL = 0xFFF7; // Scan 3 channels
    AD1CON1bits.ADON = 1; // Turn on the ADC
} // InitADC

main() {
   InitADC(0xFFF8); // initialize the ADC and analog inputs 
   char x_string [12];
   char y_string [12];
   char z_string [12];
   //TRISB = 1; // all PORTB pins as outputs
   TRISBbits.TRISB0 = 1;
   TRISBbits.TRISB1 = 1;
   TRISBbits.TRISB2 = 1;
   InitPMP(); // Initialize the Parallel Master Port
   InitLCD(); // Initialize the LCD
   float x_val;
   float y_val;
   float z_val;
   float x_axis, y_axis, z_axis;

   while (1) // main loop
   {  
    x_axis= SelectPort(0);   
    x_val= ((((x_axis * 3.3)/ 1024)-1.58)/0.380);
    
    sprintf(x_string, "X: %0.2f ", x_val);
    ms_delay(2.5);

    y_axis= SelectPort(1);  
    y_val= ((((y_axis * 3.3)/ 1024)-1.58)/0.380);
    
    sprintf(y_string, "Y: %0.2f ", y_val);
    ms_delay(2.5);

    z_axis= SelectPort(2);  
    z_val= ((((z_axis * 3.3)/ 1024)-1.58)/0.380);
    
    sprintf(z_string, "Z: %0.2f ", z_val);
    ms_delay(2.5);
}

Here is the code where the data is read:

int SelectPort(int ch)
{
//int *result; 
AD1CON1bits.ADON = 0; // Turn off the ADC to reconfigure
//result = &ADC1BUF0;

switch(ch) // set values based on the channel to use
{
    case 0: // select AN0 as analog input
        //AD1CHSbits.CH0SA=0;
        //result = ADC1BUF0;
        AD1PCFG = 0xFFFE;
        break;
    
    case 1:
        //AD1CHSbits.CH0SA=1;
        //result = ADC1BUF1;
        AD1PCFG = 0xFFFD; // select AN1 as analog input
        break;
    
    case 2:
        //AD1CHSbits.CH0SA=2;
        AD1PCFG = 0xFFFB; // select AN2 as analog input
        break;
    
    // there's only so many options here, so there's not really a default case
}

AD1CON1bits.ADON = 1; // Turn on the ADC

AD1CHS = ch; // 1. select analog input channel

AD1CON1bits.SAMP = 1; // 2. Start sampling.
while (!AD1CON1bits.DONE); //5. wait for conversion to complete
AD1CON1bits.DONE = 0; // 6. clear flag. We are responsible see text.
return ADC1BUF0; // 7. read the conversion results
}

I am new to PIC24 and need help to figure out why I am not able to get multiple ADC channels to read the data.

1
I was able to get an1 and an2 to show data continuously change like an0 but the values are wrong. I updated the above code.Romko Smuk
You comment out the channel selecton: //AD1CHS = ch; // 1. select analog input channelMike
I forgot to edit that in the above code, it's uncommented in the code that runsRomko Smuk
There are over 100 possible PIC24 controllers with an AD1PCFG special function register. Which specific controller are you using?Dan1138

1 Answers

0
votes

You should always give some time for the ADC input voltage to settle after changing its input port. Also, make sure the impedance of your inputs signals are less than 10K.

Separating the ADC channel switching and reading its value will help, and give you an opportunity to add a delay.

I could not find AD1PCFG in the PIC24 datasheet. AD1PCFG is a PIC32 register... PIC24 uses ANSx and TRSx to set pins as analog inputs. Analog inputs should be set once, during the boot sequence. Feeding an analog signal to a digital input CMOS pin will result in increased power draw, and can even lead to hardware failure!

//  Set the pins as analog inputs once and for all in your setup code.
void InitADC() 
{
    // select RB0/AN0, RB1/AN1, RB2/AN2 as analog inputs
    TRISB   |= 0x07;
    ANSB    |= 0x07;

    // ...
}

void ADC_SelectInput(int ch)
{
    AD1CHS = ch & 0x0F
}

int ADC_Read()
{
    AD1CON1bits.SAMP = 1;
    while (!AD1CON1bits.DONE)
        ;
    AD1CON1bits.DONE = 0;
    return ADC1BUF0;
}

Your loop then becomes:

// ...


int adc_in;

while (1)
{  
    ADC_SelectInput(0);
    ms_delay(3);         // settling delay, you could also do something
                         // else in the meantime instead of waiting. 
                         // NOTE: the argument to ms_delay() is an integer
                         // so waiting at least 2.5 ms makes it 3. 

    // when computing floats, use float constants, not double.
    x_val  = (((ADC_Read() * 3.3f) / 1024) - 1.58f) / 0.380f;
    sprintf(x_string, "X: %0.2f ", x_val);

    ADC_SelectInput(1);
    ms_delay(3);
    y_val  = (((ADC_Read() * 3.3f) / 1024) - 1.58f) / 0.380f;
    sprintf(y_string, "Y: %0.2f ", y_val);

    ADC_SelectInput(2);
    ms_delay(3);
    z_val  = (((ADC_Read() * 3.3f) / 1024) - 1.58f) / 0.380f;
    sprintf(z_string, "Z: %0.2f ", z_val);
}