View previous topic :: View next topic |
Author |
Message |
srikrishna
Joined: 06 Sep 2017 Posts: 82
|
How ADC value stores |
Posted: Mon Jul 02, 2018 10:09 am |
|
|
I am trying to understand how adc works and also trying to make an ADC function
If the result is left 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
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.
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
Last edited by srikrishna on Mon Jul 02, 2018 10:33 am; edited 1 time in total |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1907
|
|
Posted: Mon Jul 02, 2018 10:29 am |
|
|
No, the "unsigned int" the function you posted returns must be an unsigned int16. Always, ALWAYS, strive to specify the size of the variable in its declaration. Don't assume something is 8 bits or 16 if an 8 or 16 isn't part of its declaration.
Anyway, with this in mind, ADRESH is being cast to an int16, then left shifted 8 times, and finally ADRESL is added (or OR'd - same thing) to it, yielding a 16 bit result.
I highly suggest you look up the make16() function that is built into the compiler. |
|
|
srikrishna
Joined: 06 Sep 2017 Posts: 82
|
|
Posted: Mon Jul 02, 2018 10:38 am |
|
|
Can you show me the bitwise operation?
for example
ADRESH = 0b00000011;
ADRESL = 0b00110011;
ADD_VALUE = (ADRESH<<8) | ADRESL ;
And is ADRES is a valid register??
Last edited by srikrishna on Mon Jul 02, 2018 10:57 am; edited 3 times in total |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9225 Location: Greensville,Ontario
|
|
Posted: Mon Jul 02, 2018 10:43 am |
|
|
You need to read the datasheet, ADC section, for that PIC. The 877 has a 10 bit ADC so the PIC requires 2 registers to store the result. When you use 'left justify' the top 8 bits of the ADC result will be stored in the ADRESH register, the 2 lower bits go into ADRESL.
Now IF you use the ADC for '8 bit' mode, you'll always lose those 2 right bits of data.
How you read the 10 bit data depends upon what you want to do with the analog data. For high accuracy, you use the 10 bit result of the ADC. Overall a little slower but better numbers. You of course do need to properly lay out the PCB, use shielded cables, and a very tight Vreference. For something like a 'digital thermometer / acquarium controller' 8 bit data is fine. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Mon Jul 02, 2018 11:05 am |
|
|
One obvious question. Why?....
CCS give you a function that can directly read the ADC registers:
read_adc(ADC_READ_ONLY)
directly returns the contents of the ADC registers.
read_adc();
Automatically performs the acquisition, and reads the value. Just like the posted ADC_read, though it assumes the setup has already been performed.
Now you don't tell use what chip (except in giving an example for the 877a). On some chips there is only one primary register ADRESL, and the other bits are stored as part of another register.
There are no 'registers' automatically defined for you in CCS. You either have to use the functions that access them for you, or define them yourself. So:
ADRESL=getenV("SFR:ADRESL")
Tells the compiler to allow you to access the ADRESL register. |
|
|
srikrishna
Joined: 06 Sep 2017 Posts: 82
|
|
Posted: Mon Jul 02, 2018 11:11 am |
|
|
Ttelmah wrote: | One obvious question. Why?....
CCS give you a function that can directly read the ADC registers:
read_adc(ADC_READ_ONLY)
directly returns the contents of the ADC registers.
read_adc();
|
Actually i am trying to understand the how it works.
But Can you show me this bitwise operation?
for example
Code: | ADRESH = 0b00000011;
ADRESL = 0b00110011;
ADD_VALUE = (ADRESH<<8) | ADRESL ; |
And is ADRES is a valid register??
please read this
http://picguides.com/beginner/adc.php |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Mon Jul 02, 2018 11:28 am |
|
|
No. As I said:
Quote: |
There are no 'registers' automatically defined for you in CCS. You either have to use the functions that access them for you, or define them yourself. So:
|
The operation would not work anyway, since if a register was defined it'd be an 8bit register. You can't shift an 8bit register left 8 times. If you had defined the registers, you would need:
ADD_VALUE = ((int16)ADRESH<<8) | ADRESL ; |
|
|
srikrishna
Joined: 06 Sep 2017 Posts: 82
|
|
Posted: Mon Jul 02, 2018 11:30 am |
|
|
Ttelmah wrote: | No. As I said:
Quote: |
There are no 'registers' automatically defined for you in CCS. You either have to use the functions that access them for you, or define them yourself. So:
|
The operation would not work anyway, since if a register was defined it'd be an 8bit register. You can't shift an 8bit register left 8 times. If you had defined the registers, you would need:
ADD_VALUE = ((int16)ADRESH<<8) | ADRESL ; |
yes but can i define a 8bit sfr register as a 16 bit integer?? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Jul 02, 2018 11:49 am |
|
|
He wants to know:
Quote: | And is ADRES is a valid register??
can i define a 8bit sfr register as a 16 bit integer??
|
and the answer is no. ADRESL is at address 0x9E, and ADRESH is
at address 0x1E. These two addresses are not adjacent, so you
can not read them together as an int16.
You can do this with CCPR1L and CCPR1H because they are adjacent
to each other in the memory map. CCPR1L is at 0x15, and CCPR1H is
at 0x16. So you can do this:
Code: | #word CCP_1 = getenv("SFR:CCPR1L") |
But no, you can't do it with ADRESL and ADRESH. (in the 16F877A).
That's what this whole thread is about. |
|
|
srikrishna
Joined: 06 Sep 2017 Posts: 82
|
|
Posted: Mon Jul 02, 2018 12:06 pm |
|
|
Although i did not want to post code for mikroc compiler here. but the line
result = (ADRESH<<8)|ADRESL; or (ADRESH<<8) + ADRESL;
works perfectly during real testing and as well as in proteus simulation.
Code: | //***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
}
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) is 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
}
} |
If (ADRESH<<8) | ADRESL ; is wrong then why the result is showing correctly with out error?? |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9225 Location: Greensville,Ontario
|
|
Posted: Mon Jul 02, 2018 12:29 pm |
|
|
this....
unsigned int value; //variable to store 10 bit adc value
...
does NOT store a 10 bit value.
CCS defaults (well on my compiler version) int to 8 bits. An unsigned interger will range from 000 to 255 (0x00 to 0xFF). At least that's what the CCS manual says in the 'data definitions' page
It would appear that MikroC defaults 'int' to 16 bits, NOT to 8 bits. I'd have to go to their webpage and look around, however I tried it years ago and it's far too 'silly' to code their way considering CCS does in ONE LINE what takes them several.
Bottom line... when using CCS C, code the CCS way ! They provide LOTS of good, working example code as well as drivers for most of the common external peripherals. Also, look, scan, read the manual as there's almost everything you need to know about CCS C in the manual.
If you want to KNOW how the ADC peripheral truly works, consult the datasheet as well as several application notes from Microchip's website.
Jay
Last edited by temtronic on Mon Jul 02, 2018 12:35 pm; edited 1 time in total |
|
|
srikrishna
Joined: 06 Sep 2017 Posts: 82
|
|
Posted: Mon Jul 02, 2018 12:33 pm |
|
|
temtronic wrote: | this....
unsigned int value; //variable to store 10 bit adc value
...
does NOT store a 10 bit value.
CCS defaults( well on my compiler version) int to 8 bits. An unsigned interger will range from 000 to 255 ( 0x00 to 0xFF). At least that's what the CCS manual says in the 'data definitions' page |
This code is not for CCS C it is for mikroC. I know posting MikroC or other compiler code is irrelevant. But since it works in real thats why i have posted it.
In mikroc an unsigned int takes 2byte. To use in CCS C we must declare variable as a 2 byte arithmetic type specifiers ( i.e int16) for storing 10 bit output. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Mon Jul 02, 2018 1:22 pm |
|
|
Look, lets show you how to code this in CCS:
Code: |
//In the setup after the processor type include
#device ADC=10 //set to return left justified ten bit value
int16 adc_read2(char channel)
{
set_adc_channel(channel);
delay_us(10); //acquisition time
return read_adc();
}
|
Just three lines of code. Nothing more needed.
The code you post would not actually work correctly, since it allows no acquisition time after selecting the channel. |
|
|
|