Logging temperature using an Arduino and AD7410 sensor

This article is a quick and dirty demonstration to hack yourself a temperature data logger which saves its results to an SD card. The sensor of use is a HTU21D, a I²C temperature and humidity sensor.

hookup

Schematic:

hookup_bb

I hooked up a HTU21D sensor to an Arduino Uno + SD-card shield and let it monitor temperature (and humidity) over an entire day:

24h_log

Here is a close-up of what happens at night:

3h_log

Source code:

/*
 SD card datalogger

This example shows how to log data from three analog sensors
 to an SD card using the SD library.

The circuit:
 * analog sensors on analog ins 0, 1, and 2
 * SD card attached to SPI bus as follows:
 ** MOSI - pin 11
 ** MISO - pin 12
 ** CLK - pin 13
 ** CS - pin 4

created 24 Nov 2010
 modified 9 Apr 2012
 by Tom Igoe

This example code is in the public domain.

*/
 /*
 HTU21D Humidity Sensor Example Code
 By: Nathan Seidle
 SparkFun Electronics
 Date: September 15th, 2013
 License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).

 Uses the HTU21D library to display the current humidity and temperature

 Open serial monitor at 9600 baud to see readings. Errors 998 if not sensor is detected. Error 999 if CRC is bad.

 Hardware Connections (Breakoutboard to Arduino):
 -VCC = 3.3V
 -GND = GND
 -SDA = A4 (use inline 330 ohm resistor if your board is 5V)
 -SCL = A5 (use inline 330 ohm resistor if your board is 5V)

*/

#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include "SparkFunHTU21D.h"

//Create an instance of the object
HTU21D myHumidity;

const int chipSelect = 4;

// make a string for assembling the data to log:
String dataString = "";

void setup() {
 // Open serial communications and wait for port to open:
 Serial.begin(9600);
 while (!Serial) {
 ; // wait for serial port to connect. Needed for native USB port only
 }

 myHumidity.begin();
 Serial.println("HTU21D ready!");

Serial.print("Initializing SD card...");

// see if the card is present and can be initialized:
 if (!SD.begin(chipSelect)) {
 Serial.println("Card failed, or not present");
 // don't do anything more:
 return;
 }
 Serial.println("card initialized.");
}

void loop() {
 readTemp();

Serial.println("Writing data...");
 // open the file. note that only one file can be open at a time,
 // so you have to close this one before opening another.
 File dataFile = SD.open("datalog.txt", FILE_WRITE);

// if the file is available, write to it:
 if (dataFile) {
 dataFile.println(dataString);
 dataFile.close();
 // print to the serial port too:
 Serial.println(dataString);
 }
 // if the file isn't open, pop up an error:
 else {
 Serial.println("error opening datalog.txt");
 }
 delay(10000);
}

void readTemp() {
 float humd = myHumidity.readHumidity();
 float temp = myHumidity.readTemperature();

 // make a string for assembling the data to log:
 dataString = "Time: ";
 dataString += String(millis());
 dataString += String("; Temperature: ");
 dataString += String(temp);
 dataString += String("; Humidity: ");
 dataString += String(humd);
 dataString += String("%");
}

This was just a quick and dirty hack to get some instant results. I’m planing to do some more logging in the future to get a better understanding of how to approach my self build climate control. Stay tuned for more.

Advertisements

Arduino and AD7410 I²C temp sensor

On request, the source code of using the Analog Devices AD7410 I²C temp sensor. (Datasheet: adt7410)

#include <Wire.h>

//ADT7410 13/16-bit digital temperature sensor
//RED (VDD): 2.7 ... 5.5V
//BROWN (GND): 0V
//Arduino uno, wires:
//PURPLE 1 (SCL): SCL (near AREF, should be equal to ANALOG5)
//PURPLE 2 (SDA): SDA (near AREF, should be equal to ANALOG4)
//Arduino due, wires:
//PURPLE 1 (SCL): SCL (pin 21)
//PURPLE 2 (SDA): SDA = (pin 20)
//Arduino IDE 1.5 compatible

