Forum: Mikrocontroller und Digitale Elektronik Timer stört Temperaturmessung


von Praktikant (Gast)


Lesenswert?

Hallo zusammen.

Ich habe ein Problem und keinen Schimmer was da falsch läuft.

Mein Timer1 wird so konfiguriert, dass er jede Sekunde ein Interrupt 
auslöst:
1
  // Timer 0 konfigurieren
2
 // TCCR1A = (1<<WGM11); // CTC Modus
3
  TCCR1B |= (1<<WGM12)|(1<<CS12)|(1<<CS10); // Prescaler 8
4
  // ((4000000/64)/1000) = 62,5
5
  OCR1A = F_CPU/1024-1;
6
  // Compare Interrupt erlauben
7
  TIMSK |= (1<<OCIE1A);
8
sei();

In der Interrupt-Routine mache ich nichts weiter, als ein Flag zu 
setzten und eine Variable hochzuzählen:
1
ISR (TIMER1_COMPA_vect)
2
{
3
  sekunde++;  
4
  bSekunde=1;
5
}


In meiner While-Schleife wird auf das Flag reagiert.
1
if(bSekunde==1)
2
    {
3
      cli();
4
        bSekunde=0;
5
        if(sekunde == 60)
6
        {
7
          minute++;
8
          sekunde = 0;
9
          LCD_String(4,13,itoa(minute,Zeit,10));
10
          LCD_String(4,16,"  ");
11
        }
12
        if(minute == 60)
13
        {
14
          stunde++;
15
          minute = 0;
16
          LCD_String(4,10,itoa(stunde,Zeit,10));
17
          LCD_String(4,13,"  ");
18
          LCD_String(4,16,"  ");
19
        }
20
        if(stunde == 24)
21
        {
22
          stunde = 0;
23
          LCD_String(4,10,itoa(stunde,Zeit,10));
24
          LCD_String(4,16,"  ");
25
        }
26
    
27
        if(sekunde%5==0)
28
        {
29
  
30
        Temperature1=DS18B20_Read_Addressed_Temperature(rom1,byte);
31
        Temperature2=DS18B20_Read_Addressed_Temperature(rom2,byte);
32
        LCD_String(1,13,dtostrf(Temperature1,3,1,buf));
33
        LCD_String(2,13,dtostrf(Temperature2,3,1,buf));
34
        }
35
    
36
    LCD_String(4,16,itoa(sekunde,Zeit,10));    
37
    sei();
38
    }

Da ich weiß, dass LCD-Ansteuerung und Temperatursensor auslesen lange 
dauert habe ich mal ein cli() und ein sei()-Befehl eingebaut.
Trotz allem wird mir nach dem 3. Lesevorgang und nur bei Temperatur 1 
-0.1 °C angezeigt.
Temperatur 2 liefert immer einen korrekten Wert.

Wenn ich den Timer deaktiviere und in der While-Schleife nur
1
Temperature1=DS18B20_Read_Addressed_Temperature(rom1,byte);
2
Temperature2=DS18B20_Read_Addressed_Temperature(rom2,byte);
3
LCD_String(1,13,dtostrf(Temperature1,3,1,buf));
4
LCD_String(2,13,dtostrf(Temperature2,3,1,buf));

ausführe, dann erhalte ich von beiden Fühlern korrekte Werte.

Warum also schießt mir der Timer, trotz cli(), in die Auswertung der 
Fühler?

Jemand eine Idee?

Gruß

Der Praktikant

von Peter II (Gast)


Lesenswert?

zeige uns mal etwa mehr vom code, es fehlten alle variablen 
Deklarationen.

von Karl H. (kbuchegg)


Lesenswert?

-0.1 das dürfte Hex als 0xFFFF über die Leitung gehen.

Wie versorgst du den DS18B20, bzw. wie sieht die Abfrage des Sensors 
aus?

Der UNterschied dürfte darin liegen, dass du in dem einen Fall nur alle 
5 Sekunden den Sensor abfrägst, während du im anderen Fall den Sensor 
mehr oder weniger ständig abfrägst. So wie das aussieht, bist du im 5 
Sekunden Fall aber zu schnell - der erste Sensor ist noch nicht fertig.


Mit dem Timer, schätze ich mal, hat das ganze nur indirekt zu tun. Wenn 
du in deinen 2-ten Fall das 5 Sekunden Intervall mittels delay_ms(5000) 
einrichtest, kriegst du dann dasselbe Ergebnis?

von Praktikant (Gast)


Lesenswert?

Die Sensoren werden mit 5 V versorgt. Nicht im parasitären Modus. 4,7k 
Pull Up.

