Forum: Mikrocontroller und Digitale Elektronik ATMega 168PB Interrupt Programmieren


von C. M. (chrisso1986)


Lesenswert?

Hallo @all,

ich versuche bisher ohn Erfold einen Interrupt zu beim ATMega168 zu 
programmieren. Ich möchte nur Testen und verstehen wie das mit dem 
Interrupt funktioniert und habe entsprechend nur ein einfaches Programm 
geschrieben, welches mir eine LED zum leuchten bringen soll. Anbei mal 
der Programmcode:


-----------------------------------------------------------------------
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <stdlib.h>
4
#include <util/delay.h>
5
6
ISR(INT0_vect)
7
{  
8
  PINB|=1<<PINB5;
9
  _delay_ms(2000);
10
  PINB&=~1<<PINB5;
11
}
12
13
int main(void)
14
{
15
  DDRC|=1<<DDRC0;
16
  DDRB|=1<<DDRB5;
17
  DDRD&=~1<<DDRD2;
18
  
19
  EICRA |= (1 << ISC00);    // set INT0 to trigger on ANY logic change
20
  EIMSK |= (1 << INT0);     // Turns on INT0
21
22
  sei();                    // turn on interrupts*/
23
    
24
while(1)
25
    {
26
      PINC|=1<<PINC0; //PINC0 ist über ein Kabel mit  dem PORTD2 verbunden.
27
                        _delay_ms(500);
28
                        PINC&=~1<<PINC0;
29
                        -delay_ms(10000);
30
      
31
    }
32
}
---------------------------------------------------------------------

Ich würde mich freuen wenn mir jemand helfen kann denn ich weiß leider 
nicht mehr weiter.

MfG

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

Christian H. schrieb:

>-delay_ms(10000);
 ^Was genau soll das denn bewirken...

Oder anders ausgedrückt: Der Code, denn du gepostet hast, ist nicht der 
Code, der bei dir nicht funktioniert. Also mach's dir gefälligst selbst!

von Daniel S. (daniel_s49)


Lesenswert?

Christian H. schrieb:
> verstehen wie das mit dem
> Interrupt funktioniert

und dann sehe ich ein 2sekunden sleep in der ISR? Das Verständnis ist 
definitiv ausbaufähig.

- wieso ist C0 ein Ausgang?
- Pins schaltet man nicht so. Entweder PIN=(1<<x) oder PORT|=(1<<x)

von Stefan F. (Gast)


Lesenswert?

Beschreibe erstmal dein Problem und poste den Code EXAKT so, wie du ihn 
compiliert hast. Der oben zittierte ist ganz offensichtlich frisiert, 
denn er ist nicht compilierbar.

> PINC|=1<<PINC0

Du beschreibst hier ein Register, das für Lesezugriffe gedacht ist.

von C. M. (chrisso1986)


Lesenswert?

Anbei der Code so wie ich diesen auch compiliert habe.

----------------------------------------------------------------
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include <util/delay.h>

ISR(INT0_vect)
{
  PINB|=1<<PINB5;
  _delay_ms(2000);
  PINB&=~1<<PINB5;
}

int main(void)
{
  DDRC|=1<<DDRC0;
  DDRB|=1<<DDRB5;
  DDRD&=~1<<DDRD2;

  EICRA |= (1 << ISC00);    // set INT0 to trigger on ANY logic change
  EIMSK |= (1 << INT0);     // Turns on INT0

  sei();                    // turn on interrupts*/

  while(1)
  {
  PINC|=1<<PINC0; //PINC0 ist über ein Kabel mit  dem PORTD2 verbunden
  _delay_ms(500);
  PINC&=~1<<PINC0;
  _delay_ms(10000);

  }
  }
------------------------------------------------------------------

: Bearbeitet durch User
von C. M. (chrisso1986)


Lesenswert?

c-hater schrieb:
> Christian H. schrieb:
>
>>-delay_ms(10000);
>  ^Was genau soll das denn bewirken...
>
> Oder anders ausgedrückt: Der Code, denn du gepostet hast, ist nicht der
> Code, der bei dir nicht funktioniert. Also mach's dir gefälligst selbst!

_delay_ms(10000) einfach nur eine Pause von ca. 10sek, mehr nicht

