Digispark ATtiny85 suddenly stopps sending data

36 Views Asked by At

I am making a radio temperature sensor. It works perfectly fine until it suddenly stops sending data. I am using the Arduino IDE with the Digispark (ATtiny85) and it's normal Arduino bootloader. To reduce the energy consumption, I use the watchdog to turn on and off the CPU. It sometimes works for a long time (up to 3 days) and sometimes only a few hours. If I then reset it via pin 5, it works again.

I usually run it on 3x AAA (1.5V) batterys. (I know, it is under 5V (4.5V), but it works in the beginning) I already tried to power it with constant 5V and the same thing happened. So I think think, it has to do with the software. But I can't see any problems with it. I can't get Serial.print() to work for further debugging.

Here is my original code (in German):

#include <OneWire.h>
#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/wdt.h>

#define sensorPin 2
#define TaktLaenge 250 //ms
#define sendeIntervall 15 //min

#define primaerPin 1
#define sekundaerPin 0

//byte saveADCSRA;                      // variable to save the content of the ADC for later. if needed.
unsigned int counterWD = sendeIntervall * 8; // Count how many times WDog has fired. Used in the timing of the 
                                           // loop to increase the delay before the LED is illuminated. For example,
                                        // if WDog is set to 1 second TimeOut, and the counterWD loop to 10, the delay
                                        // between LED illuminations is increased to 1 x 10 = 10 seconds

void sleepNow ()
{
  set_sleep_mode ( SLEEP_MODE_PWR_DOWN ); // set sleep mode Power Down
  //saveADCSRA = ADCSRA;                    // save the state of the ADC. We can either restore it or leave it turned off.
  ADCSRA = 0;                             // turn off the ADC
  power_all_disable ();                   // turn power off to ADC, TIMER 1 and 2, Serial Interface
  
  noInterrupts ();                        // turn off interrupts as a precaution

  MCUSR = 0;
  WDTCR = bit ( WDCE ) | bit ( WDE ) | bit ( WDIF ); // allow changes, disable reset, clear existing interrupt
  WDTCR = bit ( WDIE ) | bit ( WDP3 )| bit ( WDP0 ); // set WDIE ( Interrupt only, no Reset ) and 8 second TimeOut. Table for WDPs: http://shelvin.de/wp-content/uploads/2014/09/atmega328-wdt-pre-500.jpg
                                                     
  wdt_reset ();                            // reset WDog to parameters

  sleep_enable ();                        // allows the system to be commanded to sleep
  interrupts ();                          // turn on interrupts
  
  sleep_cpu ();                           // send the system to sleep, night night!

  sleep_disable ();                       // after ISR fires, return to here and disable sleep
  power_all_enable ();                    // turn on power to ADC, TIMER1 and 2, Serial Interface
  
  // ADCSRA = saveADCSRA;                 // turn on and restore the ADC if needed. Commented out, not needed.
  
}

void sleep1sec ()
{
  set_sleep_mode ( SLEEP_MODE_PWR_DOWN ); // set sleep mode Power Down
  //saveADCSRA = ADCSRA;                    // save the state of the ADC. We can either restore it or leave it turned off.
  ADCSRA = 0;                             // turn off the ADC
  power_all_disable ();                   // turn power off to ADC, TIMER 1 and 2, Serial Interface
  
  noInterrupts ();                        // turn off interrupts as a precaution

  MCUSR = 0;
  WDTCR = bit ( WDCE ) | bit ( WDE ) | bit ( WDIF ); // allow changes, disable reset, clear existing interrupt
  WDTCR = bit ( WDIE ) | bit ( WDP2 )| bit ( WDP1 ); // set WDIE ( Interrupt only, no Reset ) and 1 second TimeOut. Table for WDPs: http://shelvin.de/wp-content/uploads/2014/09/atmega328-wdt-pre-500.jpg
                                                     
  wdt_reset ();                            // reset WDog to parameters

  sleep_enable ();                        // allows the system to be commanded to sleep
  interrupts ();                          // turn on interrupts
  
  sleep_cpu ();                           // send the system to sleep, night night!

  sleep_disable ();                       // after ISR fires, return to here and disable sleep
  power_all_enable ();                    // turn on power to ADC, TIMER1 and 2, Serial Interface
  
  // ADCSRA = saveADCSRA;                 // turn on and restore the ADC if needed. Commented out, not needed.
  
}

