-
11TMP36 analog temperature sensor
Not the most versatile and modern device to measure temperatures, but when you happen to have an ADC free and a bag of TMP36s, it's an easy, space efficient and reliable way to add temperature measurement to your project. The TMP36 outputs measured temperature as analog voltage, 10 mV / °C. There are also TMP35 and 37, but their measurement ranges aren't as convenient (TMP35 +10°C to +125°C, TMP36 -40°C to +125°C, TMP37 +5°C to +100°C, TMP36 being the only one good for freezing temperatures). To make it even easier, there are libraries for directly getting the C or F temperature.
Initialization
#include TMP36 myTMP36(A0, 3.2); //3.2 volts max ADC for the Wemos TMP36 myTMP36(A0, 1.0); //1.0 volts max ADC for plain ESP
setup()
Not needed.
Use
float celsius = myTMP36.getTempC(); float fahrenheit = myTMP36.getTempF();
-
12DS18B20 one-wire temperature sensor
Dallas Semiconductors' one-wire protocol is convenient for attaching several low power sensors to a single GPIO. It even supports using the power line as data wire, thus requiring only two wires for the sensors, which would in some cases make wiring much easier and robust.
For now just the simple case with separate data line, one sensor and synchronous calls.
Initialization
/* DS18B20 temperature sensor *****************************/ #include #include #define ONE_WIRE_BUS D4 OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire);
setup()
sensors.begin();
Use
sensors.requestTemperatures(); //Process temps temp_ds1820 = sensors.getTempCByIndex(0); //Get 1st sensor temp
-
13Placeholder-1
Stuff to be added here.
-
14DHTxx temperature / humidity sensor (AKA AM23xx)
Something that my project more often use than not. Max 4 of those with a single ESP8266 so far. I only use DHT22 to get proper accuracy for dew point calculations. DHT22 is commonly sold with a breakout board with a capacitor and pull-up resistor, should be more reliable and I'm mostly using those, but the plain version seems to work fine as well, and would be the choice for tight spots. The price difference is just a few cents, so might as well get those with the PCB, when not space constrained.
DHT uses its own two-way communication, and doesn't support more than one device per GPIO. Might be possible to use 1-wire or I2C GPIO extenders to add more, to be tested.
Datasheet: http://akizukidenshi.com/download/ds/aosong/AM2302.pdf (DHT22 = AM2302)
Library: https://github.com/adafruit/DHT-sensor-library
Initialization
#include "DHT.h" #define DHT_TYPE DHT22 #define PIN_DHT_1 D5 #define PIN_DHT_2 D6 //Not needed for single DHT DHT dht1(PIN_DHT_1, DHT_TYPE); DHT dht2(PIN_DHT_2, DHT_TYPE); //Not needed for single DHT
Setup()
dht1.begin(); dht2.begin(); //Not needed for single DHT
Use
float temperature_dht_1 = dht1.readTemperature(); float humidity_dht_1= dht1.readHumidity(); if (isnan(humidity_dht_1) || isnan(temperature_dht_1)) Serial.println("Failed to read from DHT sensor!"); delay(2000); //Before next round, let the DHT cool down and stabilize
-
15BMP280 / BME280 I²C air pressure, temperature and humidity (BME) sensor.
Datasheet: https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BME280_DS001-11.pdf
Library, BMP sensor: https://github.com/adafruit/Adafruit_BMP280_Library
Library: BME sensor: https://github.com/adafruit/Adafruit_BME280_Library
Single BMP280
Initialization
#include <Wire.h> #include <Adafruit_Sensor.h> #include <Adafruit_BME280.h> // BMP280.h for BMP sensor with humidity Adafruit_BME280 bme; //BMP280 for BMP sensor
Setup()
if (!bme.begin(0x76)) Serial.println("Could not find a valid BME280 sensor");
Use
float temp = bme.readTemperature(); float pressure = bme.readPressure() / 100; float humidity = bme.readHumidity(); //BME only, BMP doesn't have humidity sensor
Four BMP280s in two I²C channels
As the device only supports two addresses, we need two channels. Couldn't find documentation for using multiple channels, but just using separate "Wire.begin()"s for each channel seems to work fine. Calling "begin" over and over again might eventually run out of something, but so far I haven't noticed any problems. To be safe, you can always use the sleep mode and wake up for each measurement, this way you wouldn't be collecting any somethings laying around.
Initialization
#include <Wire.h> #include <Adafruit_Sensor.h> #include <Adafruit_BME280.h> #define BMP12_SCL 1 #define BMP12_SDA 2 #define BMP34_SCL 5 #define BMP34_SDA 6 float temp1; float temp2; float temp3; float temp4; float pressure1; float pressure2; float pressure3; float pressure4;
Setup()
None, as will be done for each data fetch round
Use
//Helper function to get values for two BM[PE]s in the same I2C channel void getData(int sda,int scl, float *temp1, float *pressure1, float *temp2, float *pressure2) { Wire.begin(sda,scl); Adafruit_BMP280 bme1; Adafruit_BMP280 bme2; if (!bme1.begin(0x76)) Serial.println((String)"Could not find a valid BMP280 sensor 1 at SDA " + sda + ", SCL " + scl); if (!bme2.begin(0x77)) Serial.println((String)"Could not find a valid BMP280 sensor 2 at SDA " + sda + ", SCL " + scl); *temp1 = bme1.readTemperature(); *temp2 = bme2.readTemperature(); *pressure1 = bme1.readPressure() / 100; //For hPa *pressure2 = bme2.readPressure() / 100; } To read the values: getData(BMP12_SDA,BMP12_SCL,&temp1,&pressure1,&temp2,&pressure2); getData(BMP34_SDA,BMP34_SCL,&temp3,&pressure3,&temp4,&pressure4)
-
16MLX90614 I²C infrared temperature sensor
Can in many places avoid cables for another temperature sensor, is quick to measure, and measures directly surfaces instead of air - brilliant for condensation warning.
Not used multiple per project so far, but apparently the MLX can be configured to any address.
As always with I²C devices, intended for short distances, but I've successfully run I²C devices connected with 15 a meter CAT5 cable, SDA paired with GND and SCL with Vcc (or the other way, don't remember), even having RJ45 connectors in both ends.
Datasheet: https://www.melexis.com/-/media/files/documents/datasheets/mlx90614-datasheet-melexis.pdf
Library: https://github.com/adafruit/Adafruit-MLX90614-Library
Initialization
#include #include Adafruit_MLX90614 mlx = Adafruit_MLX90614(0x5A); //I2C address, not required if default (0x5A)
Setup()
Wire.begin(D5,D6); //Line not required for default (D2,D1) mlx.begin();
Use
float temperature_mlx_ambient = mlx.readAmbientTempC(); float temperature_mlx_object = mlx.readObjectTempC();
-
17Dew point calculation
Not hardware, but essential with any temperature/humidity sensors, easier to have it here than to find some earlier sketch with DP calculation. Dew point resembles absolute humidity pretty well, air pressure does affect it but causes only like +/- 0.5° C difference in the dew point, close enough for me. Comparing dew points (or absolute humidity) can be used to control ventilation for example - if you want to keep inside dry, you probably don't want to pump in moister air from outside. Relative humidity doesn't work for this, as it wildly varies with air temperature, and amount of water in the air is what we'd care about.
This is the accurate version, there are quicker and less accurate ones but I've not been that much in hurry to sacrifice accuracy for CPU cycles.
double computeDewPoint(double celsius, double humidity) { double RATIO = 373.15 / (273.15 + celsius); double SUM = -7.90298 * (RATIO - 1); SUM += 5.02808 * log10(RATIO); SUM += -1.3816e-7 * (pow(10, (11.344 * (1 - 1 / RATIO ))) - 1) ; SUM += 8.1328e-3 * (pow(10, (-3.49149 * (RATIO - 1))) - 1) ; SUM += log10(1013.246); double VP = pow(10, SUM - 3) * humidity; double T = log(VP / 0.61078); // temp var return (241.88 * T) / (17.558 - T); } float dewPointIn = computeDewPoint(temperatureIn,humidityIn); float dewPointOut = computeDewPoint(temperatureOut,humidityOut); if(dewPointOut < dewPointIn) //Smaller dewpoint = less moisture in air ventilationFanOn = true; else ventilationFanOn = false;
Not my code, credits to whoever deserves, dunno who's the original writer to thank.
-
18BH1750FVI I²C light intensity sensor
Convenient, cheap and accurate way to get light intensity, to follow daylight intensity to plan for ventilation for example. Haven't tried multiple yet. Default I²C address 0x23, configurable to 0x5C.
Datasheet: http://www.mouser.com/ds/2/348/bh1750fvi-e-186247.pdf
Library: https://github.com/markbeee/BH1750FVI (does not appear to allow defining I²C address, this one might be a better bet if needed: https://github.com/drewtm/BH1750FVI)
Initialization
#include #include BH1750FVI LightSensor;
Setup()
Wire.begin(D5,D6); //Line not required for default (D2,D1) LightSensor.begin(); LightSensor.setMode(Continuously_High_Resolution_Mode);
Use
int lux = LightSensor.getAmbientLight();
-
19HC-SR04 ultrasonic distance sensor
The new laser-based Time of Flight sensors are often more convenient and accurate than these traditional ultrasonic sensors, but for some use cases ultrasonic sensors still are a good choice. And the HC-SR04 makes your robot look like Wall-E, brilliant for those being build with your kids.
The basic HC-SR04 requires 5 volts to work properly, thus its Vcc should be connected to +5 V and "echo" with a resistor ladder (2k2 and 4k7 for example; Echo - 2k2 - GPIO - 4k7 - Gnd) to a GPIO. ESP's GPIOs should be rather 5v tolerant, thus for prototyping you probably won't fry your ESP, if connected directly, but for production those sure would be needed. Same for the output "Trig", for me triggering the HC-SR04 directly from the ESP has worked fine, but by the book you would need a level converter.
The library
"Ultrasonic" in the library manager - https://github.com/ErickSimoes/Ultrasonic
Initialization
#include Ultrasonic ultrasonic(D1, D2); //trigger (out), echo (in)
setup()
None needed
Use
unsigned int distanceInCm = ultrasonic.distanceRead();
-
20VL53L0x I²C laser Time of Flight distance sensor
Compared to traditional ultrasonic distance sensors the laser-based ToF-sensors have many benefits. They are extremely small, fast, not distracted by soft materials or random side reflections, share the two pins between other I²C devices. ToF is not without caveats, L0x is limited to about 130 cm with a strong flat target, about 80 cm with more general targets, and dirt would easier distract the sensor than ultrasonic sensors (though L0x is suprisingly dirt tolerant, just don't splash mud on it). Using them used to be rather cumbersome; requiring ST's expensive and not that inviting satellite board and Embed-based libraries available for limited hardware, but when easy breakout boards and Arduino libraries came, it became pretty much trivial.
Resources
- Adafruit Arduino library, available in Library Manager
- ST's VL53L0x product page with datasheet
This libary uses I²S
Initialization
#include "Adafruit_VL53L0X.h" #include Adafruit_VL53L0X lox = Adafruit_VL53L0X();
setup()
if (!lox.begin()) Serial.println(F("Failed to boot VL53L0X"));
Use
VL53L0X_RangingMeasurementData_t measure; lox.rangingTest(&measure, false); // 'true' to print debug data to Serial if (measure.RangeStatus != 4) dist = measure.RangeMilliMeter; else Serial.println(F("Distance out of range"));
I have yet to try other I²C pins or multiple L0Xes at the same time, will add findings here.
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.