Hallo an Alle,
ich bin neu hier und suche Hilfe.
Ich möchte im Rahmen eines Projektes einen µC ATMega32 in C so
programmieren das ich über ein Menü verschiedene Sachen auswählen kann.
Also soll im ersten Menüpunkt Text auf einem Display ausgegeben werden
und nach betätigen einer bestimmten Taste, soll zum nächsten Menüpunkt
gesprungen werden, hier soll auch eine Auswahl über die angeschlossene
4x4 Matrix Tastatur getroffen werden und danach zum nächsten Menüpunkt
gesprungen werden.
Das soll dann bis zum Ende so weitergehen, dabei soll aber ab dem
zweiten Menüpunkt das zurückspringen zum ersten möglich sein.
Ich habe es jetzt über eine Case-Struktur versucht. In der Simulation
(ich benutze AVR-Studio 4) funktioniert es so wie ich es programmiert
habe, wenn ich das dann aber im µC programmiere funktioniert es nicht
mehr ganz so. Nach dem ersten Menüpunkt wird sofort der dritte Menüpunkt
angezeigt.
Ich habe zwar eine vage Vermutung was die Ursache dafür sein könnte, bin
mir aber nicht ganz sicher.
Wer hat eine Idee wie ich es mit einfachen Mitteln anstellen kann damit
es funktioniert.
Vielen Dank schon einmal im Voraus.
LG René
Oh, das ging aber schnell.
Da meine Tastatur an einem 74C922 angeschlossen ist, sollte diese damit
entprellt sein wenn ich alles richtig verstanden habe.
Ich lese also damit direkt den Wert ein der an der Tastatur gedrückt
worden ist.
Aber ich kann mich auch täuschen, ich bin noch totaler Anfänger.
René
René Geßner schrieb:> Oh, das ging aber schnell.>> Da meine Tastatur an einem 74C922 angeschlossen ist, sollte diese damit> entprellt sein wenn ich alles richtig verstanden habe.
OK.
Trotzdem. Wie sieht deine Asuwertung aus?
>> Ich lese also damit direkt den Wert ein der an der Tastatur gedrückt> worden ist.
Ja, aber hoffentlich nur einmal.
Du willst ja nicht, dass der Cursor nach unten saust SOLANGE eine Taste
gedrückt ist, sondern nur ein einziges mal.
Danach muss der Benutzer die Taste wieder loslassen und erneut drücken,
woraufhin der Cursor wieder eine Zeile tiefer geht.
Hast du das so gemacht?
Hallo,
der Fehler liegt wohl doch daran das die Tastatur nicht entprellt ist.
Wenn ich in jeder Menüebene den auszuwählenden Optionen
aufeinanderfolgende Ziffern zuweise funktioniert es, sobald aber in
Menüebene 1 und Menüebene 2
die gleichen Ziffern zugewiesen sind rauscht das Programm direkt durch
zur Menüebene 3 bzw. zur letzten Ebene die programmiert ist.
Ich hatte gehofft das ich mit der Case Struktur das unterbinden kann, da
ich ja immer in einem Case drin bin. Funktioniert aber so nicht.
Im Moment frage ich den Port direkt ab (Polling) wo die Tastatur dran
ist.
Später wird das als Interrupt gemacht. Aber da bin ich gerade am lesen
wie ich das am einfachsten machen kann. Wie gesagt ich bin noch totaler
Laie und habe eine Projektarbeit zu machen, wo das hier erst der Anfang
ist.
Um einmal mein Beispiel in Worten zu beschreiben.
Menüebene1
"Platinengroesse"
1= xyz x zyx
2= wer x rew
3= zui x iuz
dann frage ich den Tastaturport ab welche Taste gedrückt worden ist, ist
es eine 1, 2 oder 3, dann wird der Wert in einer Variablen gespreichert
der Menüzähler um eins erhöht und das Display gelöscht, damit wäre case
2 dran
das gleiche wie oben, halt nur anderer Text
Menüebene2
"Belichtungsart"
1= einseitig // wenn ich hier anstatt 1, die 4 benutze funktioniert
es
2= zweiseitig // und hier anstatt der 2 die 5
und so weiter
also brauche ich mich jetzt nur noch schlau machen wie ich schaffe das
die Ziffer nur einmal abgefragt wird in jedem Case.
René
René Geßner schrieb:> Um einmal mein Beispiel in Worten zu beschreiben.
Du sollstz nichts beschreiben .... du sollst Code zeigen.
Und mitlerweile bin ich mir sicher.
Du hast
Solange eine Taste gedrückt ist
mit
eine Taste wird einmal gedrückt und dann muss die Taste losgelassen
werden.
verwechselt.
> Im Moment frage ich den Port direkt ab (Polling) wo die Tastatur dran
ist.
und das ist auch gut so.
> Später wird das als Interrupt gemacht.
Und das ist Quatsch. Für eine Tastenauswertung braucht man keinen
Interrupt. Aus Sicht des µC agierst du in Super-Slow-Spezial-Zeitlupe.
Egal wie schnell du als Mensch versuchst eine Taste 2-mal hintereinander
zu drücken, deinem µC entlockt das nur ein müdes Gähnen. Da legt er sich
zwischendurch noch mal schlafen und macht aus seiner Sicht ein
ausgiebiges Nickerchen.
Interrupts an Tasten vereinfachen die Sache nicht. Ganz im Gegenteil.
Ganz im Gegenteil.
René Geßner schrieb:> Menüebene1> "Platinengroesse"> 1= xyz x zyx> 2= wer x rew> 3= zui x iuz>> dann frage ich den Tastaturport ab welche Taste gedrückt worden ist, ist> es eine 1, 2 oder 3, dann wird der Wert in einer Variablen gespreichert> der Menüzähler um eins erhöht und das Display gelöscht, damit wäre case> 2 dran>> das gleiche wie oben,
und weil du im Gegensatz zu deinem µC schnarchlangsam bist, ist die
Taste 2 immer noch gedrückt. Woraufhin ...
> halt nur anderer Text>> Menüebene2> "Belichtungsart"> 1= einseitig // wenn ich hier anstatt 1, die 4 benutze funktioniert> es> 2= zweiseitig // und hier anstatt der 2 die 5
dein µC hier dann sofort eine gedrückte Taste 2 feststellt und dann auch
gleich noch diesen Menüpunkt ausführt.
Tasten müssen auch mal losgelassen werden!
Darauf muss dein µC aber warten! Erst danach gilt eine gedrückte 2 als
nächster Tastendruck.
René Geßner schrieb:> wie schon gesagt wenn ich in der Ebene 2 mit 4 und 5 fortfahre> funktioniert es.
Und wie schon jetzt 2 mal gesagt: Du musst dein Programm auch darauf
warten lassen, das keine Taste gedrückt ist. Erst dann geht es mit dem
nächsten Menüpunkt bzw. der nächsten Taste weiter.
Und strukturier dein Programm mal ein wenig in Funktionen.
Gerade hierarchische Menüs eignen sich hervorragend für eine Aufteilung
in Funktionen.
Genau wie die Abfrage der Tasten. Das wird auch eine eigene Funktion. Es
gibt da keinen Grund, den ganzen Code jedesmal wieder neu aufzurollen.
genau das was du beschreibst trifft zu, ich, im vergleich zum µC,
wirklich schnarchlangsam, deswegen rauscht er durch. In der Simulation
geht das dann, weil ich da etwas tricksen muss mit den Eingängen, die
setze ich halt per Hand. das ist der Nachteil wenn man keinen Hardware
Debugger hat.
ich würde gern eine vernünftige Struktur programmieren wollen, allein
das Wissen dazu fehlt mir noch. Das was ich gelehrt bekommen habe wurde
im Raketentempo durchgezogen.
wenn du mal ein Beispiel hast, bezüglich der Funktionen, kannst du es
mir gern geben. Ich lerne gern von denen die es beherrschen.
René
René Geßner schrieb:> ich würde gern eine vernünftige Struktur programmieren wollen, allein> das Wissen dazu fehlt mir noch. Das was ich gelehrt bekommen habe wurde> im Raketentempo durchgezogen.
Fang damit an, dir eine Funktion zu schreiben, die dir einen Tastendruck
leifert. Jede Taste hat einen Code. WIchtig: Auch die 'keine Taste
gedrückt' hat einen eigenen Code, damit du diesen Zustand von den
anderen Tasten unterscheiden kannst.
Jetzt kommt der Trick: Die Funktion liefert nur dann einen
'Tastendruck-Code', wenn sich der Zustand der Tasten auch tatsächlich
verändert hat. Ansonsten liefert sie eben 'keine Taste gedrückt'. Damit
ist sichergestellt, dass dein restliches Programm jede gedrückte Taste
nur ein einziges mal zu Gesicht bekommt.
Das ist deine erste Funktion.
Definier dir ein paar Konstanten für die Tastencodes
1
#define NO_KEY -1
2
#define KEY_0 0
3
#define KEY_1 1
4
#define KEY_2 2
5
....
und schreib eine Funktion
1
int8_tlastKeyDown=NO_KEY;
2
3
int8_tkeyPressed()
4
{
5
...
6
}
die sich den Port ansieht und feststellt, welche Taste jetzt gerade
gedrückt ist (wenn überhaupt). DIese Taste, bzw. deren Code wird nur
dann als Returnwert zurückgeliefert, wenn er sich von lastKeyDown
unterscheidet (und lastKeyDown wird dann auf diesen Wert gesetzt). In
allen anderen Fällen liefert die Funktion NO_KEY.
Die Funktion testen!
Überleg dir, wie du testen kannst, ob das auch wirklich funktioniert,
dass jeder Tastendruck nur einmal gemeldet wird, egal wie oft die die
Funktion hintereinander aufrufst (ein angemessenes Minimum an Aufrufen
vorausgesetzt)
Vielen Dank schon einmal, ich werde mich gleich morgen Früh daran
setzen, für heute ist einmal Schluss, sitze schon seit heute Morgen am
Rechner und versuche das Problem zu lösen.
Ich werde morgen über Erfolg oder Misserfolg berichten. Ich hoffe es
wird ein Erfolg.
René
René Geßner schrieb:> Vielen Dank schon einmal, ich werde mich gleich morgen Früh daran> setzen, für heute ist einmal Schluss, sitze schon seit heute Morgen am> Rechner und versuche das Problem zu lösen.
Du hast am falschen Ende angefangen.
Wie fast immer beginnt die Reise von Benutzereingaben erst mal mit einer
ordentichen Auswertung von Tasten und Tastendrücken.
Solange die nicht steht, ist alles andere vergebene Liebesmühe.
Hallo kbuchegg,
so ich bin wieder am arbeiten.
Bin gerade dabei die Funktion zu erstellen.
Habe ich es richtig verstanden das ich in dieser Funktion den Port
abfrage wo die Tastatur dran hängt und den Wert dann in der Variablen
LastKeyDown ablege?
Ich steh im Moment wieder einmal auf dem Schlauch, solange die Eingaben
nicht funktionieren kann ich nicht weitermachen in meinem Projekt.
Sorry wenn ich solch blöden Fragen stelle, aber ich habe das Ganze noch
nicht wirklich verstanden. Ich meine Grundsätzlich schon aber im Detail
hängt es noch.
René
René Geßner schrieb:> Hallo kbuchegg,>> so ich bin wieder am arbeiten.> Bin gerade dabei die Funktion zu erstellen.> Habe ich es richtig verstanden das ich in dieser Funktion den Port> abfrage wo die Tastatur dran hängt und den Wert dann in der Variablen> LastKeyDown ablege?
Im Prinzip ja
1
int8_tlastKeyDown=NO_KEY;
2
3
int8_tkeyPressed()
4
{
5
int8_tdownNow;
6
7
// vom 922 erst mal abfragen, ob überhaupt eine Taste momentan
8
// gedrückt ist. Wenn keine Taste gedrückt ist dann meldet der 922
9
// das mit dem DATA AVAILABLE Pin ...
10
11
if(.....)
12
{
13
// .. es ist keine Taste gedrückt. Gleich mal merken
14
downNow=NO_KEY;
15
}
16
17
else
18
{
19
// ... es ist eine Taste gedrückt. Jetzt erst mal rausfinden welche.
20
// Der 922 hat die Tastenmatrix ja schon mal in eine Zahl umgewandelt
21
// die an den Portpins xxx anliegen
22
uint8_tkeyBits=PINA;
23
24
// jetzt rausfiltern bzw. umcodieren, welche Taste das ist
25
// Die Konstanten KEY_0, KEY_1 etc. sind ja trickreicherweise
26
// genau so angeordnet, dass ihr numerischer Wert (im Falle
27
// der Zifferntasten) genau dem entspricht, was auf der
28
// Taste aufgedruckt ist.
29
// Nur muss das dann auch entsprechend hier so umkodiert werden,
30
// dass bei einer gedrückten Taste 4, dann auch der Wert 4
31
// bzw. KEY_4 in downNow steht. Aber mit einem Array ist diese
32
// Umkodierung ja kein Problem
33
34
downNow=......
35
36
// damit steht fest, welche Taste (und zwar in unseren Einheiten)
37
// jetzt gerade gedrückt ist
38
}
39
40
// soweit so gut.
41
// jetzt ist klar, welche Taste zur Zeit gedrückt IST.
42
// Jeder Tastendruck wird aber nur einmal gemeldet.
43
// einmal und nicht öfter.
44
// D.h. was diese Funktion zurückliefert ist nur dann ein
45
// Tastencode, wenn dieser nicht identisch ist mit dem zuletzt
46
// zurückgelieferten Wert
47
48
if(downNow!=lastKeyDown)
49
{
50
lastKeyDown=downNow;
51
returndownNow;
52
}
53
else
54
returnNO_KEY;// es ist zwar eine "Taste" gedrückt. Aber die
55
// wurde vorher schon mal gemeldet.
56
}
Die Details überlass ich jetzt dir. Aus den Kommentaren sollte
eigentlich hervorgehen, was an der jeweiligen Stelle zu tun ist. (Und da
ich deine Hardware nicht kenne und nicht weiß, wie und wo du den 922
angeschlossen hast, kann ich das gar nicht weiter programmieren). Fehlt
ja nicht mehr viel.
erst einmal vielen, vielen Dank.
Jetzt verstehe ich das Ganze schon viel besser und hilft mir weiter.
Mein 922 ist am PortA angeschlossen von Pin0 -Pin3 (ABCD) und Pin4 ist
DA.
/OE liegt auf GND
Der Wert der vom 922 kommt ist der Wert der gedrückten Taste, somit
entspricht der Wert der ersten 4 Pins am PortA auch dem der gedrückten
Taste.
Eine kleine Unsicherheit hat sich jetzt aber bemerkbar gemacht.
Du schriebst in deinen Kommentaren:
// vom 922 erst mal abfragen, ob überhaupt eine Taste momentan
// gedrückt ist. Wenn"""keine""" Taste gedrückt ist dann meldet der
922
// das mit dem DATA AVAILABLE Pin ...
das keine Taste macht mich unsicher. Ist es nicht so das, wenn eine
Taste gedrückt ist das DA Signal auf High liegt?
Oder meintest du das DA damit auf Low liegt?
Ansonsten versuche ich jetzt genau das umzusetzen was du vorgeschlagen
hast.
René
René Geßner schrieb:> Der Wert der vom 922 kommt ist der Wert der gedrückten Taste, somit> entspricht der Wert der ersten 4 Pins am PortA auch dem der gedrückten> Taste.
Ja. Aber ist der Wert an den 4 unteren Portpins (wenn man ihn als Zahl
auffasst, auch 0, wenn die Taste 0 gedrückt ist
(Ich hab mir das im Datenblatt nicht weiter angesehen, welche Codes der
922 bei welcher gedrückter Taste liefert).
Es ist nämlich praktisch, wenn in dieser Funktion gleich ein
entsprechende Umkodierung gemacht wird. Ist die Taste '8' gedrückt, dann
soll die Funktion idealerweise auch gleich eine numerische 8 liefern und
nicht 0x0C, weil dsa eben genau so aus dem 922 heraus kommt. (Die Zahlen
hab ich jetzt erfunden. Wie gesagt, ich hab mir die Tabelle im
Datenblatt des 922 nicht näher angesehen, welchen Code er bei welcher
Taste liefert)
>> Eine kleine Unsicherheit hat sich jetzt aber bemerkbar gemacht.>> Du schriebst in deinen Kommentaren:>> // vom 922 erst mal abfragen, ob überhaupt eine Taste momentan> // gedrückt ist. Wenn"""keine""" Taste gedrückt ist dann meldet der> 922> // das mit dem DATA AVAILABLE Pin ...>> das keine Taste macht mich unsicher. Ist es nicht so das, wenn eine> Taste gedrückt ist das DA Signal auf High liegt?
Ich hab ja auch im Kommentar nicht geschrieben, dass in diesem Fall der
Pin auf High liegen würde. Ich hab nur geschrieben, dass man durch
betrachten des DA Pins rausfinden kann, ob zur Zeit gerade eine Taste
gedrückt ist oder nicht :-)
der 922 liefert an den Ausgängen ABCD genau den Wert der auf der
Tastatur gedrückt worden ist. A steht dann für PIN0 und D für PIN3
Wenn eine 0 gedrückt wird, liegt das DA-Signal auf High und die vier
Ausgänge ABCD auf Low, also eine Null. Bei der Taste F erscheint ein F
also ein 15.
Das habe ich gleich als erstes ausprobiert, hatte mir eine Platine
gebaut wo ich dann 4 LEDs an einem anderen Port angeschlossen hatte die
mir den Wert des eingehenden Signals gezeigt haben. Das hatte ich schon
hinbekommen. lach.
Aber ich lerne jetzt viel besser als in der Schule, learning by doing
ist viel besser. :-)
Kann ich das jetzt so machen????
int8_t lastKeyDown = NO_KEY;
int8_t keyPressed()
{
int8_t downNow;
if( !(PINA & (1<<PINA4)) )
{
downNow = NO_KEY;
}
else
{
if ( PINA & (1<<PINA4) )
downNow = (PINA & 0x0f);
}
if( downNow != lastKeyDown )
{
lastKeyDown = downNow;
return downNow;
}
else
return NO_KEY;
}
In der Main frage ich dann den Wert von lastKeyDown ab um damit weiter
zu arbeiten???
René
Frag die Tasten mit einem Timer Tick, zB alle 10ms ab. Ein Tastatur Wert
wird erst als stabil erachtet wenn er bei zwei sukzessiven Samples
anliegt.
interrupt timer {
timercame = 1;
}
main loop {
if timercame==1 {
readkeys..
Jetzt habe ich den Fehler gefunden,
also deine Variante mit der Funktion läuft.
Allerdings waren die Auswirkungen auf das Problem gleich Null.
Liegt aber nicht an der Programmierung. Es liegt an der Hardware, bzw.
an der Beschaltung. Das Übel ist der 922. Da hätte ich gleich drauf
kommen müssen. Hardware ist schon eher mein Ding.
Der 922 speichert den Wert der zuletzt gedrückten Taste, über das DA
Signal wird bekannt gegeben das eine Taste gedrückt worden ist. Da mein
/OE auf Masse liegt, sind die Ausgänge immer offen und können gelesen
werden.
Die Ausgänge am 922 ändern sich erst mit einer erneuten
Tastaturbetätigung, bleibt diese aus, bleibt der letzte Wert
gespeichert. Und genau das ist das Problem.
Wenn ich also in meiner Menüebene1 die 2 drücke, wird dieser Wert
gespeichert im 922 und da ich in jeder anderen Menüebene die 2 verwende
und den PinA abfrage erscheint da immer eine 2 und das Programm läuft
weiter.
Es gibt aber dafür eine Lösung, ich muss den DA-Ausgang über einen
Inverter auf den /OE legen, damit werden bei einem DA=Low, die Ausgänge
des 922 auf Tristate gesetzt.
Es gibt aber auch noch eine Softwarevariante.
Vielen Dank erst einmal an Alle, ihr werdet wieder von mir lesen.
Ich muss noch zwei Schrittmotoren ansteuern. :-)
René
René Geßner schrieb:> Kann ich das jetzt so machen????
Hallo René,
schau mal auf die Formatierungsmöglichkeiten. Die stehen direkt über dem
Feld, wo du René Geßner eingegeben hast:
Formatierung
[ c ] C-Code [ /c ] für C-Listings
dann sieht das so schön aus wie bei Karl Heinz.
René Geßner schrieb:> Es gibt aber dafür eine Lösung, ich muss den DA-Ausgang über einen> Inverter auf den /OE legen, damit werden bei einem DA=Low, die Ausgänge> des 922 auf Tristate gesetzt.
Das löst reinweg garnichts.
Was sollen Dir flatternde Inputs bringen?
Du mußt das DA direkt im MC auswerten. d.h. Du brauchst 5 Eingänge,
anders geht es nicht.
Mit 8 Pins (3 Pins mehr), könntest Du die Matrix einfach direkt
auswerten und den sauteuren 922 sparen.
Du könntest dann sogar 2 Tasten gleichzeitig erkennen (z.B. eine als
Umschalttaste).
@peda
Natürlich, da hast du völlig Recht. Das Da-Signal wird auch weiterhin im
µC ausgewertet. Ich würde dieses Signal nur parallel dazu an einen
Inverter geben, der dann den /OE Eingang auf Low zieht, also frei gibt,
wenn das DA-Signal auf High ist. Und zum gleichen Zeitpunkt lese ich den
Port aus, da ich ja das DA-Signal abfrage. Zu diesem Zeitpunkt ist also
der Port am 922 offen und ich kann den gespeicherten Wert auslesen,
sobald das DA-Signal auf Low ist geht der 922 in Tri-State bis zur
nächsten Eingabe an der Tastatur.
Damit kann der gespeicherte Wert im 922 so lange bleiben, solange keine
Taste gedrückt worden ist, ohne das mein Programm in den folgenden
Schritten den Wert lesen kann.
Das ist zumindest meine Theorie, ob die richtig ist werde ich morgen
sehen, muss mir erst noch einen Inverter kaufen bei Conrad.
Auch bei deinen anderen Hinweisen hast du Recht.
Da an diesen µC eine ganze Menge ran kommt, muss ich mit den Pins von
den Ports sparen wo es nur geht. Auch das Display läuft nur im
4Bit-Modus. 4 Pins gespart.
René Geßner schrieb:> In der Main frage ich dann den Wert von lastKeyDown ab um damit weiter> zu arbeiten???
In der main fragst du den Returnwert der Funktion ab, um damit
weiterzuarbeiten. Die Variable geht dich nichts an. Die braucht nur die
Funktion um sich einen Zustand zu merken.
int main()
{
....
while( 1 ) {
key = keyPressed();
if( key == KEY_0 )
Led toggeln;
else if( key == KEY_1 )
....
René Geßner schrieb:> Die Ausgänge am 922 ändern sich erst mit einer erneuten> Tastaturbetätigung, bleibt diese aus, bleibt der letzte Wert> gespeichert. Und genau das ist das Problem.
Und genau deswegen jage ich dich durch diese Funktion durch!
Die macht nämlich im Prinzip nichts anderes als eine Flankenerkennung.
Sie stellt fest, ob sich am Zustand der Tasten etwas verändert(!) hat
und sagt dir was sich verändert hat.
"verändert" ist aber bei einer Taste einfach:
entweder eine Taste ist gedrückt worden oder sie ist losgelassen worden.
Und genau das ist es, was du brauchst, wenn du eine Tastenbetätigung
feststellen willst im Gegensatz zu "Ist die Taste jetzt gerade
gedrückt". Dich interessiert nicht, ob die Taste jetzt gerade gedrückt
IST. Dich interessiert, ob die Taste im Vergleich zum letzten mal
nachsehen, in der Zwischenzeit gedrückt (oder losgelassen) wurde. Es ist
diese Veränderung, in der die dich interessierende Information steckt.
Und um die festzustellen, merkt man sich den Zustand eben, bis zum
nächsten nachsehen. Wenn vor einer halben Stunde das Licht im Haus
gegenüber nicht gebrannt hat, jetzt aber schon, dann hat in der
Zwischenzeit wer das Licht eingeschaltet. Brannte es vor einer halben
Stunde bereits, dann hat niemand was mit dem Licht gemacht. Brannte das
Licht vorhin und jetzt ist es aus, dann hat jemand das Licht
ausgeschaltet.
Das 'last' in lastKeyDown steht für 'vorher, beim letzten mal
nachsehen'. Im Gegensatz zum 'now' in 'nowDown', welches für 'genau
jetzt' steht.
Im Falle des Lichts vom Haus nebenan, kann es dir nachtürlich passieren,
dass du einmal ein/ausschalten nicht registrierst, wenn du nur alle 30
Minuten nachsiehst. Aber wir haben hier einen µC. Für den ist es
überhaupt kein Problem alle 0.001 Sekunden(!) nachzusehen. Und dann
entgeht ihm nichts mehr. Denn so schnell kann ein Mensch einen Schalter
gar nicht betätigen!
An die anderen (speziell rumpelsuri).
Bitte versucht wenigstens dem Weg zu folgen, dem ich ihn aufgezeigt habe
oder sagt wenigstens dazu, dass ihr einen komplett anderen Ansatz
vorschlagt.
Der 922 macht ihm das entprellen (das ist so von ihm vorgegeben und
dagegen kann ich jetzt erst mal nichts tun). Alles was fehlt ist, mit
den vorhandenen Mitteln eine "Flankenerkennung" zu programmieren. Und da
wollte ich ihn hintreiben. Es macht wenig Sinn, wenn da jetzt
Querschläger kommen.
> Damit kann der gespeicherte Wert im 922 so lange bleiben, solange> keine Taste gedrückt worden ist, ohne das mein Programm in den> folgenden Schritten den Wert lesen kann.
Dein µC kann Zehntausende Programmschritte ausführen, ehe du als
Benutzer auch nur einmal Pieps sagen kannst.
Du fürchtest dich da jetztz vor etwas, was kein Problem ist.
> if( !(PINA & (1<<PINA4)) )> {>> downNow = NO_KEY;> }>> else> {> if ( PINA & (1<<PINA4) )>> downNow = (PINA & 0x0f);> }
Spar dir den 2.ten Vergleich.
WEnn beim if der Pin nicht auf 1 war, dann MUSS er beim else auf 1 sein.
Anders geht es nicht. Der Pin kann nur 2 Zustände haben. Entweder er ist
0 (dann wird der erste Zweig vom if genommen), oder er ist 1 (dann wird
das else genommen). Im else steht also schon fest, dass der Pin auf 1
sein MUSS. Der kann gar nicht anders sein. Wenn die Auswahl auf
"entweder - oder" lautet UND "enweder" nicht richtig ist, dann muss
"oder" zwangsläufig richtig sein.
if( !(PINA & (1<<PINA4)) )
{
downNow = NO_KEY;
}
else
{
downNow = (PINA & 0x0f);
}
@kbuchegg
das mit dem else ist völlig korrekt, da hast du Recht. Habe es auch
schon geändert.
Also, um sicher zu sein, die Funktion die du mir gegeben hast ist
sozusagen die Flankenauswertung? Und wenn ich alles richtig gemacht habe
sollte diese dann funktionieren?
Wenn ich aber das gesamte Projekt auf den µC lade verhält er sich wie
schon beschrieben. Eine 2 gedrückt in Menüebene1 und er rauscht durch
bis zur letzten Menüebene.
Deswegen die Idee dann mit dem Inverter.
Ich habe mal das gesamte Projekt als Datei angehangen, wie auch den
Schaltplan von meiner Platine die ich zum ausprobieren benutze.
Vielleicht siehst du noch etwas was falsch läuft.
Danke schon mal.
René
René Geßner schrieb:> @kbuchegg>> das mit dem else ist völlig korrekt, da hast du Recht. Habe es auch> schon geändert.>> Also, um sicher zu sein, die Funktion die du mir gegeben hast ist> sozusagen die Flankenauswertung? Und wenn ich alles richtig gemacht habe> sollte diese dann funktionieren?
Ganz genau.
Halte aber immer auch im Hinterkopf, dass ich deine Hardware nicht da
habe. D.h. ich muss "blind" programmieren ohne das bei mir testen zu
können.
> keyPressed();>>> if (lastKeyDown == KEY_1 || lastKeyDown == KEY_2 || lastKeyDown == KEY_3)
Nein!
Lass lastKeyDown in Ruhe!
key = keyPressed();
if( key == KEY_1 || key == KEY_2 || key = KEY_3 )
Für den aufrufer ist nur und ausschliesslich der Returnwert von
keyPressed interessant! Alles andere hat ihn nicht zu interessieren.
Und speck das mal für deine ersten Tests ab.
Da main() muss nicht so kompliziert sein. Je mehr Code du bei deinen
ersten Tests hast, desto mehr Fehler kannst du machen.
1
voidMainMenu()
2
{
3
int8_tkey=NO_KEY;
4
uint8_tselectedOption=0;
5
6
lcd_setcursor(0,1);
7
lcd_string(" Option 1");
8
9
lcd_setcursor(0,2);
10
lcd_string(" Option 2");
11
12
lcd_setcursor(0,3);
13
lcd_string(" Option 3");
14
15
lcd_setcursor(0,4);
16
lcd_string(" Option 4");
17
18
lcd_setcursor(0,selectedOption+1);
19
lcd_string(">");
20
21
do{
22
key=keyPressed();
23
24
if(key!=NO_KEY)
25
{
26
lcd_setcursor(0,selectedOption+1);
27
lcd_string(" ");
28
29
if(key==KEY_1)
30
{
31
if(selectedOption<3)
32
selectedOption++;
33
}
34
35
elseif(key==KEY_2)
36
{
37
if(selectedOption>0)
38
selectedOption--;
39
}
40
41
lcd_setcursor(0,selectedOption+1);
42
lcd_string(">");
43
}
44
}while(key!=KEY_9);
45
46
47
intmain(void)
48
{
49
int8_tkey;
50
51
DDRA=0xE0;
52
53
lcd_init();
54
55
while(1)
56
{
57
lcd_clear();
58
lcd_lcd_setcursor(0,1);
59
lcd_string("Press key 1");
60
61
do{
62
key=keyPressed();
63
}while(key!=KEY_1);
64
65
MainMenu();
66
}
67
}
Probier das mal aus.
Im 'Menü' kannst du mit den Tasten '1' bzw. '2' den Cursor jeweils einen
Menüpunkt weiterschieben. Das muss auch wirklich EIN Menüpunkt sein.
Nicht 2, nicht 3, nicht einmal auf die Taste drücken und der Cursor
rauscht zum letzten durch. Nein, 1 Tastendruck -> 1 Cursorbewegung.
Mit der Taste 9, geht es aus dem Menü wieder raus.
Das genügt fürs erste um zu sehen, ob die Tastenerkennung und Auswertung
funktioniert.
jetzt, hat er´s
Jetzt funktioniert es, eine schwere Geburt. Lach.
Nun muss ich nur noch programmieren das ich in den Menüebenen auch
zurück springen kann, aber das ist ja ähnlich jetzt, muss nur andere
tastenwerte abfragen.
Danke, Danke, Danke
René
Also ich habe noch einen Fehler gefunden in den Case Strukturen, nachdem
ich den behoben hatte läuft es.
Nun komm ich zu deinem letzten Vorschlag.
Das wäre nämlich meine nächste Frage gewesen, wie man das vereinfachen
könnte.
René
René Geßner schrieb:> Also ich habe noch einen Fehler gefunden in den Case Strukturen, nachdem> ich den behoben hatte läuft es.>> Nun komm ich zu deinem letzten Vorschlag.> Das wäre nämlich meine nächste Frage gewesen, wie man das vereinfachen> könnte.>
Da gibts jetzt mehrere Möglichkeiten.
Jedes Menü, auch die Submenüs, ist eine eigen FUnktion. Ganz ähnlich der
Funktion, die ich 2 Postings vorher geschrieben habe.
Jede Funktion folgt dem Muster
void DasMenu()
{
int8_t Taste = KEY_1; // damit beim ersten mal der Text
hingeschrieben wird
do {
if( Taste != NO_KEY )
{
LCD löschen
Menüpunkte hinschreiben
}
Taste holen
if( Taste == 1 )
Aktion für Taste 1 ausführen
else if( Taste == 2 )
Aktion für Taste 2 ausführen
else if( Taste == 3 )
Aktion für Taste 3 ausführen
...
} while( Taste nicht die Taste für 'Fertig' )
}
So eine 'Aktion', die bei Betätigung einer Taste ausgeführt wird, könnte
zb der Aufruf einer Funktion sein, die ihrerseits auch wieder ein Menü
realisiert.
Das kann man zwar auch noch viel universeller regeln, aber fürs erste
ist das eine einfache Möglichkeit.
jetzt habe ich deinen letzten Vorschlag in den µC programmiert, also das
funktioniert super, da bin ich echt neidisch das ich das noch nicht
kann.
Allerdings gibt es einen kleinen Schönheitsfehler.
Im Display wird "Option11" angezeigt.
Da versuche ich gerade den Fehler zu finden.
René
Also deine Menüstruktur gefällt mir sehr gut, auch das mit den
Funktionen.
Ich lese mir das jetzt alles in Ruhe durch, damit ich auch voll verstehe
was da programmiert ist. Denn nur copy paste möchte ich nicht machen,
ich will es verstehen und weiter anwenden. Aber du bist mir eine sehr
gute Hilfe und Lehrer zugleich. Danke noch einmal.
René
Hallo kbuchegg,
ich brauche wieder deine Hilfe.
Das Menü habe ich jetzt soweit fertig, bzw. weiß wie ich es erweitern
kann.
Ich kann dir gern einmal das File schicken, damit du drüber schauen
kannst ob es jetzt vernünftig strukturiert ist.
Im Moment versuche ich gerade eine Variable in einen String umzuwandeln,
da ich den Wert der Variablen gern im LCD anzeigen möchte.
Ich habe auch den Link gefunden den du irgend wann einmal gepostet
hattest. Bin auch so vorgegangen wie beschrieben mit itoa. Aber
angezeigt wird dann das Wort nicht der Wert.
hier mal mein Versuch.
1
#include<avr/io.h>
2
#include<avr/interrupt.h>
3
#include"lcd-routines.h"
4
#include<stdlib.h>
5
6
charBuffer[10];
7
8
void....()
9
{
10
int8_tTaste=KEY_1;
11
12
lcd_setcursor(3,2);
13
itoa(Taste,Buffer,2);
14
lcd_string("Buffer");
15
16
}
Was mache ich noch falsch???
Die Augabe im LCD ist "Buffer"
Danke dir schon mal.
René
gibt es eine Möglichkeit aus einem dualen Wert das dazugehörige
ASCII-Zeichen auf dem LCD auszugeben???
In meinem Fall möchte ich das e auf dem LCD ausgeben, das entspricht
0x65 bzw. 01100101.
Einen numerischen Wert als String auszugeben geht jetzt. :-)
René Geßner schrieb:> In meinem Fall möchte ich das e auf dem LCD ausgeben, das entspricht> 0x65 bzw. 01100101.
lcd_data(0x65);
Sofern ich dich richtig verstanden habe.
ich habe mich falsch ausgedrückt.
Mit lcd-data hatte ich es auch versucht, hatte nur nicht geklappt, da
ich den Wert wieder aus einer Variablen nehmen möchte. Ich habe aber
einen Fehler in der Zuweisung der Variablen gemacht. Wenn ich der
Variablen anstatt einer 1 eine 0x65 zuweise und dann mit
lcd_data(Variable) auf das LCD schreibe dann kommt auch das e. Wieder
ein kleines Problem weniger. Ich lerne mehr und mehr.
Danke
Wenn Du ein 'e' auf dem Display ausgeben willst, dann solltest Du das
direkt hinschreiben:
1
lcd_data('e');
Geht mit einer Variable natürlich auch:
1
charzeichen='e';
2
lcd_data(zeichen);
Ich würde Dir aber erstmal dringend dazu raten, ein C-Buch oder
wenigstens Tutorial durchzuarbeiten. Ohne diese absoluten Grundlagen
kann man kein vernünftiges Programm entwickeln. Mir würden die
unzähligen "Trial & Error"-Zyklen auch keinen Spaß machen ...
Bevor ich bei dir anfrage versuche ich natürlich mir das entsprechende
Wissen im Tutorial zu holen. Nur sehr oft kommt man da nicht wirklich
weiter, denn oft trifft es nur zum Teil das eigene Problem.
Ich muss auch sagen das ich eher der Autodidakt bin, ich lerne vom
zusehen.
Ich bin auch nicht mehr der Jüngste. ;-)
Aber ich versuche immer zuerst mir alles durchzulesen.
Mein Problem ist die Zeit. Ich habe eigentlich nur diese Semesterferien,
4 Wochen, um mein Projekt auf die Beine zu bekommen. Danach geht die
Technikerschule weiter und die Abschlussprüfungen stehen vor der Tür.
Natürlich muss dann auch das Projekt fertig sein. Und bis dahin ist es
noch ein weiter Weg für mich. Eigentlich sind wir auch zu zweit an
diesem Projekt, aber da bin ich etwas im Stich gelassen worden. So muss
ich jetzt alles vorerst allein machen und programmieren war noch nie
meine große Stärke.
Ich bin eher für die Hardware. Es müssen Leiterplatten gefertigt werden,
kein Problem für mich, es müssen Schrittmotoren angeschlossen werden,
bekomme ich auch hin. Und und und..... Viele Dinge sind noch zu machen,
aber eben auch die Programmierung. Und die Zeit rennt....
Und manchmal sind es eben nur die ganz kleinen Dinge die mich aufhalten.
siehe ("Buffer") anstatt (Buffer).
Selbst das hatte ich mir erlesen und ging trotzdem schief. :-)
René
René Geßner schrieb:> Bevor ich bei dir anfrage versuche ich natürlich mir das entsprechende> Wissen im Tutorial zu holen.
Da wirst du auch in unseren Tutorials hier nicht viel dazu finden.
Umgang mit Variablen sind eigentlich C-Grundlagen und unsere Tutorien
hier gehen eigentlich davon aus, dass ein gewisser Grundstock an Wissen
vorhanden ist und konzentrieren sich auf die Spezialitäten, die in der
µC-Programmierung dann nochmal dazukommen.
Von einem Tutorial über das Lösen von Differentialgleichungen, darfst du
dir nicht erwarten, dass es dir Gleichungen umformen beibringt. Das wird
dort schon vorausgesetzt.
> Ich muss auch sagen das ich eher der Autodidakt bin, ich lerne vom> zusehen.
Genau deswegen wäre es gut, erst mal den µC beiseite zu legen, und auf
dem PC das erste Drittel eines normalen C-Buchs durchzumachen. Denn das
sind genau die Dinge, die jeder C Programmierer als
Minimum-'Ausstattung' eigentlich beherrschen sollte. Dass dann am µC
noch die Spezialitäten der µC-Programmierung dazu kommen, macht die
Sache nicht einfacher.
Ich kann dir wirklich nur zustimmen.
Die C-Grundlagen sind eigentlich gelegt worden. Wenn man sie aber nicht
ständig anwendet gehen sie schnell wieder verloren. Zumal ich im Moment
mit einer Menge neuem Wissen zugeballert werde was nicht nur µC angeht.
Da ist Steuerungstechnik, Reglungstechnik und alle wollen die
wichtigsten sein. :-)
Aber wie schon gesagt, ich verbringe auch viel Zeit damit mir Wissen
wieder anzueignen durch lesen von verschiedenen Medien.
René
@kbuchegg
Hallo,
könntest du mir wieder einmal unter die Arme greifen?
Ich habe jetzt mein Menü soweit fertig. Eine Sache muss ich aber noch
erledigen und mir fällt kein richtiger Weg dazu ein.
Ich versuche einmal zu schildern worum es geht.
Ich bin im Menüpunkt Belichtungszeiten, die Zeiten sind Variablen in
einem Array zusammengefasst jeweils. Die ausgewählte Option bestimmt den
Stellenwert im Array. Sieht auf dem LCD ungefähr so aus:
Belichtungszeit
>1: 0:00 min
2: 0:00 min
3: 0:00 min
Da ja im Moment alle Zeiten auf Null stehen müssen diese nun veränderbar
sein. Sollten schon gespeicherte Werte vorliegen soll es mit Enter
weitergehen. Wenn eine Zeit aber verändert werden soll, drücke ich die >
Taste und führe damit eine andere Funktion aus.
Sieht dann ungefähr so aus:
Aendern Zeit x // x steht für den Zeilenwert des Cursors aus der
// aufrufenden Funktion
0:00 min
wobei die Stelle der Minuten blinkt, mit den Cursortasten < > kann man
jetzt die drei Stellen anwählen. Entsprechend des Wertes der Spalte vom
Cursor möchte ich jetzt ein von der Tastatur eingebener Wert den
entsprechenden Variablen zuweisen und der eingebene Wert soll im LCD an
der blinkenden Stelle erscheinen. Aber da scheitert es dann bei mir.
hier mal der Programmcode der beiden Menüs: