Forum: Compiler & IDEs Interrupt in C 3x3x3 LED Cube


von Michael (Gast)


Lesenswert?

Hallo liebe Mikrocontroller Team :)
Und zwar hab ich folgendes Problem.
Ich hab mir einen 3x3x3 LED Cube gebaut und er funktioniert auch soweit.
Ich kann meine Programme ohne Probleme laufen lassen.
Nun möchte ich aber mittels einem Taster (Interrupt) zwischen meinen 
Programmen hin und her schalten. Nur so wie ich das Versuche geht es 
nicht vllt könnt ihr mir ja weiterhelfen.
Hier der Code:

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


uint8_t status;
void delay_ms(uint16_t ms)
{
  for(uint16_t t=0; t<=ms; t++)
  _delay_ms(1);
}

int main()
{
  cli();
  DDRD = 0b11110111;
  DDRC = 0xFF;
  DDRB = 0xFF;
  GIMSK = (1<<(INT1));            // Interrupt Freigeben
  MCUCR |= (1<<ISC11) | (1<<(ISC10)) ;    // Interrupt löst bei 
steigender Flanke aus
  sei();                  // Interrupt wird eingeschalet

    while (1)      //Endlos
    {
    if (status==1)
    {
    void OB();
    status=0;
    }
    if (status==2)
    {
    void ME();
    status=0;
    }
    if (status==3)
    {
    void UE();
    status=0;
    }
    }
    return 0;
}
ISR(INT1_vect)              //Interruptvektor
{
  status=1;

}
void OE ()
 {
     PORTD &=~(1<< PD2);
    PORTD |=(1<< PD0);        //Ebene 3
    PORTB &=~(1<<PB3);
    PORTC |=(1<< PC5) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC5)  ;
    PORTC |=(1<< PC4) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC4)  ;
    PORTC |=(1<< PC3) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC3)  ;
    PORTC |=(1<< PC2) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC2) ;
    PORTC |=(1<< PC1) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC1);
    PORTC |=(1<< PC0) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC0);
    PORTB |=(1<< PB5) ;
  //  _delay_ms(200);
    PORTB &=~(1<< PB5);
    PORTB |=(1<< PB4) ;
  //  _delay_ms(200);
    PORTB &=~(1<< PB4);
    PORTB |=(1<< PB3) ;
  //  _delay_ms(200);

    }

void ME ()
  {
    PORTD &=~(1<< PD0);       //Ebene 2
    PORTD |=(1<< PD1);
    PORTB &=~(1<<PB3);
    PORTC |=(1<< PC5) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC5)  ;
    PORTC |=(1<< PC4) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC4)  ;
    PORTC |=(1<< PC3) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC3)  ;
    PORTC |=(1<< PC2) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC2) ;
    PORTC |=(1<< PC1) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC1);
    PORTC |=(1<< PC0) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC0);
    PORTB |=(1<< PB5) ;
  //  _delay_ms(200);
    PORTB &=~(1<< PB5);
    PORTB |=(1<< PB4) ;
  //  _delay_ms(200);
    PORTB &=~(1<< PB4);
    PORTB |=(1<< PB3) ;
  //  _delay_ms(200);

    }
void UE ()
  {
    PORTD &=~(1<< PD1);       //Ebene 1
    PORTD |=(1<< PD2);
    PORTB &=~(1<<PB3);
    PORTC |=(1<< PC5) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC5)  ;
    PORTC |=(1<< PC4) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC4)  ;
    PORTC |=(1<< PC3) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC3)  ;
    PORTC |=(1<< PC2) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC2) ;
    PORTC |=(1<< PC1) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC1);
    PORTC |=(1<< PC0) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC0);
    PORTB |=(1<< PB5) ;
  //  _delay_ms(200);
    PORTB &=~(1<< PB5);
    PORTB |=(1<< PB4) ;
  //  _delay_ms(200);
    PORTB &=~(1<< PB4);
    PORTB |=(1<< PB3) ;
  //  _delay_ms(200);

    }


Danke im Vorraus :)

von Krapao (Gast)


Lesenswert?

> Nun möchte ich aber mittels einem Taster (Interrupt) zwischen meinen
> Programmen hin und her schalten.

