8000 drivers: Add driver for MH-Z19 (CO2 sensor) by frestr · Pull Request #3778 · micropython/micropython · GitHub
[go: up one dir, main page]

Skip to content

drivers: Add driver for MH-Z19 (CO2 sensor) #3778

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions drivers/mhz19/mhz19.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# MH-Z19 CO2 sensor driver for MicroPython.
# MIT license; Copyright (c) 2018 Fredrik Strupe

import machine
import utime


class TimeoutError(Exception):
pass


class MHZ19:
'''MH-Z19 CO2 sensor driver'''

def __init__(self, pin, max_value=5000):
'''
Args:
pin: the pin that the PWM pin on the MH-Z19 is connected to.
max_value: upper bound of measuring range. usually 2000 or 5000.
'''
self.pin = pin
self.max_value = max_value

def _wait_on_condition(self, cond, timeout=5000):
start = utime.ticks_ms()
while not cond():
if utime.ticks_diff(utime.ticks_ms(), start) > timeout:
raise TimeoutError

def pwm_read(self):
'''Read CO2 value via PWM pin.

Reading usually takes 1-2 seconds.

Returns:
CO2 value in ppm (parts per million), with an accuracy of
±(50 + result * 0.05) ppm.
Raises:
TimeoutError: if the reading takes more than 5 seconds.
'''
# Wait until a new cycle starts
self._wait_on_condition(lambda: self.pin.value() == 0)
self._wait_on_condition(lambda: self.pin.value() == 1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This second wait shouldn't be needed because the time_pulse_us that follows will wait until the pin goes high.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I must've overlooked that in the docs.


# Measure high and low duration during cycle
t_h = machine.time_pulse_us(self.pin, 1, 1500000) / 1000
t_l = machine.time_pulse_us(self.pin, 0, 1500000) / 1000
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you test that this works and gives accurate readings?

Copy link
Author
@frestr frestr May 15, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did and yes, it does. The results are slightly different than before because of the higher precision in the time readings, but this is negligible compared to the accuracy of the sensor itself. In the datasheet the pulses are given in 2 ms increments though, so it may be possible to round the reading to the nearest increment for more consistent readings.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, that's good to know that it works well. I think this is a good demonstration of how to use the time_pulse_us function.


return self.max_value * (t_h - 2) / (t_h + t_l - 4)
0