#define ADT7410_I2C_ADDRESS 0x48
#define tempRegister 0x00
#define configRegister 0x03
#define selectCode16bitMode 0x80


void setup() {
  Wire.begin();        // join i2c bus (address optional for master)
  Serial.begin(9600); // serial connection
  set16bitMode();
}




void loop() {
  delay(5000);
  serieelPrint(); //print on serial port
}


//set ADT7410 in 16-bit temp value mode
void set16bitMode() 
{
  Serial.println("Setting 16-bit mode...");
  Wire.beginTransmission(ADT7410_I2C_ADDRESS);
  Wire.write(configRegister);
  Wire.write(selectCode16bitMode);
}



//gives back the temperature value
float readTemp()
{
  //set read register
  Wire.beginTransmission(ADT7410_I2C_ADDRESS);
  Wire.write(tempRegister);
  Wire.endTransmission();
  //receive data
  Wire.requestFrom(ADT7410_I2C_ADDRESS, 2);
  byte MSB = Wire.read();
  byte LSB = Wire.read();
  
  //check for positive or negative sign
  boolean sign;
  if(MSB>0xA0) {
    sign=0; //negative
  } else {
    sign=1; //positive
  }
  
  //concat MSB&LSB
  float tempValue = MSB * 256;
  tempValue+=LSB;
  
  //BIN to DEC
  if(!(sign)){
    tempValue-=65536;
  }
  tempValue/=128;
  
  return tempValue;
}

void serieelPrint()
{
  Serial.print("Unit: ");
  Serial.print(ADT7410_I2C_ADDRESS, HEX);
  Serial.print(" *** temperature: ");
  //temperature readout
  Serial.print(readTemp());
  Serial.println(" degrees Celcius");
}

UPDATE: you can find my Arduino library here: https://github.com/geoffrey-vl/Easy_ADT7410_Arduino_Library

Self Synchronizing Wifi Clock, V2

Since my last encounter with a self synchronizing wifi clock I ended up learning how to implement my own display driver. Unfortunately the display died on me when testing it on a new power supply (which appeared to be malfunctioning afterwards) and so I have been thinking of porting my code to use the Adafruit 2.8″ display.  Pretty much most of the functionality remains from what I’ve made before, the most interesting thing I wanted to add this time was making use of the resistive touch screen. I could easily made a basic GUI to adjust settings and so on, but by some unknown reason I can’t get the touch positioning to work reliable on the Due board. Though it does function on Uno, Uno does not offer the needed program space (I’m at 40~50k). So, all together there is not much to it, but here is what I ended up with:

Next, I’ll check if there is the possibility to hook it up to Raspberry Pi and control it using NodeJS. Enjoy the holidays, see you in 2015!

Self Synchronizing Wifi Clock

In a previous serie of articles I showed you my progress in writing a Arduino Due driver for the Adafruit 16×32 LED matrix. Last few days I’ve focussed more on adding support for a simple font and displaying text characters, but actually during this implementation I discovered the solution behind 2 programming mistakes that were still left in the driver code. With this solved, I starting thinking about how to implement a font. After thinking of my own way of implementing this I also looked at how it was done in the original driver for Arduino Uno and actually some of the ideas matched. So I could really easy copy, adjust and implement the code for displaying characters, displaying ‘HELLO’ is now a matter of writing 6 lines of code!

After this I implemented code for reading a I2C compatible ADT7410 temperature sensor and use it for displaying the room temperature. Next I included and implemented code I’d already written before which allowed me to use the Adafruit C3300 (Wifi / SD) shield. The code connects the Arduino to the local WLAN and do NTP request to synchronize a software made clock with the internet. Furthermore it can also read and write data from/to an SD card. The SD card is used to hold the WLAN settings, it does this at boot time and it is only milliseconds later when it will use this data to configure and make the WiFi connection to you LAN. Voila, altogether there we have it: an Arduino based self synchronizing clock!

