Timer stört Temperaturmessung

Gast #3462613
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
#3462624
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?
Gast #3462643
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.
Gast #3465532
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.
Gast #3465839
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. ;-)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren