Analog CO2 Sensor for LoPy, can 5v pin power it?
I have a lopy with the pycom lopy expansion board that I am connecting an analog CO2 sensor to. This is a SEN0219 Gravity Analog Infrared CO2 sensor, more HERE
The sensor specification:
Gas Detection: Carbon Dioxide (CO2)
Operating Voltage: 4.5 ~ 5.5V DC
Average Current: <60mA @ 5V
Peak Current: 150mA @ 5V
Output Signal: Analog output (0.4 ~ 2V)
Measuring Range: 0 ~ 5000ppm
Accuracy: ± (50ppm + 3% reading)
Preheating Time: 3min
Response Time: 120s
Operating Temperature: 0 ~ 50 Ԩ
Operating Humidity: 0 ~ 95% RH (no condensation)
Service Life: >5 years
Size: 37mm * 69mm
Vendor states this can be used in a 3.3V system as long as you power it with 5VDC. On the LoPy pin out diagram, the 3.3V pin states an absolute max of 1.2-A max load capability. Does this apply to the 5V pin as well? I assumed so, but I may not be getting enough amps.
CO2 sensor connection: I have the sensor power plugged into the 5vdc pin, the gnd to the gnd and the signal (sensor output) to pin 16.
When I run
adc = machine.ADC() # create an ADC object
apin = adc.channel(pin='P16') # create an analog pin on P16 & connect CO2 sensor
value = apin()
print("ADC count = %d" %(value))
I get an ADC count = 1988
Why is this so high?
If I run the same code without anythign connected I get an ACD count of 4095...
I need to set the attinuation level to 3.3v, but the syntax from the documentation does not work. I tried:
apin = adc.channel(pin='P16', attn=ADC.ATTN_11DB)
But get the error: Traceback (most recent call last) File "stdin", line 1, in <module> ValueError: invalid argument(s) value
While this works:
apin = adc.channel(pin='P16')
How do I properly set the attinuation?
bmarkus last edited by bmarkus
@ledbelly2142 said in Analog CO2 Sensor for LoPy, can 5v pin power it?:
The COZIR sensors look nice. Are they in the sub $100 range?
First hit of Google search gives $109 USD
As an indication you can visit the webshop of ChipCAD, a Hungarian distributor
Prices are in HUF (Hungarian Forint), VAT not included. At the moment 1 USD = 262.6 HUF
But it may vary by distributor, quantity, shipping conditions, custom, etc. and model. You can ask GSS to advice where to buy it, they are good.
Here's the updated code for this sensor with everyone's help. @jmarcelino @robert-hh
In testing it, the results seem reasonable. Not super accurate but enough within 100ppm. Digy-Key has them for $58
import machine from machine import ADC adc = machine.ADC() # create an ADC object apin = adc.channel(pin='P16', attn=ADC.ATTN_11DB) # create an analog pin on P16 & connect CO2 sensor print("") print("CO2 sensor Warming Up") #need initial delay (180) # CO2 sensor needs 3 minutes to warm up print("Reading CO2 Sensor...") value = apin() print("ADC count = %d" %(value)) # LoPy has 1.1 V input range for ADC co2 = (value-400) * (3900/4096.0) print("CO2 Level = %5.1f ppm" % (co2))
The COZIR sensors look nice. Are they in the sub $100 range? I also have CO2 sensors from co2meter.com, the K30. But they are a pain to work with and give very little support. At some point I wanted to create an I2C driver for micropython, but put it off because of the support. Another IoT option for low power gas sensors is Spec-Sensors We have used some of their stuff in the past, but they don't have CO2.
bmarkus last edited by
Analog CO2 sensors does not really fit to todays IoT environment specially low power battery operated devices due to high power consumption and slow operation, long settle time. Take a look on Gas Sensing Solutions sensors. They are fast low power devices with digital interface. It is the data sheet of model I'm using with a LoRaWAN sensor (not PyCom), connected via serial line:
Thank you, makes sense now. Really appreciate it.
I can't find any proper datasheet for your sensor but this plot shows everything you need to know:
At 0 ppm the sensor outputs 0.4v so you you need to subtract 400 (in millivolts) from your voltage reading (the voltage_diference in that formula)
Then you know that 0.4 volts to 2.0 volts (a 1.6 volt range or 0 to 1600 in your voltage_diference from above) equates to a range of 0 to 5000 ppm.
Thanks for your reply and help, I appreciate it. I understand the ADC bit range to 3900 instead of 3300--makes sense.
I am missing the voltage reading completely :( I was going on the ADC example code and explanations. It's gotta be in the documentation somewhere that I can't find. Even when I search the docs for 'voltage', only DAC shows up, not in ADC.
Why do we need the voltage difference -400 value?
How do I apply the concentration to get the value?
is that something like:
int voltage_diference=voltage-400 float concentration=voltage_diference*50.0/16.0 value = apin() co2 = value * concentration(3900/4096.0)
Or would it just be
co2 = value * concentration
The ADC is 12 bit so the range is 0..4095 as @robert-hh explained. The reference is 1.1 Volts.
At ATTN_11DB the full scale goes to 3.9V:
1.1 * math.pow(10.0, 11.0/20.0)so a more correct formula is
value * (3900/4096)
Finally the sample code you linked doesn't just use the voltage reading (what you have now) as the concentration, it takes a few extra calculations.
int voltage_diference=voltage-400; float concentration=voltage_diference*50.0/16.0;
I haven't read the datasheet but I guess you'll need to do the same in your code.
Here is what I used for this sensor:
import machine from machine import ADC adc = machine.ADC() # create an ADC object apin = adc.channel(pin='P16', attn=ADC.ATTN_11DB) # create an analog pin on P16 & connect CO2 sensor print("") print("CO2 sensor Warming Up") #time.sleep(180) # CO2 sensor needs 3 minutes to warm up print("Reading CO2 Sensor...") value = apin() print("ADC count = %d" %(value)) # LoPy has 1.1 V input range for ADC co2 = value * (3300/4096.0) print("CO2 Level = %5.1f ppm" % (co2))
Thanks, I could not find where in the documentation the ADC range?
The vendor of the CO2 sensor used the formula to get CO2 ppm:
I think there are 1024 is the steps on an arduino for the analog in.
So I think the step function to interpret the ppm should be:
value*(3300/4096) which would put us in the range of 711 ppm of CO2. Which sounds about right given that is on my desk right in front of me.
robert-hh last edited by
@ledbelly2142 The range of the ADC is 0..4096. With an attenuation of 11DB, the reading of 883 tells 883*3.3/4096V = 0.71V
Thanks! yes, I only had 'import macine'
Now I get a reading, but it does not look like the sensor is working correctly. I am using ATTN_11DB to make the math conversion easier value * (3300/1024.0)
The raw ADC count is still high, at 883 and its not changing much.
Perhaps I am missing something in the documentation, is the ADC count a division of something? e.g. 883 count = 0.83v?
robert-hh last edited by robert-hh
@ledbelly2142 The 5V pin is connected to the USB 5V or Vin. So it should source enough power to run the sensor. In you example, to use the attenuator, the syntach is:
adc = machine.ADC() # create an ADC object apin = adc.channel(pin='P16', attn=machine.ADC.ATTN_11DB) # create an analog pin on P16 & connect CO2 sensor value = apin() print("ADC count = %d" %(value))
The value will never be 0, since the output of the sensor is in the range of 0.4..2 V. The esp32 is quite noisy, so you should average over a handful samples, like 10.
ADC.ATTN_11DByou must declare what ADC is with
from machine import ADC
I think in your code you must have used
import machineinstead. Alternatively you can also use
machine.ADC.ATTN_11DBbut it's longwinded and unusual.
As for the values the data sheet you linked to suggests the maximum output signal is 2V so you can use
This brings down the signal from 0-2V to the 0-1V the ADC expects, you definitely need the attenuation.
Finally note the internal ADC currently suffers from calibration issues so don't expect much accuracy from the results.