Forum: Mikrocontroller und Digitale Elektronik Tastatur über ADC einlesen


von Daniel W. (Gast)


Lesenswert?

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
int main (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

von Daniel W. (Gast)


Lesenswert?

Ist es denn möglich den AD-Wandler gleich danach wieder mit
1
 ADCSRA |= (1<<ADEN)
o.ä. zu starten?

von Karl H. (kbuchegg)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Michael Lambertz (Gast)


Lesenswert?

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
4
return ADCW;                    // ADC auslesen und zurückgeben

von Karl H. (kbuchegg)


Lesenswert?

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.

von Daniel W. (Gast)


Lesenswert?

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.

von Manfred S. (Firma: Manfred) (xfred343)


Lesenswert?

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]

von Peter D. (peda)


Lesenswert?

Manfred S. schrieb:
> Mit normalem Entprellen geht hier leider nichts.

Doch, geht sehr gut:

Beitrag "Tastenmatrix auslesen über nur 2 Leitungen"


Peter

von Manfred S. (Firma: Manfred) (xfred343)


Lesenswert?

Ja, glaub ich schon,

allerdings nicht wenn man das etwas schwammige Conrad-Tastenfeld 
erwischt...

http://www.conrad.at/ce/de/product/709840/TASTATUR-MATRIX-3X4/SHOP_AREA_17386&promotionareaSearchDetail=005

von Peter D. (peda)


Lesenswert?

Manfred S. schrieb:
> allerdings nicht wenn man das etwas schwammige Conrad-Tastenfeld
> erwischt...

Doch, genau das benutze ich auch.


Peter

von Manfred S. (Firma: Manfred) (xfred343)


Lesenswert?

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..

von Daniel W. (Gast)


Lesenswert?

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...

von Manfred S. (Firma: Manfred) (xfred343)


Lesenswert?

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%)...

von Daniel W. (Gast)


Lesenswert?

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?

von Manfred S. (Firma: Manfred) (xfred343)


Lesenswert?

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

von Daniel W. (Gast)


Lesenswert?

Vielen Dank, Manfred.

Werd mich gleich morgen an den Code setzen.
Kanns kaum erwarten ;)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.