Hi geek boys and girls!
I hope you passed a very nice Easter holidays. Unfortunately I had the flu during these days…so no great funny time for me! 😦
…But I spent some time developing my weather station (I wrot the code for meteo data acquisition, and then I succesfully connected to the Raspberry a webcam and also a internet dongle for the remote access to the weather station).
In this post I will talk about the meteo data acquisition from Arduino and the consequent data trasmission from Arduino to Raspberry via I2C (see my previous post in order to activate the I2C link).
I decided, after some unfruitful (or simply too diffcult to implement) experiment with analog sensors, to use only digital sensors to acquire with Arduino temperature, barometric pressure and relative umidity. So I bought these sensors from Robot Italy (my preferred online store for embedded resources… as you know I love all italian products/services 😉 ):
- DHT11 temperature and humidity sensor (it uses one wire for digital output)
- MPL115A1 Barometric Pressure breakout from Sparkfun (it uses a SPI connection)
This is the final circuit I’ve realized after some very basic integration test (click on the image for the zoom):
Note that I used a resistor of 4.7 KOhm instead 5 KOhm, as suggested on the DHT11 datasheet.
Ok, now it’s time to code some litttle skecth. Let’s start with Arduino.
In order to communicate with DHT11 and with MPL115A1 I used two well known libraries.
I took the DHT11 library from Arduino Playground and I took the MPL115A1 lib from the github of SMacarena (great appreciation for these very good works, and my sincere thanks to the authors 😉 ).
After some cut/paste/washing/ironing/rewashing and some other (not too many,you know me! ;-)) tests, this is the final Arduino code for the meteo data acquisition from sensors:
#include <SPI.h> #include <MPL115A1.h> #include <dht11.h> #include <Wire.h> //I2C library #define __DEBUG__ //note: I used for debug a ht1632c led display //If you can't/don't use it, undef this macro! :-) #ifdef __DEBUG__ #include <ht1632c.h> //debug display ht1632c dotmatrix = ht1632c(&PORTD, 7, 6, 4, 5, GEOM_32x16, 2); #endif //i2c settings #define SLAVE_ADDRESS 0x04 int number_command = 0; float value_to_send=0.0; //I2C commands #define TEMP 1 #define HUMI 2 #define PRES 3 #define DEW 4 //out pint for DHT11 sensor #define DHT11PIN 2 //sensors MPL115A1 Pressure_sensor; dht11 DHT11_sensor; //current atmo values float current_pressure=0.0; float current_humidity=0.0; float current_temperature=0.0; double current_dewpoint=0.0; void setup() { //serial setup Serial.begin(115200); //initialize pressure sensor Pressure_sensor.begin(); // initialize i2c as slave Wire.begin(SLAVE_ADDRESS); // define callbacks for i2c communication Wire.onReceive(receiveData); Wire.onRequest(sendData); #ifdef __DEBUG__ dotmatrix.clear(); dotmatrix.setfont(FONT_5x8); #endif } void loop() { //take & save pressure values current_pressure = GetPressure(); GetTemp_Humidity_DewPoint(); //print current valueson serial ...debug (remove it if you want)! Serial.print(current_pressure); Serial.print(" hPa\n"); Serial.print (current_humidity); Serial.print(" % Humidity\n"); Serial.print (current_temperature); Serial.print(" °C\n"); Serial.print (current_dewpoint); Serial.print(" Dew point (°C)\n"); #ifdef __DEBUG__ dotmatrix.clear(); char tmp[20] = ""; //pressure sprintf(tmp, "P=%dhPa", (int)current_pressure); byte len = strlen(tmp); for (int i = 0; i < len; i++) dotmatrix.putchar(5*i, 0, tmp[i], ORANGE); //temperaure sprintf(tmp, "T=%dC", (int)current_temperature); len = strlen(tmp); for (int i = 0; i < len; i++) dotmatrix.putchar(5*i, 8, tmp[i], RED); //humidity sprintf(tmp, "H=%d%%", (int)current_humidity); len = strlen(tmp); for (int i = 0; i < len; i++) dotmatrix.putchar(32+5*i, 8, tmp[i], GREEN); dotmatrix.sendframe(); #endif //delay delay(5000); } //Acquisition functions //from sensors float GetPressure() { float hPa = Pressure_sensor.pressure(); return hPa; } void GetTemp_Humidity_DewPoint() { //take & save DHT11 values (temp + rel. humidity) int chk = DHT11_sensor.read(DHT11PIN); switch (chk) //check errors { case DHTLIB_OK: Serial.println("read OK"); //read values current_humidity=(float)(DHT11_sensor.humidity); current_temperature=(float)(DHT11_sensor.temperature); //dew point current_dewpoint=dewPoint(DHT11_sensor.temperature, DHT11_sensor.humidity); break; case DHTLIB_ERROR_CHECKSUM: Serial.println("Checksum error"); break; case DHTLIB_ERROR_TIMEOUT: Serial.println("Time out error"); break; default: Serial.println("Unknown error"); break; } } //dewpoint function (taken from http://playground.arduino.cc/main/DHT11Lib) // dewPoint function NOAA // reference (1) : http://wahiduddin.net/calc/density_algorithms.htm // reference (2) : http://www.colorado.edu/geography/weather_station/Geog_site/about.htm // double dewPoint(double celsius, double humidity) { // (1) Saturation Vapor Pressure = ESGG(T) double RATIO = 373.15 / (273.15 + celsius); double RHS = -7.90298 * (RATIO - 1); RHS += 5.02808 * log10(RATIO); RHS += -1.3816e-7 * (pow(10, (11.344 * (1 - 1/RATIO ))) - 1) ; RHS += 8.1328e-3 * (pow(10, (-3.49149 * (RATIO - 1))) - 1) ; RHS += log10(1013.246); // factor -3 is to adjust units - Vapor Pressure SVP * humidity double VP = pow(10, RHS - 3) * humidity; // (2) DEWPOINT = F(Vapor Pressure) double T = log(VP/0.61078); // temp var return (241.88 * T) / (17.558 - T); } //I2C callbacks // callback for received command void receiveData(int byteCount) { while(Wire.available()) { number_command = Wire.read(); if(number_command==TEMP) { //request temperature value_to_send = current_temperature; } if(number_command==HUMI) { //request humidity value_to_send = current_humidity; } if(number_command==PRES) { //request humidity value_to_send = current_pressure; } if(number_command==DEW) { //request dewpoint value_to_send = current_dewpoint; } } } // callback for sending data via I2C void sendData() { //convert the float values in a vector of 4 bytes to send via i2c bus char vector_to_send[4]; memcpy(vector_to_send,(char*)&(value_to_send),4); Wire.write(vector_to_send,4); }
Write the above skecth on the Arduino UNO and power on it….on the serial shell (and/or on the led display) you will see the vaues taken from the sensors.
Ok, let’s go ahead with the correspondant Raspberry PI code (at the moment it is implemented in an interactive way). It is a little more simple than the Arduino one (it is derived from the original one, but in thsi case I manage the transmission via I2C of float numbers, mapped each one on 4 bytes):
//ML meteo lab station v2.0 Raspi side #include <string.h> #include <unistd.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <linux/i2c-dev.h> #include <sys/ioctl.h> #include <fcntl.h> #include <unistd.h> // The PiWeather board i2c address #define ADDRESS 0x04 //commands #define TEMP 1 #define HUMI 2 #define PRES 3 #define DEW 4 // The I2C bus: This is for V2 pi's. For V1 Model B you need i2c-0 static const char *devName = "/dev/i2c-1"; int main(int argc, char** argv) { printf("I2C: Connecting\n"); int file; if ((file = open(devName, O_RDWR))< 0) { fprintf(stderr, "I2C: Failed to access %d\n", devName); exit(1); } printf("I2C: acquiring buss to 0x%x\n", ADDRESS); if (ioctl(file, I2C_SLAVE, ADDRESS) < 0) { fprintf(stderr, "I2C: Failed to acquire bus access/talk to slave 0x%x\n", ADDRESS); exit(1); } int command; for (command= 1; command<=4; command++) { int val; unsigned char cmd[16]; //printf("Sending %d\n", val); cmd[0] = command; if (write(file, cmd, 1) == 1) { // As we are not talking to direct hardware but a microcontroller we // need to wait a short while so that it can respond. // // 1ms seems to be enough but it depends on what workload it has usleep(10000); char buf[5]; if (read(file, buf, 4) == 4) { //read 4 byte from i2c (a float -temp, humidity etc.-) float value_received; //convert 4 bytes received into a float memcpy((char*)&value_received,buf,4); //print the results if (command==TEMP) printf("Temperature (°C)= %f\n", value_received ); if (command==HUMI) printf("Humidity (%)= %f\n", value_received ); if (command==PRES) printf("Pressure (hPa)= %f\n", value_received ); if (command==DEW) printf("Dew Point (°C)= %f\n", value_received ); } } // Now wait else you could crash the arduino by sending requests too fast usleep(10000); } close(file); return (EXIT_SUCCESS); }
Compile the Raspberry program with the same old gcc -o meteo_lab meteo_lab.c , then, if Arduino is already powered on, launch the program with ./meteo_lab
You will see on the Raspberry shell the current values for temperature, relative humidity, pressure and dew point temperature acquired (and calculated, in case of the dew point temperature) by our two sensors.
….So, you can monitor in each moment your lab weather condition! 🙂
Ok, I think you are thinking it is not too much….So, in the next posts we will see how to visualize these data (with a good webcam image on the side) on a web page accessed from internet… this is much more interesting or not? 😉
Bye bye geeks, c ya soon!