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
intmain(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
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!
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)
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.
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);
}
}
------------------------------------------------------------------
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
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.
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......
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?
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.
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.
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?
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.
Rudolph R. schrieb:> Datenblatt und so, PINx sind die Ausgangs-Register, PORTx die> Eingangs-Register.
Ja, sorry, autsch und so, anders herum natürlch.
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.
> 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?
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. :-)
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 :-)
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.
> 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.)
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.
> 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?
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!
> 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.
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.
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)
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
intmain(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.
Danke an alle es funktioniert..... :):):):):)
falls mir noch jemand wegen der #warnung delay not defined weiterhelfen
kann würde ich mich ebenfalls noch freuen....
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.
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
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 :-)
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.