Nicht angemeldet. · Kennwort vergessen · Registrieren

lurxy
Mitglied seit 02/2013
6 Beiträge
Betreff: Klausur Juli 2013
Hallo liebe GspiCler,

Ich hab mich heute mal an der Programmieraufgabe vom Juli 2013 versucht und wollte fragen, ob jemand da vielleicht kurz mal drüber schauen kann. Ich bin mir an einigen Punkten noch nicht ganz sicher. Diese Punkte hebe ich mal mit farbigem Kommentar hervor.

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <stdint.h>
#define LOOPS_PER_MS 50
#define NBLINK 5
static uint16_t muster[8] = {420,680,210,160,370,110,920,750};
   
/* Funktionsdeklarationen, globale Variablen, etc. */
static uint8_t taste;     //Ist es für die Klausur wichtig, dass die globalen Variablen und Funktionen static sind? Es gibt letztendlich ja nur ein Modul.
static uint8_t pressed;
static uint8_t event;
static void wait(uint16_t ms);
static void send(uint8_t button);
static void init(void);

/* Unterbrechungsbehandlungsfunktion */
ISR (INT0_vect) {
    if(pressed==1) {
        event = 1;
        taste = PINA;    //Reicht das hier oder muss ich taste und PINA bitweise verknüpfen?
        pressed = 0;
    }       
}


/* Funktion main */
void main (void) {
/* Initialisierung und lokale Variablen */
    init();
/* Hauptschleife */
    while(1) {
/* auf Tastendruck warten */
        sleep_enable();
        sei();
        while(!event) {
            cli();
            sleep_cpu();
            sei();
        }
        cli();
        sleep_disable();     //Kann ich das sleep_disable() auch weglassen und das sleep_enable einmalig in der init() schreiben?
/* Betaetigung von Tasten auswerten */
        for(volatile uint8_t i=0; i<=7;i++) {
            if(taste==(1<<i)) {
                send(i);
                event=0;
                pressed=1;
                taste=0;
            }
        }
        if(event==1) {        //Diese if-Abfrage ist ja nur gültig, wenn in der for-Schleife nicht nur eine Taste gedrückt wurde und damit event=0 eintritt, oder?
            PORTB &= ~(1<<PB4);
            wait(1000);
            PORTB |= (1<<PB4);
            pressed=1;
            taste=0;
            event=0;
        }       
/* Ende main */
        pressed=1;     //Macht es hier Sinn, pressed, taste und event nochmal zurückzusetzen? Letztendlich passiert das in allen Fällen auch vorher schon, oder?
        taste=0;
        event=0;
    }
}
/* Funktion send
zu Taste gehoerendes Muster mit Infrarot-LED senden */
static void send(uint8_t button) {
    for(volatile uint8_t i=0; i<NBLINK; i++) {
        PORTC &= ~(1<<PC0);
        wait(muster[ button ]);
        PORTC |= (1<<PC0);
        wait(500);
    }
}   

/* Initialisierungsfunktion */
static void init(void) {
    DDRC |= (1<<PC0); //Infrarot LED
    PORTC |= (1<<PC0);

    DDRB |= (1<<PB4); //Fehler LED
    PORTB |= (1<<PB4);

    DDRA &= 0x00; //Taster 0-7
    PORTA |= 0xff;

    DDRD &= ~(1<<PD2); //Interrupt Leitung     //Interruptleitungen müssen immer als Eingang gesetzt werden, oder?
    PORTD |= (1<<PD2);
    GICR |= (1<<INT0);
    MCUCR &= ~(1<<ISC00);
    MCUCR |= (1<<ISC01);
    taste=0;
    pressed=1;
    event= 0;
}
/* Wartefunktion */
static void wait(uint16_t ms) {
    for(volatile uint16_t i =0; i<=(ms * LOOPS_PER_MS);i++) {}
}


Danke im Vorraus für die Zeit :)
Christian St. (Moderator)
Mitglied seit 05/2011
197 Beiträge
Einige (aber nicht alle) Antworten:

taste = PINA;    //Reicht das hier oder muss ich taste und PINA bitweise verknüpfen?
Das soll wahrscheinlich PORTA heißen oder?
An sonsten: wenn das nur den Wert des Pins zurückgibt, passt das prinzipiell.

        sleep_disable();     //Kann ich das sleep_disable() auch weglassen und das sleep_enable einmalig in der init() schreiben?
