Hallo,
ich bin Jochen und versuche mich gerade an einem kleinen Projekt.
Ich habe das Buch von Herrn Günter Spanner.
"AVR-Mikrokontroller in C programmieren"
Darin sind einige Beispielprojekte, an welchen ich mich so nach und nach
versuche.
Ich bin gerade dabei eine Tischuhr zu bauen.
Die Uhr gibt nur Stunden Minuten und Sekunden aus.
Der Programmcode, mit welchem meine Uhr soweit schon läuft sieht wie
folgt aus.
#include<lcd/lcd-routines-portd.h> // greift auf LCD-routine zu
8
#include<lcd/lcd-routines.c> // greift auf LCD-routine zu
9
#include<stdio.h>
10
11
#define TASTER1 PB0
12
#define TASTER2 PB1
13
#define TASTER3 PB2
14
#define TASTER4 PD7 // eventuell umlöten auf PB3-->(ISP)!
15
16
17
volatileinttc;
18
charhr=20,min=0,sec=0;
19
charstr[2];
20
21
22
ISR(TIMER1_OVF_vect)//1 second clock
23
{
24
TCNT1=34286;tc++;
25
}
26
27
intmain(void)
28
{
29
30
TIMSK|=_BV(TOIE1);// aktivate overflow interrupt of timer1
31
TCCR1B|=(1<<CS12);// prescaler = 256
32
TCNT1=0xFFFF;// FFFF for start
33
lcd_init();
34
lcd_clear();
35
lcd_setcursor(1,1);
36
lcd_string("00:00:00");
37
sei();
38
39
//*************UHR****************
40
41
sec=tc;
42
if(sec==60)
43
{
44
tc=0;
45
sec=0;
46
min++;
47
if(min==60)
48
{
49
min=0;
50
hr++;
51
if(hr==24)
52
{
53
hr=0;
54
}
55
}
56
sprintf(str,"%02d",min);
57
lcd_setcursor(4,1);
58
lcd_string(str);
59
60
sprintf(str,"%02d",hr);
61
lcd_setcursor(1,1);
62
lcd_string(str);
63
}
64
sprintf(str,"%02d",sec);
65
lcd_setcursor(7,1);
66
lcd_string(str);
67
//********************************
68
69
70
}
71
return0;
72
}
Dieser Code stammt auch aus dem Buch.
Eine weitere Aufgabe, welche man sich stellen soll ist die Verwendung
von Tastern, mit welchen man die Uhr stellen soll.
Ich habe nun schon etliche Versuche gestartet nur leider bekomme ich es
irgendwie nicht hin.
Kurze Frage:
Mit sei(); wird ja ein Interrupt aufgerufen. Warum steht am Ende dann
nicht cli(); ? Das Hauptprogramm läuft doch pausenlos durch.
Nun ja, ich habe 4 Taster definiert:
[c]
#define TASTER1 PB0
#define TASTER2 PB1
#define TASTER3 PB2
#define TASTER4 PD7
[c/]
Mit Taster1 möchte ich die Stunden hochzählen und mit Taster2 die
Minuten.
Mit Taster3 oder 4 soll das ganze bestätigt werden.
Ich hoffe ihr könnt mir etwas helfen, für Ideen und Vorschläge wäre ich
sehr Dankbar
schöne Grüße Jochen
MaWin schrieb:> Nein. Freigegeben.
Gut, aber was macht den unterschied ob ich cli(); am Ende setze oder
nicht.
Ich hab es ja schon ausprobiert, jedoch läuft die Uhr dann nur einmal
und bleibt bei 00:00:01 stehen.
Hm, warum stelle ich die Frage eigentlich erklärt sich ja von selbst ;)
sei();
cli();
wird beim ersten Durchlauf Freigegeben und danach geschlossen.
nur sei();
wird bei jedem Durchlauf des Hauptprogrammes Freigegeben.
> lcd_string("00:00:00");> sei();>>//*************UHR****************>> sec=tc;> if(sec==60)> {
Nach dem sei() und vor dem sec=tc fehlt mindestens eine Zeile!
Nämlich die Anweisung, dass eine Endlosschleife beginnen soll, also ein
while(1){ oder ein for(;;){
Das Abfragen von Tastern ist im AVR-GCC-Tutorial erklärt und man muss
den Artikel Entprellung beachten.
Vergiss erstmal die Uhr. Wichtiger ist eine ordentliche Programmstruktur
(funktionell + 'ästhetisch'). Wenn ich bei den bunt durcheinander
gewürfelten Klammern nicht wieder eine übersehen habe: der Code geht
nicht mal durch den Compiler.
Jochen schrieb:> Ich hab es ja schon ausprobiert, jedoch läuft die Uhr dann nur einmal> und bleibt bei 00:00:01 stehen.
Das hast du auch so programmiert! Ein Funktionsaufruf (hier zuuufällig
'main') und dann Schluss.
Krapao schrieb:> Nach dem sei() und vor dem sec=tc fehlt mindestens eine Zeile!
Hi Krapao,
ja klar die while(1) hatte ich vergessen, da ich den Code aus meinem
"Versuchscode" rauskopiert habe. die while(1) ist aber vorhanden.
Die Entprellung habe ich auch aus dem vorgeschlagenem Artikel.
Habe ihn auf meinen Taster zurecht geschnitten, jedoch noch nicht
getestet.
Habe ich damit grundlegend was falsch gemacht?
Er steht im Code genau vor der "main" Funktion.
Ich bin mir aber unsicher, ob es sich um den Code nur um die Flanken
handelt, oder ob die Prellung damit gleichzeitig "weg ist"
1
#define TASTER1 PB0
2
3
chartaster(void)
4
{
5
staticunsignedcharzustand;
6
charrw=0;
7
8
if(zustand==0&&!(PINB&(1<<TASTER1)))//Taster wird gedrueckt (steigende Flanke)
9
{
10
zustand=1;
11
rw=1;
12
}
13
elseif(zustand==1&&!(PINB&(1<<TASTER1)))//Taster wird gehalten
14
{
15
zustand=2;
16
rw=0;
17
}
18
elseif(zustand==2&&(PINB&(1<<TASTER1)))//Taster wird losgelassen (fallende Flanke)
Schreib ein kleines Zählerprogramm. Dann siehst du, ob die Entprellung
funktioniert. Jeder Tastendruck muss sauber einen Zählschritt machen.
Teile des Zählerprogramms kannst du später für das Stellen der Uhrzeit
rezyklieren. Das Stellen von Stunde/Minute ist auch nix anders als ein
Hochzählen von 0-23 bzw. 0-59.
Hier mal mein Code für das Zählprogramm.
Er ist sicher Klobig und Grob in euren Augen, jedoch bekomme ich so das
Zählen hin.
Das Problem ist dabei nur, dass der Taster ab und an nicht richtig
funktioniert und man muss 3x dücken, bevor sich was tut.
Was mich interessiert ist, ob ich den "Entprellcode" und die "Flanken"
richtig eingefügt habe?
Verbesserungsvorschläge sind natürlich gerne gesehen ;)
Du hast ein Mischmasch aus zwei Versionen :-(
1) char taster(void)
Das ist nur Beiwerk im Programm. Toter Code der nirgends aufgerufen
wird.
2) Sieht gut aus:
entprellung( &PINB, (1<<PB0) );
if( PINB & (1<<PB0) )
3) while(PINB & (1<<PB0))
"So lange wie eine Taste gedrückt ist, mache..." macht mir
programmlogisch keinen Sinn, wenn pro Tastendruck ein Zähler hochzählen
soll. Diese Funktionalität hast du bereits durch das while(1) in
Verbindung mit dem Konstrukt aus 2) weil die entprellung() dort nicht
auf das Loslassen der Taste besteht.
Du musst auch beachten, dass dein Programm durch zu viele LCD Ausgaben
träge reagiert. Mache die Ausgaben nur, wenn sich tatsächlich etwas
geändert hat.
Jochen schrieb:> entprellung( &PINB, (1<<PB0) ); // ggf. Prellen abwarten> if( PINB & (1<<PB0) ) // dann stabilen Wert einlesen
Das stimmt nicht.
Deine Entprellung macht es nur etwas warscheinlicher, daß der Zustand
danach stabil ist, sie garantiert es aber nicht.
Er kann sich zufällig gerade danach ändern.
Deine Muskeln sind ja nicht mit dem CPU-Takt synchronisiert.
Es ist deshalb deutlich zuverlässiger, wenn die Entprellung selber den
stabilen Zustand zurückgibt, denn genau dafür ist sie ja da und nur sie
kann es auch feststellen.
Programme, die wild umher den Zustand von außen neu einlesen, können die
wunderlichsten Überrraschungen erleben.
Außerdem ist das nur unnütz zusätzlicher Code.
Es gibt nur eine Instanz, die den Pin einlesen darf und das ist der
Entpreller.
Alle anderen haben stricktes Verbot den Pin direkt einzulesen, sie
dürfen nur den aufbereiteten Wert des Entprellers verwenden.
Peter
Krapao schrieb:> 3) while(PINB & (1<<PB0))>> "So lange wie eine Taste gedrückt ist, mache..." macht mir> programmlogisch keinen Sinn, wenn pro Tastendruck ein Zähler hochzählen> soll. Diese Funktionalität hast du bereits durch das while(1) in> Verbindung mit dem Konstrukt aus 2) weil die entprellung() dort nicht> auf das Loslassen der Taste besteht.
(siehe unten)
1
>charstr[2+1];// <=== War vorher zu klein für zwei Dezimalstellen!
Hm..hat vorher aber auch funktioniert, jedenfalls die Ausgabe auf dem
Display.
habe deinen Code einfach mal so übernommen und getestet;)
Ich weiß nun nicht ob es deine Absicht war ihn funktionsfähig zu
machen..., jedoch laufen die Zahlen beim gedrückt halten ununterbrochen
weiter.
Ist ja eigentlich logisch da while(1)... Die Schleife interessiert es ja
nicht ob ich den Taster gedrückt halte oder nicht?
..und nochmal..tut mir leid^^
durch das einbringen von while(PINB & (1<<PB0)) in die while(1) deines
Codes läuft das hochzählen nun tadellos!
Was spricht dagegen es nicht zu verwenden? Meine Erfahrung in Sachen C
sind einfach, dass es immer einen Hacken gibt. Also raus mit der Sprache
;)
Jochen schrieb:> Was spricht dagegen es nicht zu verwenden? Meine Erfahrung in Sachen C> sind einfach, dass es immer einen Hacken gibt. Also raus mit der Sprache> ;)
Probier mal folgendes zu programmieren:
1.
Nimm 2 LEDs und 2 Tasten, können aber auch mehr sein.
Beim Drücken einer Taste wechselt die dazu gehörende LED.
Beim gedrückt Halten, Loslassen oder ungedrückt passiert nichts.
Jede Taste arbeitet unabhängig. Also auch wärend die andere Taste
gedrückt gehalten wird, funktioniert sie.
2.
Jetzt simulieren wir eine hohe CPU-Last und bauen 500ms Delay in die
Mainloop ein.
Alles muß weiterhin funktionieren, ohne daß man 500ms lang drücken muß.
Lediglich die LEDs reagieren bis zu 500ms verzögert.
Eine gute Entprellroutine muß das können, keinen Tastendruck verlieren
und keinen Preller durchlassen.
Es ist nunmal so, daß man im Web alles veröffentlichen kann, also auch
Entprellroutinen, die deutliche Nachteile haben.
Es gibt keinen Oberlehrer, der dann diese Beiträge löscht.
Man muß also ganz genau lesen und auch die Erfahrungen anderer, was
diese so benutzen.
Man sollte auch versuchen, daß die Geräte auch nach einem Jahr noch
einwandfrei funktionieren, wenn die Federspannung nachläßt oder die
Kontakte verschmutzen.
Eine Entprellroutine testet man am besten mit alten Tastern, die man aus
Geräten ausgebaut hat, die lange (10 Jahre) und häufig benutzt wurden.
Mit fabrikneuen Tastern kann man die Qualität der Entprellsoftware nicht
feststellen.
Peter
Hallo Peter,
klar habe ich auch deinen Code gesehen.
Würde ihn auch gerne benutzen, jedoch nutzt er einen Takt, welchen meine
"Uhr" nicht nutzt.
Der Quarz schwingt mit 8MHz, der Entprellcode von dir nutzt aber eine
andere Frequenz, habe nun nicht mehr im Kopf welche.
Und genau deshalb habe ich einen Bogen um deinen Code gemacht, weil ich
mich dort wieder in Gefilde begebe, von denen ich noch etwas weit
entfernt bin ;)
Deinen Vorschlag mit den Tastern und den LED's werde ich versuchen
morgen umzusetzen.
Dennoch ist mir in letzter Zeit aufgefallen, dass die Verwendung von
Schleifen doch noch etwas Unklarheit bei mir hervorruft.
Ich habe mich natürlich auch belesen und weiß was eine Schleife macht,
verwende sie ja nicht das erste mal. ....Dennoch müsste mein Programm
doch laufen, doch dann tut sich doch nichts.
Ich beschreibe einfach einmal kurz wie ich die verschiedenen Schleifen
definiere. Wenn es da Differenzen gibt, klärt mich auf!
while(1) Endlosschleife, läuft von oben nach unten und immer so weiter.
Jede Schleife die danach kommt wird deshalb nicht erfasst.
while(Bedingung) Schleife läuft sobald die Bedingung erfüllt wird.
So lange die Bedingung erfüllt ist läuft sie weiter. Wenn die Bed. nicht
erfüllt ist, wird die Schleife ignoriert.
do while(Bedingung) im Gegensatz zur while() Schleife ist diese
Fußgesteuert. d.h. die Schleife läuft so lange durch, bis die Bedingung
erfüllt wurde.
for(;;) z.B. for(int i=0 ; i<=10 ; i++){ cout << i;} i wird so lange
gezählt, bis es den Wert 10 erreicht hat, dann geht die Schleife "zu".
> durch das einbringen von while(PINB & (1<<PB0)) in die while(1) deines> Codes läuft das hochzählen nun tadellos!>> Was spricht dagegen es nicht zu verwenden? Meine Erfahrung in Sachen C> sind einfach, dass es immer einen Hacken gibt. Also raus mit der Sprache> ;)
Die zweite while-Klammer bewirkt, dass der Taster losgelassen werden
muss, damit der Anweisungsblock wieder betreten werden kann. Ich habe
das im Beitrag "Re: Uhrzeit stellen" falsch
gesehen.
Ohne das while hat der Taster also eine Autorepeat-Funktion, deren
Geschwindigkeit man mit Delays tunen könnte; mit dem While muss jeder
Zählschritt einzeln betätigt werden.
Das war zwar nicht meine Absicht beim Schreiben, kann man aber
vielleicht brauchen. Mein Wecker aus dem Kaufhaus hat eine
Autorepeatfunktion beim Uhrzeit stellen.
Beiss dich in die saubere Entprellung rein. Mit seinen Tipps hat Peter
Recht. Das brauchst du immer mal für angenehm funktionierende Geräte.
Hi Krapao,
wird gemacht, wie gesagt versuche ich mich morgen daran.
Kannst du mir noch etwas zu den Schleifen sagen, welche ich einen Post
vorher gepostet habe?
Hab nochmal was probiert und deinen Tip eingebaut.
so könnte man es auch machen, finde es sogar recht praktisch, so kann
man den Taster betätigen und so lange gedrückt halten bis man auf der
gewünschten Zeit ist...
Diese Funktion ist mir bekannt, aber selbst auf sowas zu kommen ist für
mich wirklich schwer!
Jo, so steht's beim while und for in jedem C-Lehrbuch drin :-)
Bei deinem for-Beispiel ist das cout << i; kein C sondern C++
Wenn du das for-Beispiel in ein while-Beispiel umformen willst:
1
for(inti=0;i<=10;i++)
2
{
3
...Anweisungen...
4
}
wird daraus
1
{
2
inti=0;
3
while(i<=10)
4
{
5
...Anweisungen...
6
i++;
7
}
8
}
> do while(Bedingung) im Gegensatz zur while() Schleife ist diese> Fußgesteuert. d.h. die Schleife läuft so lange durch, bis die Bedingung> erfüllt wurde.
Nicht ganz. Der Anweisungsblock wird durchlaufen, dann wird die
Schleifenbedingung geprüft. Wenn die Schleifenbedingung wahr ist, wird
der Anweisungsblock wieder durchlaufen. Ist die Schleifenbedingung
falsch, wird die do/while Schleife verlassen. Also nicht "Mache ... bis
Bedingung wahr ist" sondern "Mache ... solange Bedingung wahr ist"
Jupp alles klar und es ist auch richtig, dass wenn z.B.
main()
{
while(1) Endlosschleife läuft unendlich
{
xxxxx
}
for(xx) Da while eine Endlosschleife, wird diese völlig ignoriert
{
xxxxx
}
}
Jochen schrieb:> klar habe ich auch deinen Code gesehen.> Würde ihn auch gerne benutzen, jedoch nutzt er einen Takt, welchen meine> "Uhr" nicht nutzt.
Und wo ist dabei das Problem?
Dein unbekannter AVR hat bestimmt mehrere Timer und diese wiederum
jeweils mehrere Compare-Interrupts.
Du kannst also haufenweise verschiedene Timerintervalle erzeugen.
Aber auch mit nur einem Timer geht das. Das kürzere Intervall legt man
einfach so, daß das längere durch ein Vielfaches erzeugt werden kann (=
Zählvariable). Und die Entprellzeit benötigt ja keinen exakten Wert,
irgendwas im Bereich 5..50ms ist ok.
Jochen schrieb:> ISR(TIMER1_OVF_vect) //1 second clock> {> TCNT1 = 34286; tc++;> }
Das solltest Du besser schnell wieder vergessen, denn jedes Programm
benötigt Ausführungszeit, auch ein Interrupt.
Zusätzlich können Interrupts durch andere Interrupts oder atomare
Codesequenzen verzögert werden.
Diese Zeiten werden hier nicht berücksichtigt.
Wird Dein Programm größer, d.h. hat mehr zu tun, kann Deine Uhr
nachgehen.
Wie kommst Du überhaupt auf diese komischen 34286?
8e6 / 256 = 31250
Peter
Peter Dannegger schrieb:> Wie kommst Du überhaupt auf diese komischen 34286?> 8e6 / 256 = 31250
Hallo Peter,
wie gesagt ist die Uhr aus einem Buch komplett herauskopiert worden.
Benutzt wird ein ATmega8.
Hier mal der komplette Uhrencode.
Als Aufgabenstellung steht drüber:
-Erweiterungsvorschlag:
Spendieren Sie der Uhr einige Taster zum Einstellen der Uhrzeit und
erweitern Sie so die Uhr zu einer vollwertigen Quarzuhr.
Im gesamten Buch mit ca. 30 Aufgaben und Beispielen wird in keinem der
Projekte ein Taster verwendet....Ich als Leihe habe deshalb schon meine
Schwierigkeiten dies zu realisieren.
Es ist natürlich nicht das erste mal, dass ich eine Schaltung realisiere
und somit weiß ich auch wie man einen Taster active high/low anschlißen
muss. Wenn man es jedoch auf das Buch beschränkt, ist diese Aussage von
dem Autor jedoch etwas weit hergeholt;)
Jochen schrieb:> wie gesagt ist die Uhr aus einem Buch komplett herauskopiert worden.
Wenn dort die 34286 nicht erklärt wird, dann taugt das Buch nichts.
Aber hier mal die Lösung:
65536 - 8e6 / 256 = 34286
Jochen schrieb:> Benutzt wird ein ATmega8.
Der hat 3 Timer und 3 Compare-Interrupts, damit kann man 3 völlig
unabhängige zyklus-genaue Timings realisieren.
Die Overflow-Interrupts sind nur mit Einschränkungen benutzbar, wenn das
Timing nicht genau sein muß, oder man abgeklärt hat, daß es aufgrund
eines hohen Vorteilers nicht zu Ungenauigkeiten kommt.
Peter
Peter Dannegger schrieb:> Aber hier mal die Lösung:> 65536 - 8e6 / 256 = 34286
hm.. gut, würdest du das Programm mit deinen Änderungen denn verwenden?
Die Uhr lief bis jetzt sowieso nicht genau. Ein 8MHz Quarz ist
angeschlossen, jedoch dauert eine Sekunde auf dem Display in
Wirklichkeit 5 Sekunden.
Ich bin nun gerade dabei
http://www.mikrocontroller.net/articles/Entprellung#Warteschleifen-Verfahren
für mein gelötetes Board zu übertragen, jedoch tut sich bis jetzt noch
nichts.
Die Testapplication müsste doch eigentlich funktionieren.
Habe zwei Taster an PB0 und PB1.
Zwei LEDs sind an PC0 und PC1.
Alles was vor der Main steht habe ich unverändert eingefügt.
> DDRB &= ~(1<<PB0);> PORTB |= 1<<PB0;> DDRB |= 1<<PC1; <========== Copy&Paste FEhler? #1> DDRB &= ~(1<<PB1); #3> PORTB |= 1<<PB1;> DDRB |= 1<<PC0; <========== Copy&Paste FEhler? #2
Schaltet Datenrichtung an PORTB.0 auf Ausgang.
Gleichzeitig ist der Pegel HIGH eingestellt,
Bei einem active-low Taster (schaltet gegen GND)
führt das Drücken des Tasters zum Kurzschluss
Bei #1 macht die Folgezeile #3 den Fehler rückgängig.
1
// LEDs an PC0 und PC1 auf Ausgang
2
DDRC|=(1<<PC1)|(1<<PC0);
3
// active-low Taster an PB1 und PB0 auf Eingang
4
DDRB&=~((1<<PB1)|(1<<PB0));
5
// Interne Pullups active-low Taster an PB1 und PB0 an
Hallo,
ja natürlich, habe vergessen DDRB auf DDRC um zu schreiben.
Krapao schrieb:>> DDRB |= 1<<PC1; <========== Copy&Paste FEhler? #1>> DDRB |= 1<<PC0; <========== Copy&Paste FEhler? #2
Danach ging eine von zwei LEDs und ich habe den Fehler im Programm
gesucht...
Naja bis ich dann mal darauf gekommen bin, dass eine LED auf
Sperrrichtung geschaltet war ist auch ein wenig Zeit vergangen.
1
/*
2
Testapplication
3
*/
4
intmain(void)
5
{
6
7
8
9
10
DDRB&=~(1<<PB0);// active-low Taster an PB0 auf Eingang
11
PORTB|=1<<PB0;// Interne Pullups active-low Taster an PB0 an
12
DDRC|=1<<PC1;// LEDs an PC1 auf Ausgang
13
DDRB&=~(1<<PB1);// active-low Taster an PB1 auf Eingang
14
PORTB|=1<<PB1;// Interne Pullups active-low Taster an PB0 an
15
DDRC|=1<<PC0;// LEDs an PC0 auf Ausgang
16
17
18
for(;;)
19
{
20
if(debounce(PINB,PB0))
21
{
22
PORTC^=1<<PC0;
23
}
24
25
if(debounce(PINB,PB1))
26
{
27
PORTC^=1<<PC1;
28
}
29
}
30
}
So funktioniert es jetzt. Beide LEDs schalten unabhängig voneinander.
Taster drücken => LED an...nochmals drücken LED aus.
Man merkt aber beim drücken eine deutliche Verzögerung, was auf dauer
recht nervig sein kann ;D
Peter Dannegger schrieb:> Nimm 2 LEDs und 2 Tasten, können aber auch mehr sein.> Beim Drücken einer Taste wechselt die dazu gehörende LED.> Beim gedrückt Halten, Loslassen oder ungedrückt passiert nichts.> Jede Taste arbeitet unabhängig. Also auch wärend die andere Taste> gedrückt gehalten wird, funktioniert sie.
Diese Aufgabe habe ich dann somit erstmal geschafft.
Danach habe ich mich nochmal ran gesetzt und das Zählen mit einbezogen.
Bei jedem Tastendruck wird nun gleichzeitig mit hochgezählt und das
Ergebnis auf dem LCD ausgegeben.
Beide Taster arbeiten immer noch völlig unabhängig voneinander.
Dies ist für mich schon mal ein Fortschritt, da ich mit dieser
Unabhängigkeit vorher einige Probleme hatte.
Was haltet ihr von meiner Lösung?
1
intmain(void)
2
{
3
lcd_init();
4
lcd_clear();
5
charstr1[2+1];
6
charstr2[2+1];
7
charcounter1=0;
8
charcounter2=0;
9
10
11
DDRB&=~(1<<PB0);// active-low Taster an PB0 auf Eingang
12
PORTB|=1<<PB0;// Interne Pullups active-low Taster an PB0 an
13
DDRC|=1<<PC1;// LEDs an PC1 auf Ausgang
14
DDRB&=~(1<<PB1);// active-low Taster an PB1 auf Eingang
15
PORTB|=1<<PB1;// Interne Pullups active-low Taster an PB0 an
Sieht gut aus. Du kannst noch Platz einsparen.
Die str-Puffer werden temporär zur Vorbereitung der LCD-Ausgabe benutzt.
Du brauchst deshalb nur einen.
Man kann sogar hingehen und sich eine Funktion z.B. lcd_zahlausgabe()
für die Augabe einer zweistelligen Dezimalzahl mit führender Null aufs
LCD schreiben, die man so aufruft:
1
lcd_zahlausgabe(counter1,2,1);
2
lcd_zahlausgabe(counter2,2,2);
und die diese doppelten Codeteile in main() ersetzt:
Hallo Krapao,
dein Vorschlag hört sich sehr gut an, das würde ich gerne umsetzen.
Hab auch schon ein bisschen herumgetürftelt, bin mir aber mit der
lcd_zahlausgabe() nicht ganz sicher, wie man diese Funktion beschreibt.
Wäre nett, wenn du es nochmal genauer erläutern könntest.
Wie muss eine Funktion lcd_zahlausgabe geschrieben werden, damit die
for-Schleife in main() später wie unten gezeigt aussieht, aber die
gleiche Arbeitsweise (formatierte und positionierte LCD-Ausgabe) hat wie
im Beitrag "Re: Uhrzeit stellen" vorhanden ist?
Jochen schrieb:> Man merkt aber beim drücken eine deutliche Verzögerung, was auf dauer> recht nervig sein kann ;D
Dann stimmt Deine F_CPU nicht mit der wirklichen Frequenz überein.
25ms merken vielleicht gerade mal Power-Gamer.
Peter
Jochen schrieb:> Die Uhr lief bis jetzt sowieso nicht genau. Ein 8MHz Quarz ist> angeschlossen, jedoch dauert eine Sekunde auf dem Display in> Wirklichkeit 5 Sekunden.Peter Dannegger schrieb:> Dann stimmt Deine F_CPU nicht mit der wirklichen Frequenz überein.
So wird es wohl sein. Und 125 ms sind schon eher fühlbar.
Die Quarzfrequenz von 8MHz muß als unsigned long angegeben werden, also
#define XTAL 8000000UL // Taktangabe
Peter Dannegger schrieb:> Dann stimmt Deine F_CPU nicht mit der wirklichen Frequenz überein.> 25ms merken vielleicht gerade mal Power-Gamer.
Ja da habt ihr beiden recht. Habe bis Dato bei Fuses immer 1 MHz
eingestellt.
Nun mal 8MHz Start up Time: 6CK +0ms. Benutze AVR Studio4.
Die Uhr läuft deutlich schneller und die Taster sind somit auch perfekt
eingestellt.
Habe momentan nicht so viel Zeit, um die lcd_zahlausgabe werde ich mich
erst heute Abend kümmern können.
Krapao schrieb:> Wie muss eine Funktion lcd_zahlausgabe geschrieben werden, damit die> for-Schleife in main() später wie unten gezeigt aussieht, aber die> gleiche Arbeitsweise (formatierte und positionierte LCD-Ausgabe) hat wie> im Beitrag "Re: Uhrzeit stellen" vorhanden ist?
Hi Krapao, habe gerade 5min Zeit mich mal ranzusetzen. So weit wie von
dir beschrieben war ich gestern auch schon.
hab trotzdem noch Gedankenlücken^^
Muss man evtl. mit Arrays arbeiten? Oder wird es auch anders gehen?
Gruß
Krapao schrieb:> Man kann sogar hingehen und sich eine Funktion z.B. lcd_zahlausgabe()> für die Augabe einer zweistelligen Dezimalzahl mit führender Null aufs> LCD schreiben
Hi, ich muss passen. Bekomme nur Murks raus. Ich denke ich mache einfach
grundlegende Fehler beim erstellen der Funktion. Es wird ja sicher nicht
damit getan sein einfach das zu schreiben
lcd_zahlausgabe();
und dann zwischen den Klammern einige Anweisungen zu geben was die
Funktion tun soll. bei mir fängt es ja schon mit counter1 und counter2
an. Wie erkläre ich der Funktion, dass es mehrere char counter1....2
gibt?
Dies dient natürlich eher zur Verschönerung/Vereinfachung des
Programmes.
Ich möchte auch noch versuchen meine Entprellten Taster mit der Uhr in
Verbindung zu kriegen.
Die erste Frage die ich mir dabei wohl stellen muss ist, wie das mit den
Timern meines Mega8 geregelt wird.
Die Entrpellung nutzt ja
1
#define F_CPU 9.6e6
Die Uhr nutzt aber
1
#define XTAL 8e6
2
#define F_CPU XTAL
Ist es überhaupt wichtig XTAL anzugeben, oder spielt dies keine Rolle?
"Klar denke ich, dass bei dieser Variante der uC weiß, dass er den Takt
von den XTAL Pins beziehen soll." Aber ob es relevant ist?!?!
Nungut, wie sage ich meinem uC, dass er jene Frequenz für die Uhr nutzen
soll und die andere für die Entprellung?
Peter Dannegger schrieb:> Dein unbekannter AVR hat bestimmt mehrere Timer und diese wiederum> jeweils mehrere Compare-Interrupts.> Du kannst also haufenweise verschiedene Timerintervalle erzeugen.>> Aber auch mit nur einem Timer geht das. Das kürzere Intervall legt man> einfach so, daß das längere durch ein Vielfaches erzeugt werden kann (=> Zählvariable). Und die Entprellzeit benötigt ja keinen exakten Wert,> irgendwas im Bereich 5..50ms ist ok.
Ich würde es natürlich gerne über zwei verschiedene Timer versuchen,
wenn dann soll es ja richtig gemacht werden.
Auf der anderen Seite müsste ich dann ja nur den Entprellcode an die
8MHz anpassen richtig?
schöne Grüße und ein herzliches Dankeschön an alle die mich hier
unterstützen, ist wirklich sehr sehr hilfreich!
Hallo,
ich habe es mit der lcd_zahlausgabe zwar nicht hinbekommen, dennoch am
Programm weiter gearbeitet.
Habe nun die Uhr und die Entprellung miteinander verschmolzen.
einen int uhrstellen habe ich auf Taster 3 gelegt. wenn dieser aktiviert
wird, stellt er uhrstellen auf true und ich kann meine Uhr einstellen.
Bei einer weiteren betätigung stelle ich diesen wieder auf false und die
Uhr läuft mit den einstellungen die man mit Taster1 und 2 gemacht hat.
Hier mal der Code!
Bin mal auf eure Meinungen gespannt. Verbesserungsvorschläge sind wie
immer willkommen ;)
1
intmain(void)
2
{
3
lcd_init();
4
lcd_clear();
5
charstr[2+1];
6
7
charhr=0;
8
charmin=0;
9
intuhrstellen=0;
10
11
12
DDRB&=~(1<<PB0);// active-low Taster an PB0 auf Eingang
13
PORTB|=1<<PB0;// Interne Pullups active-low Taster an PB0 an
14
DDRC|=1<<PC1;// LEDs an PC1 auf Ausgang
15
DDRB&=~(1<<PB1);// active-low Taster an PB1 auf Eingang
16
PORTB|=1<<PB1;// Interne Pullups active-low Taster an PB0 an
17
DDRC|=1<<PC0;// LEDs an PC0 auf Ausgang
18
19
TIMSK|=_BV(TOIE1);// aktivate overflow interrupt of timer1
Hm.. interessiert sich wohl niemand mehr für^^ Naja aber ich denke ich
habe das geschafft, was ich schaffen wollte. Natürlich mit eurer Hilfe!
Vielen dank nochmals und gehabt euch wohl :)