Forum: Mikrocontroller und Digitale Elektronik Probleme mit SMT 160 Duty Cycle auslesen, Denkfehler ?


von Markus (Gast)


Lesenswert?

Hallo,

ich bin seit ein paar Tagen dabei einen SMT 160 auszulesen. Ich bin aber 
ziemlich am verzweifeln, warum mein Programm einfach nicht funktioniert. 
Ich benutze den Input Capture von Timer 1, ich bekomme nur sehr seltsame 
springende ( von negative bis 189°) Temperaturwerte angezeigt. Ich find 
einfach meinen Fehler im Programm nicht, vielleicht habe ich einen 
denkfehler ?

Abgehesehen von der erste Messung, die mit meinem Programm so einen 
Fehler rausbringen dürfte, weiß ich einfach nicht warum´s nicht läuft.

Ich frage zuerst die Steigende Flanke ab, setze dann in mit einem 
Interrupt den Startwert und lasse die fallende Flanke abfragen und setze 
mir noch eine Erkennungsvariable. Sobald die Fallende Flanke erkannt 
wurd, wird der Endwert gespeichert,.. anschließend berechne ich Puls und 
Pausenzeit, addiere diese und erhalte die Periodenzeit. Da im 
Datenblatte des Senors steht man solle über mehrer Perioden messen und 
dann Puls und Periodenzeit ins Verhältnis setzen, addiere ich diese. 
Habe ich genug Perioden gemessen, lasse ich mir die Temperatur berechnen 
und gebe diese auf einem LCD Display aus.

Hier der Code:
1
 #include <stdlib.h>
2
#include <stdio.h>
3
#include <avr/io.h>
4
#include <inttypes.h>
5
#include <lcd/lcd.h>
6
#define F_CPU 8000000UL
7
#include <util/delay.h>
8
#include <lcd/lcd.c>
9
#include <avr/interrupt.h>
10
11
12
13
volatile uint16_t start=0;        // Globale Variable Start, übergigt Zeitwert an Main  
14
volatile uint16_t ende=0;        // Globale Variable Start, übergigt Zeitwert an Main  
15
volatile uint16_t overflow=0;      // Globale Variable Start, übergigt Timer 1 Overflows an Main  
16
17
volatile uint8_t tc_zuweis=0b11000010;  // Hilfsvariable Zuweisung TCCR1B -> Bit7 für Noise Killer, Bit6 flankenerkennung (1=steigend)
18
volatile uint8_t flanke_erkannt = 0;  // Hilfsvariable Flanke erkannt
19
20
ISR(TIMER1_CAPT_vect)        // Capture erkannt
21
{
22
  if (TCCR1B == tc_zuweis)  // steigende Flanke?
23
    {            // ja
24
    start=ICR1;        // Startwert für Puls           oder Endwert für Pause 
25
    TCCR1B = 0b10000010;  // fallende Flanke abfragen
26
    flanke_erkannt = 1;    // Flanke erkannt
27
    }        
28
  else            // nein 
29
    {
30
    ende=ICR1;        // Endwert für Puls               oder Startwert für Pause
31
    TCCR1B = 0b11000010;  // steigende Flanke abfragen
32
    flanke_erkannt = 1;    // flanke erkannt
33
    }
34
}
35
36
37
ISR(TIMER1_OVF_vect)        // Overflow T1 
38
{
39
    overflow++;  
40
}
41
42
43
int main(void)
44
{ 
45
  DDRB= 0b01001100;      // Pin B2,B3,B6 als Ausgang 
46
  DDRD= 0b10110011;      // Pin D2,D3,D6 als Eingang
47
  PORTD=0b01001100;      // Pull Up D2,D3,D6 aktivieren
48
  lcd_init(LCD_DISP_ON);    // LCD initialisieren
49
50
  char Buffer[20];       // Zeichenkette für LCD Ausgabe deklarieren
51
52
  double temp;        // Float Hilfsvariable temp deklarieren, für Temperatur ausgabe
53
  double y;          // Float Hilfsvariable
54
  double tast_verhaeltnis;  // Float Hilfsvariable für Tastverhältnis   
55
56
57
  TIMSK =  0b00100100;    // Bit5 Input Capture und Bit2 Overflow erlauben
58
  TCCR1B = tc_zuweis;      // Teiler und Input Capture Timer  
59
  sei();
60
  uint32_t puls_summe = 0;  // Hilfsvariable für Pulssumme
61
  uint32_t perioden_summe = 0;// Hilfsvariable für Periodensumme
62
  uint32_t puls = 0;      // Hilfsvariable für Pulsberechnung
63
  uint32_t pause = 0;      // Hilfsvariable für Pausenberechnung
64
  uint32_t periode = 0;    // Hilfsvariable für Periodenberechnung
65
  uint8_t periodenanzahl = 0; // Hilfsvariable für Vollständige Periodenmessung
66
  uint8_t messungen = 0;    // Hilfsvariable für Anzahl der Messungen
67
  while(1)
68
    {
69
    
70
    if ((TCCR1B == 0b11000010) && flanke_erkannt)    // Wird steigende Flanke abgefragt und wurde eine Flanke erkannt?
71
      {                  // JA
72
      puls =(overflow*65536)+ende-start;  // Puls berechnen
73
      overflow=0;              // Timer Overflow zurücksetzen
74
      flanke_erkannt = 0;          // Flanken erkannt zurücksetuen
75
      }
76
    else                  // Nein
77
      {
78
      pause=(overflow*65536)-ende+start;  // Pause berechnen
79
      overflow=0;              // Timer Overflow zurücksetzen
80
      periodenanzahl= 1 ;          // Vollständig gemessene Periode = 1
81
      flanke_erkannt = 0;          // Flanken erkannt zurücksetuen
82
      }
83
84
    if (periodenanzahl==1)                // Wenn Vollständige Periode gemessen wurde Summierung durchführen
85
      {
86
      periode     = puls     + pause;      // Periode berechnen
87
      perioden_summe   = periode   + perioden_summe;  // Messung meherer Perioden, um fehler zu minieren
88
      puls_summe     = puls     + puls_summe;    // Messung meherer Pausen, um fehler zu minieren
89
      periodenanzahl  = 0;              // Periodenanzahl zurücksetzen
90
      messungen++;                  // Messungen erhöhen
91
      }
92
    
93
    if (messungen>=10)                        // wenn mehr als x Perioden gemessen wurden, Temperatur berechnen und ausgeben
94
      {
95
      tast_verhaeltnis = (float)puls_summe / perioden_summe;    // Tastverhältnis berechnen
96
      perioden_summe   = 0;
97
      puls_summe      = 0;
98
      messungen     = 0;            
99
      y = tast_verhaeltnis - 0.32;
100
      temp= y * 212.7659574468085;
101
      sprintf( Buffer, "Temp: %3.4f", temp );
102
      lcd_clrscr();
103
      lcd_puts(Buffer );
104
      _delay_ms(200);
105
      }
106
107
    }
108
109
110
}

