Hallo Leute,
durch Studieren mehrerer Forumsbeiträge, habe ich es geschafft, eine 4x3
Matrix Tastatur über einen AD-Wandler des Atmega8 einzulesen.
Die gedrückte Taste wird auf einem LCD angezeigt und durch deaktivieren
des AD-Wandlers dort dauerhaft angezeigt. Hier ein Ausschnitt aus meinem
C-Code:
1
intmain(void)
2
{
3
while(run)
4
{
5
ADMUX=(1<<REFS0)|2;// Kanal 2 einlesen
6
ADCSRA|=(1<<ADSC);// AD-Wandlung starten
7
8
adwert=ADCW;
9
10
// Routine für die Bedientastatur:
11
12
13
if(adwert>304&&adwert<316)
14
{ADCSRA&=~(1<<ADEN);// AD - Wandlung stoppen
15
lcd_gotoxy(11,1);// Spalte 11, Zeile 1
16
lcd_string("1");}// gedrueckte Taste anzeigen
17
18
if(adwert>250&&adwert<303)
19
{ADCSRA&=~(1<<ADEN);// AD - Wandlung stoppen
20
lcd_gotoxy(11,1);// Spalte 11, Zeile 1
21
lcd_string("2");}// gedrueckte Taste anzeigen
22
23
if(adwert>317&&adwert<354)
24
{ADCSRA&=~(1<<ADEN);// AD - Wandlung stoppen
25
lcd_gotoxy(11,1);// Spalte 11, Zeile 1
26
lcd_string("3");}// gedrueckte Taste anzeigen
27
28
usw...
29
30
}
Ich möchte nun gerne eine zweiziffrige Zahl auf dem Display ausgeben,
also die erste bei:
1
lcd_gotoxy(11,1);
und die zweite bei
1
lcd_gotoxy(12,1);
Ich hab mir gedacht, dass ich eine numerische for-Schleife einsetzen
kann:
1
for(i=0;i<=1;i++){}
Oder habt ihr einen anderen Tipp für mich?
Vielen Dank und lieben Gruß
Daniel
Daniel W. schrieb:> Ich möchte nun gerne eine zweiziffrige Zahl auf dem Display ausgeben,> also die erste bei:
jetzt ist der Punkt erreicht, an dem du anfangen musst, deine bisherigen
Erkentnisse in eine Funktion zu verpacken. Deine Tastatur-Auslesen ist
nämlich noch nicht vollständig. Du stellst momentan nur fest, dass eine
Taste gedrückt IST. Das ist aber nicht dasselbe wie das Erkennen eines
Tastendrucks, der aus Niederdrücken - Halten der Taste - und Loslassen
besteht.
Erst dann, wenn du einen Tastendruck sauber erkennen kannst, macht es
Sinn, sich über die Eingabe von mehrziffrigen Zahlen zu unterhalten.
>
1
lcd_gotoxy(11,1);
> und die zweite bei>
1
lcd_gotoxy(12,1);
soweit bist du noch lange nicht. Erst mal musst du die beiden Ziffern
haben.
Daniel W. schrieb:> Ist es denn möglich den AD-Wandler gleich danach wieder mit>
1
ADCSRA|=(1<<ADEN)
> o.ä. zu starten?
Lies dir bitte den Abschnitt über den ADC im Tutorial durch
AVR-GCC-Tutorial Kapitel 12.2.1
Wenn ich mal davon ausgehe, dass du den ADC nicht im Free Running Modus
betreibst, dann ist das hier
ADCSRA |= (1<<ADSC); // AD-Wandlung starten
adwert = ADCW;
schon mal falsch, genauso wie das hier
{ADCSRA &= ~(1<<ADEN); // AD - Wandlung stoppen
unnötig ist.
Im Tutorial steht wieso.
Den AD-Wandler habe ich natürlich schon vorher initialisiert.
Also Betriebsart (Single-Conversion) und Frequenzvorteiler eingestellt
und aktiviert.
Das Problem, das sich mir bei meiner Anwendung ergeben hat, war, dass
bei Loslassen der Taste, der AD-Wert natürlich wieder auf 0 fiel und die
Ausgabe auf dem LCD sich änderte, da der Kanal permanent ausgelesen
wird.
Würde es was bringen, wenn ich mit folgenden Befehlen arbeiten würde?
1
ADMUX=(1<<REFS0)|2;// Kanal 2 einlesen
2
ADCSRA|=(1<<ADSC);// eine Wandlung "single conversion"
3
while(ADCSRA&(1<<ADSC)){}// auf Abschluss der Konvertierung warten
Michael Lambertz schrieb:>> Würde es was bringen, wenn ich mit folgenden Befehlen arbeiten würde?
Nein.
Du kannst das Problem nicht mit dem ADC lösen sondern nur damit, wie du
den erhaltenen Wert weiter behandelst. Aus dieser Behandlung muss sich
ergeben, dass die Taste wieder losgelassen wurde bzw. die nächste Taste
gedrückt uwrde.
Dein Programm muss in der Lage sein, aus den nacheinander erhaltenen
Messwerten
0
0
0
80
308
309
307
0
0
0
270
350
345
352
347
190
0
0
0
0
180
347
348
346
350
120
0
0
0
10
220
270
272
268
271
30
0
0
0
0
die gedrückten Tasten
zuerst 1
dann 3
dann noch einmal 3
danach 2
zu erkennen und zu extrahieren.
Und das ganz nicht dadurch, dass es wartet, sondern indem es 1 Messung
vornimmt und dann mit den vorhergehenden Werten vergleicht und daraus
seine Schlüsse zieht.
Ich glaub, ich versteh langsam, was du meinst.
Zwar kann ich mit meinem bisherigen Programm den Tastendruck erkennen
und ausgeben, jedoch bringt mir das nicht viel für meine weitere
Vorgehensweise.
Das Beispiel, welches du aufgeführt hast, ist sehr anschaulich.
Ist es möglich diese Folge von Werten zu "zerlegen", sodass ich immer
von einer "0" bis zur nächsten "0" messe und dabei den höchsten Wert
rausfilter?
Leider weiß ich nicht so genau, wie ich das in der Software realisieren
kann.
Hi,
ich hab mich mit der Analogtastatur eingehender beschäftigt - entgegen
anderen Beiträgen, ist die hochstabil, auch wenn die Tastatur einige
Meter vom Controller entfernt montiert wird - wenn man sie richtig
programmiert.
Mit normalem Entprellen geht hier leider nichts.
Ich hab es so programmiert:
Mit einem Timer werden alle 5mSec die Analogwerte gemessen. Wenn eine
Taste gedrückt wird, werden jeweils 12 Analogwerte erfasst und die
zugeordnete Taste hochgezählt. Sobald die 12 Messwerte da sind, werden
sie analysiert: erreicht eine Taste mehr als 50%, hat sie gewonnen.
Meine Erfahrung ist, dass die ersten 1-2 und die letzten 1-2 Messwerte
kritisch sind, da die Anlaogtastatur erst nach diesen Messungen einen
konstanten Wert erreicht. Mein Programm ist (leider oder Gott sei Dank)
in Bascom, aber wird in C ähnlich gehen...
[code] '...
dim adc0 as word
dim choff0 as word
dim chon0 as byte
dim matrix0(16) as byte '16 Tasten erfasse ich!!
dim i as long
dim bytDigit0 as byte
'...
'5msec Timerroutine
'...
Adc0 = Getadc(0)
If Adc0 < 340 Then 'keine Taste gedrückt
If Choff0 < 65535 Then Incr Choff0
If Choff0 = 5 Then 'warte 25 mSec
Chon0 = 1 'schaltet Tastenerkennung ein
End If
Else
If Chon0 >= 1 Then
If Chon0 = 1 Then 'Tastenerkennung auf null
For I = 1 To 16
Matrix0(i) = 0
Next I
End If
If Chon0 <= Ckeysamples Then
Select Case Adc0
Case 340 To 362
I = 11 '358/358 *
Case 363 To 379
I = 10 '371/372 0
Case 380 To 395
I = 12 '389/390 #
Case 396 To 411
I = 15 '406/405 C
Case 412 To 442
I = 7 '438/438 7
Case 443 To 465
I = 8 '459/459 8
Case 466 To 492
I = 9 '485/486 9
Case 493 To 529
I= 6 '512 S
case 530 to 575
I = 4 '563/565 4
Case 576 To 615
I = 5 '598/600 5
Case 616 To 660
I = 6 '644/646 6
Case 661 To 715
I = 14 '692/691 B
Case 716 To 785
I = 1 '765/766 1
Case 786 To 851
I = 2 '830/833 2
Case 852 To 940
I = 3 '921/925 3
Case 941 To 1023
I = 13 '1023/1020 T1
End Select
Incr Matrix0(i)
Cod0(chon0) = Adc0
Incr Chon0
End If
End If
Choff0 = 0
End If
'Auswertung im Hauptprogramm
const cKeySamples = 12
If Chon0 = Ckeysamples Then 'Auswertung Codeschloss,
Zehnertastatur
Bytdigit0 = 1
For I = 2 To 16 'Maxwert-Bestimmung
If Matrix0(i) > Matrix0(bytdigit0) Then
Bytdigit0 = I
End If
Next I
J = Chon0 * 0.5
Chon0 = 0 'Abschalten der Keylogik bis zur nächsten
Pause
If Matrix0(bytdigit0) > J Then
'Taste erkannt
endif
endif
[code]
Peter Dannegger schrieb:> Manfred S. schrieb:>> allerdings nicht wenn man das etwas schwammige Conrad-Tastenfeld>> erwischt...>> Doch, genau das benutze ich auch.>>> Peter
Bei der Tastatur hab ich im 5 msec Rhythmus beim Testen alle Werte auf
die serielle geschrieben - da habe ich die Schwankungen bei den ersten
und letzten Takten beobachtet, vor allem wenn man die Tasten ganz
langsam eindrückt.. manchmal auch zwischendurch, wenn man die Taste ein
bißerl loslässt..
hmm, dann werde ich mir deinen C-Code einmal zu Gemüte führen. Hab ja
schon erfolgreich deine - wirklich geniale Sommerzeitumschaltung in C
(Hut ab, der Algorithmus ist bis ins Letzte durchdacht gewesen) - auf
Bascom konvertiert.
Mir gefallen deine genialen Ideen, auch das mit dem Bitzähler fürs
Entprellen, leider sind manchmal die Möglichkeiten in Bascom nicht so
flexibel..
Ok, wenn ich euch recht verstehe, müsste es doch so gehen:
Eine Messung wird gestartet, sobald der Wert "0" übersteigt.
Die Messung wird gestoppt, sobald der Wert wieder "0" ist, usw...
Ist der Denkansatz so richtig?
Bascom ist mir leider sehr fremd, sodass ich versuchen werde, einen
ähnlichen Lösungsweg in C zu finden...
Ja, genaugenommen musst du ein bißerl "entprellen",
ich hab es so gemacht:
messen und für jeden Messwert in dem Tastenarray die dazugehörige Taste
hochzählen..
das ergibt in der geschilderten Zahlenreihe
Matrix(12) auf null setzen
0
270 - inc Matrix(2)
350 - inc Matrix(3)
345 - inc Matrix(3)
352 - inc Matrix(3)
347 - inc Matrix(3)
190 - inc Matrix(x)
0
0
Demnach hat mein Tastenarray für Matrix(2)=1 Punkt, für Matrix(3)=4
Punkte, Taste 3 wurde mit 4x daher am häufigsten gedrückt und "gewinnt"
mit 4 von 6 Messwerten (liegt über 50%)...
Danke für die anschauliche Beschreibung.
Hört sich recht logisch an und ich denke, ich habe die Idee dahinter
verstanden.
Könntest du vielleicht noch etwas zu deinem Code sagen, damit ich auch
hier die einzelnen Abschnitte nachvollziehen kann?
ich denke, es ist einfacher von Bascom nach C zu konvertieren als
umgekehrt...
...
Adc0 = Getadc(0)
If Adc0 < 340 Then 'keine Taste gedrückt,
If Choff0 < 65535 Then Incr Choff0
If Choff0 = 5 Then 'warte 25 mSec
Chon0 = 1 'schaltet Tastenerkennung ein
End If
Else
If Chon0 >= 1 Then
If Chon0 = 1 Then 'Tastenerkennung auf null
For I = 1 To 16 'meine Matrix ist erweitert auf 16
Tasten
Matrix0(i) = 0 'Lösche alle 16-Tastenzähler
Next I
End If
'ich breche schon beim 12. Sample ab - musst du aber nicht
'kannst bis zu 255 Samples weitermachen, ansonst darf halt
'der Zähler nicht bis 255 überlaufen
If Chon0 <= Ckeysamples Then
Select Case Adc0
Case 340 To 362
I = 11 '358/358 *
Case 363 To 379
I = 10 '371/372 0
Case 380 To 395
I = 12 '389/390 #
Case 396 To 411
I = 15 '406/405 C
Case 412 To 442
I = 7 '438/438 7
Case 443 To 465
I = 8 '459/459 8
Case 466 To 492
I = 9 '485/486 9
Case 493 To 529
I= 6 '512 S
case 530 to 575
I = 4 '563/565 4
Case 576 To 615
I = 5 '598/600 5
Case 616 To 660
I = 6 '644/646 6
Case 661 To 715
I = 14 '692/691 B
Case 716 To 785
I = 1 '765/766 1
Case 786 To 851
I = 2 '830/833 2
Case 852 To 940
I = 3 '921/925 3
Case 941 To 1023
I = 13 '1023/1020 T1
End Select
'in I steht die für den aktuell erfassten Messwert
'zugeordnete Taste
Incr Matrix0(i) 'Tastenzähler für diese Taste erhöhen
Cod0(chon0) = Adc0 'das ist nur zum Mitspeichern
'aller Werte für Diagnosezwecke ein eigenes Array
Incr Chon0
End If
End If
Choff0 = 0
End If
So ähnlich muss deine Timerroutine laufen, meine wird alle 5mSec
angesprungen
Und danach wertest du nur die Matrix0 aus,
das passiert hier:
Bytdigit0 = 1
For I = 2 To 16 'Maxwert-Bestimmung
If Matrix0(i) > Matrix0(bytdigit0) Then
Bytdigit0 = I
End If
Next I 'Bytdigit hat die Taste mit der höchsten Häufigkeit
J = Chon0 * 0.5
Chon0 = 0 'Abschalten der Keylogik bis zur nächsten
Pause
If Matrix0(bytdigit0) > J Then 'mehr als 50% erreicht
'Taste erkannt
endif
endif