How ADC value stores inside ADRESH and ADRESL register for pic16f877a

Thread Starter

khatus

Joined Jul 2, 2018
95
I am trying to understand how adc works and also trying to make an ADC function

If the result is Right justified can anyone describe how the adc value stored??
And IS ADRES is a valid MCU register??

If the adc value taken is 563. In binary it is 1101010101.
Then the lower 8 bit stored in ADRESL register (8 bit register).

That is 01010101 goes to ADRESL register (8 bit register).

and the upper 2 bit i.e 11 goes to bit0 and bit1 of ADRESL respectively
but is some example of other compiler (like mikro c , mplab ) they always use a step:
Code:
(ADRESH<<8) | ADRESL ;

and stored this value in a variable (16 bit or 2 byte variable required).

My question is why (ADRESH << 8) is step is required
if the contain of ADRESH is 00000011; then after shifting 8 times to the left it becomes 00000000 and if we bit wise ORED with ADRESL it becomes
ADRESH -> 00000000
ADRESL -> 00110011 ( BITWISE OR operation)
-------------------------
00110011 ???( a 8 bit number but it should be a 10 bit )

Here is the example of MPLAB XC8


Can someone show me the bitwise operation?
for example
ADRESH = 0b00000011;
ADRESL = 0b00110011;
ADD_VALUE = (ADRESH<<8) | ADRESL ;

And is ADRES is a valid register??
 

MrChips

Joined Oct 2, 2009
30,802
ADRES is not a valid resister.

adval has been declared as an unsigned integer, i.e. 16 bits.

ADRESH is an 8-bit register, containing the upper bits of the ADC result.

Setting
adval = ADRESH;

first guarantees that the 8-bit result gets stored into a 16-bit variable.
Then
adval = (adval << 8);
will shift the result to the left by 8 (the same as multiplying by 256).

Now you can add (or OR) the lower 8-bit value ADRESL.
adval = adval | ADRESL;
 
ADRESH = 00000011 is expanded into 16 bit: 00000000 00000011

ADRESH << 8 = 00000000 00000011 << 8 = 0000011 00000000

ADRESL = 00110011 is expanded into 16 bits: 0000000 00110011

Then they're added together

0000011 00000000
0000000 00110011
---------------------------
0000011 00110011
 

MrChips

Joined Oct 2, 2009
30,802
Not on the 16F877 it isn't because the two halves are in different banks.
On some PICs you can get away with 'unsigned int adval = ADRES;' but it isn't really recommended.
That's one of the reasons I don't do PICs.
I thought bank addressing went with the dodo bird, like segment addressing.
 

Thread Starter

khatus

Joined Jul 2, 2018
95
ADRESH = 00000011 is expanded into 16 bit: 00000000 00000011

ADRESH << 8 = 00000000 00000011 << 8 = 0000011 00000000

ADRESL = 00110011 is expanded into 16 bits: 0000000 00110011

Then they're added together

0000011 00000000
0000000 00110011
---------------------------
0000011 00110011
but how can you expand an 8 bit sfr register to 16 bit ???
 

Thread Starter

khatus

Joined Jul 2, 2018
95
I have understand your logic but
(ADRESH<<8) | ADRESL ;
or
(ADRESH<<8) + ADRESL ;
this also works!!! i don't know why?? can you explain it ??
 

Thread Starter

khatus

Joined Jul 2, 2018
95
ADRESH = 00000011 is expanded into 16 bit: 00000000 00000011

I have the following confusion
1. ADRESH is a 8 bit register and i can't understand how a 8 bit SFR register is defined/expanded into a 16 bit variable?? Since they can handle only 8bit?
and also i thought the bit shifting operation is done inside those 8 bit ADRESL and ADRESH register after then they added and assigned to the 16 bit variable.

I guess the correct process would be
1.declare three 2-byte variable for ADRESH , ADRESL and result.
2. Assign contain of ADRESH (8 bit) and ADRESL to the declared 16 bit variable.
3.Bit shifting those two 16-bit variables.
4.Added or ORED them and stores inside another 16 bit variable
 
Last edited:

Thread Starter

khatus

Joined Jul 2, 2018
95
THE address of ADRES and ADRESL is same.
ADRES is unsigned int(16bit) and
ADRESH , ADRESL both are unsigned short (8bit) type

 

Thread Starter

khatus

Joined Jul 2, 2018
95
The microcontroller i am using for testing is PIC 18f452

This one works perfectly for PIC 18f452


//***PIC 18f452 micro controller with 4Mhz crystal oscillator***//
unsigned int value; //variable to store 10 bit adc value
unsigned int adc_read2(char channel)
{
switch (channel)
{
case (0): // for channel 0
{
ADCON0.CHS2 = 0;
ADCON0.CHS1 = 0;
ADCON0.CHS0 = 0;
break;
}
case (1): // for channel 1
{
ADCON0.CHS2 = 0;
ADCON0.CHS1 = 0;
ADCON0.CHS0 = 1;
break;
}
case (2): // for channel 2
{
ADCON0.CHS2 = 0;
ADCON0.CHS1 = 1;
ADCON0.CHS0 = 0;
break;
}
}
ADCON0.GO_DONE = 1; // start conversion
while (ADCON0.GO_DONE); // wait for conversion
return (ADRESH<<8) | ADRESL ; // return value from ADRES(ADRESH+ADRESL) register
}
void main()
{
//INTCON = 0; // disable all interrupts

///*** A/D Port configuration cointrol bits****////
ADCON1.PCFG0 = 0;
ADCON1.PCFG1 = 0;
ADCON1.PCFG2 = 0; //All analog channels are declared as analog
ADCON1.PCFG3 = 0; //refernce voltage is VDD and VSS


///***Input and Output declaration bits***///
TRISA = 0b11111111; // PORTA (Pin RA0-RA7) are input
TRISB = 0b00000000; // PORTB (Pin RB0-RB7) are output
TRISC = 0b00111111; // Pins RC6, RC7 are output
//Delay_ms(2000);

///****Conversion clock select bits****///
ADCON0.ADCS0 = 1;//Fosc/8 setting
ADCON0.ADCS1 = 0; //100 combination gives a TAD about 1us
ADCON1.ADCS2 = 0; // I used 4mhZ crystal and the TAD is 1.6us

ADCON1.ADFM = 1; // result is right Justified
ADCON0.ADON = 1; // enable A/D converter
while (1)
{
//***let's use our open source function***//
value = ADC_read2(0); // get ADC value from channel 0
PORTB = value; // Send lower 8 bits to PORTB here RB0(LSB)
PORTC = value >> 2; // Send 2 most significant bits to RC7(MSB), RC6 pin
}
}

The ADC read function which will convert analog input given to channel 1 to 10 bit digital number with low voltage reference (Vref-) 0v and high voltage reference (Vref+) 5V. The output will be displayed using 10 LEDs.

The analog value in decimal is 563 -> binary 1000110011;
 
Last edited:

John P

Joined Oct 14, 2008
2,026
THE address of ADRES and ADRESL is same.
ADRES is unsigned int(16bit) and
ADRESH , ADRESL both are unsigned short (8bit) type

What you're seeing there is your compiler being helpful. The processor has 2 bytes that hold the A/D result, ADRESL and ADRESH. The compiler lets you use a "virtual" 16-bit variable ADRES, which has a location in memory that's the same as ADRESL, but being 2 actual bytes it also uses the next one up, ADRESH. You go and check the list file, and you'll find that every time the variable is used, the processor is looking at first a low byte, then a high byte. It makes your C code easier to follow, but the resulting hex codes are the same as if you accessed ADRESL and ADRESH separately.
 
Top