Blog previously known as 'Home Theatre PC'
Comments have been disabled due to spam and lack of time for moderation.
Use the contact link on top to get in touch if you wish.
« Reset Kiosk 0.4Ubuntu 10.04 Lucid Lynx - PXE bootable installation without any bootable media to begin with »

1-wire temperatures with Arduino

  07/27/11 18:47, by Esa, Categories: Hardware, Software

I have used 1-wire temperature sensors (DS18S20) around my house for a few years now. Just recently the home made serial port adapter stopped working and I thought I'd look into replacing it with Arduino.

There was already 1-wire library and dallas temperature library available for Arduino under GPL license and wiring only required connecting data line to any of the digital io ports (I chose port 2) and 4k7 resistor between Arduino 5V and 1-wire bus data line for parasite power and grounding of course. Here's the code which reads the sensors and outputs to the usbserial.

#include <OneWire.h>
#include "DallasTemperature.h"

#define ONE_WIRE_BUS_DATA_PORT 3
#define LOOP_DELAY_1 30000 // max 32k...
#define LOOP_DELAY_2 30000
#define _NUM_SAMPLES 3
#define _SAMPLE_DELAY 1000

OneWire oneWire(ONE_WIRE_BUS_DATA_PORT);
DallasTemperature sensors(&oneWire);

void setup(void)
{
  Serial.begin(9600);
}

char* batoh(uint8_t deviceAddress[]) {
  char* buf_str = (char*) malloc(2*8 + 1);
  char* buf_ptr = buf_str;
  for (uint8_t i = 0; i < 8; i++) {
    buf_ptr += sprintf(buf_ptr, "%02X", deviceAddress[i]);
  }
  *(buf_ptr) = '\0';
  return buf_str;
}

float getTemp(uint8_t* addr, int samples, int delay_ms) {
  float sample[samples];
  float tmp;
  uint8_t l,i,j;
  for ( l = 0; l < samples; l++) {
    sensors.requestTemperaturesByAddress(addr); 
    sample[l] = sensors.getTempC(addr); 
    Serial.print("D "); 
    Serial.print(batoh(addr)); Serial.print(" "); 
    Serial.print(sample[l]); 
    Serial.println(" D");
    delay(delay_ms);
  }
  
  for ( i = 0; i < samples; i++ ) {
    for ( j = 1; j < (samples-i); j++ ) {
      if (sample[j-1] > sample[j]) {
        tmp = sample[j-1];
        sample[j-1]=sample[j];
        sample[j]=tmp;
      }
    }
  }
 
    
  return sample[samples/2];
}

void loop(void)
{ 
  uint8_t i;
  uint8_t addr[8];  
  uint8_t dcnt;
  
  sensors.begin();

  dcnt = sensors.getDeviceCount();
  //sensors.requestTemperatures();
  
  for ( i = 0; i < dcnt; i++ ) {
    sensors.getAddress(addr,i);
    float temp_c = getTemp(addr,_NUM_SAMPLES,_SAMPLE_DELAY);
    if (temp_c < -55.0 || temp_c > 125.0) { // range really -55 - +125, retry once if value returned is outside that range
      delay(_SAMPLE_DELAY);
      sensors.begin();
      temp_c = getTemp(addr,_NUM_SAMPLES,_SAMPLE_DELAY);
    } 
      Serial.print(batoh(addr));
      Serial.print(" ");
      Serial.println(temp_c);
  } 
  
  delay(LOOP_DELAY_1);
  delay(LOOP_DELAY_2);
}

Why read the same sensor several times? Because some of my sensors want to send either 85.00 or -127.00 every now and then once or twice in a row. Also sometimes I've been getting reading of the previous requested sensor when reading the next one. Reading 3 times and discarding the highest & lowest is not optimal, but it's good enough for me, for now. I had these same problems with the old, now broken, system using digitemp.

All the readings go to mysql database from which I create graphs with jpgraph library. I didn't want to include any date & time logic in the arduino part, so I'm reading the values from the serial port and inserting them to the db with 'current_timestamp'. I do that by reading the serial port constantly, with awk

awk '{ gsub("\\r",""); if (NF == 2) print "insert into temps (time_date,temp_c,sensor_serial) values (current_timestamp,\047"$2"\047,\047"$1"\047);"; fflush();}' /dev/cu.usbserial-A9007TRT | /opt/local/bin/mysql5 -u temps -pxxxxxx automation2

I use OSX for that, so I've made a little launchd script out of it (in linux the same can be done with inittab), it just makes sure the process keeps running.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Disabled</key>
    <false/>
    <key>KeepAlive</key>
    <true/>
    <key>Label</key>
    <string>com.cue.onewire.temperatures</string>
    <key>RunAtLoad</key>
    <true/>
    <key>Umask</key>
    <integer>7</integer>
    <key>ProgramArguments</key>
    <array>
        <string>/opt/local/bin/storetemperatures.sh</string>
    </array>    
    <key>UserName</key>
    <string>esav</string>
</dict>
</plist>

Tell launchd to load your plist and you're done. Note that I've put the awk into a shell script because I didn't want to escape those parameters to plist &amp;#58;&amp;#41;

sudo launchctl load /Library/LaunchDaemons/your.own.plist

No feedback yet

Search

Contents

powered by b2evolution free blog software
 

©2017 by admin

Contact | Help | Blog skin by Asevo | blogsoft | LAMP hosting | blog ads