void sleep250ms ()
{
  set_sleep_mode ( SLEEP_MODE_PWR_DOWN ); // set sleep mode Power Down
  //saveADCSRA = ADCSRA;                    // save the state of the ADC. We can either restore it or leave it turned off.
  ADCSRA = 0;                             // turn off the ADC
  power_all_disable ();                   // turn power off to ADC, TIMER 1 and 2, Serial Interface
  
  noInterrupts ();                        // turn off interrupts as a precaution

  MCUSR = 0;
  WDTCR = bit ( WDCE ) | bit ( WDE ) | bit ( WDIF ); // allow changes, disable reset, clear existing interrupt
  WDTCR = bit ( WDIE ) | bit ( WDP2 ); // set WDIE ( Interrupt only, no Reset ) and 0.5 second TimeOut. Table for WDPs: http://shelvin.de/wp-content/uploads/2014/09/atmega328-wdt-pre-500.jpg
                                                     
  wdt_reset ();                            // reset WDog to parameters

  sleep_enable ();                        // allows the system to be commanded to sleep
  interrupts ();                          // turn on interrupts
  
  sleep_cpu ();                           // send the system to sleep, night night!

  sleep_disable ();                       // after ISR fires, return to here and disable sleep
  power_all_enable ();                    // turn on power to ADC, TIMER1 and 2, Serial Interface
  
  // ADCSRA = saveADCSRA;                 // turn on and restore the ADC if needed. Commented out, not needed.
  
}

ISR ( WDT_vect )
{
  wdt_disable ();                           // until next time....
  //counterWD ++;                             // increase the WDog firing counter. Used in the loop to time the flash
                                            // interval of the LED. If you only want the WDog to fire within the normal 
                                            // presets, say 2 seconds, then comment out this command and also the associated
                                            // commands in the if ( counterWD..... ) loop, except the 2 digitalWrites and the
                                            // delay () commands.
} // end of ISR

