Search code examples
cpicadc

Struggling to understand channel selection using the ADC on a PIC microcontroller?


I'm trying to write a program that for a PIC18F252 microcontroller to use the ADC to convert 3 analogue signals (on 3 separate pins) into digital signals for use at the output of the program. The guide I've been using to help me understand the ADC has been helpful, but I'm struggling with the part where they put it all together. Here's the code:

unsigned int ADC_Read(unsigned char channel)
{
  ADCON0 &= 0x11000101; //Clearing the Channel Selection Bits
  ADCON0 |= channel<<3; //Setting the required Bits
  __delay_ms(2); //Acquisition time to charge hold capacitor
  GO_nDONE = 1; //Initializes A/D Conversion
  while(GO_nDONE); //Wait for A/D Conversion to complete
  return ((ADRESH<<8)+ADRESL); //Returns Result
}

Then you can call the function and assign it to a variable using this:

i = (ADC_Read(4)); //store the result of adc in “i”

My problem is that I'm struggling to understand the bitshifting part of the code. I get why and how it clears the channel selection bits, but my struggle is understanding how 'channel<<3', when channel=4 in this example, can create a binary value that can be OR'd with the ADCON0 value. Is anyone able to explain what the value of channel is after the code has run, if it starts as 4, and also what the new configuration of ADCON0 would be after the OR line?

I understand each line individually I'm just struggling to get how they piece together because this has to be done 3 times, selecting a different channel each time, and at the moment I can't tell what channel this is setting.


Solution

  • The other answers provide the layout of the registers. This answer illustrates the process of changing the desired bits.

    First, we clear the channel bits (and the unimplemented bit 1).

            7   6   5   4   3   2   1   0
          +---+---+---+---+---+---+---+---+
          | a | b | c | d | e | f | g | h |   Initial state
          +---+---+---+---+---+---+---+---+
          
          +---+---+---+---+---+---+---+---+   (The OP incorrectly
    &     | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 1 |   used 0x11000101
          +---+---+---+---+---+---+---+---+   instead of 0b11000101.)
          
          +---+---+---+---+---+---+---+---+
    =     | a | b | 0 | 0 | 0 | f | 0 | h |
          +---+---+---+---+---+---+---+---+
    

    Next, we need to slide the channel into bits 5-3.

          +---+---+---+---+---+---+---+---+
          |(0)|(0)|(0)|(0)|(0)| 1 | 0 | 0 |   4   (Channel in bits 2-0)
          +---+---+---+---+---+---+---+---+
    
          +---+---+---+---+---+---+---+---+
    << 3  |(0)|(0)| 1 | 0 | 0 |(0)|(0)|(0)|       (Channel in bits 5-3)
          +---+---+---+---+---+---+---+---+
    

    Now, we can OR it in.

          +---+---+---+---+---+---+---+---+
          | a | b | 0 | 0 | 0 | f | 0 | h |
          +---+---+---+---+---+---+---+---+
    
          +---+---+---+---+---+---+---+---+
    |     |(0)|(0)| 1 | 0 | 0 |(0)|(0)|(0)|
          +---+---+---+---+---+---+---+---+
    
          +---+---+---+---+---+---+---+---+
    =     | a | b | 1 | 0 | 0 | f | 0 | h |
          +---+---+---+---+---+---+---+---+
    

    I used (0) to denote a zero bit that doesn't carry data.