von Markus (Gast)


Lesenswert?

Ach ja, Atmega 16 mit 8 Mhz im STK 500. Sensor und LCD sind auf 
Steckboard gesteckt.

Vielen Dank schonmal !

von Markus (Gast)


Lesenswert?

Also ich konnte den Fehler jetzt weiter einschränken, die Puls bzw. 
Pausenzeit ist bei mir ab und zu mal negativ. Nur wie kann das sein ?

von Peter D. (peda)


Lesenswert?

Das Zählen mit Overflow ist etwas tricky, sonst gibts Zahlensalat:

Beitrag "AVR Timer mit 32 Bit"

Ist hier aber auch garnicht nötig, da sich 4kHz komplett in 16Bit zählen 
lassen.

Hier mal mein Code:
1
u32 time_hi;
2
u32 time_period;
3
u8 period_count;
4
5
6
void smt160_init( void )
7
{
8
#if 0
9
//              Initialisation done by init PWM (mode 15)
10
//
11
  TCCR1A = 0;                           // mode 0
12
  TCCR1B = 1<<ICNC1^1<<CS10;            // count XTAL / 1
13
                                        // ICP on falling edge
14
                                        // noise canceler on
15
#endif
16
  TIMSK1 = 1<<ICIE1;                    // capture interrupt
17
  period_count = 1;
18
}
19
20
21
ISR( TIMER1_CAPT_vect )
22
{
23
  static u32 count_hi, count_period;
24
  static u16 old_time;
25
26
  u16 diff_time;
27
  u8 i;
28
29
  i = ICR1H;                            // save high byte!
30
  diff_time = ICR1 - old_time;
31
  ICR1H = i;                            // restore high byte
32
33
  TCCR1B = i = TCCR1B ^ 1<<ICES1;       // toggle direction
34
35
  if( i & 1<<ICES1 ){
36
    count_hi += diff_time;              // + high duration
37
  }else{
38
    old_time += diff_time;              // old_time = new ICR1
39
    count_period += diff_time;          // + period duration
40
41
    if( --period_count == 0 ){          // 4kHz / 256 = 64ms
42
      time_period = count_period;       // store results
43
      time_hi = count_hi;
44
      count_period = 0;                 // clear counters
45
      count_hi = 0;
46
    }
47
  }
48
}


Peter

von Thomas D (Gast)


Lesenswert?

Hallo Peter,

danke für deine Antwort. Ich hab´s jetzt schon ein bisschen anders 
gelöst, werde mir aber dein Vorschlag nochmal genau ansehen, ist 
bestimmt viel besser als meine Lösung.