Progress: Adafruit 16×32 LED matrix on Arduino Due (5)

Past couple of days I’ve been working on abstracting and hiding the actual display driver code from the main Arduino project., this involves writing C++ code in an object oriented way. Although I’m used to work with objects in Java and C#, my experience with C++ classes, arrays  and pointers is rather limited. And so it took me quite some time to get it all working in an n-tier architecture, but in the end trial and error got me through it and at this moment it is working more or less okay. The phone camera is still taking messy pictures, but you get the picture I’d guess:

2014-04-12 11.43.17

 

The benefits from using this n-tier architecture is that now all driver code and display logic are concentrated in the same file, plus one can easily replace the driver without affecting code at other layers. While the color correctness is still not 100% working okay, my next goal is to add more logic that allows me to easily draw chars or circles or whatever. Furthermore it would also be great if I could send images over the serial bus and finally put some use to the driver I’ve been working on past few weeks. In the mean time also have a look at this guys project: http://bikerglen.com/projects/lighting/led-panel-1up/. He uses the same panel but instead uses an FPGA as hardware platform to drive the display. He clearly shows the power of FPGA’s in driving displays, to do the same in sequential microprocessor code things would get really complicated if not impossible to do.

Adafruit 16×32 LED matrix on Arduino Due (4)

I’m finally making some progress with introducing a higher color depth. Using BCM I’m now more or less on a 12-bit color depth. In the Adafruit driver I found parts of code that first were not very clear to me. There are methods like Color888(uint8_t r, uint8_t g, uint8_t b) and Color333(uint8_t r, uint8_t g, uint8_t b) but than I found that these are actually related to how colors are kept in memory bit wise. You see, with 333 colors you’re using 3 bits for the red value, 3 for green and 3 for blue. So this means there is a total bit depth of 0…7 for each RGB value resulting in a total 9-bit color depth which gives us 512 colors. 8/8/8 colors are 24-bit large in total and are the so called True Colors. They’re often used on PC’s in results in different colors. The 5/6/5 colors, also called High Colors, are 5+6+5 = 16 bits wide and result in 65536 different colors. This is also often used on computers. The awkwardness here is that the green portion has one bit extra compared to the red and blue portion. This is done because there was otherwise one bit unused (better to use it right!) and because of our perception is green is different that for red/blue one bit extra for green would be best suited (don’t ask me the exact scientifical reason, look for it on wikipedia). This 16-bit color depth is also used for storing images in the Adafruit driver. But so far it’s used only for storing, to display these images the driver falls back to a 12-bit color depth in 4/4/4 format and this because of two reasons. More colors would be kind of hard to do because it would dramatically reduce refresh rate and this you certainly don’t want. Although LEDs are used, refresh rates in between 25 and 50MHz are still not high enough for the human eye to experience the display as smooth. So it’s better to stuck at 12-bits deep. Also, in the 5/6/5 setup, if you use BCM modulation, there is one moment where you’ll be displaying only the green portion because red and blue are not equally in bit size.

But BCM, what is this exactly. BCM is a modulation technique like PWM is. With PWM you define the percentage of on and off time. Say you’re having a pulse of 70% on and 30% off during the total period, if you have a LED connected to that pulse you’ll experience it as slightly dimmed. With BCM you’re not giving any percentages, you’re using the bit value instead. Let’s say you’re using 2-bit BCM, for this the 2 bits are divided over the total period and so the more ‘1’s you have in your binary BCM value the more the LED will be pulsed on during the period, and the brighter it will look. Let’s say you’ve the value 11, the LED will be set on for the total period of time and will look very bright. 00 means it will be off all the time. But what about 01 and 10? Well, here the bit-value comes into play otherwise both codes would result in 50% on and 50% off. Using the bit-value the ‘1’ in ’10’ has a higher bit value than the ‘1’ in ’01’ and so it will stay on longer depending on the weight of the bit. There is a nice introduction to BCM found here.

