ATMega328 DS18B20
Jump to navigation
Jump to search
/*
DS18B20 code for ATMega328 (arduino)
This code does not rely on any external OneWire or DallasTemperature sensor libraries.
DS18B20 temperature sensor
-------------------------
DS18S20
byte 1 byte 2
-------------------------------
76543210 76543210
00101010 00000000
IIIIDDDD SSSSSIII
3210 654
I = Celsius integer digits (signed) 000 0010 = 2
D = Number of decimal steps (x multiplier) 1010 = 10 steps x 0.0625
S = Signedness (0=positive, 1=negative) 00000 = +
DS1820
LSB (1st 7 bits are the temperature)
and the last bit represents .0 or .5 degrees
Example: '87654321'
TTTTTTTH
T = Temperature
H = halves H=0 (.0), H=1 (.5)
MSB (is 0 when positive, 1 when negative)
*/
//#include <avr/io.h>
//#include <util/delay.h>
//#include <string.h>
//#include <math.h>
#define THERM_PORT PORTB
#define THERM_DDR DDRB
#define THERM_PIN PINB
#define THERM_DQ PB2 // Define DS1820 DQ pin
#define THERM_INPUT_MODE() THERM_DDR&=~(1<<THERM_DQ)
#define THERM_OUTPUT_MODE() THERM_DDR|=(1<<THERM_DQ)
#define THERM_LOW() THERM_PORT&=~(1<<THERM_DQ)
#define THERM_HIGH() THERM_PORT|=(1<<THERM_DQ)
#define HIGH 1
#define LOW 0
#define INPUT 1
#define OUTPUT 0
#define THERM_CMD_CONVERTTEMP 0x44
#define THERM_CMD_RSCRATCHPAD 0xbe
#define THERM_CMD_WSCRATCHPAD 0x4e
#define THERM_CMD_CPYSCRATCHPAD 0x48
#define THERM_CMD_RECEEPROM 0xb8
#define THERM_CMD_RPWRSUPPLY 0xb4
#define THERM_CMD_SEARCHROM 0xf0
#define THERM_CMD_READROM 0x33
#define THERM_CMD_MATCHROM 0x55
#define THERM_CMD_SKIPROM 0xcc
#define THERM_CMD_ALARMSEARCH 0xec
#define THERM_DECIMAL_STEPS_12BIT 625 // 0.0625, for 12-bit accuracy
#define PRESENCE_ERR 0xFF
#define DATA_ERR 0xFF
#define LAST_DEVICE 0x00
#define SEARCH_FIRST 0xFF
#define CLEAR(s) memset(&(s), 0, sizeof(s)) // to clear an array
int got_ack;
uint8_t romcodes[20][9]; // store romcode of 20 sensors max
uint8_t scratchpad[9]; // stores a scratchpad
char buffer[16];
void setup()
{
Serial.begin(9600);
}
void pMode(int pin,int state)
{
if (state == OUTPUT)
{
(DDRB |= (1 << pin));
} else {
(DDRB &= ~(1 << pin));
}
}
void dWrite(int pin, int state)
{
if (state == HIGH)
{
(PORTB |= (1 << pin));
} else {
(PORTB &= ~(1 << pin));
}
}
int dRead(int pin)
{
if (bit_is_set(PINB,pin))
{
return 1;
} else {
return 0;
}
}
// -- OneWire functions --
uint8_t owReset(int Pin)
{
uint8_t i;
dWrite(Pin, HIGH);
pMode(Pin, INPUT);
dWrite(Pin, LOW);
pMode(Pin, OUTPUT); // bring low for 480us
_delay_us(480);
// Release line and wait for 60us
dWrite(Pin, HIGH);
pMode(Pin, INPUT);
_delay_us(60);
// store line value and wait for completion of 480us period
i=dRead(Pin);
_delay_us(480);
// return measured line value
return i;
}
uint8_t therm_reset()
{
uint8_t i;
// pull line low and wait for 480us
THERM_LOW();
THERM_OUTPUT_MODE();
//therm_delay(480);
_delay_us(480);
// Release line and wait for 60us
THERM_INPUT_MODE();
//therm_delay(60);
_delay_us(60);
// store line value and wait for completion of 480us period
i=(THERM_PIN & (1<<THERM_DQ));
//therm_delay(420);
_delay_us(480);
// return measured line value
return i;
}
void therm_write_bit(uint8_t bit)
{
// pull line low for 1us
THERM_LOW();
THERM_OUTPUT_MODE();
//therm_delay(1);
_delay_us(1);
// if we want to write 1, release the line (if not will keep low)
if (bit) THERM_INPUT_MODE();
// wait for 60us and release the line
//therm_delay(60);
_delay_us(60);
THERM_INPUT_MODE();
}
uint8_t therm_read_bit(void)
{
uint8_t bit=0;
// pull line low for 1us
THERM_LOW();
THERM_OUTPUT_MODE();
//therm_delay(1);
_delay_us(1);
// release line and wait for 14us
THERM_INPUT_MODE();
//therm_delay(14);
_delay_us(14);
// read line value
if (THERM_PIN&(1<<THERM_DQ)) bit=1;
// wait for 45us to end and return read value
//therm_delay(45);
_delay_us(45);
return bit;
}
uint8_t therm_read_byte(void)
{
uint8_t i=8, n=0;
while(i--)
{
// shift one position right and store read value
n>>=1;
n|=(therm_read_bit()<<7);
}
return n;
}
void therm_write_byte(uint8_t byte)
{
uint8_t i=8;
while(i--)
{
// write actual bit and shift one position right to make the next bit ready
therm_write_bit(byte&1);
byte>>=1;
}
}
unsigned char therm_rom_search(unsigned char diff, unsigned char *id)
{
// scans a one-wire bus for all attached DS18x20 sensors
unsigned char i, j, next_diff;
unsigned char b;
if( therm_reset() )
return PRESENCE_ERR; // error, no device found
therm_write_byte( THERM_CMD_SEARCHROM ); // ROM search command
next_diff = LAST_DEVICE; // unchanged on last device
i = 8 * 8; // 8 bytes
do
{
j = 8; // 8 bits
do
{
b = therm_read_bit(); // read bit
// read complement bit
if( therm_read_bit() )
{
if( b ) // 11
return DATA_ERR; // data error
} else {
if( !b )
{
// 00 = 2 devices
if( diff > i || ((*id & 1) && diff != i) )
{
b = 1; // now 1
next_diff = i; // next pass 0
}
}
}
therm_write_bit( b ); // write bit
*id >>= 1;
if( b ) // store bit
*id |= 0x80;
i--;
} while( --j );
id++; // next byte
} while( i );
return next_diff; // to continue search
}
void start_meas( void )
{
if( PINB & 1<< THERM_DQ )
{
therm_write_byte(THERM_CMD_CONVERTTEMP); // read scratchpad
PORTB |= 1<< THERM_DQ;
DDRB |= 1<< THERM_DQ; // parasite power on
} else {
// Short circuit on bus
_delay_ms(1000);
}
}
int scanbus(void)
{
// outputs the number of found devices and stores all roms in an array
unsigned char id[8], diff;
unsigned char i,x;
unsigned char device_counter=0;
// clear array
for (x=1; x <= 20; x++)
{
romcodes[x][0] = 0;
}
for( diff = SEARCH_FIRST; diff != LAST_DEVICE; )
{
diff = therm_rom_search( diff, id );
if( diff == PRESENCE_ERR )
{
//Serial.println("scanbus: no sensors found");
_delay_ms(1000);
break;
}
if( diff == DATA_ERR )
{
//Serial.println("scanbus: Bus error");
_delay_ms(1000);
break;
}
if( id[0] == 0x28 || id[0] == 0x10 )
{
// valid temperature sensor found
// store romcode in array
for( i = 0; i < 8; i++ )
{
romcodes[device_counter][i]=id[i];
}
device_counter=device_counter+1;
}
}
return device_counter;
}
void therm_romtemp(uint8_t device)
{
// address a specific sensor and retrieve its temperature
uint8_t i;
therm_reset();
therm_write_byte(THERM_CMD_MATCHROM);
for (i=0 ; i < 8; i++)
{
therm_write_byte(romcodes[device][i]);
}
therm_write_byte(THERM_CMD_CONVERTTEMP);
// wait until conversion is complete
while(!therm_read_bit());
therm_reset();
therm_write_byte(THERM_CMD_MATCHROM);
for (i=0 ; i < 8; i++)
{
therm_write_byte(romcodes[device][i]);
}
therm_write_byte(THERM_CMD_RSCRATCHPAD);
// store the replies in the 'scratchpad' variable
for (i=0 ; i < 2; i++)
{
scratchpad[i]=therm_read_byte();
}
therm_reset();
}
void showdevs()
{
// outputs all device romcodes stored in the array
unsigned char device=0;
unsigned char rombyte=0;
uint8_t digit;
uint16_t decimal;
while (1)
{
if (romcodes[device][0] != 0)
{
// valid romcode found in array
// target the sensor and read its temperature
therm_romtemp(device); // this fills the 'scratchpad' variable
for (rombyte=0; rombyte < 8; rombyte++)
{
Serial.print(romcodes[device][rombyte],HEX); // display the romcode
Serial.print(" ");
}
Serial.print(" ");
// store temperature integer digits and decimal digits
// display the 'scratchpad' variable fields
// --half degree accuracy -- (9 bit)
// test if temperature is .0 or .5
//decimal = scratchpad[0] & (1 << 0); // decimals is in bit 0, store value
// move temperature bits on position to the right
//scratchpad[0]>>=1;
//Serial.print(scratchpad[0]);
//if (decimal == 0)
// Serial.print(".0");
//else
// Serial.print(".5");
// -- 2-decimal of a degree accuracy -- (12 bit)
// store whole digits
digit=scratchpad[0]>>4;
digit|=(scratchpad[1]&0x7)<<4;
// store decimal digits
decimal=scratchpad[0]&0xf;
decimal*=THERM_DECIMAL_STEPS_12BIT;
Serial.print(digit);
Serial.print(".");
Serial.print(decimal);
Serial.print(" C");
Serial.println();
_delay_ms(1000);
device=device+1;
} else {
break;
}
}
}
void loop()
{
uint8_t ack;
int devs;
while (1)
{
ack = owReset(THERM_DQ);
if (ack == 1)
{
//Serial.println("no sensors found");
_delay_ms(1000);
} else {
// sensor activity detected
while (1)
{
devs=scanbus(); // detect and store device rom's in an array
if (devs > 0)
{
_delay_ms(1000);
_delay_ms(1000);
showdevs();
} else {
Serial.print(devs);
Serial.println(" sensors found");
}
_delay_ms(1000);
_delay_ms(1000);
_delay_ms(1000);
_delay_ms(1000);
}
}
_delay_ms(1000);
_delay_ms(1000);
}
}