ATtiny85 DS18B20

From wikipost
Revision as of 11:49, 27 December 2021 by Admin (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search



/*


  DS18B20 code for DigiSpark (ATtiny85) programmed with Arduino

   - board manager url: http://digistump.com/package_digistump_index.json 

   - board: Digispark Default (16.5MHz)
   
   - programmer: Micronucleus

  
  NOTE: the digispark board requires re-insertion in a USB socket every time you wish to upload code to it.

   
  
  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>

#define THERM_PORT   PORTB
#define THERM_DDR    DDRB
#define THERM_PIN    PINB
#define THERM_DQ     PB0  // Define DS1820 DQ pin

#define LEDPIN  PB1  // built-in LED is on PB1 (Digispark Model A)

#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() 
{
  
  
   
}


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; 
  }
} 


void singleBlink()
{
  pMode(LEDPIN,OUTPUT);
  dWrite(LEDPIN,HIGH);
  _delay_ms(50);
  dWrite(LEDPIN,LOW);
  _delay_ms(500);
}

void nrBlinker(int nr)
{

  if (nr < 100)    
    for (int i=int(nr/10); i>0; i--)
      singleBlink(); // blink tens

  nr = nr - (int) (nr / 10) * 10;  
  delay(1000);

  if (nr < 10)
    for (int i=nr; i>0; i--)
      singleBlink(); // blink ones

}



// -- 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");
      
      nrBlinker(digit); 
      _delay_ms(1000);

      // decimals are stored as a 4-digit positive number (e.g. 3625), scale back to < 100
      decimal = (int) (decimal / 100);
      nrBlinker(decimal); 
         
      _delay_ms(1000);
      _delay_ms(1000);

      device=device+1;

    } else {

      break;

    }

  } 

}




void loop()
{ 
  

  uint8_t  ack;
  int devs;  
 
  while (1)
  {

    ack = owReset(THERM_DQ);

    if (ack == 1)
    {

      // no sensors found
      nrBlinker(2);

    } else {

      // sensor activity detected       

      devs=scanbus();  // detect and store device rom's in an array       
        
      if (devs > 0)
      {
    
        _delay_ms(1000);
        _delay_ms(1000);

        showdevs();

      } else {

        // unable to get sensible data back from sensors
 
      }


      _delay_ms(1000);
      _delay_ms(1000);
      _delay_ms(1000);
      _delay_ms(1000);


    }

    _delay_ms(1000);
    _delay_ms(1000);
  
  } 
}