Gelesen wird wie im Datenblatt angegeben
1
float DS18B20_Read_Addressed_Temperature(uint8_t *address, uint8_t *buffer)
2
  {
3
    uint8_t i;
4
5
    W1_Address_Device(address);
6
    W1_Byte_Write(CONVERT); // Start Conversion
7
    // für neuen Befehl bereit machen
8
    W1_DQ_High();
9
    _delay_ms(750);
10
    W1_Address_Device(address);
11
    W1_Byte_Write(READ_SP);
12
    // jetzt werden 9 Byte empfangen
13
    for(i=0;i<9;i++)
14
    {
15
      buffer[i] = W1_Byte_Read();
16
    }
17
    buffer[9]=0;
18
    //temp_msb = byte[1]; // Byte 1 enthält das Vorzeichen, 0 = +, 1 = -
19
    //temp_lsb = byte[0]; // Byte 0 enthält die Temperatur
20
    return((buffer[1]<<8 | buffer[0])*0.0625);
21
    
22
    
23
  }

Das mit dem delay_ms(5000) bringt nichts, da hier nur gewartet wird.

Wie? Ich bin im 5 Sekunden Fall zu schnell? Vielleicht habe ich das 
falsch formuliert. Statt alle 5 Sekunden kann ich auch jede Sekunde, 
oder alle 30 s die asuwertung machen. Das Ergebnis ist das Gleiche und 
damit hat der Timer sehr wohl etwas damit zu tun


Fall 1: Der Timer ist Aktiv -> TIMSK |= (1<<OCIE1A);
1
  while(1)
2
    {
3
  
4
    if(bSekunde==1)
5
    {
6
      cli();
7
        bSekunde=0;
8
        if(sekunde == 60)
9
        {
10
          minute++;
11
          sekunde = 0;
12
          LCD_String(4,13,itoa(minute,Zeit,10));
13
          LCD_String(4,16,"  ");
14
        }
15
        if(minute == 60)
16
        {
17
          stunde++;
18
          minute = 0;
19
                LCD_String(4,10,itoa(stunde,Zeit,10));
20
          LCD_String(4,13,"  ");
21
          LCD_String(4,16,"  ");
22
        }
23
        if(stunde == 24)
24
        {
25
          stunde = 0;
26
          LCD_String(4,10,itoa(stunde,Zeit,10));
27
          LCD_String(4,16,"  ");
28
        }
29
    
30
        if(sekunde%5==0)
31
        {
32
  
33
        Temperature1=DS18B20_Read_Addressed_Temperature(rom1,byte);
34
        Temperature2=DS18B20_Read_Addressed_Temperature(rom2,byte);
35
        LCD_String(1,13,dtostrf(Temperature1,3,1,buf));
36
        LCD_String(2,13,dtostrf(Temperature2,3,1,buf));
37
        }
38
    
39
    LCD_String(4,16,itoa(sekunde,Zeit,10));    
40
    sei();
41
    }
42
}

Fall 2: Der Timer wurde deaktiviert -> //TIMSK |= (1<<OCIE1A);
1
  while(1)
2
    {
3
  Temperature1=DS18B20_Read_Addressed_Temperature(rom1,byte);
4
  Temperature2=DS18B20_Read_Addressed_Temperature(rom2,byte);
5
  LCD_String(1,13,dtostrf(Temperature1,3,1,buf));
6
  LCD_String(2,13,dtostrf(Temperature2,3,1,buf));
7
    }

Im zweiten Fall findet die Auswertung permanent statt. Wie lange das 
dauert wird durch die einzelenen Wartezeiten bestimmt.

Im ersten Fall haut mir der Interrupt jede Sekunde dazwischen. D. h. 
wenn er gerade beim Lesen des Fühlers ist, unterrbricht der Timer.
ABER.
Ich habe ein cli() eingebaut, damit mir der Timer nicht mehr 
dazwischkloppen kann. Nur geht das irgendwie nicht.

von Pratikant (Gast)


Lesenswert?

Ich wollte nur kurz mitteilen, dass das Problem gelöst wurde.

Ähem. Scheint wohl so, dass der Programmierer den Buffer der 
itoa-Funktion zu, öhm zu kleine dimensioniert hat.

Ich hasse diese ständigen Layer 8 Probleme


Einen guten Rutsch an alle, die das hier noch lesen.

von ha. (Gast)


Lesenswert?

Ein LCD in einem Timer anzusteuern ist grottenschlechter Stil. Der 
Anfang vom Ende.

von Praktikant (Gast)


Lesenswert?

Ähhh? Das LCD wird nicht im Timer angesteuert.

Wie ganz oben beschrieben setze ich im Interrupt nur ein Flag das ich in 
meiner Hauptschleife auswerte.

Nicht den Anfangsbeitrag lesen ist ein grottenschlechter Stil. ;-)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.