Hello!
I'm building a preamp for my amplifier and now I want to monitor the temperature of the radiators.
I would like to have it on main screen and also do something when temperature is too high.
So I found easy to implement library here: http://milesburton.com/wiki/index.php?title=Dallas_Temperature_Control_Library
I have two sensors, so what do I do:
This is from example of the library.
My problem is that it takes too long for sensor.getTemperature() function to execute, which slows down the whole loop. Althought I can display temperature on my LCD I can't do nothing else.
I don't do any temperature conversions (I heard it take 750ms).
I use 3 wirer to connect to the sensors, so it's not in parasitic mode.
Using the plain oneWire library (long hand programming, you set your own delays) and reducing the resolution of the Dallas chip you can get much faster responses. 750 ms is for 1/16th degree resolution, it reduces if you reduce the resolution. You might need to study some examples using said library and the codes you need to set from a spec sheet. It seems to have been removed from the playground, hmmm.........
Heres a page with a sample sketch using the onewire library :
I too am not using parasite mode, but the DallasTemperature library still does take the 0.75sec to take a reading. Still working on finding out what I'm doing wrong there.
The OneWire library is much faster - i can take many readings per second. Frustratingly though, it doesn't work properly when running at 8Mhz. 16Mhz though no problem.
Even if it does take 0.75 seconds, using the one wire library and coding a loop that fires every 0.75 seconds, the arduino can be doing a lot of other things in the meantime. Not just sitting there waiting for the time to elapse. My monitoring system only checks the temperatures once every couple of seconds, but its doing an awful lot of other time sensitive stuff besides. It just plain wouldn't work using the new library.
time = millis();
if (time >= secs){ // 1 second loop
secs = time + 1000;
// blah blah
// stuff you want doing every second;
}
// stuff thats going all the time in main loop
time and secs are type long, alter the 1000 value for a different time.
Thank you all for responses!
I'm now trying to work with onewire library.
I get readings from both sensors in hex values as described in Playground: http://www.arduino.cc/playground/Learning/OneWire
LowByte = data[0];
HighByte = data[1];
TReading = (HighByte << 8) + LowByte;
SignBit = TReading & 0x8000; // test most sig bit
if (SignBit) // negative
{
TReading = (TReading ^ 0xffff) + 1; // 2's comp
}
Tc_100 = (6 * TReading) + TReading / 4; // multiply by (100 * 0.0625) or 6.25
Whole = Tc_100 / 100; // separate off the whole and fractional portions
Fract = Tc_100 % 100;
if (SignBit) // If its negative
{
Serial.print("-");
}
Serial.print(Whole);
Serial.print(".");
if (Fract < 10)
{
Serial.print("0");
}
Serial.print(Fract);
Serial.print("\n");
I guess this code is for DS18B20 and I have DS18S20.
Right now the output is 3.25 and I now that my room is not that cold
How do I modify this code for DS18S20?
Here is sample output from my sensors:
Hi all, I'm glad I found this thread as I am having issues with 3 DS18B20s using the DallasTemperature library from MilesBurton.com, it uses the onewire library to communicate with the sensors. It seems slow and doesn't always see all of my sensors, then to cap it all when one sensor is ditched sometimes one of the other 2 is picked up as a ghost.
So looking through the library and checking on the forums it would appear that there is an issue somewhere. The on-topic issue is that there are direct delay() calls in the code, with the delay being according to the resolution, this of course blocks the whole system for that amount of time
Is there a way around this through the library, I was thinking of splitting the get temperature function in to 2 functions, request temp and retrieve temp?
It also seems like it is set to autorequest the temperature, which is fine for one slave sensor but can cause issues if they are all set to autorequest as they all try and respond at the same time causing collisions.
I'd already used the millis()-lastmillis statement to reduce delays in my code, which doesn't actually stop them I need my code to be responsive for other things that it will be doing whilst its monitoring temperatures.
Here's the code from the library that I think needs splitting, remove the delay and split the 2 parts:
// returns a float with the temperature in degrees C.
float DallasTemperature::getTemperature()
{
// If we're ready to rock, begin communication channel
if (isValid() != SLAVEGOOD) return 0; // return a value outside our range
// you can send the convert request to all devices on the
// same bus so you can read them all after the conversion
// delay
if (autoRequest)
{
pDataWire.reset();
pDataWire.select(arSlaveAddr);
pDataWire.write(STARTCONVO, parasite); // start conversion
conversionDelay(); <<********** REMOVE THIS ************
***** SPLIT HERE *****
// The temp is the first two bytes so just request those 2
[color=#00ff00] readScratchPad(2);
int16_t rawTemperature = (((int16_t) tempMSB) << 8) | tempLSB;
switch (arSlaveAddr[0]) {
case DS18B20MODEL:
case DS1822MODEL:
switch (resolution)
{
case TEMP_12_BIT:
return (float)rawTemperature * 0.0625;
break;
case TEMP_11_BIT:
return (float)(rawTemperature >> 1) * 0.125;
break;
case TEMP_10_BIT:
return (float)(rawTemperature >> 2) * 0.25;
break;
case TEMP_9_BIT:
return (float)(rawTemperature >> 3) * 0.5;
break;
}
break;
case DS18S20MODEL:
return (float)rawTemperature * 0.5;
break;
}
I'm not sure I entirely understand how each of the dallas temperature functions work, I think that it should work where autorequest? is set for one sensor, do a globaltemprequest() then get temperature does a delay on the autorequest sensor, then on subsequent sensors you can just grab the data directly as the delay on the first one is long enough for the other 2 to perform conversion? If that's how its supposed to work that cuts my delay down for millis()-lastmillis code from 2.25s to 750ms, better but still not good.
I should mention in my current code I am using a 128x128 4096 color LCD sheild, it has a set of buttons that run off an interrupt, this becomes unresponsive whilst the heater code is running.
As long as the sensor is not parasitically powered there is also the possibility to check if the conversion is completed. This is described on page 3 of the datasheet.
If the DS18S20
is powered by an external supply, the master can issue “read-time slots” (see the 1-Wire Bus System
section) after the Convert T command and the DS18S20 will respond by transmitting 0 while the temperature conversion is in progress and 1 when the conversion is done. If the DS18S20 is powered with
parasite power, this notification technique cannot be used since the bus must be pulled high by a strong
pullup during the entire temperature conversion.
My "convert temperature' function looks like this.
void convertTempAll() {
ds.reset();
ds.skip(); // tell all sensors on bus
ds.write(0x44,0); // to convert temperature
while (ds.read() == 0) { // reading timeslot (0 = not done with conversion)
delay(100); // and wait until done (not parasitically powered)
}
}
Not exactly an answer to remove the delay but at least you can check if its done or not. Average conversiondelay i've experienced is around 0.6 seconds with 8 sensors on the same bus. Also i'm only using the OneWire library.
Thanks Yot, I'm developing a multiple DS18B20 sensor unit, I have them all wired so they they are getting their own power from the arduino, so they shouldn't be in parasite mode. I'm really considering ditching the dallas library as it seems to be a bit all over the place and the ghosting stuff is just plain odd.
I'm going to try the latest version to see if its better for the ghosting, as I really need this to get going a bit quicker
When I was coding for the Dallas the playgrounds example code was using Onewire and it was comparatively easy to split this up to do the conversion and reading in seperate parts of the code. (I do the initial conversion in setup then do the reading followed by the next conversion inside a loop as in one of my earlier posts). This dedicated library is only of any use if reading temperatures and displaying them is all the Arduino is doing and it makes no allowance if you bother to wire up the third pin. The onewire code is messy but at least its granular.
Maybe it will be useful for someone - reading temperatures from 2 sensors with no delay whatsoever
Code is not perfect - first sketch, but works.
#include <OneWire.h>
int oneWirePin = 7;
OneWire ds(oneWirePin);
int temp_0 [2]; //arrays to store temeratures
int temp_1 [2];
void read_temp(byte addr[8], int number); //reads temerature on given address and saves it to the array (temp_0 or temp_1)
void send_for_temp(byte addr[8]); //asks for temerature on given address
long previousMillis = 0; // will store last time DS was updated
long interval = 1000; // interval at which to read temp (milliseconds)
void setup() {
Serial.begin (9600); //for debug
ds.search(ds_addr0); //find addresses of 2 devices we have
ds.search(ds_addr1);
send_for_temp(ds_addr0); //ask firs and second for temperature
send_for_temp(ds_addr1);
/* this is more elegant: have to try it
ds.reset();
ds.skip(); // tell all sensors on bus
ds.write(0x44,0); // to convert temperature
*/
}
void loop() {
//do your cool stuff here
if (millis() - previousMillis > interval) {
previousMillis = millis();
//reading data from old requests:
read_temp(ds_addr0, 0);
read_temp(ds_addr1, 1);
//sending new requests:
send_for_temp(ds_addr0);
send_for_temp(ds_addr1);
}
//print data from arrays - if it's not updated - will print old
Serial.print(temp_0[0]);
Serial.print(".");
Serial.print(temp_0[1]);
Serial.print(" ");
Serial.print(temp_1[0]);
Serial.print(".");
Serial.print(temp_1[1]);
}
void send_for_temp(byte addr[8]){
ds.reset();
ds.select(addr);
ds.write(0x44,1); // start conversion, with parasite power on at the end
}
void read_temp(byte addr[8], int number){
byte i;
byte data[12];
ds.reset();
ds.select(addr);
ds.write(0xBE); // Read Scratchpad
for (i = 0; i < 9; i++) { // we need 9 bytes
data[i] = ds.read();
}
int HighByte, LowByte, TReading, SignBit, Tc_100, Whole, Fract;
LowByte = data[0];
HighByte = data[1];
TReading = (HighByte << 8) + LowByte;
SignBit = TReading & 0x8000; // test most sig bit
if (SignBit) // negative
{
TReading = (TReading ^ 0xffff) + 1; // 2's comp
}
Tc_100 = 50 * TReading; // multiply by 100 * 0.5
Whole = Tc_100 / 100; // separate off the whole and fractional portions
Fract = Tc_100 % 100;
//code we acrually need:
switch (number){
case 0:
temp_0[0] = Whole;
temp_0[1] = Fract;
break;
case 1:
temp_1[0] = Whole;
temp_1[1] = Fract;
break;
default: break;
}
}
in my init function I do a heater_sensor*->begin() for each device.*
*then I iterate through a loop to display the 64bit unique code, at this point I either have 3 unique 64bit numbers which means all sensors are working or I get the ghosting situation where I get 2 unique numbers returned and the 3rd number is one of the 2 previous numbers (the sensors that get the same number also display the same temperature). something has obviously gone wrong at this point. I've used the same code on just the tempSensor0,1,2 type declaration and the pointer array and get the same outcome. * btw. can anyone tell me if I've declared my sensors correctly? I wanted an array and it was the only way that I could declare one.
Sorry but i cant give any direct tips with the ghosting problem or with the declaring of sensors. Partially because i do not use the DallasTemperature library. The thing i can do is give my sketch that does what i want (without ghosting) Maybe the "fillArrayWithAdresses();" function gives some help. but... i'm not pretending that i know anything about, eh, anything. Its the thinkering that i like. Please keep that in mind.
I have 7 dallas DS18S20 sensors connected to pin 53 of an arduino mega with a resistor between 5V and the data pins of the sensors. So they are not parasitically powered.
The sketch does the following;
fills an array with the unique serial codes,
spits them out through serial port,
tells all sensors to convert temperature and waits until finished,
fills another array with scratchpad data,
reproduces it through serial port,
fills yet another array with degrees celsius and
finally spits that through the serial port.
The processing from raw data to deg. C. comes partially from this forum and partially from the datasheet. Im not good at the different kinds of math (bit, int, float) on a microcontroller so there could (will) be some weard action going on.
#include <OneWire.h>
byte done = 0; // Do we have all Unique ID's
byte addr[8]; // to store ID while searching
byte i; // for looping
byte addresses[7][8]; // to store 7 ID's of 8 wide
byte j; // for looping
byte rawdata[7][9]; // to store 7 sets of raw data
float temperaturesC[7]; // to store 7 temperatures
int HighByte, LowByte, CountPerC, CountRemain;
float ResolutionFactor;
int rawtemp = 0;
float tempc = 0;
OneWire ds(53); // DS18S20 Temperature chip i/o on pin 53
//------------------- PROGRAM --------------------------
//------------------------------------------------------
void setup(void) {
Serial.begin(9600);
}
void loop(void) {
fillArrayWithAdresses();
reproduceAdressesFromArray();
delay(1000);
convertTempAll();
fillArrayWithRawData();
reproduceRawDataFromArray();
delay(1000);
fillArrayWithProcessedData();
reproduceProcessedDataFromArray();
delay(1000);
//------------------ END OF PROGRAM --------------------
//------------------------------------------------------
}
//------------------ FUNCTIONS -------------------------
//------------------------------------------------------
void reproduceProcessedDataFromArray() {
for( j = 0; j < 7; j++) {
Serial.print("Sensor ");
Serial.print(j, DEC);
Serial.print("= ");
Serial.print(temperaturesC[j]);
Serial.print(" deg. C ");
Serial.println();
}
Serial.println();
}
void fillArrayWithProcessedData() {
for( j = 0; j < 7; j++) {
LowByte = rawdata[j][0];
HighByte = rawdata[j][1];
CountRemain = rawdata[j][6];
CountPerC = rawdata[j][7];
rawtemp = (HighByte << 8) + LowByte;
ResolutionFactor = CountPerC - CountRemain;
ResolutionFactor = ResolutionFactor / CountPerC;
tempc = (float(rawtemp) / 2.0);
tempc = tempc - 0.25;
tempc = tempc + ResolutionFactor;
temperaturesC[j] = tempc;
}
}
void convertTempAll() { // tell all sensors on bus to convert temperature
ds.reset(); // and wait until done (NOT PARASITIC POWERED)
ds.skip();
ds.write(0x44,0);
while (ds.read() == 0) {
delay(100);
}
}
void fillArrayWithRawData() {
for( j = 0; j < 7; j++) {
for( i = 0; i < 8; i++) {
addr[i] = addresses[j][i];
}
ds.reset();
ds.select(addr);
ds.write(0xBE);
for ( i = 0; i < 9; i++) {
rawdata[j][i]=ds.read();
}
}
}
void reproduceRawDataFromArray() {
for( j = 0; j < 7; j++) {
Serial.print("Raw data=");
for( i = 0; i < 8; i++) {
Serial.print(rawdata[j][i], HEX);
Serial.print(":");
}
Serial.println();
}
}
void reproduceAdressesFromArray() {
for( j = 0; j < 7; j++) {
Serial.print("Unique ID=");
for( i = 0; i < 9; i++) {
Serial.print(addresses[j][i], HEX);
Serial.print(":");
}
Serial.println();
}
}
void fillArrayWithAdresses() {
j = 0;
done = 0;
while (done==0) { // while searching is not done
if ( ds.search(addr) != 1) { // if there are no more unique id's
ds.reset_search();
done = 1; // we have all unique id's
return;
}
else { // there are more unique id's
for( i = 0; i < 8; i++) {
addresses[j][i] = addr[i];
}
j = j + 1;
}
}
}
my DS18B20s are all hooked to pin 26 and they also have a resistor between 5v and the data pin.
It looks like I may have over estimated the library, I want the amount of sensors to be dynamic (1 to n) which is easily set with an array declaration. I think I should be able to do the same to just the onewires and still work them just the same. the library looked pretty comprehensive, at the expense of performance for the rest of the system.
I've had to build my own functions for the Nokia_LCD library as it is lacking in quite a few things, I wanted to avoid having to do the same for the dallas sensors, oh well, at least my code will be as tight as it can be
There is an interesting part to the Dallas library that I might keep NewOneWire.cpp and .h, it adds a destructor to mix, so if a sensor dies you can let go of the instance and try and rediscover it, I think
my DS18B20s are all hooked to pin 26 and they also have a resistor between 5v and the data pin.
Leonti, your code looks interesting, I'll have a look at all of this in more detail a little later on.