Eine auf den ersten Blick offensichtliche, aber auf den zweiten Blick 
ungünstige Idee.

Stand der Technik ist eine andere Art der Tasterabfrage.

Zu dem Thema gibt es 'zig Beiträge hier im Forum und Tutorials in der 
Artikelsammlung (Entprellung).

von Michael (Gast)


Lesenswert?

Danke für die Schnelle Antwort.

Mit der Taserabfrage wollt ich ja auch machen aber ist in unseren 
Aufgabenstellung nicht so gegeben. Wir sollen es mittels Interrrupts 
lösen. Blos ich weiß nicht wo meine Fehler im Code ist. eigentlich soll 
ja wenn der Interrupt ausgelöst wurde der status auf 1 gestzt werden ... 
jedoch geschieht das nicht, denn in der Main wird dann das Programm 
nicht aufgerufen. Es werden nur die If anweißungen abgefragt, als wäre 
nix passiert.

MfG Michael

von Stefan E. (sternst)


Lesenswert?

volatile

von Karl H. (kbuchegg)


Lesenswert?

> Blos ich weiß nicht wo meine Fehler im Code ist.

Der eigentliche Fehler in deinem Programm besteht in der Ansteuerung des 
Cube.

Die gehört in einen Interrupt (und muss völlig ohne _delay_ms 
auskommen), nicht die Tastenabfrage.

Und by the way.

Das hier
    if (status==1)
    {
    void OB();

ist kein Aufruf der Funktion OB.

von Michael (Gast)


Lesenswert?

Was meinst du mit "volatile"?

Wie meinste das bei der Ansteurung an meinem Cube?

MfG Michael

von Karl H. (kbuchegg)


Lesenswert?

Michael schrieb:
> Was meinst du mit "volatile"?

FAQ: Was hat es mit volatile auf sich

> Wie meinste das bei der Ansteurung an meinem Cube?

Die ganze Ansteuerung ist verkorkst.

von Michael (Gast)


Lesenswert?

So.. ich habs jetzt soweit geschrieben.
Jetzt möchte ich noch gerne das das Interrupt mitzählt und 1. Programm 
auswählt danach 2. und so weiter ... und bis zu einem bestimmten Punkt 
zählt und wieder aufhört.

Hier erstma der Code:

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

void OE(),ME(),UE();
volatile int i;
void delay_ms(uint16_t ms)
{
  for(uint16_t t=0; t<=ms; t++)
  _delay_ms(1);
}

int main()
{
  cli();
  DDRD = 0b11110111;
  DDRC = 0xFF;
  DDRB = 0xFF;
  GIMSK = (1<<(INT1));            // Interrupt Freigeben
  MCUCR |= (1<<ISC11) | (1<<(ISC10)) ;    // Interrupt löst bei 
steigender Flanke aus
  sei();                  // Interrupt wird eingeschalet


              //B 000 001 Startwert für Wanderbalken          //B 000 
001 Startwert für Wanderbalken
    while (1)      //Endlos
    {
    if (i==1)
    {
    OE();
    i=0;
    }
    if (i==2)
    {
    ME();
    i=0;
    }
    if (i==3)
    {
    UE();
    i=0;
    }
    }
    return 0;
}
ISR(INT1_vect)              //Interruptvektor
{
  i=1;

}
void OE ()
 {
     PORTD &=~(1<< PD2);
    PORTD |=(1<< PD0);        //Ebene 3
    PORTB &=~(1<<PB3);
    PORTC |=(1<< PC5) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC5)  ;
    PORTC |=(1<< PC4) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC4)  ;
    PORTC |=(1<< PC3) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC3)  ;
    PORTC |=(1<< PC2) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC2) ;
    PORTC |=(1<< PC1) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC1);
    PORTC |=(1<< PC0) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC0);
    PORTB |=(1<< PB5) ;
  //  _delay_ms(200);
    PORTB &=~(1<< PB5);
    PORTB |=(1<< PB4) ;
  //  _delay_ms(200);
    PORTB &=~(1<< PB4);
    PORTB |=(1<< PB3) ;
  //  _delay_ms(200);

    }