Theoretisch ja, aber das wäre schlechter Stil. Das sleep_disable() ist dazu da, um versehentliches Schlafenlegen (z.B. durch Bitkipper, Programmierfehler, Schreiben in falsche Register, Überlauf des Stacks, …) zu verhindern. Also besser sleep_disable() verwenden.

        if(event==1) {        //Diese if-Abfrage ist ja nur gültig, wenn in der for-Schleife nicht nur eine Taste gedrückt wurde und damit event=0 eintritt, oder?
Wenn ich deinen Code richtig verstehe, wird dieser Abschnitt nie aufgerufen, weil in der for-Schleife drüber auf jeden Fall event=0; ausgeführt wird.

        pressed=1;     //Macht es hier Sinn, pressed, taste und event nochmal zurückzusetzen? Letztendlich passiert das in allen Fällen auch vorher schon, oder?
Mehrfach zurücksetzen bringt nichts.
KapHa
Mitglied seit 10/2011
13 Beiträge
Wenn es recht ist, schreibe ich hier auch mal was zu der Lösung:
Schau dir bitte noch mal deinen Code zu "auf Tastendruck warten" an, da stimmt - meiner Meinung nach - etwas ganz und gar nicht...
Des Weiteren solltest du dir genau überlegen, wo du volatile brauchst: Wenn ich das richtig sehe, hast du nämlich sowohl volatile vergessen, als auch überflüssige in deinem Programm.

Zitat von lurxy:
static uint8_t taste;     //Ist es für die Klausur wichtig, dass die globalen Variablen und Funktionen static sind? Es gibt letztendlich ja nur ein Modul.
Deine Argumentation stimmt prinzipiell. Wenn ich mich allerdings richtig erinnere, wurden für fehlende static aber Punkte abgezogen, so dass ich das in der Klausur hinschreiben würde. (Genauere Informationen beim Übungsleiter/Betreuer deines Vertrauens ;) )

Zitat von lurxy:
DDRD &= ~(1<<PD2); //Interrupt Leitung     //Interruptleitungen müssen immer als Eingang gesetzt werden, oder?
Interruptleitungen müssen nicht zwangsläufig als Eingang konfiguriert sein (siehe: http://www.atmel.com/Images/doc2503.pdf#66, Seite 66). In diesem Fall ist es aber sinnvoll, da deine Interruptquelle (der Knopf bzw. die Knöpfe) nicht deine Software ist, sondern die Hardware.

Zitat von Christian St.:
taste = PINA;    //Reicht das hier oder muss ich taste und PINA bitweise verknüpfen?
Das soll wahrscheinlich PORTA heißen oder?
An sonsten: wenn das nur den Wert des Pins zurückgibt, passt das prinzipiell.
Also meiner Meinung nach, sollte PINA schon passen, da der Zustand des Tasters abgefragt werden soll und nicht, ob der Pull-Up Widerstand aktiv ist oder nicht. Würde zumindest auch zu den Folien passen... (https://www4.cs.fau.de/Lehre/WS13/V_GSPIC/Vorlesung/Folien…, Seite 71)

Zitat von Christian St.:
        if(event==1) {        //Diese if-Abfrage ist ja nur gültig, wenn in der for-Schleife nicht nur eine Taste gedrückt wurde und damit event=0 eintritt, oder?
Wenn ich deinen Code richtig verstehe, wird dieser Abschnitt nie aufgerufen, weil in der for-Schleife drüber auf jeden Fall event=0; ausgeführt wird.
Sehe ich leider auch anders, da event = 0 nur ausgeführt wird, wenn taste == (1<<i) gilt. Oder habe ich da etwas übersehen?
lurxy
Mitglied seit 02/2013
6 Beiträge
Wenn es recht ist, schreibe ich hier auch mal was zu der Lösung:
Schau dir bitte noch mal deinen Code zu "auf Tastendruck warten" an, da stimmt - meiner Meinung nach - etwas ganz und gar nicht...
Des Weiteren solltest du dir genau überlegen, wo du volatile brauchst: Wenn ich das richtig sehe, hast du nämlich sowohl volatile vergessen, als auch überflüssige in deinem Programm.

Oh tatsächlich, ich hab sei() und cli() jeweils genau vertauscht. Sprich, da wo ein sei() steht gehört ein cli() hin und andersherum.
Was die volatiles angeht habe ich nochmal ins Skript geschaut, die Variablen, die das Hauptprogramm und die Unterbrechungsfunktion lesen und schreiben müssen demnach volatile sein, also pressed, event und taste. Überflüssig wäre an sich ja volatile in der Laufvariable in "/* Funktion send zu Taste gehoerendes Muster mit Infrarot-LED senden */", da der Präprozessor diese Schleife ja nicht verwerfen würde, da in der for-Schleife ja Befehle stehen, oder?

    taste = PINA;    //Reicht das hier oder muss ich taste und PINA bitweise verknüpfen?

Das soll wahrscheinlich PORTA heißen oder?
An sonsten: wenn das nur den Wert des Pins zurückgibt, passt das prinzipiell.

Hier hatte ich auch an den Pull Up Widerstand gedacht, da die Tasten ja als Eingänge konfiguriert sind. In dem Moment gibt PORTA ja nur noch Aussagen über den Pull Up und man muss mit PINA den Zustand schreiben/lesen.

            if(event==1) {        //Diese if-Abfrage ist ja nur gültig, wenn in der for-Schleife nicht nur eine Taste gedrückt wurde und damit event=0 eintritt, oder?

Wenn ich deinen Code richtig verstehe, wird dieser Abschnitt nie aufgerufen, weil in der for-Schleife drüber auf jeden Fall event=0; ausgeführt wird.

Ich weiß nicht, ob ich jetzt einen Fehler im Code habe, aber die Absicht war, dass in der for-Schleife vorher event nur dann auf 0 gesetzt wird, wenn taste genau einem 8-Bit Code mit einer Einsstelle entspricht ( in der Angabe steht hier, man soll send() nur aufrufen, wenn nur eine Taste gedrückt wird, ansonsten soll die Fehler LED auf PB4 leuchten). Kann natürlich aber auch sein, dass ich irgendwo etwas übersehen habe und event dennoch immer 0 gesetzt wird.
KapHa
Mitglied seit 10/2011
13 Beiträge
Zitat von lurxy:
Was die volatiles angeht habe ich nochmal ins Skript geschaut, die Variablen, die das Hauptprogramm und die Unterbrechungsfunktion lesen und schreiben müssen demnach volatile sein, also pressed, event und taste. Überflüssig wäre an sich ja volatile in der Laufvariable in "/* Funktion send zu Taste gehoerendes Muster mit Infrarot-LED senden */", da der Präprozessor diese Schleife ja nicht verwerfen würde, da in der for-Schleife ja Befehle stehen, oder?
Genau, nur dass die Optimierung der Compiler und nicht der Präprozessor übernehmen würde (der Präprozessor nimmt eigentlich nur (Text-)Ersetzungen vor), aber ich glaube, das muss man in GSPiC nicht wissen. Allerdings kommt es sehr darauf an, welche Befehle in der Schleife vorkommen. Solche Späße wie
for (uint8_t i = 0; i < 50; ++i)
    ++i;
werden natürlich trotzdem wegoptimiert. Aber solange es "sinnvolle" Befehle sind, bleibt die Schleife natürlich bestehen.
Übrigens müsste auch das volatile in der for-Schleife bei /* Betaetigung von Tasten auswerten */ meiner Meinung nach überflüssig sein.

Zitat von lurxy:
In dem Moment gibt PORTA ja nur noch Aussagen über den Pull Up und man muss mit PINA den Zustand schreiben/lesen.
Bitte verwende die PINx Register nur zum Lesen. Ein schreibender Zugriff ist nicht erlaubt bzw. nicht definiert (siehe: http://www.atmel.com/Images/doc2503.pdf#64, Seite 64).
Schließen Kleiner – Größer + Auf diesen Beitrag antworten:
Prüfcode: VeriCode Gib bitte das Wort aus dem Bild ins folgende Textfeld ein. (Nur die Buchstaben eingeben, Kleinschreibung ist in Ordnung.)
Smileys: :-) ;-) :-D :-p :blush: :cool: :rolleyes: :huh: :-/ <_< :-( :'( :#: :scared: 8-( :nuts: :-O :troll:
Weitere Zeichen:
Gehe zu Forum
Powered by the Unclassified NewsBoard software, 20110527-dev, © 2003-8 by Yves Goergen