It depends on what you mean by "convert". If you mean that you have a binary value and you want to display it as a decimal value, then you'd use the .dec method in whatever display driver you're using. If you want to produce a string of characters suitable for writing to a disc file, some of the SD card drivers have the same .dec method.
If you are meaning that the 00000000-11111111 is a binary value, then
x = %1111_1111
You can use the underscore in a binary value like this
00000000_11111111 but not the hyphen. SPIN ignores the "_" in a binary number.
i mean i want to convert a binary value ranging from 00000000 to 11111111 to a dec value ranging from 1 to 100 that i can have as a varible in the program
i mean i want to convert a binary value ranging from 00000000 to 11111111 to a dec value ranging from 1 to 100 that i can have as a varible in the program
Oh, sorry about that.
You don't convert anything still
Say that X = 1, then that is the same as saying X = %00000001 or $01
You can use the numbers interchangeably, no need to convert anthing except for display purposes on TV or LCD etc. In those cases, you display using ser.dec or ser.hex or ser.bin and show what you want to see as output.
%000000000 = 0 = $00
%11111111 = 255 == $FF there no conversion internally required.
1. Convert binary to dec
2. Change the range of a variable
1. You only need to convert when inputting or outputing the value in a variable is the same. So if you have a variable x and you have assign a binary value as T Chap explained then its also the same value in dec.
2. If you want to change the range from 0-255 to 0-100 then multiply by the output range and divide by the input range so
x_100 := (x_255 * 100)/255
To follow on from Timmoore, converting 0-255 to 0-100 would be to divide by 2.55. However, that assumes you are using floating point numbers. If you are using integers, then first multiply by 100 and then divide by 255. You can do that in two lines of code, or combine it to one line as Timmoore has done.
2. If you want to change the range from 0-255 to 0-100 then multiply by the output range and divide by the input range so
x_100 := (x_255 * 100)/255
I think you are close -- but radialrandy is converting from 256 values (0..255) to 101 values (0..100) so I think a more accurate computation would be:
x_100 := (x_255 * 101)/256
Both calculations, for x_255 == 255, give x_100 == 100, but for x_255 == 254, Timmoore's calculation gives x_100 == 99, while this one gives x_100 == 100.
The more general conversion from x in [a..b] to y in [s..t] would be:
y := ((x - a) * (t-s+1) / (b-a+1)) + s
But I think this might be a bit of nit-picking, because:
ill be reading a 0 to 100psi sensor that will be converted through a 8bit ADC. so i want to convert the 8 bit value to 0 to 100 in my program
So the the maximum pressure signal from the pressure sensor might not correspond to the maximum measurable signal for the ADC, without careful calibration, and then there is always drift...
x_100 and x_255 are variable names. The "_" is treated like a letter for the purpose of making up a variable name. It also is allowed as a separator in numbers where it's ignored, but used to make a long string of digits more readable.
The formula is the same as A := (B * 101) / 256
It takes value B which ranges from 0 to 255 and converts it to a value A which ranges from 0 to 100 keeping all values proportional.
I think they are simply to distinguish two variables, one named "x_100" which holds a value in the range 0..100 and "x_255" that holds a value in the range 0..255. They could as easily be called "Fred" and "Ginger":
Fred := (Ginger * 101) / 256
This "convention" was intrduced in the post by Timmoore, but it might be a little clearer if it were completely written up as a method:
PUB ConvertADCtoPSI( x_255 ) : x_100
'' Convert an ADC 8-bit value to a PSI value in the 0..100 psi range
'' x_255 -- the incoming ADC value, in the range 0..255
'' Returns a value in the range 0..100
x_100 := (x_255 * 101) / 256
Phil, I didn't mean to imply that Tim Moore's formula would not work -- if I did, I apologize.
I was trying to point out the Tim's formula was not uniform over the input range -- it seems to be a little off at the high end.
Maybe I can explain another way, with a simpler example all for the truncation (rounding down) case.
Tim's formula is for the input range of [0..255] (call that [0..A]), and an output range of [0..100] (call that [0..B]):
output := (input * B) / A ' Tim Moore
My formula for the same ranges is:
output := (input * (B+1)) / (A+1) ' Ding-Batty
So, consider a slightly different input and output range: input of [0..99], and output of [0..9]. This is obviously (to me) a divide-by-ten, so that 90..99 should become 9, 80..89 should become 8, etc.
Using Tim's approach, the function used would be:
output == ( input * 9 ) / 99
== input / 11
This does correctly turn 99 / 11 --> 9, but 90 through 98 all become 98/99 --> 8!
Using the approach I suggested:
output == ( input * 10 ) / 100
== input / 10
Now, perhaps the problem is that "100" value, perhaps it is special, in that it is the upper limit of the range from the sensor. That would imply that the "255" input value was also somehow special But I think that all depends on the interpretation of the sensor signal as converted by the ADC, and from what I understand about ADC conversions, I think it should not be treated as special.
The nearest common ADC I have is my "3-1/2 digit DMM" with a 20VDC input range. The meter can show me converted values from 00.00 to 19.99, plus it has a overrange indicator which means the input is 20 volts or greater.
That maximum value of 19.99 really corresponds to voltages in the range 19.990000...V to 19.999999...V (up to, but below, 20V). The easy way to indicate this range is [19.99 .. 20.00) (that is math notation for a half-open interval, which includes the left number, all the way up to, but not including the right number).
In the same way, for the 0..255 output of the ADC, each value, including 255, stands for a range of input values. The "special" limit value is really 256, which corresponds to the 20.00 for the DMM.
Here's where we get the the second point I was trying to make. Radialrandy said that he is using a pressure sensor that goes up to 100psi. I don't know if that really means 0..99.9999... psi. Furthermore, I am sure that there is some variation in construction of the sensors, so that some can report pressures higher than 100psi. And there may be variation in the precision of the output between individual sensors, so that the same pressure produces different output signals from different sensors. So there needs to be calibration of the sensor and ADC combination, and only then is there enough information about the meaning of the input signal (0..255) to know which of the several conversions is most appropriate. This is the meaning of the "nit-picking" comment I originally made.
One more possible misunderstanding on my part: if the ADC output value of "255" corresponds to the overflow value (i.e. all input values bigger than the max expected value are converted to this), then if the ADC is calibrated for 255 to be returned when 100.000 psi is reached, and not at any lower pressure, then Tim Moore's function would match mine, in that I would calculate: output := (input * 100) / 255 as well, because the basic ranges are [0..254] and [0..99], with 255 and 100 both handled as a special case. But that all depends on the real meaning of the values coming out of the ADC. (Clearly, I don't have much experience with real ADC chips...)
thanks guys I have a much better understanding now. This pressure scale does not have to be perfect just close. I understand that the pressure sensor may not give perfect value so any of your recommendation will work great. I found that the sensor that I'm using actually has a span on 4.5V.
.2 volts = 0psi
4.7volts = 101.5psi
So I'm going to have to modify the formulas examples that you all gave me alittle more.
thanks for the good info.
I'm leaning more and more every time you guys give your inputs.
PUB sensor | ADC, T, dT
dira[23..16]~ 'pins reading ADC of psi sensor
dira[24]~~ 'output pin to WD/RDY tp start measurement
outa[24]~~
T := cnt
dT := 800_000
repeat
T += dT
waitcnt(T)
outa[24]~
waitcnt(40_000 + cnt)
outa[24]~~
waitcnt(40_000 + cnt)
ADC := ina[23..16] '0 to 255 binary reading from 8bit parallel ADC
co2psi := (ADC * 101) / 256
OK guys with your help I got this thing to scale a 0 to 255 reading to a 0 to 100 reading perfectly . Id like to go a step further and scale the 0 to 255 to 0 to 100 but in .5 incrementals. Is this doable?
ADC := ina[23..16] '0 to 255 binary reading from 8bit parallel ADC
co2psi := (ADC * 101) / 256
OK guys with your help I got this thing to scale a 0 to 255 reading to a 0 to 100 reading perfectly . Id like to go a step further and scale the 0 to 255 to 0 to 100 but in .5 incrementals. Is this doable?
You could probably figure this one out yourself, without our help. But here's how I'd approach it...
You want the output range to be 0.0..100.0 in 0.5 increments. I'd consider the values to be doubled, i.e. 0.0..200.0 and divide at the end by 2. So I'd use something like this:
ADC := ina[23..16] '0 to 255 binary reading from 8bit parallel ADC
co2psi_x_2 := (ADC * 201) / 256 ' 0..200
co2psi_int := co2psi_x_2 >> 1 ' divide by two to get 0..100
if ( co2psi_x_2 & 1 )
co2psi_frac := 5 ' for 0.5, since the scaling was odd
else
co2psi_frac := 0
One good measure of an integer scaling formula is to measure the root mean square (RMS) error of each scaled and rounded value vs. what the scaled value would have been in floating point, over the domain of interest. The RMS error is given by:
ErrorRMS = sqrt(Σ(yi - ri)2 / n), where
yi and ri are the rounded and real values, respectively, and n is the number of values in the range of interest.
The smaller ErrorRMS is, the better the rounding formula.
I'm assuming, for the sake of argument, that in this app, ri = i * 100 / 255, where i is the ADC reading in the range 0 to 255, making n equal to 256.
So I wrote a little Perl script to compare Tim Moore's round-down formula, Ding-Batty's "Fred and Ginger" formula (with the 101), and my 5/4 round up/down formula. Here's the script:
Comments
x = %1111_1111
You can use the underscore in a binary value like this
00000000_11111111 but not the hyphen. SPIN ignores the "_" in a binary number.
i mean i want to convert a binary value ranging from 00000000 to 11111111 to a dec value ranging from 1 to 100 that i can have as a varible in the program
Oh, sorry about that.
You don't convert anything still
Say that X = 1, then that is the same as saying X = %00000001 or $01
You can use the numbers interchangeably, no need to convert anthing except for display purposes on TV or LCD etc. In those cases, you display using ser.dec or ser.hex or ser.bin and show what you want to see as output.
%000000000 = 0 = $00
%11111111 = 255 == $FF there no conversion internally required.
Oops. Just read your last addition.
1. Convert binary to dec
2. Change the range of a variable
1. You only need to convert when inputting or outputing the value in a variable is the same. So if you have a variable x and you have assign a binary value as T Chap explained then its also the same value in dec.
2. If you want to change the range from 0-255 to 0-100 then multiply by the output range and divide by the input range so
x_100 := (x_255 * 100)/255
I think you are close -- but radialrandy is converting from 256 values (0..255) to 101 values (0..100) so I think a more accurate computation would be:
Both calculations, for x_255 == 255, give x_100 == 100, but for x_255 == 254, Timmoore's calculation gives x_100 == 99, while this one gives x_100 == 100.
The more general conversion from x in [a..b] to y in [s..t] would be: But I think this might be a bit of nit-picking, because:
So the the maximum pressure signal from the pressure sensor might not correspond to the maximum measurable signal for the ADC, without careful calibration, and then there is always drift...
what exactly is the formula doing?
x_100 := (x_255 * 101)/256
wheres the binary number?
I could not find info on the x_ in the prop book
The formula is the same as A := (B * 101) / 256
It takes value B which ranges from 0 to 255 and converts it to a value A which ranges from 0 to 100 keeping all values proportional.
This "convention" was intrduced in the post by Timmoore, but it might be a little clearer if it were completely written up as a method:
Tim Moore's formula is correct for round-down (i.e. integer truncation):
255 * 100 / 255 == 100.
255 * 0 / 255 == 0.
For 5/4 round-up/down, the correct forumula would be:
x100 = int(x255 * (100 / 255) + 0.5)
= int((x255 * 200 + 255) / 510)
= (x255 * 200 + 255) / 510, using integer arithmetic.
-Phil
I was trying to point out the Tim's formula was not uniform over the input range -- it seems to be a little off at the high end.
Maybe I can explain another way, with a simpler example all for the truncation (rounding down) case.
Tim's formula is for the input range of [0..255] (call that [0..A]), and an output range of [0..100] (call that [0..B]):
My formula for the same ranges is:
So, consider a slightly different input and output range: input of [0..99], and output of [0..9]. This is obviously (to me) a divide-by-ten, so that 90..99 should become 9, 80..89 should become 8, etc.
Using Tim's approach, the function used would be:
output == ( input * 9 ) / 99
== input / 11
This does correctly turn 99 / 11 --> 9, but 90 through 98 all become 98/99 --> 8!
Using the approach I suggested:
output == ( input * 10 ) / 100
== input / 10
Now, perhaps the problem is that "100" value, perhaps it is special, in that it is the upper limit of the range from the sensor. That would imply that the "255" input value was also somehow special But I think that all depends on the interpretation of the sensor signal as converted by the ADC, and from what I understand about ADC conversions, I think it should not be treated as special.
The nearest common ADC I have is my "3-1/2 digit DMM" with a 20VDC input range. The meter can show me converted values from 00.00 to 19.99, plus it has a overrange indicator which means the input is 20 volts or greater.
That maximum value of 19.99 really corresponds to voltages in the range 19.990000...V to 19.999999...V (up to, but below, 20V). The easy way to indicate this range is [19.99 .. 20.00) (that is math notation for a half-open interval, which includes the left number, all the way up to, but not including the right number).
In the same way, for the 0..255 output of the ADC, each value, including 255, stands for a range of input values. The "special" limit value is really 256, which corresponds to the 20.00 for the DMM.
Here's where we get the the second point I was trying to make. Radialrandy said that he is using a pressure sensor that goes up to 100psi. I don't know if that really means 0..99.9999... psi. Furthermore, I am sure that there is some variation in construction of the sensors, so that some can report pressures higher than 100psi. And there may be variation in the precision of the output between individual sensors, so that the same pressure produces different output signals from different sensors. So there needs to be calibration of the sensor and ADC combination, and only then is there enough information about the meaning of the input signal (0..255) to know which of the several conversions is most appropriate. This is the meaning of the "nit-picking" comment I originally made.
One more possible misunderstanding on my part: if the ADC output value of "255" corresponds to the overflow value (i.e. all input values bigger than the max expected value are converted to this), then if the ADC is calibrated for 255 to be returned when 100.000 psi is reached, and not at any lower pressure, then Tim Moore's function would match mine, in that I would calculate: output := (input * 100) / 255 as well, because the basic ranges are [0..254] and [0..99], with 255 and 100 both handled as a special case. But that all depends on the real meaning of the values coming out of the ADC. (Clearly, I don't have much experience with real ADC chips...)
BTW, you can call me Tom...
.2 volts = 0psi
4.7volts = 101.5psi
So I'm going to have to modify the formulas examples that you all gave me alittle more.
thanks for the good info.
I'm leaning more and more every time you guys give your inputs.
OK guys with your help I got this thing to scale a 0 to 255 reading to a 0 to 100 reading perfectly . Id like to go a step further and scale the 0 to 255 to 0 to 100 but in .5 incrementals. Is this doable?
You could probably figure this one out yourself, without our help. But here's how I'd approach it...
You want the output range to be 0.0..100.0 in 0.5 increments. I'd consider the values to be doubled, i.e. 0.0..200.0 and divide at the end by 2. So I'd use something like this:
yi and ri are the rounded and real values, respectively, and
n is the number of values in the range of interest.
The smaller ErrorRMS is, the better the rounding formula.
I'm assuming, for the sake of argument, that in this app, ri = i * 100 / 255, where i is the ADC reading in the range 0 to 255, making n equal to 256.
So I wrote a little Perl script to compare Tim Moore's round-down formula, Ding-Batty's "Fred and Ginger" formula (with the 101), and my 5/4 round up/down formula. Here's the script:
And here's the output from the script:
-Phil