from ADC data to SIGNED16

Go To Last Post
14 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello,

I have to change the raw data of a 10 bit ADC into a signed, left adjusted, 16bit value to transmit it. The problem is, how I make this conversion with GCC.

If this ADC is from 0V to 5V, I think I have to left shift this raw data by 5 bits because it is a positive one (MSB is left bit):

Quote:
ADC: 10 0110 0110b
To transmit: 0100 1100 1100 0000b

and the receive device must evaluate the first 11 bits.

But if this ADC is from -5V to 5V, I must left shift the ADC data by 6 bits:

Quote:
ADC: 10 0110 0110b
To transmit: 1001 1001 1000 0000b

And the receive device must evaluate the first 10 bits.
Is this thought correct?

Thank you.
Senmeis

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Senmeis,

I admit, I haven't checked your bit calculations; I find arithmetic expressions simpler to handle.

e.g. if you have ADC value of 10 bits and you want to map it onto a interval of [A, B], then just use a linear interpolation:

A + adc_value * (B-A) / 1024

If you want to map it to 16 bit values, then A = -(2^15) and B = 2^15 - 1. (Be wary of integer overflows when you implement this equation).

This assumes an implicit scaling factor of 2^15/5V.

Once it works, you can always optimise it to use bit operations, if needed.

my 2 cents,
Thomas

pycrc -- a free CRC calculator and C source code generator

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello,

Thank you for your reply.
For my case your formula should be: ADC * 2^6 – 2^15.
But if the ADC is 0, I got ‘-32768’ according to this formula. Where does this mistake come from?

Thank you.
Senmeis

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But -32768 is the right answer for an ADC reading of 0?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Senmeis,

I had the impression this was the requested value.
It would help if you could express the desired conversion in a table, like this one:

 V |  ADC |  value
---+------+-------
-5 |    0 | -32768
+5 | 1024 |  32767

PS: I might be wrong, but AVR's ADC can only convert values from 0-Vcc, so I suppose you have a signal conditioning circuit that converts the input voltage of [-5V, +5V] to the range [0V, Vcc]. You might want to include this factor in your table as well.

pycrc -- a free CRC calculator and C source code generator

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Also check out the ADLAR (ADC Left Adjust Result) bit available on some (most?) AVRs. This will automatically left adjust the result.

I also do not understand the "signed" part of this equation. The ADC measures 0V to VDD, full scale. What is the reference "zero"? I suppose you could arbitrarily choose one at 512<<5 and subtract that from the left shifted ADC value. Hmm.

Stu

Engineering seems to boil down to: Cheap. Fast. Good. Choose two. Sometimes choose only one.

Newbie? Be sure to read the thread Newbie? Start here!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As I said, the receiver regards there bits as signed16, so the ADC of 0V to Vcc should only fill the positive half room of signed16 => "ADC << 5".

Actually I use the "ADLAR" so the bits are already left adjusted, but from bit15 to bit6, which might be interpreted as negative value wrongly. Is it helpful to use this:

int16_t adc_result = ADC?

Or must I right shift the result by 1 bit?

Thank you.
Senmeis

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Senmeis,

you have lost me. If you don't tell us what you want to achieve (i.e. what the desired range of adc_result is) then I'm afraid we can't tell you if it is right or wrong what you are doing.

Thomas

pycrc -- a free CRC calculator and C source code generator

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Because the receiver regards the bit stream as signed16, I think all positive values (for example 0V to 5V) should be in the range 0 to 32767. As for negative values (for example -5V to 0V), the receiver will interpret the bit stream as two's complement if bit15 is '1'.

Thank you.
Senmeis

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Senmeis,

I think you need to distinguish between 4 different figures:

a) the voltage you want to measure
b) the voltage applied to the ADC input
c) the integer value read from the ADC
d) the internal representation of the measurement

The figues b) and c) are defined by the chip. In fact, the ADC voltage b) must be between 0V and Vcc, and the ADC value c) is defined by the resolution of the Analog to Digital converter, and its values range from 0x00 to 2^(number of bits). In your case the number of bits is 10, and thus a value of 0x00 corresponds to 0V applied to the input of the ADC and a value of 1023 corresponds to Vcc - Vcc/1024.

The other two figures, a) and d) are defined by you. If you need to measure negative voltages, then you need to design an analogue circuit that converts the voltage to 0..Vcc ADC voltage. I am not the right person to tell you how this should look like, but a common way would be to add a constant offset and to scale the result to make it stay in the 0..Vcc range.

The short morale from this long story is that a ADC value of 0x00 could correspond to -5V, depending on the analogue circuitry between the voltage you want to measure and the ADC input pin of the AVR. You are the only one here who knows the how this circuitry looks like.

Cheers
Thomas

PS: If there is no analogue circuitry on your board, then you can not measure negative voltages and you know already how to scale the value in that case.

Edit: spelling and phrasing

pycrc -- a free CRC calculator and C source code generator

Last Edited: Tue. Aug 12, 2008 - 10:49 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
As for negative values (for example -5V to 0V), the receiver will interpret the bit stream as two's complement if bit15 is '1'.

But how are you measuring this value? The ADCs on the AVR measure from 0 to the reference voltage (which must be above 0), so how could you possibly be measuring a negative voltage?

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks, tpircher.

I think I must make it clear that I am talking about a system, not necessary AVR chips, so I don't care how to implement the negative voltage. What I know is following: the receiver regards the bit stream as signed16 and the received bit stream will be interpreted as two's complement if bit15 is '1'.

I think I cannot use 'ADLAR' directly because it can set bit15 to '1' and this will be seen as a negative by the receiver although the original value is positive (This sentence is referred to AVR).

Thank you.
Senmeis

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Senmeis, you are exaggerating an issue where there is non. If your receiver interprets the high bit as a sign bit and you don't want this, then for $DEITYS sake just don't send data with a high bit. Yes, it is that simple. Do not send a high bit if you don't want to send on. It is a single line of plain stupid C to make sure you don't send one (a cast with a right shift, or a binary AND, depending on what you want to do. Unfortunately you refuse to tell us what you want to do).

For the third time or so you ignore issues which others, as well as I do, consider important to understand what you are really trying. In fact, you apparently deliberately refuse to consider them. In this light statements line

Quote:
I think I must make it clear
sound very arrogant. Because instead of making things clear you are just beating around the bush.

Really,what is so difficult to tell us

tpircher wrote:

a) the voltage you want to measure
b) the voltage applied to the ADC input
c) the integer value read from the ADC
d) the internal representation of the measurement

Stealing Proteus doesn't make you an engineer.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
int16_t hardmath = ADC>>1; // shifts ADLAR induced msb crap away from it. 

/*
can also be achieved by dividing left adjusted result by two, or multiplying the right adjusted result by 32 or shifting by, what, 5, or something.
*/

- Jani