void ME ()
  {
    PORTD &=~(1<< PD0);       //Ebene 2
    PORTD |=(1<< PD1);
    PORTB &=~(1<<PB3);
    PORTC |=(1<< PC5) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC5)  ;
    PORTC |=(1<< PC4) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC4)  ;
    PORTC |=(1<< PC3) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC3)  ;
    PORTC |=(1<< PC2) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC2) ;
    PORTC |=(1<< PC1) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC1);
    PORTC |=(1<< PC0) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC0);
    PORTB |=(1<< PB5) ;
  //  _delay_ms(200);
    PORTB &=~(1<< PB5);
    PORTB |=(1<< PB4) ;
  //  _delay_ms(200);
    PORTB &=~(1<< PB4);
    PORTB |=(1<< PB3) ;
  //  _delay_ms(200);

    }
void UE ()
  {
    PORTD &=~(1<< PD1);       //Ebene 1
    PORTD |=(1<< PD2);
    PORTB &=~(1<<PB3);
    PORTC |=(1<< PC5) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC5)  ;
    PORTC |=(1<< PC4) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC4)  ;
    PORTC |=(1<< PC3) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC3)  ;
    PORTC |=(1<< PC2) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC2) ;
    PORTC |=(1<< PC1) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC1);
    PORTC |=(1<< PC0) ;
  //  _delay_ms(200);
    PORTC &=~(1<< PC0);
    PORTB |=(1<< PB5) ;
  //  _delay_ms(200);
    PORTB &=~(1<< PB5);
    PORTB |=(1<< PB4) ;
  //  _delay_ms(200);
    PORTB &=~(1<< PB4);
    PORTB |=(1<< PB3) ;
  //  _delay_ms(200);

    }

MfG Michael Dankeschön schonmal :P

von Krapao (Gast)


Lesenswert?

> Jetzt möchte ich noch gerne das das Interrupt mitzählt

Dann darfst du halt nicht schreiben
1
ISR(INT1_vect)              //Interruptvektor
2
{
3
  i = 1;
4
}

sondern du müsstest schreiben
1
ISR(INT1_vect)              //Interruptvektor
2
{
3
  i += 1;
4
}

damit du andere Werte als i==1 bekommst.

Dann wirst du aber sehen, dass es dir mit dem Taster nicht gelingt, 
gezielt eins der Programme auszuwählen.

Das liegt einmal an deiner Programmlogik.

Du setzt nämlich i nach dem Ausführen eines Programmteils wieder auf 0, 
d.h. ein Programmteil wird einmal ausgeführt und nicht wiederholt. Um 
jetzt z.B. in den Programmteil UE zu kommen (i==3), müsstest du per 
Taster und Interrupt i dreimal erhöhen, ohne dass ein anderer 
Programmteil aktiv wird und i wieder nullt. Von der Programmlogik her 
bräuchtest du also eine Erkennung, wann ist der Benutzer fertig mit der 
Eingabe und wann kann dar Programmteil gestartet werden. Diese Erkennung 
kann z.B. eine weitere Taste liefern oder z.B. eine längere Pause nach 
einer oder mehreren Tastendrücken.

Zum anderen liegt es an der verkorksten, d.h. nicht entprellten 
Tasterabfrage.

Du erwartet pro Tastendruck exakt eine steigende Flanke. Das ist aber in 
der Realität nicht so. Es kommen durch das Prellen wesentlich mehr 
Flanken und i wird unreproduzierbar oft erhöht! Deswegen wird der 
"Aufwand" betrieben, der in Entprellung beschrieben ist.

von Michael (Gast)


Lesenswert?

Ich möchte das ja so machen das er das Programm ausführt und per 
Tastendruck das nächste usw ... wenn er alle Programme durchlaufen hat 
soll er wieder von neuen beginnen .. gibts es da keine einfache 
Zählmöglichkeit?

von Krapao (Gast)


Lesenswert?

> Mit der Taserabfrage wollt ich ja auch machen aber ist in unseren
> Aufgabenstellung nicht so gegeben. Wir sollen es mittels Interrrupts
> lösen.

Eine Tasterabfrage mit Entprellung kann auch mit dem Timer-Interrupt 
gemacht werden. so gesehen wäre die Aufgabenstellung doch auch gelöst 
oder?

