to the electrical engineers and c programmers

Homebrew Talk - Beer, Wine, Mead, & Cider Brewing Discussion Forum

Help Support Homebrew Talk - Beer, Wine, Mead, & Cider Brewing Discussion Forum:

This site may earn a commission from merchant affiliate links, including eBay, Amazon, and others.

KuntzBrewing

Well-Known Member
Joined
Aug 22, 2011
Messages
630
Reaction score
13
Location
Kokomo
I'm using Atmega Studio 6 and an ATmega328P on an arduino board. I've coded an Analog to Digital converter and can successfully read analog inputs on a scale of 0-1023 (10bit memory space is fixed)

I made a voltage splitter (voltage divider circuit) that halves my input of 5Vcc, but for some reason I cannot convert my adc value to a voltage. Which sounds simple (adcvalue*5000mV/1023) to get a value saved in an unsigned 16bit value. My result is 0 or some invalid answer. I tried saving this as a float in a regular voltage (*5V not *5000Mv) but using print(%f, voltagevalue) returns a "?", using %d yields "0"

I thought it was an overflow issue (adc of 512 * 5000 gives 2.5Million+ return) I went as far as saving it as a unit64_t. Didn't work. I want to make sure my values are correct so I use printf and read them on a hyper terminal using serial communication between board and computer. I even printed a hex number (showed 0xFC78) which wouldn't be correct.
Has anyone ran into this problem or can anyone come up with a solution.

The whole reason behind this is to read a thermistor, but I'm using a voltage divider to test the values for now. Grounding gives me a reading of 0 full on gives 1023. Circuit reads 512 (which is about half) so I know its right
 
Sounds like a type casting issue. Can you post the line of code that is not working, and the type defs for the variables uses?

It might be as simple as changing 5000 to 5000.0
 
Firstly, I think your "/1023" should be /1024
Next, I agree with the overflow as 512 * 5000 is > 16 bits. (I'm not sure what a unit64_t is. I'm guessing uint64_t but does your compiler and hardware support 64 bit ints?)
The easy fix is to change 500mV/1024 to 625mV/128 (divide both components by 8). This ensures that the multiplication of the adc value does not overflow.
As WoodlandBrew said, if you try saving it as a float but you multiply by 5 instead of 5.0, you will get wrong answers (and you should get compiler warnings).

-a.
 
You'll have to typecast (for promotion) such that the intermediate result does not overflow:

unsigned short adcvalue = ReadADC();
unsigned short result = (unsigned short)((int)adcvalue * (int)5000 / (int)1023);

Just make sure your int's are 32 bit, otherwise you'll have to more work.

Also make sure you're reading the 10bit adc into at least a 16 bit variable.

The " / 1023 " is correct as your min and max values are 0 and 1023 which give you 1024 unique values for the range. Using 1024 would produce a scaling error at the top of range limiting it to 4995.
 
If you want the best accuracy, try:

unit16 reply;

reply = (adcvalue * (5000 / 8) + 1024 / 16) / (1024 / 8) ;

This will work with 16 bit unsigned integers, handles all 1024 adcvalues, and includes rounding.

-a.
 
I would mask the 10 bit value you are reading when you do the assignment as well, to make sure it's exactly 10 bits of data. It could be you are getting junk in the other 6 bits (or however many bits are in the data type you're assigning to).
 
weirdboy said:
I would mask the 10 bit value you are reading when you do the assignment as well, to make sure it's exactly 10 bits of data. It could be you are getting junk in the other 6 bits (or however many bits are in the data type you're assigning to).

Which would explain the 0xFC78, which is 6 1s followed by 0x0078 (120).
 
Im gonna try type casting. Im kinda jumping the gun on this project i basically know the basics of c and am in an intro to digital systems class. But now that im able to flash leds i think i can write huge complex codes to do all kinds of cool stuff. Thats partially my problem lol but its fun to learn anyways.
 
That's more than likely the two's compliment representation of a negative number.

Invert:
0x0387
add one
0x0388
convert to decimal and add the sign:
-905


Ya know that crossed my mind, although the negative value seemed less relevant.

I once tried to pull undocumented data from Canon digital pictures' EXIF field. There were some values in 2's compliment, and some straight signed binary. It was a mess. Hopefully if nothing else this board is consistent. For the sake of doing math efficiently it would almost have to be.
 
Which would explain the 0xFC78, which is 6 1s followed by 0x0078 (120).
Looks to me like a 16 bit read from the ADC. The lower 10 bits are driven, but the upper 6 bits default to 1's With the OP's current knowledge of programming, he may not have considered the state of the upper 6 bits.

-a.
 
weirdboy and ajf have a point and it certainly wouldn't hurt to try.

unsigned short value = adc & 1023;

Just remember to promote back to int to avoid overflow.
 
I solved the problem. I dont know why but the order that i was having the program print the variables. I changed nothing but the order they were printed (in the same line of code and on screen) and it magically worked.

The compiler is always out to get you
 
This didnt work:
Printf("ADC value is %d and voltage is %d \r", adcValue, inVoltage);

This did:
Printf("ADC value is %d and voltage is %d \r", inVoltage, adcValue); of course this one didn't make correct sense until I changed the wording around to the correct statement went with the correct value.

Makes no sense but its fixed lol
 
Back
Top