8 years, 7 months ago.

ADC normalized number in LPC1768.

Hi guys! These days, I'm making the AD converter using LPC1768. And I'd got some error and solved due to you guys help!

But I still have some question about uint16_t and read_u16() <- these functions.

I read the data sheet about LPC1768 and this support only 12-bit ADC. So in my opinion, if I use the 16bit data type, maximum analog value should be [ 65535-15 ] because LPC1768 cannot read last 4 digit.(I think maximum number is 1111111111110000 )

However, when I used the uint16_t and read_u16() function, I've still got 65535 adcValue. if you know about this, could you explain this situation? Thanks!!

Charlie.

  1. include "mbed.h"

AnalogIn adc(p20);

Serial pc(USBTX,USBRX);tx,rx

int main() {

uint16_t adcValue;

float voltage;

while(1) {

adcValue = adc.read_u16(); &0xFFF

voltage = adcValue * 3.3 /65535; 2^16 = 65536

pc.printf("ADC Value : %i, %.3f volt \r\n", adcValue,voltage);

wait(0.1);

} }

1 Answer

8 years, 7 months ago.

As I mentioned in the previous question: Those four LSBs of your result are filled with the four MSB values. This allows it to go from 0x0000 to 0xFFFF.

So if it goes from 0x0FF to 0x100, the 16-bit result will go from 0x0FF0 to 0x1001. It isn't perfect, but that is also not possible since it is just a 12-bit ADC. This way it can go from zero to 0xFFFF in a monotonic fashion.

Accepted Answer

Hi Erik!.

Thank you for your help! really appreciate it!

Now I got what you said. is that basic knowledge about C++? if you have some pages which explain about that, could you let me know?

Charlie.

posted by Gucheol Jeong 23 Oct 2015

The functions to do it are basic C, but I don't know if it is anywhere really explained. The function used in the source code to go from 12-bit to 16-bit is:

result16 = (value12 << 4) | (value12 >> 8);
posted by Erik - 23 Oct 2015

It's not c++, it's maths and logic combined with a little understanding of the relative speeds of different operations inside a processor.

Different boards have different numbers of bits in the ADC. So that software is portable read_16() needs to always return a value between 0x0000 (0) and 0xFFFF (65535)

So we need to scale a value that goes from 0 to 4095 to instead go from 0 to 65535. A simply multiply by 16 (shift left by 4 bits) almost gets us there but that would give us a value from 0 to 65520. How do we do better?

You could do it by converting it to a floating point number, multiply by 16.003663 and then rounding it back to an integer.

Or you could do it all with binary integer operations:

  • Take the ADC value and shift it left 4 bits. (multiply by 2^4 = 16)
  • Take the ADC value and shift right by 8 bits. (divide by 2^8 = 256, or multiply by 1/256 = 0.00390625)
  • Finally add the two values together (multiply by 16.0039)

Only since we know the two values won't have any bits overlapping we can use a bitwise or rather than an addition.

Multiplying by 16.0039 and then rounding down to the nearest whole number works out perfect for what we want.

The big difference is that the integer method takes about 3 CPU cycles. The floating point method would take about 300 CPU cycles.

How you structure the code to make sure the compiler does it as efficiently as possible may be c/c++ specific but everything else is completely generic and true for any language and any CPU.

posted by Andy A 23 Oct 2015

Wow! I got it haha

Thank you for answer Erik and Andy.

Charlie.

posted by Gucheol Jeong 26 Oct 2015