von Rudolph R. (rudolph)


Lesenswert?

Stefan U. schrieb:
>> PINC|=1<<PINC0
>
> Du beschreibst hier ein Register, das für Lesezugriffe gedacht ist.

Was durchaus auch funktioniert, aber wahrscheinlich nicht so wie das 
hier gedacht ist.

Mit PINC = (1<<PINC0) wechselt man den Zustand des zum Ausgang 
geschalteten Pin 0 vom Port C.

von C. M. (chrisso1986)


Lesenswert?

Daniel S. schrieb:
> Christian H. schrieb:
>> verstehen wie das mit dem
>> Interrupt funktioniert
>
> und dann sehe ich ein 2sekunden sleep in der ISR? Das Verständnis ist
> definitiv ausbaufähig.
>
> - wieso ist C0 ein Ausgang?
> - Pins schaltet man nicht so. Entweder PIN=(1<<x) oder PORT|=(1<<x)

PORTs sind für mich die Eingänge PORT|=1<<x Bit=1; PORT&=~1<<x Bit=0
PINs die Ausgänge

PINC0 setze ich einfach auf High um den Interrupt an PORTB2 auszulösen.
PINC0 ist mit PORTD2 über ein Kabel verbunden.

Ich möchte das einfach nur mal so testen.

falls das falsch lasse ich mich gern eines besseren belehren......

von S. Landolt (Gast)


Lesenswert?

PIN sind Eingänge, PORT Ausgänge.
Also erstmal PIN durch PORT ersetzen, dann sehen wir weiter.

von C. M. (chrisso1986)


Lesenswert?

Rudolph R. schrieb:
> Stefan U. schrieb:
>>> PINC|=1<<PINC0
>>
>> Du beschreibst hier ein Register, das für Lesezugriffe gedacht ist.
>
> Was durchaus auch funktioniert, aber wahrscheinlich nicht so wie das
> hier gedacht ist.
>
> Mit PINC = (1<<PINC0) wechselt man den Zustand des zum Ausgang
> geschalteten Pin 0 vom Port C.

Ich definiere doch mit DDRC|=1<<DDRC0; als Ausgang
und mit PINC|=1<<PINC0 setze ich den Ausgang dann auf High oder nicht?

von Rudolph R. (rudolph)


Lesenswert?

Datenblatt und so, PINx sind die Ausgangs-Register, PORTx die 
Eingangs-Register.

Bei Eingängen schaltet man die mit PORTx die Pullup-Widerstände ein.
Bei Ausgängen wechselst man mit PINx den Zustand.

Wobei ein Read-Modify-Write bei PINx keinen Sinn macht.

Und DDRx ist das dritte-Register und für die Datenrichtung, das passt.

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

Christian H. schrieb:

> Ich definiere doch mit DDRC|=1<<DDRC0; als Ausgang

Ja.

> und mit PINC|=1<<PINC0 setze ich den Ausgang dann auf High oder nicht?

Nein. Enweder machst du damit genau garnix (bei älteren AVR8) oder du 
toggelst den aktuellen Zustand des Pins.

von Dieter F. (Gast)


Lesenswert?

c-hater schrieb:
> du
> toggelst den aktuellen Zustand des Pins.

Kann man mit oder "toggeln" ? Wäre mir neu ... :-)

von Peter II (Gast)


Lesenswert?

Dieter F. schrieb:
> Kann man mit oder "toggeln" ? Wäre mir neu ...

ja kann man, wenn es die Hardware so vorgibt.

von Guck an (Gast)


Lesenswert?

S. Landolt schrieb:
> PIN sind Eingänge, PORT Ausgänge.

Rudolph R. schrieb:
> Datenblatt und so, PINx sind die Ausgangs-Register, PORTx die
> Eingangs-Register.

Würfelbecher gefällig?

von S. Landolt (Gast)


Lesenswert?

Was Würfelbecher! - Duell auf Degen oder Pistolen.

von Guck an (Gast)


Lesenswert?

S. Landolt schrieb:
> Was Würfelbecher! - Duell auf Degen oder Pistolen.

Nur Kurzwaffen -Needles and Pins.

von c-hater (Gast)


Lesenswert?

