www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik ICP Caputre Unit mit wechselnder Flanke


Autor: Martin Neumann (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

ich bin dabei, mit einer Capture Unit ein Frequenz zu messen. die 
Frequenz ist recht gering und spielt zwischen 0 und ca. 250Hz.
Verwendet wird dabei ein Atmega 8. Ein Optokoppler schaltet dabei bei 
jedem Signal Masse an den ICP Pin durch. Sonst liegt der ICP Pin durch 
den internen pullup auf "high". Eine LED hängt an PB1 auf active low 
(zur Frequenzdarstellung).
Das Hauptprogramm soll später einmal die Frequenz dann aus den Timer 
werten berechnen, aber das Einlesen klappt im Moment noch nicht ganz.
Gedacht ist, zunächst bei fallender Flanke einzulesen, Wert sichern eine 
LED einschalten, die Flanke wechseln, darin dann die LED ausschalten, 
nächste fallende einlesen, Endwert sichern, LED wieder anschalten, 
wieder auf steigende Flanke wechseln und darin die LED ausschalten.
Durch den Start und Endwert kann ich dann später meine Frequenz 
errechnen.

Nur das Problem ist, die LED müsste mit steigender Frequenz immer 
kräftiger erscheinen, bis sie für das Auge ab ca. 30-40 Hz in 
"Dauerleuchten" übergeht. Leider "hängt" die LED manchmal zwischendrin, 
als ob sie nicht ausgeschaltet wird.
Die Singale sind vom OK logischerweise prellfrei, daher vermute ich das 
Problem im Code:


/****************************************************************************/
/*                                      */
/*            Input Capture Funktion Atmega8            */
/*                                      */
/****************************************************************************/

// ----------------------------------------------------------------------------
// INCLUDES
// ----------------------------------------------------------------------------

#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <inttypes.h>

// ----------------------------------------------------------------------------
// DEFINES
// ----------------------------------------------------------------------------
#ifndef F_CPU
#define F_CPU           8000000UL                   // processor clock frequency 8Mhz
#endif


#define Input    PB0    //Pin des Input Captures PB0=ICP
#define LED      PB1    //Pin der LED die leuchtet im Takt der Frequenz


#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif


// ----------------------------------------------------------------------------
// Funktionsdeklarationen
// ----------------------------------------------------------------------------
void init(void);

// ----------------------------------------------------------------------------
// globale Variablen die durch Interrupts verändert werden
// ----------------------------------------------------------------------------
volatile unsigned char NrOverflowsTC1 = 0;    //gibt die Anzahl der Overflows des 16-bit Timers an
                        //pro Sekunde läuft der 16-bit Timer knapp 2mal über-->NROverflow läuft nach ca. 134s über
volatile unsigned int StartTime = 0;      //TCNT1-Wert bei der 1.Low-Flanke speichern
volatile unsigned int EndTime = 0;        //TCNT1-Wert bei der 2.Low-Flanke speichern
volatile unsigned char Messung_vollstaendig = 0;//JobFlag, das Timer Interrupt 2x vollständig richtig durchlaufen wurde, hat die Variable den Wert 2, erst dann wird im Hauptprogramm die Drehzahl berechnet werden
volatile unsigned char ErsteFlanke = TRUE;    //Zu Beginn soll die erste Flanke eingelesen werden, FALSE wäre die 2. Flanke

// ----------------------------------------------------------------------------
// globale Variablen des Programms
// ----------------------------------------------------------------------------




//Timer1 (16-Bit) Capture Interrupt Service Routine

ISR( TIMER1_CAPT_vect ){
    if ( !(TCCR1B & (1<<ICES1) )){        //Interrupt Caputre reagiert fallende Flanke
      if ( ErsteFlanke ){            //Ist es die erste Flanke oder Wurde schon eine Flanke eingelesen? 
        StartTime = ICR1;          //Start Wert sichern
        TCCR1B |= ( 1 << ICES1 );      //Schreibt bit für steigende Flanke
        TIFR |= ( 1 << ICF1 );        /*Nachdem ein Flankenwechsel gesetzt wird, muss das Interrupt Flag von der Software gelöscht werden
                            dies geschieht durch Schreiben einer logischen 1 in das ICF1 Register*/
        PORTB &= ~( 1 << LED );      //LED an PB1 einschalten  
        NrOverflowsTC1 = 0;          //Setzt die Overflows des Timer1 (16-bit) zurück
        ErsteFlanke = FALSE;             //Die naechste Flanke ist das Ende der Messung
      }
    
      else{                  //es wurde bereits eine 1. Flanke eingelesen, dies ist ist folgich die 2. Flanke
        EndTime = ICR1;            //End Wert sicehrn
        TCCR1B |= ( 1 << ICES1 );      //Schreibt bit für steigende Flanke
        TIFR |= ( 1 << ICF1 );        /*Nachdem ein Flankenwechsel gesetzt wird, muss das Interrupt Flag von der Software gelöscht werden
                            dies geschieht durch Schreiben einer logischen 1 in das ICF1 Register*/
        PORTB &= ~( 1 << LED );      //LED an PB1 einschalten  
      }
    }
    else{                    //sonst Interrupt bei fallender Flanke
      TCCR1B &= ~( 1 << ICES1 );        //Löscht bit für steigende Flanke --> Capture Interrupt reagiert nun wieder auf fallende Flanke
      TIFR |= ( 1 << ICF1 );          /*Nachdem ein Flankenwechsel gesetzt wird, muss das Interrupt Flag von der Software gelöscht werden
                            dies geschieht durch Schreiben einer logischen 1 in das ICF1 Register*/
      PORTB |= ( 1 << LED);          //schaltet die LED an PB1 wieder aus
      Messung_vollstaendig++;          //Wenn diese Anweisung 2x durchlaufen wird, hat die Variable Messung_vollstaendig den Wert 2 und es kann eine neue Messung begonnen werden
      if (Messung_vollstaendig == 2){      //Liegt eine vollständige Messung vor? Wenn 2 Durchgänge durchlaufen sind, ja
        ErsteFlanke = TRUE;               
        Messung_vollstaendig = 0;
      }
    }  
}


//Timer1 (16-Bit) Overflow Interrupt Service Routine

ISR (TIMER1_OVF_vect){
NrOverflowsTC1++;

}

//Hauptprogramm
int main()
{

  init();                              //Initialisieren der Ports über die Funktion init()
  
  while(1){
  // hier soll dann die Frequenz ausgewertet werden
  }
  
}


// ----------------------------------------------------------------------------
// Funktionen
// ----------------------------------------------------------------------------

/*Funktion zum Initialisierein des µC*/

void init(void) {
  
  DDRB = 0x00;                    //Datenrichtungsregister zunächst alle Eingang 
  DDRB |= (1 << DDB1);         //PB1 als Ausgang schalten für LED, PB2 ebenfalls
  PORTB |= (1 << Input) | (1 << LED);  //interner Pullup am Input Capture Eingang, LED am Anfang ausschalten
  
  // ========================================================================
  // 16-bit Timer1 initialisieren (dient zum zählen der Flankendauer)
  // ========================================================================
    
  //Timer für die Input Capture Funktion, zählt dies Zeiten zwischen zwei steigenden Flanken, Prescaler
  TCCR1B = (1 << CS00) | (1 << CS01);          // Prescaler 64
  TCCR1B &= ~(1<<ICES1);                  // Interrupt Capture wird zunächst auf fallende Flanke eingestellt
  TIMSK = (1<<TICIE1) | (1<<TOIE1);             // Aktiviert Input Capture Interrupt und Timer1 Overflow Interrupt
  
  //=========================================================================
  // Sonstiges
  //=========================================================================
  sei();                  //setzt globales Interrupt enable
  
  return;
}

Jemand eine Idee, wo ein Fehler sich eingeschlichen hat?

: Verschoben durch Admin

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.