Hallo Zusammen,
im Rahmen eines Hochschulprojekts müssen wir auf einem ATMega32 mit dem
AVR Studio 4 eine Uhr schreiben, inklusive Datum und Weckfunktion.
Die Compiler-Einstellungen sind auf -0O und -0S, in beiden Einstellungen
ging es nicht. Auch unser Dozent ist überfragt und somit seid ihr unsere
letzte Hilfe.
Folgendes steht ganz oben:
1
#include<avr/io.h>
2
#include<util/delay.h>
3
#include"lcd.h"
4
5
//sprich die 'Standard', die delay und die lcd-Headerfile
6
//auch eine weitere Source-File für das LCD-Display ist eingebunden
7
//alle Variablen wurden als uint8_t udn als globale Variable definiert
Nach Start der Uhr wird der Benutzer aufgefordert das Datum
einzustellen. Natürlich besteht hier die Problematik mit Schaltjahren
und die Tagen pro Monat. Dies wurde über die beiden folgenden Funktionen
realisiert, welche im Laufe des Einstellens auf gerufen werden.
Das Einstellen der Monate findet in folgender Funktion statt, welche
soweit auch funktioniert:
1
voidsetMonth()
2
{
3
y1=5;// Monate-Einer -- Schema siehe oben
4
y2=0;
5
mon1=-1;
6
lcd_gotoxy(0,0);
7
lcd_puts("Monat Einer*****");
8
lcd_gotoxy(y1,1);
9
lcd_putc(y2+0x30);
10
11
while(bit_is_set(PIND,PD3));
12
while(bit_is_clear(PIND,PD3))
13
for(mon1=0;mon1<10&&bit_is_clear(PIND,PD3);)
14
{
15
y2=mon1+0x30;
16
lcd_gotoxy(y1,1);
17
lcd_putc(y2);
18
_delay_ms(350);
19
mon1++;
20
}
21
22
y1=4;// Monate-Zehner -- Schema siehe oben
23
y2=0;
24
mon2=-1;
25
lcd_gotoxy(0,0);
26
lcd_puts("Monat Zehner****");
27
lcd_gotoxy(y1,1);
28
lcd_putc(y2+0x30);
29
30
if(mon1>3)// wenn März bis September
31
{
32
y2=0+0x30;
33
lcd_gotoxy(y1,1);
34
lcd_putc(y2);
35
}
36
else// sonst Wahl des Zehner-Monats
37
{
38
while(bit_is_set(PIND,PD3));
39
while(bit_is_clear(PIND,PD3))
40
for(mon2=0;mon2<2&&bit_is_clear(PIND,PD3);)
41
{
42
y2=mon2+0x30;
43
lcd_gotoxy(y1,1);
44
lcd_putc(y2);
45
_delay_ms(350);
46
mon2++;
47
}
48
49
}
50
// Berechnen des Monats als Integer
51
month_complete=((mon2*10)+mon1);
52
}
Das Problem ist nun, dass wir nach Einstellen des Monats überprüfen
wollten, ob 00 eingegeben wurde. Falls ja, soll die Funktion erneut
aufgerufen werden, um das ganze korrigieren zu können. Wir hatten dies
mit einer do-while, while und einer if-Probiert. Alle drei Möglichkeiten
werden entweder komplett ignoriert oder es blieb in der Schleife
hängen.
Das Ganze sah so aus:
1
if(month_complete==0)
2
setMonth();
oder
1
do{setMonth();}while(month_complete==0);
Beim Einstellen der Tage gibt es dann genau dasselbe Problem: es bleibt
hängen oder die Bedingung wird ignoriert.
Ich hoffe ich hab alle Infos, die ihr braucht, und alles verständlich
beschrieben. Wenn nicht, meldet euch einfach.
Ganz lieben Dank,
fimami!
Fritz Müller schrieb:> Ich hoffe ich hab alle Infos, die ihr braucht
Nein. Das sind nur Schnipsel. Es ist nicht klar, wo und wie die
darin benutzten Variablen deklariert sind.
Schlechter Stil ist es obendrein, denn offenbar wird selbst die
popeligste lokale Variable irgendwo „weit weg“ global deklariert.
Eine Deklaration der Form
1
voidfoo();
ist in C etwas anderes als eine der Form
1
voidfoo(void);
(In C++ sind beide gleich.) Erstgenannte Form sollte man sich in C
grundsätzlich gar nicht erst angewöhen.
Timm Reinisch schrieb:> Und da sieht Dein Dozent keinen Fehler? Hmm...
Wer durch diese negiert-negierte Logik noch durchsteigt, gewinnt
einen Preis. :-)
Fritz Müller schrieb:> Ich hoffe ich hab alle Infos, die ihr braucht
Nicht wirklich.
EIn komplettes testbares Programm wäre besser.
Lasst euch halt mal den Zahlenwert der Variablen wo ausgeben. Dann wisst
ihr exakt was da drinnen steht.
PS: Das ganze wäre wesentlich einfacher, wenn ihr nicht nach Einern und
Zehnern trennen würdet. Bei 2-stelligen Zahlen, gerade in dem Bereich
wie sie bei Uhren vorkommen, lohnt das nicht wirklich. Da ist das
rumfummeln mit Einern und Zehnern sowohl für einen Benutzer als auch im
Programm komplizierter, als wenn bei den Monaten einfach die Zahlen von
1 bis 12 durchlaufen. Eine ordentliche Zahlenausgabefunktion, die
2-stellige Zahlen an eine bestimmte Position am LCD ausgeben kann und
nicht dieses Gefrickel wie da im Code und die Sache ist zu 70% gegessen.
Und der Codelänge würde das auch zugute kommen. Denn gerade bei einer
Uhr braucht man so eine Funktion an allen Ecken und Enden. Genauso wie
eine ordentliche Tasten-Funktion und nicht dieses Pin_set Pin_Clear
Gefrickel von da oben.
Hier mal das komplette Programm. Mir ist bewusst, dass es teilweise noch
nicht vollständig ist. Im Prinzip geht es nur um den Teil bis "Uhr
stellen".
Der leapyeartester müsste aber eigentlich gehen, das ist eine Ausnahme
mit einer Ausnahme von der Ausnahme :D Lass mich gerne eines besseren
belehren.
Das mit dem Haufen an globalen Variablen war im Endeffekt nur eine
Notfalllösung, da wir dachten es gäbe u.U. Probleme mit
Gültigkeitsbereichen.
lg und vielen vielen Dank für die schnellen Antworten, bin zwar noch
dezent überfordert aber vielleicht legt sich das ja noch :)
Jörg Wunsch schrieb:> Timm Reinisch schrieb:>> Und da sieht Dein Dozent keinen Fehler? Hmm...>> Wer durch diese negiert-negierte Logik noch durchsteigt, gewinnt> einen Preis. :-)
meinst Du meinen Satz oder die If-Anweisung?
Ich hätte halt Bedenken, ob man einen uint8_t wirklich sinnvoll modulo
400 rechnen kann.
Habe ich da jetzt einen Denkfehler? Doch wohl nicht?
Vlg
Timm
Timm Reinisch schrieb:> Ich hätte halt Bedenken, ob man einen uint8_t wirklich sinnvoll modulo> 400 rechnen kann.> Habe ich da jetzt einen Denkfehler? Doch wohl nicht?
Wir hatten jetzt ca 18 Stunden Microcontroller, davon waren 50% unnütz
für unseren Code. Also wenn du das sagst, glaub ich dir das :) Was wäre
denn eine Alternative?
Euer Code ist FURCHTBAR!
Das da keiner mehr durchblickt wundert mich nicht.
Macht mal eure Hausafgaben und schreibt euch für immer wiederkehrende
Teile eigene Funktionen! Zb die Ausgabe von 2-stelligen Zahlen ist so
ein immer wieder kehrender Baustein. Und da finden sich noch viele
andere Dinge.
Die Monatseinstellung mit einem ordentlichen Unterbau an Funktionen bzw.
Funktionalität kann so einfach sein wie
Fritz Müller schrieb:> Wir hatten jetzt ca 18 Stunden Microcontroller, davon waren 50% unnütz> für unseren Code. Also wenn du das sagst, glaub ich dir das :) Was wäre> denn eine Alternative?
Was die Jungs dir damit sagen wollen, ist, das uint8_t (1 Byte) einen
max. Wert von 255 haben kann.
Ein module 400 darauf macht nun wirklich keinen Sinn. Was soll den genau
in Year genau stehen? (ich habe mir nicht den ganzen Code durchgesehen).
Grüsse,
R.
Karl Heinz Buchegger schrieb:> Und da braucht man noch nicht mal testen, was der Benutzer eingegeben> hat, weil er gar keine Möglichkeit hat, einen ungültigen Monat> einzugeben.
doch mit diesen code schafft man es eine 0 einzugeben:
müsste doch bestimmt
if( month == 13 )
month = 1;
sein.
Jörg Wunsch schrieb:> void foo();>> sollte man sich in C grundsätzlich gar nicht erst angewöhen.
Hilfreich sind dabei die Optionen
-Werror=strict-prototypes
-Werror=missing-prototypes
Bleibt die Frage, warum tolle GUIs wie AVR Studio diese nicht setzen...?
Ja das macht irgendwie Sinn..sorry, muss geändert werden.
Aber das kann ja nicht Grund für das Problem sein, das leapyeartester
wird ja zu dem Zeitpunkt noch gar nicht aufgerufen.
kbuchegg..ja das mag sein aber dazu fehlt es uns einfach an Übung und am
nötigen "Wortschatz". Dein Vorschlag klingt natürlich irgendwie besser
und auch mehr auf den Punkt gebracht, jedoch übertrifft das unsere
bisherigen Kenntnisse um einiges.
>> Beim Einstellen der Tage gibt es dann genau dasselbe Problem: es bleibt> hängen oder die Bedingung wird ignoriert.
do_while:
wenn "setMonth()" "month_complete" nicht ändert, rutscht er einmal durch
die Schleife. Vor_ oder _in setMonth muss month_complete also auf !=0
gesetzt werden und falls "00" eingegeben wird auf =0 gesetzt werden.
if:
month_complete muss vorher !=0 sein, des weiteren müsst noch ne Schleife
drumherum mit Abbruchbedingung =0
Hallo Fritz,
ich habe mal drüber geschaut. Generell solltet ihr nochmals durch den
Code (wenn ihr aus Zeitnot/druck nicht alles nochmals schreiben wollt)
und euch überlegen, welche Maximalwerte die Variabeln annehmen können.
Beispiel:
1
uint8_tyear_complete=0;// Jahr als Integer
später:
1
// Berechnen der Jahreszahl als Integer
2
year_complete=(2000+(j2*10)+j1)
year_complete wrd somit schon mal grösser wie 2000 ==> uint16_t nehmen.
Grüsse,
R.
Im Prinzip haben wir noch knapp 3 Wochen Zeit, jedoch ist Semesterende
und es ist nicht die einzige praktische Arbeit, welche abgegeben werden
muss - ganz abgesehen von den Klausuren.
Ihr habt uns auf jeden Fall schonmal sehr geholfen!
** Lötlackl schrieb:> Das da habe ich mal irgendwo in einem Codefetzen von Jörg Wunsch> gefunden.
Wirklich von mir? Kann ich mich gar nicht mehr erinnern. ;-)
Tststs, mittlerweile ist in der avr-libc eine total umfangreiche
time-Bibliothek mit drin, die würde natürlich derartige „Gurken“
gleich von vornherein vermeiden. Gibt's aber noch keinen Release
davon (ja, ich weiß, ist lange überfällig).
Fritz Müller schrieb:> Der leapyeartester müsste aber eigentlich gehen, das ist eine Ausnahme> mit einer Ausnahme von der Ausnahme :D Lass mich gerne eines besseren> belehren.
Setz doch mal das Jahr 2012 - nachdem die Jahreszahl von 8 auf 16bit
erweitert wurde - ein, das ja zweifelsfrei ein Schaltjahr war:
2012%400 = 12 --> Bedingung gibt 0 zurück und damit wird der ganze
Ausdruck unabhängig vom Ausdruck hinter dem && zu 0, weil 0 && x = 0.
Die Bedingung für ein Schaltjahr heißt: (Jahreszahl muss durch 4 teilbar
sein UND nicht durch 100) ODER (durch 400). Die Klammern stehen da rein
zufällig ;-).
Nachtrag: War wohl zu langsam...
Jörg Wunsch schrieb:> Wirklich von mir? Kann ich mich gar nicht mehr erinnern. ;-)
Man, bin ich doof. Der Gute, von dem ich klaute, hieß Martin Thomas.
Gerade noch mal nachgesehen. :-(
Euer Leerkörper hat euch auch strikt verboten, unter Androhung von
Punktabzug, nie nicht auf keinen Fall vor der Umsetzung mit der
Programmiersprache ein
Nassi-Shneiderman-Diagramm
oder einen
Programmablaufplan
anzufertigen.
Der Arbeitsmarkt freut sich schon auf solch hoch qualifizierte
Fachkräfte. Wenigsten sind die dann billig zu haben.
Grüsse
Ablaufplan steht, aber bringt uns in diesem Fall auch nicht weiter.
Das Kernproblem ist ja, dass die Schleifen und if-Anweisungen in keinem
Fall richtig durchgeführt werden. Einzig while(1) scheint zu
funktionieren.
Das Komische: nach dem compilieren und 'rüberschicken per Khazama hat es
einige Male perfekt funktioniert. Nach einem einfachen Reset ging es
erneut nicht.
>> Mein Delphi würde das anmeckern.
C ist auch nicht Pascal. :-) Wofür allerdings das überflüssige
Element überhaupt erst allokiert wird, bleibt ein Rätsel. Element 0
kann man natürlich genauso einsparen, indem man dann beim Zugriff
jeweils 1 abzieht.
Da ist das Array nun schon mal eine lokale Variable, dann wird sie
aber auch noch als Speicherklasse “auto” angelegt, was in diesem
Falle wenig sinnvoll ist … “static” wäre hier angebrachter, und
eigentlich kann man sich auch gleich “static const” für sowas
angewöhnen.
Jörg Wunsch schrieb:> Eine Deklaration der Form> void foo();>> ist in C etwas anderes als eine der Form> void foo(void);
Wo liegt denn genau der Unterschied?
Ich habe irgendwas gefunden bezüglich alten Stil aber nicht genau
herausgefunden wo der Unterschied ist.
@Fritz
Setze doch das alles mal um, zu was dir hier geraten wurde. Dann bring
etwas Leserlichkeit/Ordnung in den Code. Zum Beispiel:
statt:
1
y2=t2+0x30;
so:
1
y2=t2+0x30;
Vor if/while was auch immer eine Leerzeile etc. (schau dir Beispielcode
an).
Wenn Du dann immer noch Probleme hast, bekommst Du hier sicher
Hilfestellung auf konkrete Fragen (und selbstverständlich auch den einen
oder anderen unsachlichen Kommentar, etwas Blutgeld für die Hilfe muss
man in Kauf nehmen ;-)).
Grüsse,
René
godi S. schrieb:> Jörg Wunsch schrieb:>> Eine Deklaration der Form>> void foo();>>>> ist in C etwas anderes als eine der Form>> void foo(void);>> Wo liegt denn genau der Unterschied?> Ich habe irgendwas gefunden bezüglich alten Stil aber nicht genau> herausgefunden wo der Unterschied ist.
void foo() ist eine Funktion, deren Übergabeparameter nicht definiert
sind. Man kann ihr also irgendwas übergeben.
void foo(void) ist eine Funktion, die laut Definition keine
Übergabeparameter besitzt. Übergibt man ihr etwas, meckert der Compiler.
Rene H. schrieb:> @Fritz>> Setze doch das alles mal um, zu was dir hier geraten wurde. Dann bring> etwas Leserlichkeit/Ordnung in den Code. Zum Beispiel:>> statt:>>
1
>y2=t2+0x30;
2
>
>> so:>>
1
>y2=t2+0x30;
2
>
Noch besser
1
y2=t2+'0';
Aber eigentlich sollte das Ausgeben einer 2-stelligen Zahl sofort mal in
eine Funktion verschwinden. Schon alleine das würde den Code über den
Daumen um mindestens 30% schrumpfen lassen.
Peter II schrieb:> Karl Heinz Buchegger schrieb:>> Und da braucht man noch nicht mal testen, was der Benutzer eingegeben>> hat, weil er gar keine Möglichkeit hat, einen ungültigen Monat>> einzugeben.>> doch mit diesen code schafft man es eine 0 einzugeben:>> müsste doch bestimmt>> if( month == 13 )> month = 1;>> sein.
Mist. Punkt für dich.
> Das Kernproblem ist ja, dass die Schleifen und if-Anweisungen in keinem Fall
richtig durchgeführt werden.
Das Kernproblem ist, dass in diesem Codewust irgendwo ein Hund steckt,
den man aber ob der schieren Code-Übermacht nicht findet. Der Code
erschlägt einen förmlich.
Den muss man jetzt erst mal ein wenig strukturieren und in kleinere
Abschnitte aufteilen - sprich in Funktionen gruppieren, die überschaubar
sind und bei denen man durch blosses hinsehen schon sagen kann: das
passt.
Hier mal die verbesserte Version..zumindest bis Datum und Uhrzeit
eingestellt sind. Hatte leider keinen Compiler zur Hand, aber dürfte
schonmal besser sein als vorhin :)
Fritz Müller schrieb:> Hier mal die verbesserte Version..zumindest bis Datum und Uhrzeit> eingestellt sind. Hatte leider keinen Compiler zur Hand, aber dürfte> schonmal besser sein als vorhin :)
Ich geb zu, ich hab mir nur eine Zeile angeschaut:
1
if((year%400==0)&&!((year%100==0)&&!(year%4==0)))
Teste die bitte mal mit verschiedenen Jahreszahlen aus. Bei 2000
stimmts, bei 2004 stimmts nicht mehr. Da ist noch ein Knoten in der
Formel...
stimmt. dann hat ich das falsch in Erinnerung. Dann versuch ich mich mal
an euren Vorschlägen :)
Danke!
edit: geht! Danke an alle, welche das korrigiert hatten und sorry, dass
ich da nicht einsichtig war ;-)
while(bit_is_clear(PIND,PD3))// Bei Tastendruck...
7
for(m=0;(m<60)&&
8
bit_is_clear(PIND,PD3);)
9
{
10
showNumber(12,1,m);
11
_delay_ms(350);
12
m++;
13
}
(ich hab jetzt mehr zufällig die Minuten herausgegriffen)
... ist für die Eingabe von Zahlen immer der gleiche. Einzig die
Vergleichszahl für die höchste zulässige Zahl ist immer anders.
-> Ab in eine FUnktion mit der kompletten Funktionalität
und du hast den Vorteil, dass du den kompletten Bereich, wie
Benutzereingaben eigentlich funktionieren, an einer Stelle beisammen
hast. Wenn dir die Systematik nicht mehr gefällt, dann änderst du sie an
EINER Stelle ab und ALLE Eingaben funktionieren dann automatisch alle
gleich nach deinem neuen Schema.
Hehe..ja das dacht ich mir anfangs auch - wenn ich schon dabei bin. War
nur ehrlich gesagt zu faul nach dem ganzen Informatik heute (3 Stunden
verzweifelt vor AVR Studio gesessen, 2 weitere nur halbwegs verzweifelt
und dann noch 2 Stunden Java-GUI...bei dem schönen Wetter;-))
Vielen Dank! Das macht doch gleich viel mehr her!
Würde ja sagen "hast was gut", aber ich wüsste nicht wie ich mich
revanchieren sollte.
Sonst? Im Vergleich zum Anfang ein Tick besser?
p.s.
müsste folgendermaßen heißen oder?
h = getNumber( "-----Stunden----" , 9, 1, 0, 23 );
Hallo Fritz,
ich habe den Code nur kurz angeschaut, sauber, um Welten besser. Noch
etwas zur Lesbarkeit, versuche Sequenzblöcke optisch abzuheben. Also
auch nach einem if (xxx) { } eine Leerzeile.
Vieles wurde sonst bereits gesagt (ich habe morgen ein Interview und
kann mich jetzt fachlich nicht reinhängen).
Sourcecode ist nie einfach funktional, er muss auch optisch ohne ihn zu
verstehen etwas hergeben. Man schaut ihn an und es sieht einfach
aufgeräumt aus.
Ach noch was, bei einem Funktionsaufruf, nach dem Komma immer ein Space,
also Func(a, b).
Grüsse,
R.
Danke dir!
Werde im Laufe der nächsten Tage noch den Wecker einbauen, das sollte
aber vermutlich keine Komplikationen mehr bereiten und es dann mal auf
den Atmega hauen.
Wünsch dir für morgen viel Erfolg und Spaß beim Interview!
Ich verabschiede mich für heute auch!
lg
Fritz Müller schrieb:>> Vielen Dank! Das macht doch gleich viel mehr her!> Würde ja sagen "hast was gut", aber ich wüsste nicht wie ich mich> revanchieren sollte.>
Die Hilfestellungen von Karl-Heinz sind hier im Forum beinahe Legendär.
Er macht das einfach so. Ich bin längst (Jahre...) beeindruckt ob dem
Engagement.
Ein Kompliment an der Stelle an die Moderatoren hier, das ist nicht
selbstverständlich in der Ausführlichkeit!
Grüsse,
René
Rene H. schrieb:> Ein Kompliment an der Stelle an die Moderatoren hier, das ist nicht> selbstverständlich in der Ausführlichkeit!
Dem muss ich mich gleich anschließen. Auch natürlich an den Rest ein
herzliches Danke! Weiß das echt zu schätzen. Wenn jemand Hilfe in
HTML/CSS benötigen sollte, kann ich ja vielleicht was gutes tun ;-D
Rene H. schrieb:> Die Hilfestellungen von Karl-Heinz sind hier im Forum beinahe Legendär.> Er macht das einfach so. Ich bin längst (Jahre...) beeindruckt ob dem> Engagement.>> Ein Kompliment an der Stelle an die Moderatoren hier, das ist nicht> selbstverständlich in der Ausführlichkeit!
dem möchte ich mich auch mal anschließen !
Manchmal lese ich ich Threads durch und mitten im Text denk ich, so wie
das erklärt wird, kann es nur Karl-Heinz sein und meist bestätigt sich
das dann auch.
Hat mir schon oft geholfen, vielen Dank dafür.
Holger
Fritz Müller schrieb:> Die Compiler-Einstellungen sind auf -0O und -0S, in beiden Einstellungen> ging es nicht. Auch unser Dozent ist überfragt und somit seid ihr unsere> letzte Hilfe.
Möglicherweise weil die Einstellungen -O0 und -Os lauten?
Hat jemand eine Idee, warum mein Compiler mit
lcd_puts("Uhr 00:00:00");
kein Problem hat, aber dafür mit folgendem?
lcd_puts("00:00:00");
Gibt's da Probleme wegen der '0' am Anfang?
Lg
Ich dachte ich melde mich zum Schluss nochmal.
Programm lief soweit, einige Kleinigkeiten mussten noch geändert werden.
Jetzt läuft alles, wie es von Anfang an geplant war. Besteht auf jeden
Fall Motivation da weiter zu machen und mich auch weiterhin damit zu
beschäftigen.
Lg das Team