Dieter F. schrieb:
> c-hater schrieb:
>> du
>> toggelst den aktuellen Zustand des Pins.
>
> Kann man mit oder "toggeln" ? Wäre mir neu ...

Wenn es sich um ein Strobe-Bit handelt (und genau das ist beim 
PINx-Register aller neueren AVR8 der Fall): natürlich.

Du solltest nach zehn Jahren (oder so) endlich mal wieder ein Datenblatt 
lesen...

Natürlich ist das "oder" dabei eigentlich völlig überflüssig, aber es 
schadet, abgesehen von der sinnlosen Verschwendung eines Takts, auch 
nicht weiter. Die Scheiße toggelt.

von Guck an (Gast)


Lesenswert?

c-hater schrieb:
> Die Scheiße toggelt

Das spritzt doch! Sauerei.

von Rudolph R. (rudolph)


Lesenswert?

Rudolph R. schrieb:
> Datenblatt und so, PINx sind die Ausgangs-Register, PORTx die
> Eingangs-Register.

Ja, sorry, autsch und so, anders herum natürlch.

von c-hater (Gast)


Lesenswert?

Rudolph R. schrieb:
> Rudolph R. schrieb:
>> Datenblatt und so, PINx sind die Ausgangs-Register, PORTx die
>> Eingangs-Register.
>
> Ja, sorry, autsch und so, anders herum natürlch.

Nein. PINx ist inzwischen mehr als nur Eingangs-Register.

von S. Landolt (Gast)


Lesenswert?

> Nein. PINx ist inzwischen mehr als nur Eingangs-Register.

Das stimmt zwar, bringt den Fragenden aber bei seinem derzeitigen 
Kenntnisstand wohl nicht weiter. Wo ist C. Hoffmann eigentlich 
abgeblieben?

von Guck an (Gast)


Lesenswert?

S. Landolt schrieb:
> Wo ist C. Hoffmann eigentlich
> abgeblieben?

Der arbeitet noch den Interrupt ab.

von C. M. (chrisso1986)


Lesenswert?

Also trotz wechsel von PIN zu PORT und anders herum kein erfolg.

von Rudolph R. (rudolph)


Lesenswert?

c-hater schrieb:
>> Ja, sorry, autsch und so, anders herum natürlch.
>
> Nein. PINx ist inzwischen mehr als nur Eingangs-Register.

Natürlich, der Rest von meinem Geschreibsel war ja nicht falsch. :-)

von Dieter F. (Gast)


Lesenswert?

c-hater schrieb:
> Wenn es sich um ein Strobe-Bit handelt (und genau das ist beim
> PINx-Register aller neueren AVR8 der Fall): natürlich.

Ah ja, beim ATMega168 (und den hat der TO) wird mit

PINC |= 1<<PINC0

getoggelt. Das Datenblatt zeige mir bitte mal :-)

von Rudolph R. (rudolph)


Lesenswert?

Christian H. schrieb:
> Also trotz wechsel von PIN zu PORT und anders herum kein erfolg.

Poste mal den Quelltext - und zwar den richtigen. :-)

Und delay() im Interrupt geht mal garnicht.

von Dieter F. (Gast)


Lesenswert?

c-hater schrieb:
> Die Scheiße toggelt.

Die vielleicht - der Pin aber nicht ...

von S. Landolt (Gast)


Lesenswert?

> Also trotz wechsel von PIN zu PORT und anders herum kein erfolg.

Bitte das aktuelle Programm zeigen.
(Das muss doch auf die Reihe zu bekommen sein bis zu den 
Sternschnuppen.)

von Rudolph R. (rudolph)


Lesenswert?

http://www.atmel.com/Images/Atmel-42176-ATmega48PB-88PB-168PB_Datasheet.pdf

15.2.1   Configuring the Pin
Each port pin consists of three register
bits: DDxn, PORTxn, and PINxn. As shown in
”Register Description” on
page 88
, the DDxn bits are accessed at the DDRx I/O address,
 the PORTxn bits at the PORTx I/O address, and
the PINxn bits at the PINx I/O address.
The DDxn bit in the DDRx Register selects the direction of
this pin. If DDxn is written
logic one, Pxn is configured
as an output pin. If DDxn is
 written logic zero, Pxn is configured as an input pin.
If PORTxn is written logic one when the pin is configured as
an input pin, the pull-up resistor is activated. To switch
the pull-up resistor off, PORTxn has to be written logic zero
or the pin has to be configured as an output pin. The
port pins are tri-stated when reset condition
becomes active, even if no clocks are running.
If PORTxn is written logic one when the pin is configured
as an output pin, the port pin is driven high (one). If
PORTxn is written logic zero when the pin is configured as
 an output pin, the port pin is driven low (zero)

15.2.2   Toggling the Pin
Writing a logic one to PINxn toggles the value of PORTxn
, independent on the value of DDRxn. Note that the SBI
instruction can be used to toggle one single bit in a port.

: Bearbeitet durch User
von S. Landolt (Gast)


Lesenswert?

> PINC&=~1<<PINC0;

Ich kann kein C - geht das, oder müssen Klammern gesetzt werden:
PINC&=~(1<<PINC0);  ?

Und könnte es sein, dass die Ausgabe auf B5 gestört wird durch SCK des 
ISP?

von Stefan F. (Gast)


Lesenswert?

Poste den aktuellen Quelltext und beschreibe, was genau nicht 
funktioniert.

Dein Programm hat ja ganz offensichtlich mindestens zwei Funktionen.

Kommentiere mal die Interrupt-Freigabe aus und dann sag uns, was am 
Anschluss PC0 passiert. Eine dort angeschlossene LED sollte bltzen, 
richtig?

Und dann aktiviere den Interrupt wieder. Was macht die LED dann? Was 
hast du stattdessen erwartet? Was macht die LED an PB% und was hast du 
stattdessen erwartet?

1)
Das allerwichtigste bei der Fehlersuche ist, dass du für dich selbst 
zuerst mal formulierst, welches Ergebnis erwartet wurde und was statt 
dessen passiert.

2)
Das Programm reduzieren, um die Fehlerquelle einzukreisen. Ja, auch 
dieses kleine Programm kann man weiter reduzieren.

3)
Wenn man andere fragt, dann im mer den Quelltext posten - nicht nur ein 
frisiertes Fragment davon. Und dann beschreibt man zuerst, wass das Ding 
tun soll und was es stattdessen tut.

Einfach nur sagen: "Irgendwas geht nicht, findet heraus, was und warum" 
kommt hier gar nicht gut an. Du siehst schon an den Antworten, dass sie 
total vom Thema (deinem Problem) abdriften. Selbst Schuld!

von Stefan F. (Gast)


Lesenswert?

> Ich kann kein C - geht das, oder müssen Klammern
> gesetzt werden: PINC&=~(1<<PINC0);  ?

Richtig, die Klammern sind nötig. Denn ~ hat Vorrang vor <<.

Aber zum Toggeln schreibt man normalerweise PINC = (1<<PINC0)

Jedoch wollte der TO den Pin nicht toggeln, sondern zuerst auf High 
setzen, dann etwas warten und dann wieder auf Low setzen. Dazu muss er 
das PORT Register beschreiben.

> Und könnte es sein, dass die Ausgabe auf B5 gestört wird durch
> SCK des ISP?

Nein, denn der ISP Anschluss ist nur während des Reset aktiv, sonst 
hochohmig. Ich kann mit zwar vorstellen, dass ein Programmer sich 
eventuell nicht an diese Regel hält, den würde ich dann allerdings als 
Fehlkonstruktion wegwerfen.

von S. Landolt (Gast)


Lesenswert?

Also, dann muss das doch laufen, wenn nur noch "PORT"s vorkommen (keine 
"PIN"s) und diese Klammern gesetzt sind: die LED blinkt, bei Anschluss 
gegen GND, mit einer kurzen und einer langen Pause.

von S. Landolt (Gast)


Lesenswert?

Ein letzter Hinweis an C. Hoffmann:
> und diese Klammern gesetzt sind
gilt für mehrere Stellen in Ihrem Programm.


Einen schönen Abend, speziell an Stefan Us.
(Ich geh jetzt Sternschnuppen schauen und wünschen)

von C. M. (chrisso1986)


Lesenswert?

Vielen Dank für eure Hilfe anbei nochmal der geänderte Code

--------------------------------------------------------------
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <stdlib.h>
4
#include <util/delay.h>
5
6
ISR(INT0_vect)
7
{
8
  PORTB|=(1<<PORTB5);
9
  _delay_ms(2000);
10
  PORTB&=~(1<<PORTB5);
11
}
12
13
int main(void)
14
{
15
  DDRC|=(1<<DDRC0);
16
  DDRB|=(1<<DDRB5);
17
  DDRD&=~(1<<DDRD2);
18
19
  EICRA |=(1<<ISC00);    // set INT0 to trigger on ANY logic change
20
  EIMSK |=(1<<INT0);     // Turns on INT0
21
22
  sei();                    // turn on interrupts*/
23
24
  while(1)
25
  {
26
  PORTC|=(1<<PORTC0); //PINC0 ist über ein Kabel mit  dem PORTD2 verbunden
27
  _delay_ms(500);
28
  PORTC&=~(1<<PORTC0);
29
  _delay_ms(10000);
30
31
  }
32
}
------------------------------------------------------------------

Also das Programm funktioniert fass, jedoch blinkt die LED Zweimal kurz 
nacheinander.

Eigentlich war es so gedacht, PINC0 wird für 500ms auf hight gesetzt und 
löst den Interrupt aus. Danach startet das Programm im Interrupt lässt 
die LED für 2sek aufleuchten und setzt den PORTB5 wieder auf null. 
Danach sollte der Zeiger doch wieder an die Stelle des hauptprogramms 
springen wo es aufgehört und sollte dann dort 10sek warten. Danach 
beginnt alles wieder von vorne.....

Vielleicht liegt das auch an dem Probleme das immer die Warnung delay 
nicht definiert kommt obwohl ich in der libery delay.h 16MHz eingestellt 
habe.

: Bearbeitet durch User
von C. M. (chrisso1986)


Lesenswert?

Danke an alle es funktioniert..... :):):):):)

falls mir noch jemand wegen der #warnung delay not defined weiterhelfen 
kann würde ich mich ebenfalls noch freuen....

von Daniel S. (daniel_s49)


Lesenswert?

Christian H. schrieb:
> obwohl ich in der libery delay.h 16MHz eingestellt
> habe

Du hast die library verändert um dort den Takt anzugeben? Es hätte 
gereicht das #define F_CPU 16000000 ganz oben in deine Hauptdatei zu 
schreiben (vor das include). Alternativ kann man das bei vielen 
Entwicklungsumgebungen auch in den Einstellungen festlegen.
Libraries sind dafür da, von verschiedenen Projekten eingebunden zu 
werden und deshalb hält man die so allgemein wie möglich bzw. fasst sie 
beim Programmieren nicht mehr an.

Wegen der Warnung weiß ich aber leider auch nicht weiter.

von Jobst M. (jobstens-de)


Lesenswert?

Daniel S. schrieb:
> und dann sehe ich ein 2sekunden sleep in der ISR? Das Verständnis ist
> definitiv ausbaufähig.

Hmmm jain. So lange er garantieren kann, dass während der Abarbeitung 
der ISR kein weiterer IRQ auftritt, kann er darin so lange verweilen, 
wie er mag.
Und dieses Programm, wenn es denn laufen würde wie gewollt, garantiert 
das.


@TO: Wie sieht das Programm denn nun im Moment aus?

Edit: Whoops - zu spät ...


Gruß

Jobst

: Bearbeitet durch User
von Dieter F. (Gast)


Lesenswert?

c-hater schrieb:
> Du solltest nach zehn Jahren (oder so) endlich mal wieder ein Datenblatt
> lesen...

Rudolph R. schrieb:
> 15.2.2   Toggling the Pin
> Writing a logic one to PINxn toggles the value of PORTxn
> , independent on the value of DDRxn.

Ja, hätte ich machen sollen, bevor ich hier rumpupse ...
Habe heute mein Büßergewand an :-)

von Stefan F. (Gast)


Lesenswert?

Hast du die Definition F_CPU gesetzt?

#define F_CPU 16000000

Oder im Makefile als Compiler-Option. Oder im AVR Studio, da gibt ein 
Dialogfenster zum Setzen der Compiler-Optionen.

Zittiere doch mal die genaue Fehlermeldung.

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.