10-bit ADC converted into decimal number between 0 and 100

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

I am trying to take in 10-bit result from an ADC and then change it to a number between 0 and 100. Ideally, this would be done by dividing by 2.56.

How can I do this without loosing all my precision? (I am writing in assembly.)

Also, I am confused about the format (N.Q) as described in the 8-bit AVR instruction set under FMUL.

Thanks,
Beth

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

A 10 bit number from the ADC represents a number from 0 to 1024. If you divide by 10 you get a number between 0 and 102. In practice it is somtiemes ideal to assume that if the vlaue read is within 1 or 2% of Full scale, it is assumed to be full scale. This avoids problems with slight voltage drops due to a reference voltage driving sensor electronics.
If this was the case then by simply making 101 and 102 equal 100, you are acheiveing this objective very simply.

In c this would be written

value = ADC / 10; //Value and ADC both being 16 bit
if (value > 100) value = 100;

Lachlan

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

Take your 10 bit number, multiply by 25, then divide by 256 (take upper byte of result). For example A/D reading = 1024
1024 x 25 = 25600 or 6400hex
upper byte = 64hex or 100dec.

Where did 25 come from ? 1024/100 = 10.24 If we were able to divide by 10.24 we would scale the A/D reading to a value ranging from 0-100. But we should avoid dividing when possible. So lets multiply by the recipicol (1/10.24 = 0.09765625). Next question - how do you multiply by 0.09765625 ? We will rescale our scaler by multipling it by 256 (0.09765625 x 256 = 25). The additional scaler of 256 is nice because it's easy to take back out of the answer by just using the MSB of the result.

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

Hi,

I am pretty noob at all this, but how did you read the 10 bit data in? Aren't you limited to just 8 bits with an 8 bit microcontroller?

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

cached21 wrote:
Hi,

I am pretty noob at all this, but how did you read the 10 bit data in? Aren't you limited to just 8 bits with an 8 bit microcontroller?

You can combine registers, to increase your data size.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

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

You are correct SteveN. Let me give this another shot.

1023/100 = 10.23
(1/10.23) x 256 = 25.02443793 or ~= 25

1023 x 25 = 25575 or 63E7 hex or 63.E7 hex or 01100011.11100111 (MSB.LSB)

Take look at bit 7 of the LSB. Since it is set, we will round up (add 1 to) MSB of result. Value 63hex (99dec) rounds up to (100dec). We will do this for all values for which bit 7 of the LSB is set. Of course, if bit 7 of the LSB is clear, we do not change the MSB value.

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

awesome gahelton, thats some magic steps there to get a result.
I had to improvise on your equation to get a scale from 0 to 100 to one decimal place.
for info:
10bits all set --> [gahelton's process] --> dec(upper byte)
now take the lower byte [after gahelton's process] multiply by 10 and again take the dec(upper byte) for the decimal

Quote:
You can combine registers, to increase your data size.

Im new to AVR. how do you do this? [no mention in the m16 datasheet or avrbegginners]

I tried this :

convertadc:	
clr		xl	; here we convert the 10 bit adc to a 100 decimal
clr		xh
;ldi		xh,0b00000011     ;test with all 10bits set
;ser		xl							
mov		adclow,xl	;move adc  10 bit to 16 bit x register
mov		adcup,xh
ldi		temp,25				
mul		x,temp	; multiply X reg by 25
mov		adcup,xh	; strip off upper byte of X and store  on adcup
clr		x                   ;clear upper byte of X
ldi		temp2,10
mul		x,temp2	;multiply X reg by 10
mov		adclow,xh	; strip off upper byte of X and store  on adclow
ret

the mul instruction doesnt seem to be working! HELP?

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

actually we do mention 16-bit maths: http://www.avrbeginners.net -> avr assembler -> math -> multiple byte maths

Regards,

Christoph

I tend to post off-topic replies when I've noticed some interesting detail.
Feel free to stop me.

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

And maybe 0 to 99 is more true than 0 to 100

Because your ADC is also going from 0 to 1023 (and not 1024)
Where 1024 would represent 100% of VRef (ADC)
But your ADC is ever decoding up to 1LSB below VRef.

With 0 to 100 in fact it can be correct(with rounding), but with one decimal added, you only get values from 0.0 to 99.9 (with rounding).

from 0 to 100 i would do it gahelton´s way.

Rounding:
(INFO: if i do maths with assembler and AVR,
i often use to set Reg2 =0
so i can perform: ADC DReg,Reg2 to add the carry to DReg. i avoid the BRCS/BRCC or SBRS/SBRC instructions --> I don´t like the many branches)

shift lower byte one to the left: lsl Lowbyte (then bit 7 is in Carry)
then add Carry to Highbyte: ADC highbyte, Reg2, (reg2=0)
(That´s a kind of taste i think)

Or the common way:
SBRC lowbyte, 7
adi highbyte,1
*Rounding finished

Klaus
********************************
Look at: www.megausb.de (German)
********************************

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

Soory to all,

SteveN is absolutely right!

1) there is no ADI
2) ADIW is used with words, and it can be done if 16 bits are needed.
3) to add only the carry: look at my TASTE
4) i sometime use "SUBI REG, -1" or "SUBI REG,255" instead of "ADI REG,1" but i don´t know what the Flags say after the instruction.

My mind is:
* A + B = A - (-B) where A is my Register and B the "1"
* 255(unsigned) = 0xFF = -1 (signed)

again sorry for my mistake

Klaus

Klaus
********************************
Look at: www.megausb.de (German)
********************************

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

I have the same problem. Using the ADC 10bit at the Mega16 chip. In CodevisionAVR I get the 10bits number in ADCW register (ADCL and ADCH registers together). How do convert this number to decimal number that shows the analog voltage at the ADC?

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

ebbesson wrote:
I have the same problem. Using the ADC 10bit at the Mega16 chip. In CodevisionAVR I get the 10bits number in ADCW register (ADCL and ADCH registers together). How do convert this number to decimal number that shows the analog voltage at the ADC?

With a bin2dec conversion.
The trick is substract 1000 (but subi r16, 1000 is not possible!) and when smaller then 1000 start substracting 100 until smaller then 100, then start substracting 10 until smaller then 10, etc.
All the counts are the decimal numbers from msb to lsb.

1 0 2 and 3 makes 1023.

RES

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

I dont know if I understand. Can u give me a exampel? Ex. if I hade the register ADCW = 0b0110011111 ?

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

Or can i do the bitvalue to the voltage that I have on the ADC pin?

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

ebbesson wrote:
I dont know if I understand. Can u give me a exampel? Ex. if I hade the register ADCW = 0b0110011111 ?

You can use your Windows calculator for help substracting 1000 binairy, or hexadecimally, etc.
Numbers greater than 256 and smaller than 65536 use 2 registers. Upper and lower bytes.
I don't know how to substract > 1000 binairy with ASM or C. Not yet done it.

RES

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

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.