CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

How ADC value stores

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
srikrishna



Joined: 06 Sep 2017
Posts: 82

View user's profile Send private message

How ADC value stores
PostPosted: Mon Jul 02, 2018 10:09 am     Reply with quote

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: 1901

View user's profile Send private message

PostPosted: Mon Jul 02, 2018 10:29 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Jul 02, 2018 10:38 am     Reply with quote

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: 9103
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Mon Jul 02, 2018 10:43 am     Reply with quote

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: 19218

View user's profile Send private message

PostPosted: Mon Jul 02, 2018 11:05 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Jul 02, 2018 11:11 am     Reply with quote

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: 19218

View user's profile Send private message

PostPosted: Mon Jul 02, 2018 11:28 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Jul 02, 2018 11:30 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Jul 02, 2018 11:49 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Jul 02, 2018 12:06 pm     Reply with quote

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: 9103
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Mon Jul 02, 2018 12:29 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Jul 02, 2018 12:33 pm     Reply with quote

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: 19218

View user's profile Send private message

PostPosted: Mon Jul 02, 2018 1:22 pm     Reply with quote

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.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group