Important changes to forums and questions
All forums and questions are now archived. To start a new conversation or read the latest updates go to forums.mbed.com.
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.
- 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.
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 23 Oct 2015The 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);
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 23 Oct 2015