Trotzdem wollte ich meine Lösung hier kurz darstellen, vielleicht kann 
die ja irgendwann mal jemand gebrauchen.
1
#include <stdlib.h>
2
#include <stdio.h>
3
#include <avr/io.h>
4
#include <inttypes.h>
5
#include <lcd/lcd.h>
6
#define F_CPU 8000000
7
#include <util/delay.h>
8
#include <lcd/lcd.c>
9
#include <avr/interrupt.h>
10
11
12
volatile uint16_t start=0;        // Globale Variable Start, übergigt Zeitwert an Main  
13
volatile uint16_t ende=0;        // Globale Variable Start, übergigt Zeitwert an Main  
14
volatile uint16_t overflow=0;      // Globale Variable Start, übergigt Timer 1 Overflows an Main  
15
volatile uint8_t flanke_erkannt = 0;  // Hilfsvariable Flanke erkannt
16
17
ISR(TIMER1_CAPT_vect)        // Capture erkannt
18
{
19
  if (TCCR1B == 0b11000001)  // steigende Flanke?
20
    {            // ja
21
    start=ICR1;        // Startwert für Puls           oder Endwert für Pause 
22
    TCCR1B = 0b10000001;  // fallende Flanke abfragen
23
    }        
24
  else            // nein 
25
    {
26
    ende=ICR1;        // Endwert für Puls               oder Startwert für Pause
27
    TCCR1B = 0b11000001;  // steigende Flanke abfragen
28
    }
29
flanke_erkannt = 1;        // Signal Flanke wurde erkannt setzen
30
}
31
32
33
ISR(TIMER1_OVF_vect)        // Overflow T1 
34
{
35
    overflow++;  
36
}
37
38
39
int main(void)
40
{ 
41
  DDRB= 0b01001100;      // Pin B2,B3,B6 als Ausgang 
42
  DDRD= 0b10110011;      // Pin D2,D3,D6 als Eingang
43
  PORTD=0b01001100;      // Pull Up D2,D3,D6 aktivieren
44
  lcd_init(LCD_DISP_ON);    // LCD initialisieren
45
46
  char Buffer[16];       // Zeichenkette für LCD Ausgabe deklarieren
47
48
  float temp=0.0;          // Float Hilfsvariable temp deklarieren, für Temperatur ausgabe
49
  float y;          // Float Hilfsvariable
50
  float tast_verhaeltnis=0.0;  // Float Hilfsvariable für Tastverhältnis   
51
52
53
54
  TIMSK =  0b00100100;    // Bit5 Input Capture und Bit2 Overflow erlauben
55
  TCCR1B = 0b11000001;    // Teiler und Input Capture Timer  
56
  sei();
57
  uint32_t puls_summe = 0;  // Hilfsvariable für Pulssumme
58
  uint32_t perioden_summe = 0;// Hilfsvariable für Periodensumme
59
  uint32_t pausen_summe = 0;  // Hilfsvariable für Pausensumme
60
  uint16_t puls = 0;      // Hilfsvariable für Pulsberechnung
61
  uint16_t pause = 0;      // Hilfsvariable für Pausenberechnung
62
  uint16_t pausenanzahl = 0;  // Hilfsvariable für Vollständige Periodenmessung
63
  uint16_t pulsanzahl = 0;   // Hilfsvariable für Vollständige Periodenmessung
64
  
65
66
67
  while(1)
68
    {
69
    if (flanke_erkannt==1)
70
      {
71
      
72
      if (TCCR1B == 0b11000001)                 // Wird steigende Flanke abgefragt und wurde eine Flanke erkannt?
73
        {
74
        if (pulsanzahl<=pausenanzahl)            // Puls und Pausenzahl angleichen
75
          {                        
76
          puls =(overflow*65536)+ende-start;        // Puls berechnen
77
          pulsanzahl++;
78
          puls_summe = puls + puls_summe;          // Messung meherer Pausen, um fehler zu minieren
79
          }
80
        }
81
      else                          
82
        {
83
          if (pausenanzahl<=pulsanzahl)          // Puls und Pausenzahl angleichen
84
          {
85
          pause=(overflow*65536)-ende+start;        // Pause berechnen
86
          pausenanzahl++ ;                // Vollständig gemessene Periode = 1
87
          pausen_summe = pause + pausen_summe;      // Messung meherer Pausen, um fehler zu minieren
88
          }
89
        }
90
91
      overflow=0;                        // Timer Overflow zurücksetzen
92
      flanke_erkannt = 0;                    // Signal Flanken erkannt zurücksetzen
93
      }        
94
    
95
96
    if ((pulsanzahl==pausenanzahl)&(pulsanzahl>=2500))      // Wenn 2500 Vollständige Periode gemessen wurde Berechnung
97
      {                            
98
      perioden_summe   = puls_summe + pausen_summe;      // Gesamtzeit berechnen
99
      tast_verhaeltnis=(float)puls_summe/perioden_summe;    // Tastverhaeltnis berechnen
100
      y = tast_verhaeltnis - 0.32;              // Achsenabschnitt subtrahieren
101
      temp= y * 212.765957;                  // Temperatur brechnen
102
      
103
      lcd_clrscr();                      // LCD löschen
104
      sprintf( Buffer, "Temp: %2.4f",temp);          // Float in String umwandeln
105
      lcd_puts(Buffer );                    // String auf LCD ausgeben
106
      
107
      pulsanzahl  = 0;                    // Pulsanzahl zurücksetzen
108
      pausenanzahl =0;                    // Pausenanzahl zurücksetzen
109
      puls_summe=0;                      // Gesamt Pulse zurücksetzen
110
      pausen_summe=0;                      // Gesamt Summe zurücksetzen
111
                        
112
      }      
113
114
    }
115
116
}

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.