mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik INT0 INT1 sperren und freigeben


Autor: Leandro Leandro (tetef)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

ich möchte mit INT0 und INT1 die Impulse messen. Dafür habe ich diese 
Interrumps so programmiert, dass ich auf die High Flanke auf INT0 wird 
der Timer gestartet und bei Low Flanke auf INT1 wird der Timer gestopt.
void extern_interrumps_init()
{
        //Interrumpt aufloesen beim High- und Low-Flanke
  MCUCR |= (1<<ISC00) | (1<<ISC01) | (1<<ISC11);
  GICR |= (1<<INT0);  //High-Flanke
  GICR |= (1<< INT1);     //Low-Flanke
}


//Interrumps
SIGNAL (SIG_INTERRUPT0)
{
  TCNT1=0;  //timer auf Null setzen
  TCCR1B |= (0<<CS12) | (0<<CS11) | (1<<CS10);
}
SIGNAL (SIG_INTERRUPT1)
{
  //INT1 timer stop
  TCCR1B = (0<<CS12) | (0<<CS11) | (0<<CS10)
  value= TCNT1;   // Wert lesen.

}
Nun möchte jetzt zuerst ein paar Rechnungen durchführen ohne 
Unterbrechungen von INT0 und INT1, sonst bekomme ich Werte die nicht 
zusammenpassen.

Meine Überlegung, dass ich Beide Interrumps sperre bis meine Rechnungen 
fertig sind.

Leider weiss ich nicht, wie und wo ich diese Interrumps sperren bzw. 
freigen kann.

Dankeim Voraus für jede Hilfe.

P.S. ich verwende Atmega16

