Hello all, figured out my problems with the onewire temperature sensor, now I have a new task.
Since I want to run this on an attiny85, alongside code to control an rgb led, I need to shrink this down as much as I possibly can, so I was wondering if anyone more experienced could help. I'm going to poke around a bit and take out stuff that I don't think is needed but advice/examples would be great.
#include <OneWire.h>
// OneWire DS18S20, DS18B20, DS1822 Temperature Example
//
// http://www.pjrc.com/teensy/td_libs_OneWire.html
//
// The DallasTemperature library can do all this work for you!
// http://milesburton.com/Dallas_Temperature_Control_Library
OneWire ds(10); // on pin 10 (a 4.7K resistor is necessary)
void setup(void) {
Serial.begin(9600);
}
void loop(void) {
byte i;
byte present = 0;
byte type_s;
byte data[12];
byte addr[8];
float celsius, fahrenheit;
if ( !ds.search(addr)) {
Serial.println("No more addresses.");
Serial.println();
ds.reset_search();
delay(250);
return;
}
Serial.print("ROM =");
for( i = 0; i < 8; i++) {
Serial.write(' ');
Serial.print(addr[i], HEX);
}
if (OneWire::crc8(addr, 7) != addr[7]) {
Serial.println("CRC is not valid!");
return;
}
Serial.println();
// the first ROM byte indicates which chip
switch (addr[0]) {
case 0x10:
Serial.println(" Chip = DS18S20"); // or old DS1820
type_s = 1;
break;
case 0x28:
Serial.println(" Chip = DS18B20");
type_s = 0;
break;
case 0x22:
Serial.println(" Chip = DS1822");
type_s = 0;
break;
default:
Serial.println("Device is not a DS18x20 family device.");
return;
}
ds.reset();
ds.select(addr);
ds.write(0x44, 1); // start conversion, with parasite power on at the end
delay(1000); // maybe 750ms is enough, maybe not
// we might do a ds.depower() here, but the reset will take care of it.
present = ds.reset();
ds.select(addr);
ds.write(0xBE); // Read Scratchpad
Serial.print(" Data = ");
Serial.print(present, HEX);
Serial.print(" ");
for ( i = 0; i < 9; i++) { // we need 9 bytes
data[i] = ds.read();
Serial.print(data[i], HEX);
Serial.print(" ");
}
Serial.print(" CRC=");
Serial.print(OneWire::crc8(data, 8), HEX);
Serial.println();
// Convert the data to actual temperature
// because the result is a 16 bit signed integer, it should
// be stored to an "int16_t" type, which is always 16 bits
// even when compiled on a 32 bit processor.
int16_t raw = (data[1] << 8) | data[0];
if (type_s) {
raw = raw << 3; // 9 bit resolution default
if (data[7] == 0x10) {
// "count remain" gives full 12 bit resolution
raw = (raw & 0xFFF0) + 12 - data[6];
}
} else {
byte cfg = (data[4] & 0x60);
// at lower res, the low bits are undefined, so let's zero them
if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms
else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
//// default is 12 bit resolution, 750 ms conversion time
}
celsius = (float)raw / 16.0;
fahrenheit = celsius * 1.8 + 32.0;
Serial.print(" Temperature = ");
Serial.print(celsius);
Serial.print(" Celsius, ");
Serial.print(fahrenheit);
Serial.println(" Fahrenheit");
}
Taking out all the serial print lines dropped it down to 5,370 bytes, I'm going to keep working though. It scans for an address, but if I took that out and had the address in by itself I bet that would help.
#include <OneWire.h>
// OneWire DS18S20, DS18B20, DS1822 Temperature Example
//
// http://www.pjrc.com/teensy/td_libs_OneWire.html
//
// The DallasTemperature library can do all this work for you!
// http://milesburton.com/Dallas_Temperature_Control_Library
OneWire ds(10); // on pin 10 (a 4.7K resistor is necessary)
void setup(void) {
Serial.begin(9600);
}
void loop(void) {
byte i;
byte present = 0;
byte type_s;
byte data[12];
byte addr[8];
float celsius, fahrenheit;
if ( !ds.search(addr)) {
ds.reset_search();
delay(250);
return;
}
for( i = 0; i < 8; i++) {
}
if (OneWire::crc8(addr, 7) != addr[7]) {
return;
}
// the first ROM byte indicates which chip
switch (addr[0]) {
case 0x10:
type_s = 1;
break;
case 0x28:
type_s = 0;
break;
case 0x22:
type_s = 0;
break;
default:
return;
}
ds.reset();
ds.select(addr);
ds.write(0x44, 1); // start conversion, with parasite power on at the end
delay(1000); // maybe 750ms is enough, maybe not
// we might do a ds.depower() here, but the reset will take care of it.
present = ds.reset();
ds.select(addr);
ds.write(0xBE); // Read Scratchpad
for ( i = 0; i < 9; i++) { // we need 9 bytes
data[i] = ds.read();
}
// Convert the data to actual temperature
// because the result is a 16 bit signed integer, it should
// be stored to an "int16_t" type, which is always 16 bits
// even when compiled on a 32 bit processor.
int16_t raw = (data[1] << 8) | data[0];
if (type_s) {
raw = raw << 3; // 9 bit resolution default
if (data[7] == 0x10) {
// "count remain" gives full 12 bit resolution
raw = (raw & 0xFFF0) + 12 - data[6];
}
} else {
byte cfg = (data[4] & 0x60);
// at lower res, the low bits are undefined, so let's zero them
if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms
else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
//// default is 12 bit resolution, 750 ms conversion time
}
celsius = (float)raw / 16.0;
fahrenheit = celsius * 1.8 + 32.0;
}
Presumably you know (or can find out) the chip type, so the switch that follows is superfluous. Given that, you know type_s the if that tests it can go and either the code in the if or else clause too.
I'll try those tips out, one thing though, how can I make the Celsius readout into a variable? I just need it to be the same, giving the temperature, so that I can use a if statement with it.
edit: whoops. just saw what I did wrong and why it wasn't working lol
XOIIO:
I'll try those tips out, one thing though, how can I make the Celsius readout into a variable?
I don't understand the question. The Celsius value is already stored in variable.
Yeah, I had been trying to use the one with a capital C thinking that was it.
Anyways another question for you guys, I am setting an RGB LED's color based on the temperature, is there a better way of doing this other than the if statements I am using or is this pretty much my only option?
I have them set up like this, but it will need quite a few more instances of this by the time it's done taking up more space.
Put the thresholds and colour settings in an array stored in PROGMEM, then iterate through it. If you keep the thresholds in order in the array then you can terminate as soon as the threshold rises too high.
is there a better way of doing this other than the if statements I am using or is this pretty much my only option?
You could create an array of values for the RGB values, and assuming the limits are linear, use division and addition/subtraction to convert the temperature into array indexes.
I'm not familiar with this sensor, so this is likely dumb, but what is the purpose of:
for( i = 0; i < 8; i++) {
}
I did download the OneWire library, but when I try to compile the code, I get an error message stating: OneWire does not name a type, which is the statement
OneWire ds(10);
on line 12 of the program. I've looked in the header file and it appears it should be calling the constructor correctly. What am I missing?
is there a better way of doing this other than the if statements I am using or is this pretty much my only option?
You could create an array of values for the RGB values, and assuming the limits are linear, use division and addition/subtraction to convert the temperature into array indexes.
If you learn to count in binary and use the right thresholds you can use shifts instead of division. If you have your thresholds every 4 or 8 degrees instead of every 5 you can then just add the right offset (the lowest negative) and shift the result 2 or 3 places right to get the array index. Very efficient and small code.
The array of RGB values sounds easier than learning to count in binary, but that's out of my programming knowledge right now, I actually don't know how I would set up the code for that and the equations to trigger it.
I did notice though, each one of those lines only adds 4 bytes so maybe it would work out this way.
Yup, this will work, after taking out those serial prints its fine, and I changed the board to the attiny85, and for some reason the code size went down, I'm only using around half the available space now.