# Getting a number from ADS1015

I have got one of these https://shop.pimoroni.com/products/adafruit-ga1a12s202-log-scale-analog-light-sensor

I am having no trouble reading the value but it is coming out as a voltage.

with

``````from envirophat import analog

``````

but is there a way to get a number like on an arduino analog pin? (between 0 and 1023)
if not how could I map the voltage to a number.
Could I change something in the library?

William

This is a weird question. Iâ€™m sorry :D

Whatâ€™s your use-case? As-in- why do you want to take a perfectly sane voltage reading and map it to a seemingly arbitrary numerical range?

Assuming a target range of 0-1023 (which is what youâ€™d get from a 10bit ADC) and a source voltage of 0-5v (it rarely hits the extremes) then you can just figure out a scale value and simply multiply the value back up:

``````>>> scale = 1023/5.0
204.6
``````

But thatâ€™s a little ugly, so letâ€™s talk about the guts of the system :D

The ADS1015 on Enviro pHAT is configured with a 6.144v â€śfull scale rangeâ€ť, this means its value maxes out at 6.144v, with a granularity of 3 mV.

The ADS1015 is 12bit double-ended (it can measure a positive voltage or a negative voltage) and 11bit single-ended (that 12th bit is the sign bit to denote positive or negative). So thatâ€™s a possible range of 0-2047. (`6.144v / 2047 = 0.003v`)

You can work out how big a number you can store in a given number of bits like so: `2^11-1 = 2047`

To convert it to the 10bit value youâ€™re after (`2^10-1 = 1023) you just shift this value down once, like so:

``````>>> 2047 >> 1
1023
``````

This gives you a precision of 1 == 6mV. So a value of 500 would equal 3V.

### The Code

Now we dive into the library itself. Fortunately itâ€™s not complex code and you need only worry about lines 72 to 78 of ads1015.py: https://github.com/pimoroni/enviro-phat/blob/master/library/envirophat/ads1015.py#L72-L78

``````value /= 2047.0
value *= float(programmable_gain)

if value > self.max_voltage:
self._over_voltage[channel] = True

return round(value / 1000.0,3)
``````

At a full scale range of 6.144v the `programmable_gain` value is simply `6144`, the max voltage stuff is irrelevant and the over_voltage stuff is cruft you probably donâ€™t care about, so letâ€™s simplify this to:

``````value /= 2047.0 # At this point the value is 0 to 2047, this converts it to: 0.0 to 1.0
value *= 6144 # Now we scale back up our range to: 0.0 to 6144.0

return round(value / 1000.0,3) # And divide by 1000 to convert the mV value to V resulting in 0.0 to 6.144
#  (actually 0.0 to 5.3 since you're not supposed to put more than VDD + 0.3v into the ADC!).

# ( note, precision is also lost here because we round to 3 decimal places,
# so the multiply up answer given above is not optimal )
``````

So to get your 0-1023 value, you can change all of this to:

``````return value >> 1
``````

And thatâ€™s a good example of a complex explanation for a simple 1-line answer :D Whew.

### The Problem

If you havenâ€™t noticed already, your 0-1023 range would now be mapped to the full-scale range of the ADC. IE: 0.0v to 6.144v, but you can only input up to 5.3v. This means the biggest number youâ€™ll ever get out of it is about 904. If you can live with that, great, otherwiseâ€¦ well itâ€™s probably just easier to use the first answer :D

Alternatively, you could scale the value slightly differently.

Given that you want 0V to 5V to equate to 0 to 1023 you could come up with a new scale factor to figure out what the 6.144v overvoltage would equal under this scheme.

``````>>> 6144/5000
1.2288
>>> 1023 * 1.2288
1257.0624
``````

When you input 5v (5000mV) at a precision of `1=3mV` you get: 1666.66666667

If we divide this by the full scale range, and then multiply it by our new scale factor, we get the new range:

``````>>> 5000/3.0
1666.66666667
>>> 1666.66666667 / 2047
0.81419964175
>>> 0.81419964175 * 1257.0624
1023.49975574
``````

Damn it, thatâ€™s close enough! Letâ€™s sweep some of that under the rugâ€¦

``````>>> int(1023.49975574)
1023
``````

So the new code snippet becomes:

``````value /= 2047.0 # At this point the value is 0 to 2047, this converts it to: 0.0 to 1.0
value *= 1257.0624

return int(value)
``````
1 Like

Man what an answer! The use case is just displaying it on an led bargraph which I thought would be easier to display with a number. I agree the voltage would definitely be more sane otherwise!

Errrâ€¦ yesâ€¦ apologies for getting maybe a tad carried away ;) And good luck!