Forum: Mikrocontroller und Digitale Elektronik AVR tiny2313 Interrupt


von Roman L. (bleicher)


Lesenswert?

Hallo,
ich bin ein absoluter Neuling, aber ich habe bereits so gut es ging 
gegoogelt - die Treffer die ich zum Thema AVR/Interrupts fand, brachten 
mich nicht weiter
(http://www.windmeadow.com/node/19 ist veraltet, 
http://www.avr-tutorials.com/interrupts/avr-external-interrupt-c-programming 
nicht so verständlich)

Mein Problem ist leider, dass ich das Manual zum ttiny2313 nicht 
eindeutig verstehe - ich danke im Voraus für die Geduld der Kenner.

Laut Datenblatt sind es bei tiny2313 folgende Register:

MCUCR - wenn ich richtig verstehe, stellt er NUR für INTO und INT1 den 
Triggerfall (steigend, fallend..) mit den ISCxx ein? Und für Interrupts 
an den PCINTx nicht nötig/wirkungslos?

GIMSK - Schaltet Interrupts für INTx und PCINTx ein - für alle PCIONTx 
auf einmal. MUSS aktiviert werden damit Interrupts registriert werden?

EIFR - scheint aus der Beschreibung das gleiche zu tun wie GIMSK - wo 
ist aber der unterschied? Wegen "Extern" vermute ich, dass die 
Interrupts die so gesetzt wurden, nicht durch interne Schaltung der Pins 
ausgelöst werden? ALso müssen extern(taster) ausgelöste Pins in GIMSK 
und EIFR gesetzt werden?

PCMSK - von der Beschreibung her soll er bestimmte Pins der PCINTx Reihe 
die in GIMSK alle auf einmal gesetzt werden, einzeln 
aufnehmen/ausschließen?

Wenn es stimmt - was ist mein Fehler in dem Versuch, die 
Blinkgeschwindigkeit zu ändern -
1
#include <avr/io.h>          
2
#include <util/delay.h>
3
#include <avr/interrupt.h>
4
 
5
volatile int speed=500; 
6
7
ISR(INT0_vect){
8
  //switchen wenn registriert
9
  if(PINB & (1<<PINB0)){
10
    PORTB&=~(1<<PB0);
11
    speed=100;
12
  }else{
13
    PORTB|=(1<<PB0);
14
    speed=500;
15
  }
16
  _delay_ms(500);//zeit für tasterloslassen
17
} 
18
 
19
void long_delay(uint16_t ms)
20
{
21
    for(; ms>0; ms--) _delay_ms(1);
22
}
23
 
24
int main (void) {            // (2)
25
uint8_t i;
26
  //portb1,2 auf aus, portb 3,4 auf ein, pullups
27
  DDRB=0x03;
28
  PORTB =0x0F;
29
  
30
  MCUCR=0x01;
31
  GIMSK=(1<<INT0);
32
  EIFR=(1<<INTF0);
33
  
34
  sei();
35
  
36
 int schalt=0;
37
 int speed=1000;
38
  while(1){
39
    //blinkschleife
40
    if(schalt){//ausschalten
41
      PORTB&=~(1<<PB1);
42
      schalt=0;
43
      _delay_ms(speed);
44
    }else{//einschalten
45
      PORTB|=(1<<PB1);
46
      schalt=1;
47
      _delay_ms(speed);
48
    }
49
  }
50
   return 0;                
51
}

Wäre für Tipps sehr dankbar,
Grüße

von Karl H. (kbuchegg)


Lesenswert?

Ohne jetzt den Rest deiner Registerbeschreibung kontrolliert zu haben

      _delay_ms(speed);

No, no.
Du kannst bei _delay_ms keine Variable angeben.
D.h. technisch kannst du es schon. Nur stimmen die Zeiten nicht.


Zum Rest:
geh nicht davon aus, dass ein bestimmtes Register für bestimmte 
Funktionalität zuständig ist. Das stimmt schon lange nicht mehr. Zäume 
das Pferd von hinten auf: für eine bestimmte Funktionalität benötige ich 
wlche Bits? Und nachdem feststeht, welche Bits wie sein müssen: in 
welchem Register ist dieses Bit?

von amateur (Gast)


Lesenswert?

Todsünde: Delay in ISR

von troll (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Du kannst bei _delay_ms keine Variable angeben.
Dabei enthält sein Quellcode schon die Lösung: long_delay()

von troll (Gast)


Lesenswert?

amateur schrieb:
> Todsünde: Delay in ISR
Naja, zum Testen...

von Karl H. (kbuchegg)


Lesenswert?

> EIFR - scheint aus der Beschreibung das gleiche zu tun wie GIMSK

Das EIFR benutzt der Tiny intern um dort drinnen festzuhalten, dass ein 
Interruptwürdiges 'Ereignis' eingetreten ist.
Irgendwo muss dieses ja vermerkt werden, denn falls zum Zeitpunkt des 
Auftreten zb der Flanke am INT1 die Interrupts gerade gesperrt sind (mit 
cli()), dann muss dieser Interrupt ja nach erneuter Freigabe der 
Interrupts (mit sei()) ja nachgeholt werden.

von Roman L. (bleicher)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Das EIFR benutzt der Tiny intern um dort drinnen festzuhalten, dass ein
> Interruptwürdiges 'Ereignis' eingetreten ist.

heißt es, das ist internes "Ist-Zustand" Register und ich sollte den 
nicht beschreiben, sondern auslesen, wenn ich den Interrupt händisch 
lesen sollte?
Und beim schreiben in den wird entsprechendes Interrupt ausgelöst?

von amateur (Gast)


Lesenswert?

Wie aktivierst Du INT0?

Mit einer Taste?

Beim Drücken lässt Du einen Ider los laufen beim Loslassen den zweiten. 
Warum nicht gleich: MCUCR=0x02 oder MCUCR=0x03 - keine Ahnung wie deine 
Hardware bzw. Deine Logikpegel aussehen.

von Roman L. (bleicher)


Lesenswert?

amateur schrieb:
> eim Drücken lässt Du einen Ider los laufen beim Loslassen den zweiten.

was sind denn Ider? meinst du die falling/rising edge events? Mein 
Problem mit dem oberen Code ist, dass er nicht funktioniert. Ich 
schließe mit dem Taster den INT0-Pin mit dem GND - das LED am PIN1 
blinkt aber mit dem gleichen Takt,
Beim kurzschließen des Tasters erlischt die LED0 nur kurz - der 
Intervall (speed) der LED am PIN1 ändert sich nicht.

Kann es sein dass ich am INT0 noch den pull-up aktivieren muss bzw 
input? Oder ist das aktivieren des INT0 interrupt schon genug?


Ich hätte vllt erwähnen sollen - den guloprog hab ich am Freitag 
gekriegt, am Samstag den ladyada-Tutorial zu AVR angeschaut und Blinker 
auf den chip geladen, also alles ineinem habe ich ca. 5-7 Stunden mit 
dem Thema verbracht. C ist mir nicht neu, aber das hardwarenahe 
Programmieren hat so einiges an sich :)

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.