Forum: Mikrocontroller und Digitale Elektronik INT0 INT1 sperren und freigeben


von Leandro L. (tetef)


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

von Timmo H. (masterfx)


Lesenswert?

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

von Karl H. (kbuchegg)


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.

von TicTac (Gast)


Lesenswert?

Tetef El schrieb:
> Interrumps

Obergeil!  :-D

von Karl H. (kbuchegg)


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.

von tetef (Gast)


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

von Karl H. (kbuchegg)


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.

von Leandro L. (tetef)


Lesenswert?

ich werde es testen und Dir ein Feedback geben.

von Leandro L. (tetef)


Angehängte Dateien:

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?

von Karl H. (kbuchegg)


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

von Karl H. (kbuchegg)


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.
1
volatile uint8_t haveValue;
2
uint16_t prevCount;
3
uint16_t ticks;
4
5
//Interrupts
6
ISR(SIG_INPUT_CAPTURE1)
7
{
8
  uint16_t nowCount = ICR1;
9
10
  ticks = nowCount - prevCount;
11
  haveValue = TRUE;
12
13
  prevCount = nowCount;
14
}

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)

von Leandro L. (tetef)


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.

von Karl H. (kbuchegg)


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.

von Leandro L. (tetef)


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));

    }
}

von Karl H. (kbuchegg)


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
1
volatile uint8_t haveValue;
2
uint16_t prevCount;
3
uint16_t ticks;
4
5
//Interrupts
6
ISR(SIG_INPUT_CAPTURE1)
7
{
8
  uint16_t nowCount = ICR1;
9
10
  ticks = nowCount - prevCount;
11
  haveValue = TRUE;
12
13
  prevCount = nowCount;
14
}
15
16
....
17
18
int main()
19
{
20
  ...
21
22
  while( 1 ) {
23
24
    ...
25
26
    if( haveValue ) {     // es gibt ein Ergebnis
27
                          // das Ergebnis steht in ticks
28
      haveValue = FALSE;
29
      mach was mit ticks
30
    }
31
  }

Lass doch die Hardware für dich arbeiten!

von Leandro L. (tetef)


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?

von Karl H. (kbuchegg)


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 :-)
1
//Interrupts
2
ISR(SIG_INPUT_CAPTURE1)
3
{
4
  uint16_t nowCount = ICR1;
5
6
  if( TCCR1B & ( 1 << ICES1 ) ) {
7
    lowDuty = nowCount - prevCount;  // wir sind auf einer steigenden Flanke ->
8
                                     // d.h. der low Duty wurde gemessen
9
    TCCR1B &= ~( 1 << ICES1 );   // die nächste Flanke soll eine fallende sein
10
  }
11
  else {
12
    highDuty = nowCount - prevCount;
13
    TCCR1B |= ( 1 << ICES1 );   // die nächste Flanke soll eine steigende sein
14
  }
15
16
  haveValue = TRUE;
17
  prevCount = nowCount;
18
}

von Stefan E. (sternst)


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:
1
After a change of the edge, the Input Capture Flag (ICF1) must be
2
cleared by software (writing a logical one to the I/O bit location).
(nur so als Hinweis)

von Karl H. (kbuchegg)


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:
>
1
After a change of the edge, the Input Capture Flag (ICF1) must be
2
> cleared by software (writing a logical one to the I/O bit
3
> location).
> (nur so als Hinweis)

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

von Stefan E. (sternst)


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. ;-)

von Leandro L. (tetef)


Lesenswert?

Wo sollte man die ICF1 löschen??

von Karl H. (kbuchegg)


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.

von Leandro L. (tetef)


Angehängte Dateien:

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.

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.