And so the Adafruit driver uses 4-bit BCM, using only the 4 most significant bits of their 16-bit (5/6/5) representation in memory. I’ve gone the same direction and got it more or less functional:

2014-03-26-074234

This lowres picture doesn’t exactly show you a lot, I’ll have to look for better photo footage. The higher color depth is now possible using BCM but it’s still not finished yet. Resetting the timer each time kind of screws up the refresh rates so instead of using the due timer library I talked of before I’ll have to write the timer code myself and cut off an overhead. Also I noticed that I’m doing a lot of digital writes (6) to set just the RGB pins, where in the Adafruit driver they can set all 6 pins altogether. If a could do this it would also greatly reduce the timer interrupt time and allow me to bump up the refresh rate. So, more work ahead…

About Arduino’s DigitalWrite – Adafruit 16×32 LED matrix on Arduino Due (3)

In the previous article I already noticed how the display was starting to get less bright when I bumped up the refresh rate. Reading some parts of the Arduino Uno driver I noticed this one comment hinting to the slow Arduino DigitalWrite function. I never knew or red about this function not being very fast, I was expecting maybe a little impact but not as much as described in some online articles. And so I began to think of also looking for a way to faster manipulate pin outputs so that the driver works faster and better, and maybe allow us to do more than before. For Arduino Uno there is tons of information to find, however for Due you have to look a lot better. On the Arduino forums however I found this thread where faster port manipulation code has been presented:

inline void digitalWriteDirect(int pin, boolean val){
  if(val) g_APinDescription[pin].pPort -> PIO_SODR = g_APinDescription[pin].ulPin;
  else    g_APinDescription[pin].pPort -> PIO_CODR = g_APinDescription[pin].ulPin;
}

inline int digitalReadDirect(int pin){
  return !!(g_APinDescription[pin].pPort -> PIO_PDSR & g_APinDescription[pin].ulPin);
}

void setup() {                
  pinMode(13, OUTPUT);     
  pinMode(12, INPUT);     
  Serial.begin(9600);
}

void loop() {
  digitalWriteDirect(13, HIGH);   
  delay(1000);           
  digitalWriteDirect(13, LOW);    
  delay(1000);          
  Serial.println(digitalReadDirect(12));
}

In my current driver I swapped all digitalWrite methods with the digitalWriteDirect methods from above and than compared how fast writing one (double) row of LEDs goes. Time was measured by calling the micros() method before and after writing on row of data, taking the difference of both and next report back by doing a single Serial.write(). Here is a comparison:
digitalWriteDirect: 91us
digitalWrite: 661us
So as you can see the direct implementation gives us nearly 7 times better performance, or the other way around I kind nearly draw the entire display this time where before I could draw only one row. I also now noticed that in my display only the last rows of each half screen were illuminating very bright while others where nearly not illuminating at all. The reason is because now we switch so fast from one row to the next that the HIGH time of the pixels in a row is very small compared to before when using the slow Arduino implementation. The reason why the last row was however bright is because it get’s drawn as last and from here on it takes nearly 5000us before the next interrupt is being called, so it is really obvious that it was appearing really bright. In my last update I changed to drawing only one row per timer interrupt. This way rows get painted on a steady time base, and with using the faster digitalWriteDirect method we can easily bump up the refresh rate of the display so now the interrupt routine gets called 8 times more than before.
Next problem I get is that I need to call the interrupt code each 1250us in order to get a steady image. That is a 800MHz refresh rate per pixel row, and so 100Hz for the entire display, which kinds of bothers me because now interrupt code will interrupt normal program flow a lot of times, and I’m still at only 3 bit colors and I don’t have any support for dimming. I guess there is more reading ahead of me…