namespace RCautoSender {
  uint8_t ohneUEbertragAddieren(uint8_t daten[15], uint8_t anzahl){
    uint8_t output = 0;
    for(uint8_t i = 0; i < anzahl; i++){
      output ^= daten[i];
    }
    return output;
  }
  void sendeFloat(float Zahl){
    int VorKomma;
    int NachKomma;
    if(Zahl < 0){
      VorKomma = Zahl * -1; // Wird automatisch abgerundet
      NachKomma = (Zahl + VorKomma) * -10; // -10 aendern, fuer mehr Kommastellen     
    } else {
      VorKomma = Zahl; // Wird automatisch abgerundet
      NachKomma = (Zahl - VorKomma) * 10; // 10 aendern, fuer mehr Kommastellen     
    }
    uint32_t bits = 0;
    uint8_t einsen[13];
    uint8_t gemeinsamesI = 0;
    uint8_t einsenZaehler = 0;
    for(uint8_t i = 0; i < 8; gemeinsamesI++){
      if(((gemeinsamesI + 1) & gemeinsamesI) != 0){ // gemeinsamesI+1 (bei 1 angefangen) ist keine Zweierpotenz und somit kein Pharitaetsbit
        bitWrite(bits, gemeinsamesI, bitRead(VorKomma, i));
        if(bitRead(bits, gemeinsamesI) == 1){
          einsen[einsenZaehler] = gemeinsamesI + 1;
          einsenZaehler++;
        }
        i++;
      }
    }
    for(uint8_t i = 0; i < 5; gemeinsamesI++){
      if(((gemeinsamesI + 1) & gemeinsamesI) != 0){ // gemeinsamesI+1 (bei 1 angefangen) ist keine Zweierpotenz und somit kein Pharitaetsbit
        if(i == 4){ // Positiv oder Negativ Indikator: 0=Positiv; 1=Negativ
          bitWrite(bits, gemeinsamesI, Zahl < 0);
          if(Zahl < 0){
            einsen[einsenZaehler] = gemeinsamesI + 1;
            einsenZaehler++;
          }
          i++;
        } else {
          bitWrite(bits, gemeinsamesI, bitRead(NachKomma, i));
          if(bitRead(bits, gemeinsamesI) == 1){
            einsen[einsenZaehler] = gemeinsamesI + 1;
            einsenZaehler++;
          }
          i++;
        }
      }
    }

    uint8_t pharitaeten = ohneUEbertragAddieren(einsen, einsenZaehler);
    uint8_t pharitaetszaehler = 0;
    for(uint8_t i = 0; i < gemeinsamesI; i++){
      if(((i + 1) & i) == 0){ // i+1 (bei 1 angefangen) ist eine Zweierpotenz und somit ein Pharitaetsbit
        bitWrite(bits, i, bitRead(pharitaeten, pharitaetszaehler));
        if(bitRead(pharitaeten, pharitaetszaehler) == 1){
          einsenZaehler++;
        }
        pharitaetszaehler++;
      }
    }

    pinMode(primaerPin, OUTPUT);
    pinMode(sekundaerPin, OUTPUT);

    //bits = 0b0011001110000110000;
    byte startbits = 0b01; // wird wie binaer 10 behandelt
    digitalWrite(sekundaerPin, HIGH);
    sleep1sec(); //delay(1000);
    for(int i = 0; i < 2; i++){ // Um ca. die gleiche zusaetzliche Zeit wie in der realen Schleife zu benötigen
      digitalWrite(primaerPin, bitRead(startbits, i));
      sleep250ms(); //delay(TaktLaenge);
    }

    for(int i = 0; i < 10; i++){
      digitalWrite(primaerPin, bitRead(bits, i));
      sleep250ms(); //delay(TaktLaenge);
    }

    digitalWrite(primaerPin, LOW);
    sleep250ms(); //delay(1000);
    for(int i = 0; i < 2; i++){ // Um ca. die gleiche zusaetzliche Zeit wie in der realen Schleife zu benötigen
      digitalWrite(primaerPin, bitRead(startbits, i));
      sleep250ms(); //delay(TaktLaenge);
    }

    for(int i = 10; i < gemeinsamesI; i++){
      digitalWrite(primaerPin, bitRead(bits, i));
      sleep250ms(); //delay(TaktLaenge);
    }

    //Ist die Anzahl aller Bits ungerade (ungerade = 1)
    digitalWrite(primaerPin, einsenZaehler % 2);
    sleep250ms(); //delay(TaktLaenge);

    digitalWrite(sekundaerPin, LOW);
    digitalWrite(primaerPin, LOW);

    pinMode(primaerPin, INPUT);
    pinMode(sekundaerPin, INPUT);
  }
  void sendeFehler(){ // Sendet eine -0.00 (waehre eigentlich 0.00) der Empfänger erkennt das.
    pinMode(primaerPin, OUTPUT);
    pinMode(sekundaerPin, OUTPUT);

    digitalWrite(sekundaerPin, HIGH);
    sleep1sec(); //delay(1000);
    digitalWrite(primaerPin, HIGH);
    sleep250ms(); //delay(TaktLaenge);
    digitalWrite(primaerPin, LOW);
    sleep250ms(); //delay(TaktLaenge);

    // Die mit Hammingcode gesicherte version von -0,0 ist 010000000000000101b (mit 2. Erkennung: 0100000000 010 00000101)
    // (primaerPin ist bereits auf 0)
    sleep250ms();
    digitalWrite(primaerPin, 1);
    sleep250ms();
    digitalWrite(primaerPin, 0);
    sleep1sec();
    sleep1sec();

    sleep250ms();
    digitalWrite(primaerPin, 1);
    sleep250ms();
    digitalWrite(primaerPin, 0);
    sleep250ms();

    sleep1sec();
    sleep250ms();
    digitalWrite(primaerPin, 1);
    sleep250ms();
    digitalWrite(primaerPin, 0);
    sleep250ms();
    digitalWrite(primaerPin, 1);
    sleep250ms();
    //die Anzahl aller Bits ist ungerade (ungerade = 1)
    // (primaerPin ist bereits auf 1)
    sleep250ms();

    digitalWrite(sekundaerPin, LOW);
    digitalWrite(primaerPin, LOW);

    pinMode(primaerPin, INPUT);
    pinMode(sekundaerPin, INPUT);
  }
};

OneWire ds(sensorPin);

float tempC; // temperature in Celsius

void setup() {
}

void loop() {
  if ( counterWD >= sendeIntervall * 7.5 ){
    byte i;
    byte present = 0;
    byte type_s;
    byte data[9];
    byte addr[8];
    
    if ( !ds.search(addr)) {
      ds.reset_search();
      sleep1sec();
      if ( !ds.search(addr)) {
        RCautoSender::sendeFehler(); // No more addresses.
        ds.reset_search();
        counterWD = 0;
        sleepNow();
        return;
      }
    }
    
    if (OneWire::crc8(addr, 7) != addr[7]) {
        RCautoSender::sendeFehler(); // CRC is not valid!
        counterWD = 0;
        sleepNow();
        return;
    }
  
    // 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:
        RCautoSender::sendeFehler(); //Serial.println("Device is not a DS18x20 family device.");
        counterWD = 0;
        sleepNow();
        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
    sleep1sec();
    // 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
    }
    tempC = (float)raw / 16.0;

    RCautoSender::sendeFloat(round(tempC*10.00)/10.00);
    //RCautoSender::sendeFloat(-1.7);

    counterWD = 0;
  }
  //delay(sendeIntervall * 60000);
  counterWD ++;
  sleepNow();
}

In case anyone needs it, here is the scematics: Scematics of the circuit

Please help me and give tips.

0

There are 0 best solutions below