ATMega 168PB Interrupt Programmieren

OP #4231647
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
Gast #4231658
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.
OP #4231682
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);

  }
  }
------------------------------------------------------------------
OP #4231690
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......
OP #4231694
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?
#4231698
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.
Gast #4231724
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.
Gast #4231775
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?
#4231819
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.
Gast #4231847
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!
Gast #4231855
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.
Gast #4231888
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)
OP #4231896
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.
#4231935
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.
#4231993
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
Gast #4232242
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren