Still digging into the MH-Z14 CO2-sensor from Winsensor.com. This great module offers calibrated measurements of CO2-levels. Currently, I'm already using the module over PWM on my Arduino project. Yet, I'm dreaming of having it up using UART.
Under Arduino, I couldn't get it running up to present. The friendly people at Winsensor have been very patient answering my questions. On their advice, I tried getting the sensor to work directly over FTDI. For this project, you'll be needing an FTDI connector on 3.3 V (and a 5V power source). My friend Netrunner borrowed me his great USB-FTDI adaptor from moderndevice.com called USB-BUB 1. It supplies both 5V and 3.3 power and you can choose what voltage the logic levels run on. Don't forget to set the jumper to 3.3V or you'll fry a pretty expensive sensor.
So I dug up my Python, went to the hackerspace and started trying stuff out... Ptr_ gave me some great pointers and helped me out when I got stuck every now and then.
So first thing I needed, was to figure out what USB-port the FTDI device was on. The command line terminal and the "dmesg" command helped me out on that one. I just added a piped command "grep FTDI" to filter out only those lines showing FTDI in them... Straight after pluggin in the FTDI device, it should appear at the end. Here's my output:jurgen@jurgen-ThinkPad-X200:~/python$ dmesg | grep FTDI[12596.125347] USB Serial support registered for FTDI USB Serial Device[29945.160257] ftdi_sio ttyUSB0: FTDI USB Serial Device converter now disconnected from ttyUSB0
[29947.589276] ftdi_sio 3-1:1.0: FTDI USB Serial Device converter detected
[29947.591270] usb 3-1: FTDI USB Serial Device converter now attached to ttyUSB0jurgen@jurgen-ThinkPad-X200:~/python$
For connecting the CO2-sensor to the FTDI, I put pad 12 (TX) to the RX-pin, pad 13 (RX) to the TX-pin, 14 to the 5V-pin and pad 2 to the GND-pin. Note that the datasheet of the MH-Z14 contains some errors on the pad assigments... RX and TX were mixed up. The information printed on the PCB is correct though.
The output tells me the connector is found on USB connection ttyUSB0. We're going to need this in our Python code. The Python pySerial library is doing all the magic here... so be sure to love the online documentation.
Here's the code we put together during the day:import time # Not strictly needed, but used to slow down the readings, and add a timestamp
import serial # Needed for communicationser = serial.Serial('/dev/ttyUSB0',9600,timeout=1) # open first serial port
print("connected to: " + ser.portstr)sendList = ['ff','01','86','00','00','00','00','00','79'] # Found in the datasheet # Calculated the last byte# A small helper function to send the needed bytes to the UART portdef launch():
for item in sendList:
ser.write(chr(int(item, 16)))while True: # The first occurance tends to return empty - skip it
characters = ser.read(9)
if(len(characters) == 9):
print time.strftime("%H:%M:%S - "),
print "CO2-level: ", # CO2-level is value of byte 2 * 256 + the value of byte 3 of the stream # Using ord() to convert the value from an ASCII sign to it's ordinal value
print ord(characters)*256 + ord(characters) launch()
time.sleep(15) # just a little delay in the loop ser.close() # close port
Now, the main reasons for this approach were: speed (not needing a full second to read the data) and accuracy (the current PWM-approach is really an approximation and probably contains small errors). Surprisingly, when using the MH-Z14 sensor (I have the one configured for the range 0-2000 PPM), the range easily exceeds the guaranteed range and returns values of up to 5000 PPM. This is an added advantage! Don't think you can then still rely on the same accuracy, though.Hope to be reporting on how to use UART to interface with the Arduino somewhere in the near future now...