> Blos ich weiß nicht wo meine Fehler im Code ist. eigentlich soll
> ja wenn der Interrupt ausgelöst wurde der status auf 1 gestzt werden ...
> jedoch geschieht das nicht, denn in der Main wird dann das Programm
> nicht aufgerufen. Es werden nur die If anweißungen abgefragt, als wäre
> nix passiert.

Wird dein INT1-Interrupt überhaupt aufgerufen?

Ich habe deine Schaltung am INT1-Pin nicht gesehen. Besteht das 
überhaupt die Möglichkeit, dass da eine steigende Flanke auftaucht?

Und ich habe deinen Sourcecode zur Einstellung des INT1 nicht mit dem 
Datenblatt verglichen. Bist du sicher, dass bei deinem hier unbekannten 
AVR diese Abfolge korrekt und ausreichend ist?
1
  GIMSK = (1<<(INT1));
2
  MCUCR |= (1<<ISC11) | (1<<(ISC10)) ; // steigende Flanke
3
  sei();

Wenn möglich installiere an einem freien Output-Pin eine LED (natürlich 
mit Vorwiderstand) und benutze diese LED zur Anzeige, ob die ISR von 
INT1 überhauot angesprungen wurde z.B. durch Toggeln dieser 
ISR-Anzeige-LED.

Bei der Programmentwicklung mit Interrupts ist es auch nützlich, wenn 
man eine LED hat, die zeigt, ob der AVR "abgestürzt" ist und sich 
resettet hat. Dazu kann man z.b. zu Beginn von main() eine LED 1s 
leuchten lassen. Wenn das folgende Programm dann korrekt läuft, darf 
diese RESET-Anzeige-LED nicht mehr leuchten.

von Krapao (Gast)


Lesenswert?

> Ich möchte das ja so machen das er das Programm ausführt und per
> Tastendruck das nächste usw ... wenn er alle Programme durchlaufen hat
> soll er wieder von neuen beginnen .. gibts es da keine einfache
> Zählmöglichkeit?

Sicher gibt es die, aber du hast was angefangen, dass von Haus aus 
verkorkst und kompliziert ist. Das möchte man (ich) nicht umbiegen, so 
dass es doch noch geht.

Geh in deiner Programmentwicklung einen Schritt zurück und lerne, wie 
man sauber eine Taste abfragt. Z.B. mit einer Routinen aus 
Entprellung oder dem Beispiel 
http://www.mikrocontroller.net/articles/Pollin_Funk-AVR-Evaluationsboard#Tasty_Reloaded

Dann bau damit einen Zähler. Pro sauber entprelltem Tastendruck zählst 
du eine Variable hoch. Überlege dir, welche Werte die Variable annehmen 
darf und was passieren soll, wenn der Wertebereich verlassen wird. Soll 
dann runtergezählt werden oder von vorne angefangen werden?

Dann mach was mit der Variablen, also vergleiche sie mit einem Wert und 
führe die geplanten Aktionen durch. Überlege dir was passieren soll, 
wenn die Aktion abgeschlossen ist. Soll dann "nix" (was ist das?) 
gemacht oder soll die Aktion wiederholt werden oder soll die nächste 
Aktion gemacht werden?

von Michael (Gast)


Lesenswert?

also es funktioniert soweit ... wenn ich ein taster drücke führt er das 
nächste Programm aus .. dann hab ich in der isr noch eine if Anweisung 
gemacht die die variable i auf 0 zuruecksetz ... bloß manchmal werden 2 
Programme mit einmal ausgeführt und manchmal klappt alles ... liegt das 
dann am taster ? was ich mir eigentlich schon denke...
danke schonmal ... hast mir schon viel geholfen ;)

mfg Michael

von Karl H. (kbuchegg)


Lesenswert?

Michael schrieb:

> gemacht die die variable i auf 0 zuruecksetz ... bloß manchmal werden 2
> Programme mit einmal ausgeführt und manchmal klappt alles ... liegt das
> dann am taster ? was ich mir eigentlich schon denke...

Du hast höchst wahrscheinlich gerade das erste mal Tastenprellen in 
Aktion gesehen. Warte noch ein Weilchen, bis deine Tasten alt und 
abgenutzt werden. Dann wird aus dem 'manchmal' ein 'fast immer'

von Michael (Gast)


Lesenswert?

Ok da muss ich die halt noch entprellen ... danke für die Antwort :)

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.