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
202 Beiträge
|
![]()
Einige (aber nicht alle) Antworten:
Das soll wahrscheinlich PORTA heißen oder? An sonsten: wenn das nur den Wert des Pins zurückgibt, passt das prinzipiell. 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. 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. Mehrfach zurücksetzen bringt nichts. |
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. 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 ![]() 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. 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) Sehe ich leider auch anders, da event = 0 nur ausgeführt wird, wenn taste == (1<<i) gilt. Oder habe ich da etwas übersehen? |
Mitglied seit 02/2013
6 Beiträge
|
![]()
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?
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.
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. |
Mitglied seit 10/2011
13 Beiträge
|
![]() 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) werden natürlich trotzdem wegoptimiert. Aber solange es "sinnvolle" Befehle sind, bleibt die Schleife natürlich bestehen.++i; Übrigens müsste auch das volatile in der for-Schleife bei /* Betaetigung von Tasten auswerten */ meiner Meinung nach überflüssig sein. 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). |
Powered by the Unclassified NewsBoard software, 20110527-dev,
© 2003-8 by Yves Goergen