Autor: Timmo H. (masterfx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es heisst Interrupt und nicht Interrumpt.
Und zum Deaktivieren: GIMSK

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
PS: Es heißt Interrupt. nicht Interrumpt
lat: Interruptus .. die Unterbrechung

Du hast Glück
  TCCR1B = (0<<CS12) | (0<<CS11) | (0<<CS10)

Das ist eigentlich nicht so ganz richtig. In Kurzform ist das 
gleichbedeutend mit

  TCCR1B |= 0;

Und das ist wahrscheinlich nicht die Operation, die du haben willst. 
Einzelne Bits kann man nicht mit deiner Methode auf 0 setzen

  TCCR1B &= ~( (1<<CS12) | (1<<CS11) | (1<<CS10) );

... so geht das

> Leider weiss ich nicht, wie und wo ich diese Interrumps
> sperren bzw. freigen kann.

Wenn du keine anderen Interrupts mehr im System hast, die weiter laufen 
müssen, kannst du einfach mittels cli() alle Interrupts sperren und 
mittels sei() alle Interrupts auf einmal wieder freigeben.
Ansonsten bleibt dir natürlich immer noch der Weg, die beiden Interrupts 
um die es hier geht, im GICR wieder durch setzen ihres Bites auf 0 zu 
sperren.

Autor: TicTac (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tetef El schrieb:
> Interrumps

Obergeil!  :-D

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und noch ein PS.
Periodenlängen misst man am Besten mit der Input Capture Einheit vom 
Timer 1. Genau dafür ist die nämlich gebaut worden.

Autor: tetef (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hallo Karl Heinz,

danke für die kurze Erklärung.
wenn Ich Dich richtig verstanden habe und Du darfst mich natürlich 
korrigieren, es ist am besten die Impulsedauer der Input Capture Einheit 
zu messen. Nun mit welcher Taktfrequenz wird es alles gemessen? Kann ich 
die Voll CPU-Frequenz nutzen?

Danke

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
tetef schrieb:
> hallo Karl Heinz,
>
> danke für die kurze Erklärung.
> wenn Ich Dich richtig verstanden habe und Du darfst mich natürlich
> korrigieren, es ist am besten die Impulsedauer der Input Capture Einheit
> zu messen. Nun mit welcher Taktfrequenz wird es alles gemessen? Kann ich
> die Voll CPU-Frequenz nutzen?

Kannst du.
Du musst nur auf mehr als einem Timerüberläuf acht geben.

Autor: Leandro Leandro (tetef)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich werde es testen und Dir ein Feedback geben.

Autor: Leandro Leandro (tetef)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hi Karl Heinz,

Ich stosse mich mit einem kleinem Problem und zwar, ich versuche, wie Du 
erwähnt hast, dass ich mit dem Input Capture arbeite um die Impulse zu 
messen.
Nun ich soll nur die Zeitdauer der high-Flanken messen.
Ich habe:
1. Mein Signal an den Port ICP Port (PD6 Atmega16) angeschlossen.
2. Den Timer1 habe ich initialisiert.
3. Die Interrupts wurden initialisiert.

Leider bekomme ich nicht die exakte Messungen, warum? bin ich ehrlich 
ratlos?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
//Interrupts
ISR(SIG_INPUT_CAPTURE1)
{
  //timer capture
  phase0 = TCNT1;
}


Der Sinn eines INput Capture besteht nicht darin, dass man sich dann von 
TCNT1 den aktuellen Zählerstand holt. Bei einem Input Capture kopiert 
die Hardware den aktuellen Zählerstand beim Auftreten des Ereignisses 
in ein spezielles Register

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
while(1) // Unendlich lang wiederholen
    {
    //wait until PD6 low
    while(!(PIND & (1<<PD6)));
    //timer value initialize, measurement will be started
    TCNT1 = 0;
    //wit until PD6 high
    while(PIND & (1<<PD6));


Genau das brauchst du dann nämlich nicht tun!
Du wartest auf nichts mehr.

In der ISR nimmst du die Differenz zum Zählerstand, der im 
vorhergehenden ISR Aufruf gesichert wurde. Da deine ISR bei jeder 
Low-High Flanke aufgerufen wird, ist diese Differenz exakt die Anzahl 
der Timerticks von einer steigenden Flanke zur nächsten.
volatile uint8_t haveValue;
uint16_t prevCount;
uint16_t ticks;

//Interrupts
ISR(SIG_INPUT_CAPTURE1)
{
  uint16_t nowCount = ICR1;

  ticks = nowCount - prevCount;
  haveValue = TRUE;

  prevCount = nowCount;
}

in ticks steht das Messergebnis. Liegt ein weiterzuverarbeitendes 
Ergebnis vor, so wird haveValue auf TRUE gesetzt, damit man in main auch 
weiß, dass wieder etwas vorliegt, was verarbeitet werden möchte.

(Und benutze bitte die für ISR vorgesehenen Namen der Interrupt 
Routinen)

Autor: Leandro Leandro (tetef)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe nicht verstanden.

Ein Iterrupt wird gerufen, wenn ein high-low Flanke vorkommt.
Aber ich möchte, die Zeit zwischen low-high und high-low Flanke messen.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tetef El schrieb:
> Ich habe nicht verstanden.
>
> Ein Iterrupt wird gerufen, wenn ein high-low Flanke vorkommt.
> Aber ich möchte, die Zeit zwischen low-high und high-low Flanke messen.

Du kannst auch innerhalb einer ISR die Art der Flankenerkennung 
umschalten :-)
Ich habs jetzt nicht im Kopf, aber ich denke man kann die Erkennung auch 
so konfigurieren, dass sie bei jeder Flanke auslöst. Ein Blick auf den 
Input-Pin sagt dir dann ob es eine High-Low oder eine Low-High Flanke 
war.

Autor: Leandro Leandro (tetef)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es ist nicht das, was ich in main geschrieben habe. solange ich die low 
Flanke habe warte ich. Danach kommt natürlich eine high Flanke, wird 
kutz davor der Timer auf 0 gestezt. Bei der nächsten high-low Flanke 
wird die Interrupt ausgelöst. Ich habe die Übertragung in ISR 
geschrieben. Aber troztdem bekomme ich nicht die richtigen Daten.


//Interrupts
ISR(SIG_INPUT_CAPTURE1)
{
  //timer capture
  phase0 = ICR1;
  uart_puti(phase0);
  uart_putc('\n');
  uart_putc(13);
}

int main(void)
{
    DDRD &= ~(1<<PD6);
  uart_init(1, 1);
  input_capture_init() ;
  sei();
    while(1) // Unendlich lang wiederholen
    {
    //wait until PD6 low
    while(!(PIND & (1<<PD6)));
    //timer value initialize, measurement will be started
    TCNT1 = 0;
    //wit until PD6 high
    while(PIND & (1<<PD6));

    }
}

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tetef El schrieb:
> Es ist nicht das, was ich in main geschrieben habe. solange ich die low
> Flanke habe warte ich.

Nochmal.
Wozu?

Die ISR (meine Version) teilt dir mit, wann ein Ergebnis vorliegt

volatile uint8_t haveValue;
uint16_t prevCount;
uint16_t ticks;

//Interrupts
ISR(SIG_INPUT_CAPTURE1)
{
  uint16_t nowCount = ICR1;

  ticks = nowCount - prevCount;
  haveValue = TRUE;

  prevCount = nowCount;
}

....

int main()
{
  ...

  while( 1 ) {

    ...

    if( haveValue ) {     // es gibt ein Ergebnis
                          // das Ergebnis steht in ticks
      haveValue = FALSE;
      mach was mit ticks
    }
  }

Lass doch die Hardware für dich arbeiten!

Autor: Leandro Leandro (tetef)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hi Karl Heiz,

Ich gebe dir recht, wenn Du schreibst, ich soll die Hardware für mich 
arbeiten.
Nun mit Deiner Methode werde ich die Frequenz messen, aber ich möchte 
das Tastverhältnis messen. Wie lange ist mein High Flanke?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tetef El schrieb:
> hi Karl Heiz,
>
> Ich gebe dir recht, wenn Du schreibst, ich soll die Hardware für mich
> arbeiten.
> Nun mit Deiner Methode werde ich die Frequenz messen, aber ich möchte
> das Tastverhältnis messen. Wie lange ist mein High Flanke?

Dann musst du in der ISR die High-Flanke von der Low-Flanke trennen.

(Hab jetzt doch im Datenblatt vom Mega16 nachgesehen. Den Input Capture 
kann man nur auf entweder Fallend oder Steigend einstellen, Beides 
zusammen geht nicht. Aber man kann natürlich in der ISR die jeweilige 
Richtung umschalten :-)

//Interrupts
ISR(SIG_INPUT_CAPTURE1)
{
  uint16_t nowCount = ICR1;

  if( TCCR1B & ( 1 << ICES1 ) ) {
    lowDuty = nowCount - prevCount;  // wir sind auf einer steigenden Flanke ->
                                     // d.h. der low Duty wurde gemessen
    TCCR1B &= ~( 1 << ICES1 );   // die nächste Flanke soll eine fallende sein
  }
  else {
    highDuty = nowCount - prevCount;
    TCCR1B |= ( 1 << ICES1 );   // die nächste Flanke soll eine steigende sein
  }

  haveValue = TRUE;
  prevCount = nowCount;
}

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bezüglich des Umschaltens der Flanke gibt es in jedem Datenblatt 
(zumindest jedem, in das ich bisher gesehen habe) einen Satz, der gerne 
übersehen wird:
After a change of the edge, the Input Capture Flag (ICF1) must be
cleared by software (writing a logical one to the I/O bit location).
(nur so als Hinweis)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan Ernst schrieb:
> Bezüglich des Umschaltens der Flanke gibt es in jedem Datenblatt
> (zumindest jedem, in das ich bisher gesehen habe) einen Satz, der gerne
> übersehen wird:
>
After a change of the edge, the Input Capture Flag (ICF1) must be
> cleared by software (writing a logical one to the I/O bit
> location).
> (nur so als Hinweis)

Danke!
Hätt ich glatt übersehen :-)

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Danke!
> Hätt ich glatt übersehen :-)

Mir ist sowieso schleierhaft, warum diese Info nicht auch dort steht, wo 
sie meiner Meinung nach hingehören würde, nämlich bei der 
Detailbeschreibung von ICES. Vielleicht ist dieser Satz mitten in der 
Input-Capture-Unit-Beschreibung ja auch nur ein Überbleibsel aus "alten 
Tagen" und nicht mehr gültig. Ich habe auch schon Code gesehen, der das 
nicht berücksichtigt hat, und laut Autor einwandfrei funktionieren soll. 
Wäre ja nicht das erste Copy&Paste-Problem bei AVR-Datenblättern. ;-)

Autor: Leandro Leandro (tetef)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wo sollte man die ICF1 löschen??

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tetef El schrieb:
> Wo sollte man die ICF1 löschen??

Nach der Modusumschaltung. Steht doch dort.
Die Modusumschaltung ist in der ISR, also wird man dort das Flag 
löschen.

Autor: Leandro Leandro (tetef)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
hallo Karl Heiny,

ich habe jetzt das Programm geschrieben dank Deiner Hilfe.
Wenn ich einen Sensor (eine Spule) über ein Metall ziehe, dass ein Riss 
hat, dann entsteht ein Wirbelstrom. Die Darstellung der Wirbelstrom 
erfolgs durch
die bechnung vom Real und Imag. Teil.Diese komplexen Werte werden 
übertragen und dargestellt.
Die Problematik, die ich jetzt habe, ist, dass wenn ich mit dem Sensor 
langsam über ein Metall ziehe, dann bekomme ich ein schöne Darstellung 
(bild2), aber wenn ich schnell ziehe, bekomme ich ein schrecklische 
Darstellung (bild2).

Ich frage mich, was mache ich falsch oder liegt das an meinem µC, weil 
er langsam ist. ich Amplitude umwandeln und jedes Mal die Zeit messen 
und berechnen.
P.S µC Atmega16 mit 16Mhz. Generatorfrequenz 20kHz.

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.