Forum: Mikrocontroller und Digitale Elektronik 5 Tasten am ADC


von Rick M. (rick00)


Angehängte Dateien:

Lesenswert?

Hallo!

Ich besitze ein RN-Control 1.4 Board mit Atmega32.
Dort sind 5 Tasten über einen Spg.-Teiler am ADC angeschlossen. (siehe 
Schaltplan). Ich habe zusätzlich den Pin PA7 mit 100k gegen GND gezogen, 
damit der ADC nicht in der Luft hängt.
Als Anfänger schlage ich mich gerade herum, diese Tasten anständig 
auszulesen. Es gibt zwar ein Demoprogramm in C, aber dieses beinhaltet 
nichts brauchbares dazu.
Ich weiß, daß es eine Komfort-Routine und das Bsp. mit der 
Matrixtastatur am ADC von Peter Dannegger dazu gibt, aber leider ist mir 
das als Anfänger etwas zu hoch....

Meine Idee:

Da ich sowieso zur Erzeugung eines Sekundentaktes (Programm von Peter 
Dannegger) eine ISR habe die alle 4msec abläuft, benutze ich gleich 
diese, um alle 8msec eine ADC-Wandlung zu starten. Wird 2mal 
hintereinander die gleiche Taste detektiert, so wird was gemacht, 
ansonsten nichts.

Der Vergleich in MAIN:
1
if(button_read_puls == 2)      // 8msec vergangen
2
      button1 = read_button();    // Tasten auslesen 
3
      
4
    if(button_read_puls == 4)      // weitere 8msec vergangen
5
      button2 = read_button();    // Tasten auslesen
6
            
7
          
8
      
9
    
10
    if( button1 == button2 )      // Nach 8msec noch selbe Taste?
11
    {  
12
      switch ( button2 )        // Handlung zuweisen


Die Funktion read_button:
1
uint8_t read_button(void)
2
{
3
  
4
  uint8_t button = 0;
5
  
6
  adc_value_button = adc_read_avg(7,4);
7
  //ADC-Wert für Tasten auslesen, Channel 7 / 4 Messungen
8
  
9
  // Wertebereich für AREF = 2,13V !!
10
  
11
  if( (adc_value_button >= 0) && (adc_value_button <= 10 ) ) button = 0; // keine Taste gedrückt
12
  
13
  else if( (adc_value_button >= 750) && (adc_value_button <= 770) ) button = 1;
14
  //liegt der ADC-Wert innerhalb des Fensters für Taster 1 ?
15
  
16
  else if ( (adc_value_button >= 600) && (adc_value_button <= 620) ) button = 2;    // Taste 2
17
  else if ( (adc_value_button >= 450) && (adc_value_button <= 470) ) button = 3;    // Taste 3
18
  else if ( (adc_value_button >= 297) && (adc_value_button <= 317) ) button = 4;    // Taste 4  
19
  else if ( (adc_value_button >= 144) && (adc_value_button <= 164) ) button = 5;    // Taste 5
20
  else button = 99; // Fehler bei Tastenerkennung !!
21
    
22
    
23
  return button;    // Tastennummer zurückgeben
24
    
25
}


Leider funktioniert die Tastenerkennung überhaupt nicht und ich kann 
meinen Denkfehler nicht erkennen.

Gruß Rick

von moep (Gast)


Lesenswert?

Dein Aref und die Werte für den ADC passen nicht.
Rechne mal aus was du für jeden Taster für eine Spannung am Pin anliegen 
hast.

von moep (Gast)


Lesenswert?

Korrektur:
Aref passt natürlich, aber die Werte sind soweit ich das auf die 
schnelle gerechnet hab nicht ganz korrekt.
Du musst den 100k gegen Masse in den Spannungsteiler auch einrechnen.

von Rick M. (rick00)


Lesenswert?

Die Werte passen. Sowohl rechnerisch, als auch angezeigt per LCD.

Rechnung:

Versorgungsspannung der Tasten gemessen: 4,93V
Referenzspannung am ADC gemessen: 2,13V

ADC-Wert = (R_taster / R_ges) * (U_ges / AREF) * 1024

zu beachten ist, daß es sich jeweils um eine Parallelschaltung von  (1 
bis 5k) und 100k handelt.
So ergebne sich für die einzelnen Tasten folgende Widerstanswerte:

Taster1: 4,76k

Taster2: 3,846k

Taster3: 2,913k

Taster4: 1,961k

Taster1: 990 Ohm


Somit ergeben sich folgende ADC-Werte:

Taster1: berechnet 156 // real 154

Taster2: berechnet 310 // real 307

Taster3: berechnet 460 // real 459

Taster4: berechnet 608 // real 609

Taster1: berechnet 752 // real 760

Gruß Rick

von Rick M. (rick00)


Lesenswert?

Rechen-Bsp für Taster 5:

ADC-Wert = (0,99k/15k) * (4,93V / 2,13V) * 1024

ADC-Wert = 156,4268 -> 156

Per LCD angezeigt: 154

Fenster für Auswertung: 144 bis 164

von moep (Gast)


Lesenswert?

Ok, ok :)
Oben steht 5V (und nicht 4,xx) und damit fallen die Werte rechnerisch 
nun mal aus deinem jeweiligen Wertebereich.
Aber wenn du die Werte auch per Messung kontrolliert hast ist ja sowieso 
alles in Ordnung.

Dann kontrollier' die Werte doch einfach mal an verschiedenen Stellen um 
herauzufinden wo es hakt.

Bekommst du denn die richtige Tastennummer zurückgegeben wenn du die 
Funktion read_butten in der main einfach mal aufrufst?
(Mal von Hand per wait-Befehl alle paar ms aufrufen und den Rückgabewert 
auf dem LCD ausgeben).

Die Variable "button_read_puls" wird in der Timer-ISR hochgezählt, ja?
Ist die auch als "volatile" deklariert?

von Rick M. (rick00)


Lesenswert?

Entschuldige, war mein Fehler, da ich die reale Spannung am 
Spannungteiler nicht angegeben habe.

Die realen Werte hab ich per LCD ermittelt, wenn ich die Tasten schön 
lange gedrückt halte.
Aber ich glaube durch die Tastenprellung bekomme ich bei der Mittelung 
der ADC-Werte nur Mist raus. Da müsste ich warscheinlich jeweils den 
größten und kleinsten Ausreisser wegschmeissen?

Hier die Fkt. adc_read_avg:
1
uint16_t adc_read_avg (uint8_t channel , uint8_t average)
2
{
3
4
  uint16_t result;
5
  
6
7
  ADMUX = ( (ADMUX & ~(0x1F)) | (channel & 0x1F) );
8
  /* Kanal wählen, ohne andere Bits zu verändern
9
10
   0bxxx00000    ADMUX & ~(0x1F) -> Channel Bits auf 0 setzen
11
   0bxxx00001    1 & 0x1F  (=channel=1)
12
  ____________  oder - Verknüpfung
13
   0bxxx00001                  */
14
15
   /* Nach der Kanalwahl des ADC wird ein "Dummy Readout" zur Sicherheit durchgeführt.
16
    Man startet eine Wandlung, liest den Wert aus und verwirft diesen */
17
  
18
  ADCSRA |= (1<<ADSC); // ADSC=1 Wandlung starten
19
  
20
  while (ADCSRA & (1<<ADSC)) {}
21
  //Solange ADSC = 1 ist, ist die Wandlung noch nicht abgeschlossen
22
    
23
24
  result = ADCW;          
25
  // Ergebnis der Wandlung auslesen, sonst wird Ergebnis der nächsten Wandlung nicht 
26
  // übernommen
27
28
  result = 0;                // Ergebnis verwerfen
29
30
  // Durchführung mehrerer Messungen und Ergebnise aufaddieren:
31
  for (uint8_t i=0; i < average; i++)
32
    {
33
      ADCSRA |= (1<<ADSC);      // 1ne Wandlung durchführen
34
      while (ADCSRA & (1<<ADSC)) {}  // Warten bis Wandlung beendet
35
      result += ADCW;          // Ergebnisse aufaddieren
36
    }
37
38
  result = result / average;        // Mittelwert bilden
39
  return result;              // Ergebnis zurück geben
40
  
41
}


und hier meine ISR von Timer1:

von der Header-Datei:
1
#define XTAL 16000000L          // Quarzfrequenz in Hertz
2
#define SOFT_PRESCALER 250L        // Software Teiler
3
4
5
uint8_t volatile soft_prescaler;
6
uint8_t volatile second_puls;
7
uint8_t volatile button_read_puls;

und der Code:
1
/*****************************************************************************************
2
*              Interrupt Service Routine: TIMER1_COMPA
3
*
4
*
5
*
6
*
7
*Aufgabe:  Der Vergleichswert von Timer1 (OCR1A) ist so gewählt, daß er alle 4msec
8
*      ereicht wird und auch zum Entprellen von Tasten genutzt werden kann.
9
*      Diese 4msec werden zusätzlich durch den Software_Teiler multipliziert, sodaß
10
*      ein Sekundenimpuls ( 4msec * 250 = 1sec) entsteht.
11
*
12
*****************************************************************************************/
13
14
ISR (TIMER1_COMPA_vect)
15
{
16
17
  
18
  button_read_puls++;
19
  if (button_read_puls == 5)
20
    button_read_puls = 0;
21
    
22
23
24
  #if XTAL % SOFT_PRESCALER        // Rest? wenn ja: OCR1A = normaler Vergleichswert
25
    OCR1A = XTAL / SOFT_PRESCALER - 1;  // Nach dem verlängerten Vergleichswert muß wieder
26
  #endif                  // der normale Comparewert geladen werden
27
28
  
29
    if(--soft_prescaler == 0)      // zähle software_teiler (250) runter bei 0 ist 
30
                      // eine sekunde vergangen
31
    {
32
      soft_prescaler = (uint8_t) SOFT_PRESCALER;  // setze software_teiler wieder auf 
33
                            // Anfangswert
34
        
35
      if (++second_puls == 2)    // second_puls +1, wenn 2 dann Rücksetzen 
36
        {second_puls = 0;}
37
38
    #if XTAL % SOFT_PRESCALER    // Rest? wenn ja: 
39
                    //OCR1A = korrigierter Vergleiswert (nur 1x pro sec)
40
      OCR1A = (XTAL / SOFT_PRESCALER - 1) + XTAL % SOFT_PRESCALER
41
    #endif
42
    }
43
  
44
}

von Mario (Gast)


Lesenswert?

also ganz langsam:

angenommen bei R3-GND liegen 4,93 V an.....

somit ergibt sich für mich:

R4: 1,643V
R5: 1,314V
R6: 0,986V
R7: 0,657V
R8: 0,328V

d.h: Bei AREF: 2,13V
-->1V = 480,75

Berechnung:

R4: 1,643*480,75= 789,87 (790)
R5: 631,705 (632)
R6: 474,01 (474)
R7: 315,85 (316)
R8: 157,68 (158)


lg

von Rick M. (rick00)


Lesenswert?

Hallo Mario!

Hast Du die 100k parallel mit einbezogen?

Für mich kommt da raus:

R8: 0,325V
R7: 0,645V
R6: 0,957V
R5: 1,264V
R4: 1,564V

lg Rick

von Mario (Gast)


Lesenswert?

wo sind noch 100k?

am Screenshot sind die nicht angegeben!?

von Rick M. (rick00)


Lesenswert?

Nein, am Schaltplan nicht, daß hab ich dazugeschieben und auch anhand 
meines Rechenbeispieles nochmal gezeigt.

hier
Rick M. schrieb:
> Ich besitze ein RN-Control 1.4 Board mit Atmega32.
> Dort sind 5 Tasten über einen Spg.-Teiler am ADC angeschlossen. (siehe
> Schaltplan). Ich habe zusätzlich den Pin PA7 mit 100k gegen GND gezogen,
> damit der ADC nicht in der Luft hängt.

und hier
Rick M. schrieb:
> zu beachten ist, daß es sich jeweils um eine Parallelschaltung von  (1
> bis 5k) und 100k handelt.
> So ergebne sich für die einzelnen Tasten folgende Widerstanswerte:
>
> Taster1: 4,76k
>
> Taster2: 3,846k
>
> Taster3: 2,913k
>
> Taster4: 1,961k
>
> Taster1: 990 Ohm

von Rick M. (rick00)


Lesenswert?

Ich habe jetzt herausgefunden, daß die Fkt. "read_button" nur die 
richtige Tastennummer zurückgibt, wenn man die Taste länger gedrückt 
hält.
Ansonsten wird keine Taste erkannt.
Ich rufe die Funktion "read_butten" alle 10msec (_delay_ms(10)) auf und 
werte den Rückgabewert per switch-Fkt. aus.

Anscheinend messe ich durch die Prellerei nur blödsinn??

Gruß Rick

von Mario (Gast)


Lesenswert?

OK, verstehe :)

sry, ich sollte doch genauer lesen gg

von Hannes L. (hannes)


Lesenswert?

Rick M. schrieb:
> Aber ich glaube durch die Tastenprellung bekomme ich bei der Mittelung
> der ADC-Werte nur Mist raus. Da müsste ich warscheinlich jeweils den
> größten und kleinsten Ausreisser wegschmeissen?

Ich mittle da überhaupt nix. Ich lese in regelmäßigen Intervallen den 
ADC ein, extrahiere anhand einer LUT die Tasten-Nummer und entprelle die 
Taste, indem ich die Tastennummer mit der Nummer der letzten Abfrage 
vergleiche. Bei Gleichheit wird der Prellzähler erhöht (und auf einen 
Max-Wert begrenzt), bei Ungleichheit wird der Prellzähler ausgewertet 
und danach gelöscht.

War der Prellzähler über der Lang/kurz-Schwelle, dann ist es ein langer 
Tastendruck, war er unter der Prellschwelle, dann war der Tastendruck 
ungültig. War der Prellzähler zwischen Prellschwelle und 
Lang/kurz-Schwelle, dann war es ein kurzer Tastendruck.

War der Tastendruck gültig und der Tastenwert nicht 0 (0 = keine Taste 
gedrückt), so wird dem Hauptprogramm die Tasten-Nummer übergeben 
(globale Variable). Das Hauptprogramm verzweigt nun anhand der 
Tastennummer zur gewünschten Aktion und diese löscht dabei die 
Tastennummer.

Das funktioniert bei mir in verschiedenen Varianten (Timer-Interrupt, 
ADC-Interrupt) mit bis zu 16 Tasten (mehr müsste auch gehen, habe ich 
aber noch nicht probiert) ohne Probleme. Allerdings in ASM.

...

von Rick M. (rick00)


Lesenswert?

Hannes Lux schrieb:
> Ich lese in regelmäßigen Intervallen den
> ADC ein, extrahiere anhand einer LUT die Tasten-Nummer und entprelle die
> Taste, indem ich die Tastennummer mit der Nummer der letzten Abfrage
> vergleiche.

LUT?


Hannes Lux schrieb:
> bei Ungleichheit wird der Prellzähler ausgewertet
> und danach gelöscht.

Wieso bei Ungleichheit auswerten? Dann war doch die Erkennung ungültig, 
oder?

von Thomas W. (thomas0906)


Lesenswert?

Hey, das ist ne gute Idee mit Tastern am ADC Eingang.

Gruß
Thomas

von Matthias (Gast)


Lesenswert?

Rick M. schrieb:
> Versorgungsspannung der Tasten gemessen: 4,93V
> Referenzspannung am ADC gemessen: 2,13V

Für die Tastenerkennung wäre es wesentlich sicherer, eine ratiometrische 
Meßmethode zu verwenden, d.h. sowohl für den Spannungsteiler als auch 
für den ADC die selbe Bezugsspannung zu verwenden, z.B. AVCC.
Mit dem Teiler an VCC und der internen Referenz für den ADC gibt es 
immer eine üble Eierei der Entscheidungsschwellen (besonders bei den 
oberen Tasten), sobald VCC schwankt.
Gruß
Matthias

von Rick M. (rick00)


Lesenswert?

Auch ohne Mittelung bekomme ich erst nachdem ich die Taste länger 
gedrückt halte, die richtige Tastennummer zurück.
Das Prellen kann doch keine Sekunde dauern?

von Rick M. (rick00)


Lesenswert?

Matthias schrieb:
> Rick M. schrieb:
>> Versorgungsspannung der Tasten gemessen: 4,93V
>> Referenzspannung am ADC gemessen: 2,13V
>
> Für die Tastenerkennung wäre es wesentlich sicherer, eine ratiometrische
> Meßmethode zu verwenden, d.h. sowohl für den Spannungsteiler als auch
> für den ADC die selbe Bezugsspannung zu verwenden, z.B. AVCC.
> Mit dem Teiler an VCC und der internen Referenz für den ADC gibt es
> immer eine üble Eierei der Entscheidungsschwellen (besonders bei den
> oberen Tasten), sobald VCC schwankt.
> Gruß
> Matthias

Leider muß ich auch noch Spannung und Strom am ADC messen und sehe dafür 
eine Referenzspannung von 2,56V per LM336-2,5 vor.

Leider ist auf dem Board auch der AD-Wandler nicht von der 
Versorgungsspannung entkoppelt.

von Hannes L. (hannes)


Lesenswert?

Rick M. schrieb:
> Hannes Lux schrieb:
>> Ich lese in regelmäßigen Intervallen den
>> ADC ein, extrahiere anhand einer LUT die Tasten-Nummer und entprelle die
>> Taste, indem ich die Tastennummer mit der Nummer der letzten Abfrage
>> vergleiche.
>
> LUT?

Lookuptable

>
>
> Hannes Lux schrieb:
>> bei Ungleichheit wird der Prellzähler ausgewertet
>> und danach gelöscht.
>
> Wieso bei Ungleichheit auswerten?

Weil erst dann der Tastendruck zu Ende ist.

> Dann war doch die Erkennung ungültig,
> oder?

Die war ungültig, wenn der Prellzähler die Prellschwelle nicht 
überschreiten konnte.

Jede Änderung an der Tastatur (drücken, loslassen) ergibt eine Änderung 
des zyklisch eingelesenen ADC-Wertes. Da dieser etwas streuen kann, wird 
daraus erstmal die unter Einhaltung der Toleranzen Tasten-Nummer 
ermittelt. Nummer 0 entspricht unbetätigte Tastatur, die anderen Nummern 
entsprechen den Tasten.

Solange immer dieselbe Tasten-Nummer ermittelt wird, ist der Zustand der 
Tastatur unverändert (also unbetätigt oder eine Taste betätigt).

Betätigt man eine Taste, endet erstmal der "Tastendruck 0", der dem 
Hauptprogramm nicht übergeben wird.

Nun zählt der Prellzähler, wie lange der neue Zustand anhält, also wie 
oft die neue Taste aus dem ADC-Wert ermittelt wird. Natürlich könnte man 
bei Erreichen der Prellschwelle sofort den Tastenwert an das 
Hauptprogramm übergeben, aber dann wird die Aktion ja bereits ausgelöst, 
ehe man weiß, ob es nicht doch noch ein langer Tastendruck (mit anderer 
Funktion) werden könnte. Also wertet man den (vor Überlauf geschützen) 
Prellzähler erst aus, wenn die Taste wieder losgelassen wurde. Und das 
ist nunmal die Ungleichheit (alt war Nummer der gedrückten Taste, neu 
ist 0, also unbetätigt). Natürlich muss man "alt" noch temporär sichern, 
um es dem Hauptprogramm übergeben zu können, falls der Tastendruck 
gültig war.
Gültig war der Tastendruck, wenn der gesicherte Alt-Wert nicht 0 war und 
der Prellzähler die Prellschwelle überschritten hat. Doch vor dem 
Übergeben des Tastenwertes an das Hauptprogramm prüft man noch den 
Prellzähler auf Überschreiten der zweiten Schwelle, die den "langen 
Tastendruck" definiert. Ist diese überschritten, wird ein oberes Bit in 
der Tastennummer gesetzt, an dem das Hauptprogramm erkennt, dass es sich 
um einen langen Tastendruck handelt, der anders behandelt werden muss. 
Das alles erfolgt in einer ISR, entweder im ADC-Interrupt, oder nebenbei 
im Timer-Interrupt, der noch andere Dinge zu erledigen hat. Das kostet 
also nur minimale Rechenzeit und läuft quasi im Hintergrund ab.

Das Hauptprogramm (oder eine Funktion davon) fragt dann (bei 
Gelegenheit) die übergebene Tasten-Nummer ab, reagiert darauf und löscht 
(entwertet) sie. Die übergebene Tasten-Nummer ist also eine Art 
Jobauftrag, der nach der Abarbeitung entwertet wird.

Das alles ist sehr ressourcenschonend, denn es verwendet keine 
rechenzeitvernichtenden Warteschleifen.

...

von Hannes L. (hannes)


Lesenswert?

Matthias schrieb:
> d.h. sowohl für den Spannungsteiler als auch
> für den ADC die selbe Bezugsspannung zu verwenden, z.B. AVCC.

Das sollte eine Selbstverständlichkeit sein.

Rick M. schrieb:
> Leider muß ich auch noch Spannung und Strom am ADC messen und sehe dafür
> eine Referenzspannung von 2,56V per LM336-2,5 vor.

Dann solltest Du den Tasten-Spannungsteiler auch an die Referenz 
anschließen.

Bei Verwenden der internen Referenz kann man auch die Referenz von 
Messung zu Messung umschalten.

Sind mehrere ADC-Eingänge zu messen, so bietet sich auch der 
ADC-Interrupt an. Dann wird eben mit einem "Mess-Stellen-Zähler" 
gearbeitet, der als Index auf ein Array mit ADMUX-Werten, ein Array mit 
Ergebnissen und als "Zeitscheibe" fungiert, anhand der die ISR bei 
Tastenabfrage in die richtige Routine verzweigt. Läuft auch im 
Hintergrund und frisst keine unnötige Rechenzeit.

...

von Hannes L. (hannes)


Lesenswert?

Rick M. schrieb:
> Auch ohne Mittelung bekomme ich erst nachdem ich die Taste länger
> gedrückt halte, die richtige Tastennummer zurück.

Dann machst Du mit dem ADC etwas Anderes falsch...

> Das Prellen kann doch keine Sekunde dauern?

Nein.

...

von Rick M. (rick00)


Lesenswert?

Hannes Lux schrieb:
> Dann machst Du mit dem ADC etwas Anderes falsch...

Im Prinzip halte ich mich beim Auslesevorgang an das Tutorial "AVR-GCC":

XX Kanal wählen

XX Eine Wandlung anstoßen (sigle shot)

XX Warten bis Wandlung abgeschlossen

XX Ergebnis auslesen und verwerfen

XX Neue Wandlung und Ergebnis verwerten

Mein Code:
1
uint8_t read_button(void)
2
{
3
  
4
  uint8_t button = 0;
5
  
6
  
7
8
  ADMUX = ( (ADMUX & ~(0x1F)) | (7 & 0x1F) );
9
  // Kanal 7 wählen, ohne andere Bits zu verändern
10
11
  ADCSRA |= (1<<ADSC); // ADSC=1 Wandlung starten
12
  
13
  while (ADCSRA & (1<<ADSC)) {}
14
  //Solange ADSC = 1 ist, ist die Wandlung noch nicht abgeschlossen
15
    
16
17
  adc_value_button = ADCW;          
18
  
19
  adc_value_button = 0;    // Ergebnis verwerfen
20
  
21
  ADCSRA |= (1<<ADSC); // ADSC=1 Wandlung starten
22
  
23
  while (ADCSRA & (1<<ADSC)) {}
24
  //Solange ADSC = 1 ist, ist die Wandlung noch nicht abgeschlossen
25
  
26
  adc_value_button = ADCW;          
27
  // Ergebnis der Wandlung auslesen
28
  
29
  // Wertebereich für AREF = 2,13V !!
30
    
31
  if( (adc_value_button >= 750) && (adc_value_button <= 770) ) button = 1;
32
  //liegt der ADC-Wert innerhalb des Fensters für Taster 1 ?
33
  
34
  else if ( (adc_value_button >= 600) && (adc_value_button <= 620) ) button = 2;    // Taste 2
35
  else if ( (adc_value_button >= 450) && (adc_value_button <= 470) ) button = 3;    // Taste 3
36
  else if ( (adc_value_button >= 297) && (adc_value_button <= 317) ) button = 4;    // Taste 4  
37
  else if ( (adc_value_button >= 144) && (adc_value_button <= 164) ) button = 5;    // Taste 5
38
  else button = 99; // Fehler bei Tastenerkennung !!
39
    
40
    
41
  return button;    // Tastennummer zurückgeben
42
    
43
}

Wenn keine Taste gedrückt wird, ergibt das momentan immer einen 
Fehlercode.
Damit wird mir der ADC-Wert im Display angezeigt.
Normalerweise hab ich noch ein Fenster für "keine Taste gedrückt", was 
den Wert 0 zurückgibt.

Ich kann hier keinen Fehler erkennen.

Hannes Lux schrieb:
> Dann solltest Du den Tasten-Spannungsteiler auch an die Referenz
> anschließen.

Was ja momentan der Fall ist.

In der Praxis erzeugt mir das aber dann Spannungsschwankungen in der 
Referenzspannung, was zu Messungenauigkeiten führt.

Hannes Lux schrieb:
> Sind mehrere ADC-Eingänge zu messen, so bietet sich auch der
> ADC-Interrupt an. Dann wird eben mit einem "Mess-Stellen-Zähler"
> gearbeitet, der als Index auf ein Array mit ADMUX-Werten, ein Array mit
> Ergebnissen und als "Zeitscheibe" fungiert, anhand der die ISR bei
> Tastenabfrage in die richtige Routine verzweigt. Läuft auch im
> Hintergrund und frisst keine unnötige Rechenzeit.

Hatte ich schon erwähnt, daß ich Anfänger bin ;-)

von Rick M. (rick00)


Lesenswert?

Hast Du das in etwa so gemeint?

1
if(button_read_puls == 2)      // 8msec vergangen
2
      button1 = read_button();    // Tasten auslesen 
3
      
4
    if(button_read_puls == 4)      // weitere 8msec vergangen
5
      {
6
        button2 = read_button();    // Tasten auslesen
7
        if(button1 == button2)
8
          equal_counter++;      // Zählvariable für Übereinstimmung
9
      }
10
      
11
    
12
    if (equal_counter == 5)
13
    {
14
      equal_counter = 0;
15
    
16
                
17
      switch ( button1 )        // Handlung zuweisen
18
      {

Gruß Rick

von Peter D. (peda)


Lesenswert?

Du mußt debuggen, also die Aufgaben unterteilen und einzeln testen.

Gib doch erstmal die ADC-Ergebnisse auf LCD oder UART aus und schau sie 
Dir an.


Peter

von Rick M. (rick00)


Angehängte Dateien:

Lesenswert?

Mache ich bereits, leider liefert meine Fkt. read_button nur die 
gedrückte Taste zurück, wenn ich sie lange gedrückt halte und ich weiß 
einfach nicht, was ich beim lesen des ADC und der Tasenzuweisung falsch 
mache.
Hier nochmal meine Fkt. als Anhang.

Gruß Rick

von Hannes L. (hannes)


Lesenswert?

Rick M. schrieb:
> Im Prinzip halte ich mich beim Auslesevorgang an das Tutorial "AVR-GCC":
>
> XX Kanal wählen
>
> XX Eine Wandlung anstoßen (sigle shot)
>
> XX Warten bis Wandlung abgeschlossen
>
> XX Ergebnis auslesen und verwerfen
>
> XX Neue Wandlung und Ergebnis verwerten

Diese Vorgehensweise ist akzeptabel, wenn man den ADC mal testen will 
oder erklären/demonstrieren will, wie der ADC funktioniert. Ernsthaft zu 
Gebrauchen ist dies aber nicht, da es blockierend arbeitet. Denn der ADC 
braucht Zeit zum Wandeln, wer ihm den Kanal mitteilt und dann auf das 
Ergebnis "wartet", der vertrödelt unnötig Rechenzeit. Ich mach' das 
deshalb anders:

XX Ergebnis auslesen und über den Index in ein Array werfen

XX Index erhöhen und auf Anzahl der Mess-Eingänge begrenzen

XX Bitmuster für ADMUX für die nächste Messung aus einem anderen Array
   holen und in ADMUX schreiben

XX ADC starten

Das alles erfolgt in einem Interrupt. Entweder nebenher in einem 
Timer-Interrupt, der z.B. die genaue Millisekunde als Basis für eine Uhr 
bereitstellt, oder eben im Interrupt des ADC. Somit gibt es nirgendwo 
die Notwendigkeit, auf das Fertigwerden des ADC zu warten. Wenn der 
nächste Interrupt fällig wird, ist der ADC mit Sicherheit fertig. Und in 
der Zwischenzeit kann das Programm andere Dinge erledigen.

>
> Mein Code:

Ich kann kein C.

Rick M. schrieb:
> Hatte ich schon erwähnt, daß ich Anfänger bin ;-)

Waren wir alle mal. Betreffs C bin ich sogar weniger als ein Anfänger, 
nämlich ein Ignorant. Aber meine Basteleien sind meist so klein und 
überschaubar, dass ich sie in ASM erschlagen kann und ohne C auskomme.

Andererseits hat auch ein Anfänger das Recht, Fortschritte zu machen und 
ungünstige Algorithmen zu meiden.

Rick M. schrieb:
> Hannes Lux schrieb:
>> Dann machst Du mit dem ADC etwas Anderes falsch...

Damit meinte ich z.B. auch das Einhalten der Vorgaben betreffs ADC-Takt 
(50..200 kHz) sowie sinnvolle Hardware-Beschaltung.

Dein Spannungsteiler hat einen ständigen Querstrom. Ich mach' das 
anders:
Die Widerstandskette geht von GND zum ADC-Eingang. Die Taster schalten 
zum Widerstand, der nach + führt. Somit liegt bei unbetätigten Tastern 
der ADC über die Widerstände an GND. Wird ein Taster betätigt, dann 
bildet sich ein Spannungsteiler aus der Anzahl der unteren Widerstände 
(von GND bis zum Taster) und dem Widerstand nach Plus. Die restlichen 
Widerstände der Kette liegen zwischen Taster und ADC und sind im 
Verhältnis zum Eingangswiderstand des ADC sehr niederohmig, verfälschen 
also das Ergebnis nicht.
Damit belastest Du AREF nur solange eine Taste betätigt ist.

...

von spess53 (Gast)


Lesenswert?

Hi

>Mache ich bereits, leider liefert meine Fkt. read_button nur die
>gedrückte Taste zurück, wenn ich sie lange gedrückt halte und ich weiß
>einfach nicht, was ich beim lesen des ADC und der Tasenzuweisung falsch
>mache.

Wieso versteifst du dich darauf, das das an dieser Funktion liegt?

Du wartest z.B. nach 99 im Hauptprogramm eine Sekunde. Vielleicht stimmt 
auch dein angenommener Controllertakt nicht.

MfG Spess

von Rick M. (rick00)


Lesenswert?

Das was Du hier schilderst fällt bei mir unter Programmoptimierung.
Daß ich Zeit vertrödle, indem ich auf das Wandlungsende warte, ist mir 
klar, hindert die Funktion aber nicht daran korrekt zu arbeiten. 
Jedenfalls soweit mein derzeitiges Wissen reicht.

Daß ich den Spannungsteiler selber nicht so machen würde, ist mir auch 
klar, aber wie ich ganz am Anfang schon beschrieben habe, habe ich ein 
fertig aufgebautes Testboard (RN-Control 1.4) und das hat nunmal eben 
dieses layout.
Deswegen hau ich das Board jetzt nicht in die Tonne.
Das dieses Enwicklungsboard nicht gerade der Hammer ist, wird mir jetzt 
auch immer mehr klar.

Das Board hat einen 16MHz Quarz, daher muß ich den Prescaler auf 128 
setzen.
Der ADC läuft also mit einer Frequenz von 125kHz.

Gruß Rick

von spess53 (Gast)


Lesenswert?

Hi

>Das Board hat einen 16MHz Quarz, daher muß ich den Prescaler auf 128
>setzen.

Bist du 100%-ig sicher, das der Controller auch mit dem Quarz läuft?

MfG Spess

von Rick M. (rick00)


Lesenswert?

Ja, das Board wurde mit dem Quarz ausgeliefert und der ATmega32 geht bis 
16MHz.

von Rick M. (rick00)


Lesenswert?

spess53 schrieb:
> Wieso versteifst du dich darauf, das das an dieser Funktion liegt?
>
> Du wartest z.B. nach 99 im Hauptprogramm eine Sekunde.

Danke für den Tipp. Das habe ich total übersehen und war ein Denkfehler.
Das kann natürlich nicht funktionieren.

von spess53 (Gast)


Lesenswert?

Hi

>Ja, das Board wurde mit dem Quarz ausgeliefert und der ATmega32 geht bis
>16MHz.

Hast du auch die Fuses auf den Quarz eingestellt. Ein fabrikneuer AVR 
läuft mit 1MHz. Auch wenn ein 16MHz-Quarz angeschlossen ist.

MfG Spess

von Hannes L. (hannes)


Lesenswert?

spess53 schrieb:
> Hast du auch die Fuses auf den Quarz eingestellt. Ein fabrikneuer AVR
> läuft mit 1MHz. Auch wenn ein 16MHz-Quarz angeschlossen ist.

Aua, jetzt wird vermutlich wieder ein AVR verfust, bevor das erste 
Programm so richtig drauf gelaufen ist...

...

von Rick M. (rick00)


Lesenswert?

Hi!

Die Fuses waren schon voreingestellt.
Ich toggle eine LED per Timer1-ISR im Sekundentakt.
Wenn mein MC nur mit 1MHz laufen würde, wäre der Takt 16sec lang und 
nicht 1sec.

Gruß Rick

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

so etwas habe ich auch schon mal gemacht

wichtig ist nicht eine einzelne messung auszuwerten sonder mindestens 3 
auffeinanderfolgende messungen sollten innerhalb eines fensters liegen 
bevor die eingabe als gültig gilt.

ich suche das mal raus hatte eine ganze handytastatur drann und hat 
zuverlässig funktioniert

von Rick M. (rick00)


Lesenswert?

Die Tasten werden jetzt korrekt am LCD ausgegeben.
Ich habe jeder Tase eine LED zugeteilt, daran merke ich, da ich die LEDs 
bei jedem Tastendruck toggle, daß der Ausgang pro Tastendruck mehrfach 
ein und ausgeschaltet wird.
Bei den Tasten 3-5 funktioniert nichtmal das?
Auch kann es vorkommen, wenn eine Taste gedrückt wird, daß die LED7, 
welche im Sekundentakt blikt, nicht mehr vollkommen ausgeht, obwohl ich 
den Ausgang nirgedswo anders schalte?
Kann es sein, daß mir die ISR von Timer1 den Code unbrauchbar macht.
Die Interrupts muß man doch nur temporär deaktivieren, wenn z.B in der 
ISR Register verändert werden, die auch im Hauptprogramm verändert 
werden, oder Variablen die größer 1Byte sind?




Gruß Rick

von Rick M. (rick00)


Angehängte Dateien:

Lesenswert?

Hier der momentande Code, falls es jemanden interessiert:

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

oben rechts die handy Tastatur bild vergößern


http://www.nisch-aufzuege.at/bilder/atmega32_adc_r_tastatur.jpg
1
// ADC interrupt service routine
2
// with auto input scanning
3
interrupt [ADC_INT] void adc_isr(void)
4
{ 
5
static char t,t0,t1,t2;
6
register static unsigned char input_index=0;
7
// Read the AD conversion result
8
adc1=ADCW ;     
9
if (adc1<adc1_o) 
10
{
11
adc1_o=adc1;
12
}
13
if (adc1>=0x0060)
14
{
15
adc1_o=0x3ff;
16
t=0x00; t0=0x00; t1=0x00; t2=0x00;
17
} 
18
if (adc1_o <= 0x004C)  {t = 0x33;}
19
if (adc1_o <= 0x0048)  {t = 0x32;}
20
if (adc1_o <= 0x0045)  {t = 0x31;}
21
if (adc1_o <= 0x0040)  {t = 0x4c;} //left
22
if (adc1_o <= 0x0038)  {t = 0x36;}
23
if (adc1_o <= 0x0035)  {t = 0x35;}
24
if (adc1_o <= 0x0030)  {t = 0x34;}
25
if (adc1_o <= 0x002D)  {t = 0x55;} //up
26
if (adc1_o <= 0x0029)  {t = 0x47;} //deal
27
if (adc1_o <= 0x0025)  {t = 0x39;}
28
if (adc1_o <= 0x0021)  {t = 0x38;}
29
if (adc1_o <= 0x001C)  {t = 0x37;}
30
if (adc1_o <= 0x0019)  {t = 0x44;} //down
31
if (adc1_o <= 0x0016)  {t = 0x43;} //hang off
32
if (adc1_o <= 0x0010)  {t = 0x23;}
33
if (adc1_o <= 0x000D)  {t = 0x30;}
34
if (adc1_o <= 0x0009)  {t = 0x2a;}
35
if (adc1_o <= 0x0004)  {t = 0x52;} //right
36
37
if (t2==t1)
38
  {
39
  if (t1==t0)
40
    {
41
      if (t2==t)
42
        {
43
        PORTD=~t2;  // nach 4 gleichen Mesunngen Ausgabe  des Tastencodes PortD   
44
              //Signalinvertierung da LEDs über R-Netz an +5V geführt werden. 
45
        }
46
    }
47
  }
48
49
t2=t1;
50
t1=t0;
51
t0=t;
52
53
// Select next ADC input
54
if (++input_index > (LAST_ADC_INPUT-FIRST_ADC_INPUT))
55
   input_index=0;
56
ADMUX=(FIRST_ADC_INPUT|ADC_VREF_TYPE)+input_index;
57
// Start the AD conversion
58
ADCSRA|=0x40;
59
}

von Rick M. (rick00)


Lesenswert?

PC2 bis PC5 funktioniert nicht als Ausgang. Da dies die 
JTAG-Schnittstelle ist, hab ich probeweise, das JTAG-Fuse mal mit Pony 
Prog gesetzt. Keine Änderung??
Die Pins sind immer auf 3,74V ??

Danke für den Code.
Is mir aber n bisserl zu hoch. Was machst Du da in der Tabelle?

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

Zur Funktion meiner Auswertung

Die Matrix ist so aufgebaut, dass der Widerstandswert aus der Summe der 
Spalten- und Zeilenwiderständen gebildet wird.

Die Summe der widerstände in einer Reihe muss kleiner sein als die 
Differenz zwischen 2 Spalten.


das einer Messung startet die nächste Messung

im 1.Schritt wird gewartet bis eine minimale Spannung anliegt
im 2.Schritt wird gewartet bis eine schwelle unterschritten ist welche 
deutlich über einem gültigen Tastenwert liegt andernfalls werden alle 
Zwischenspeicher neu initialisiert.

Jetzt wird gesiebt (Schwellwertkette) bis der Wert der Taste ermittelt 
ist.

Erst vier gleich Messungen werden gültig erkannt und ausgegeben.

Dann werden alle Zwischenspeicher reinitialisiert und die nächste 
messung ausgelöst.

eine sichere Messung war so in etwa 0,2 sec möglich für eine Tastatur 
ein angemessener Wert

Nnachteil gleichzeitige Tastdrücke werden nicht erkannt

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

t wird auf die ascii werte der Taste gesetzt

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

der Code wurde von mir für einen Atmega32 geschrieben und diente nur 
Testzwecken

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

Rick M. schrieb:
> PC2 bis PC5 funktioniert nicht als Ausgang. Da dies die
> JTAG-Schnittstelle ist, hab ich probeweise, das JTAG-Fuse mal mit Pony
> Prog gesetzt. Keine Änderung??
> Die Pins sind immer auf 3,74V ??
>

die fuse musst du nicht ändern aber wärend des init in MCUCR das 
jtagenablebit 2 mal binnen vier Takten disabeln.


> Danke für den Code.
> Is mir aber n bisserl zu hoch. Was machst Du da in der Tabelle?

von Rick M. (rick00)


Lesenswert?

Winfried J. schrieb:
> die fuse musst du nicht ändern aber wärend des init in MCUCR das
> jtagenablebit 2 mal binnen vier Takten disabeln.

Im Datenblatt steht folgendes:

When the JTAG-Fuse is unprogrammed, these four TAP pins are normal port 
pins.

unprogrammed ist 1, in Pony Prog also kein Häkchen. Trotzdem 
funktionieren bei mir die 4 Pins nicht.

Weiters steht im Datenblatt zum MCUCSR-Register:

JTD-Bit: If this bit is one the JTAG interface is disabled. (write twice 
within four cycles)

von Rick M. (rick00)


Lesenswert?

Hannes Lux schrieb:
> XX Ergebnis auslesen und über den Index in ein Array werfen
>
> XX Index erhöhen und auf Anzahl der Mess-Eingänge begrenzen
>
> XX Bitmuster für ADMUX für die nächste Messung aus einem anderen Array
>    holen und in ADMUX schreiben
>
> XX ADC starten

Wenn ich das richtig verstanden habe:

Angenommen wir haben 3 Messeingänge für Spannung/Strom + 1 Eingang für 
Tasten.

Das würde jetzt ein 16bit-Array mit 4 Stellen ergeben.
Ich nenns jetzt mal uint16_t adc_ergebnis[4];

und noch mal eins für die Adressen
uint8_t adc_adresse[] = {0 , 1 , 2 , 3 };
Das ginge glaub ich auch ohne Array

Wenn ich das in die ADC-ISR packen möchte, so muß der Anstoß zur 
Wandlung aber von wo anders erfolgen, wenn ich den ADC nicht frei laufen 
lassen möchte. Z.B. in meiner Timer1-ISR, alle 8msec? Von dort muß ich 
aber auch dann die Kanäle wechslen und die Kanalnummer muß eine globale 
Variable sein, damit ich in der ADC-ISR weiß, in welches Array ich das 
Ergebnis schreiben muß.

Habe ich da richtig gedacht?


Gruß Rick

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

Rick M. schrieb:
> JTD-Bit: If this bit is one the JTAG interface is disabled. (write twice
> within four cycles)

muss in C So aussehehn

MCUCSR=0x80;
MCUCSR=0x80;//jtag off

Es kann zur Laufzeit genau so eingestellt werden.
pass aber auf das der Compiler die Dopplung der Sequenz nicht 
wegoptimiert, sie soll ein versehentliches ausperren vehindern und ist 
daher genau so auszuführen am besten während des PowerON

Das ist wollte ich hier sagen aber das Register war um eins daneben
richtig ist MCUCSR

Winfried J. schrieb:
> die fuse musst du nicht ändern aber wärend des init in MCUCR das
> jtagenablebit 2 mal binnen vier Takten disabeln.


Lass die Finger von den Fuse bits bis du die negative logik und den 
Proggy gut beherscht!

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

Rick M. schrieb:
> Hannes Lux schrieb:
>> XX Ergebnis auslesen und über den Index in ein Array werfen
>>
>> XX Index erhöhen und auf Anzahl der Mess-Eingänge begrenzen
>>
>> XX Bitmuster für ADMUX für die nächste Messung aus einem anderen Array
>>    holen und in ADMUX schreiben
>>
>> XX ADC starten
>
> Wenn ich das richtig verstanden habe:
>
> Angenommen wir haben 3 Messeingänge für Spannung/Strom + 1 Eingang für
> Tasten.
>
> Das würde jetzt ein 16bit-Array mit 4 Stellen ergeben.
> Ich nenns jetzt mal uint16_t adc_ergebnis[4];
>
> und noch mal eins für die Adressen
> uint8_t adc_adresse[] = {0 , 1 , 2 , 3 };
> Das ginge glaub ich auch ohne Array
arry oder variablen das kannst du halten wie du willst

>
> Wenn ich das in die ADC-ISR packen möchte, so muß der Anstoß zur
> Wandlung aber von wo anders erfolgen, wenn ich den ADC nicht frei laufen
> lassen möchte.
ja
>Z.B. in meiner Timer1-ISR, alle 8msec?
ja
>Von dort muß ich aber auch dann die Kanäle wechslen und die Kanalnummer
> muß eine globale Variable sein, damit ich in der ADC-ISR weiß, in
> welches Array ich das Ergebnis schreiben muß.
Ja, oder Parameter anfunktion und Returnwert übergeben dann passiert das 
auf dem Stack.

wenn du genug RAM hast nimm globale Variablen das schont auch den 
Stack(und die Nerven), weil du nicht tausend Parameter übergeben musst
profis nutzen lieber lokale variablen

Namaste

von Rick M. (rick00)


Lesenswert?

Hallo!

Der PORC funktioniert jetzt, warum das bei mir per Fuses nicht klappt 
kann ich nicht sagen.

Deaktiviere JTAG jetzt so in der Init-Phase:
1
MCUCSR |= (1<<JTD);    // JTAG aus
2
MCUCSR |= (1<<JTD);

Danke für den Tipp!

Ich habe versucht, Deine Vorgehensweise bezüglich der Tastenauswertung 
umzusetzen. Leider erkennt mein Programm keine Tasten mehr, wenn ich in 
den Vergleichen für den equal_counter (bei Dir Prellzähler) die 
Bedingung button2 == 0 hinzufüge. Dieser zusätzliche Vergleich soll die 
Erkennung bewerkstelligen, daß die Taste wiede losgelassen wurde.
1
if(button_read_puls == 2)      // 8msec vergangen
2
      button1 = read_button();    // Tasten auslesen 
3
      
4
    if(button_read_puls == 4)      // weitere 8msec vergangen
5
      {
6
        button2 = read_button();  // Tasten auslesen
7
        
8
        if( button1 == button2 )      // wenn Tastennummer 1 = Tastennummer 2 
9
          if(++equal_counter == 255)    // Zählvariable für Übereinstimmung +1
10
            equal_counter = 0;      // Schutz vor Überlauf
11
      }
12
      
13
    if( (equal_counter >= 10) && (equal_counter <= 50) && (button2 == 0) )  // kurzer Tastendruck und Tastendruck vorbei
14
    {
15
      button = button1;    // Tastennummer sichern
16
      equal_counter = 0;    // Zähler zurücksetzen
17
    }    
18
    
19
    if( (equal_counter >= 100) && (equal_counter <= 200) && (button2 == 0) )  // langer Tastendruck und Tastendruck vorbei
20
    {  
21
      button = button1 +10;    // neue Tastennummer für 2te Funktion
22
      equal_counter = 0;      // Zähler zurücksetzen
23
    }    
24
    
25
                    
26
      switch ( button )        // Handlung zuweisen

Gruß Rick

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

schick mir mal ne PN mit dem Ganzen Quellcode einschliesslich dem 
nichtfunktionierenden vergleich (markieren)
ich bin für ne stunde einkaufen dann schau ichs mir mal an

so muss ich mehr raten als verstehen.

mein Test war damals nur für mich gedacht deshalb schwach kommentiert
aber das problem ist beim filtern die klar zuerkennen wann die taste 
aufhört zu prellen und wann sich das Messergergebnis stabilisiert hat 
und  wann sie losgelassen wird. besonders bei autorepeat.

wichtig war auch die Fenstergrenzen  für die Tasten zu optimieren

von Rick M. (rick00)


Angehängte Dateien:

Lesenswert?

Hallo!

Bei PMs kann man keine Anhänge verschicken, deshalb hier als Anhang

Gruß Rick

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

o. K. habe jetz gesehen was du machst

Ddu startest die messung  und nach der messung versuchst du die Taste zu 
zu ordnen.

Das ist leider Murks weil du keine Garantie hast das die Ttaste nicht 
während der Messung prellt oder gedrückt oder losgelassen wird.

Ich habe auch so angefangen damals. Es kam nur murks herraus.
Genau deshalb habe ich meinen ADC  frei laufen lassen. (ist natürlich 
blöd für deine Sache, aber eins nach dem andern)

Ich schalte gegen Masse, du gegen Plus deshalb muss deine Strategie 
entgegen meiner ein maximum suchen während meine das minimum suchte.
1
if (adc1<adc1_o) 
2
{
3
adc1_o=adc1;
4
}

nur werte kleiner als der vorherige kamen zur auswertung
wurde losgelassen (wert größer 0x60)so wurde  alles verworfen
1
if (adc1>=0x0060)
2
{
3
adc1_o=0x3ff;
4
t=0x00; t0=0x00; t1=0x00; t2=0x00;
5
}

müsste bei dir umgekehrt sein

jetzt erst folgte die siebkette
natürlich auch mit abfallenden Werten umgekehrt ist auch möglich (hat 
nichts mehr mit der Polarität der schaltung zu tun)
so kann man die Fenstergrenzen maximieren und mit wenigen vergleichen 
die Richtige von vielen tasten zuordnen
wo der wert nicht mehr durch geht wird der letze als gültig genommen
1
if (adc1_o <= 0x004C)  {t = 0x33;}
2
if (adc1_o <= 0x0048)  {t = 0x32;}
3
if (adc1_o <= 0x0045)  {t = 0x31;}
4
if (adc1_o <= 0x0040)  {t = 0x4c;} //left
5
if (adc1_o <= 0x0038)  {t = 0x36;}
6
if (adc1_o <= 0x0035)  {t = 0x35;}
7
if (adc1_o <= 0x0030)  {t = 0x34;}
8
if (adc1_o <= 0x002D)  {t = 0x55;} //up
9
if (adc1_o <= 0x0029)  {t = 0x47;} //deal
10
if (adc1_o <= 0x0025)  {t = 0x39;}
11
if (adc1_o <= 0x0021)  {t = 0x38;}
12
if (adc1_o <= 0x001C)  {t = 0x37;}
13
if (adc1_o <= 0x0019)  {t = 0x44;} //down
14
if (adc1_o <= 0x0016)  {t = 0x43;} //hang off
15
if (adc1_o <= 0x0010)  {t = 0x23;}
16
if (adc1_o <= 0x000D)  {t = 0x30;}
17
if (adc1_o <= 0x0009)  {t = 0x2a;}
18
if (adc1_o <= 0x0004)  {t = 0x52;} //right
erst jetzt werden 4 aueinanderfolgende Tastenergebnisse jeweils mit dem 
vorherigen verglichen ungleiche setzen die Zählung zurück
1
if (t2==t1)
2
  {
3
  if (t1==t0)
4
    {
5
      if (t2==t)
6
        {
7
        PORTD=~t2;  // nach 4 gleichen Mesunngen Ausgabe  des Tastencodes PortD   
8
              //Signalinvertierung da LEDs über R-Netz an +5V geführt 
9
werden. 
10
              // hier must du deinen gültige taste in den den rückgabewert schreiben. Der funktion schreiben. 
11
        }
12
    }
13
  }
14
15
t2=t1;
16
t1=t0;
17
t0=t;

jet müssen wir sehen wie das mit deinen anderen messungen zu 
koordinieren ist.

von Rick M. (rick00)


Lesenswert?

Hallo!

Eine Frage:

Warum benutzt Du überall Zahlen im Hex-Format, das kann doch keiner 
lesen?
Mann muß da alle Konstanten in Dezimal umrechnen, um sich etwas darunter 
vorstellen zu können.

0x0060 = 96

adc1_o steht für? oben?

Gruß Rick

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

Am Besten triggerst du den ADC so oft bis du ein gültiges Tastenergebnis 
(4 gleiche Tasten nacheinander) besitzt. 4*Keine Taste ist auch ein 
gültiges Ergebnis und kehrst erst dann nach main zurück.

Nur der einsprung in die Messreihe sollte durch den Timer initialisiert 
werden.

Namaste

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

weil ich  in binär/hex denke jedes hexziffer steht für ein nibble aus 4 
bit

wnn man das erst mal im hirn hat weis man erst was dez für eine Krücke 
ist

ich sehe f und wis alle 4 bit des nibble sind gesetzt
sehe ich c weis ich die oberen beden nibble singesetzt
sehe ich eine ungerade hexziffer wis ich das unterste bit des nibbles 
ist gesetzt

dazu muss man die 2er potenzen natürlich wie leuchtdioden vor sich sehen

Da rechne ich keine Sekunde, ich sehe es wie beim kleinen Einmaleins
Genauso beim Ascii. Kennst du dessen hexadezimale struktutur so kannst 
du die tabelle im schlaf herbeten. Das mach mal in dec.

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

adc1_o steht für? oben?

merker für Minimum

wird nur zurückgesetzt wenn die Taste losgelassen wird

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

beachte das nur die minima in der siebkette ausgewertet werden

von Rick M. (rick00)


Lesenswert?

Na erzähl das blos nicht einen Psychiater, der läßt dich nicht mehr raus 
;-)

Die Zuweisung von t, t0, t1, t2 machst du wie?

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

da musst du natürlich maxima suchen, weil du nach plus schaltest.

von Rick M. (rick00)


Lesenswert?

t machst du ja in der LUT

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

1
if (t2==t1)
2
  {
3
  if (t1==t0)
4
    {
5
      if (t2==t)
6
        {
7
        PORTD=~t2;  // nach 4 gleichen Mesunngen Ausgabe  des Tastencodes PortD   
8
              //Signalinvertierung da LEDs über R-Netz an +5V geführt 
9
werden. 
10
              // hier must du deinen gültige taste in den den rückgabewert schreiben. Der funktion schreiben. 
11
        }
12
    }
13
  }
14
15
t2=t1; // Hier !!!
16
t1=t0; //
17
t0=t; //
zurücksetzen wenn losgelassen (adc1>0x60)

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

Rick M. schrieb:
> Na erzähl das blos nicht einen Psychiater, der läßt dich nicht mehr raus
> ;-)

to late

bin schon ewig wieder draußen

Mit dem Schaden muss ich weiterleben, übrigens der typische schaden von 
Programierern meines Alters. Manche haben auch einen BCD- oder Grey- 
star.

Aber mit so einem Spatz lebt sich leicht, so lange man keinen größeren 
Vogel hat.

Irgendwelche Eulen sind nicht hier oder?

Namaste

von Rick M. (rick00)


Lesenswert?

Sorry, aber ich versteh Dein Denkschema einfach nicht.

Du hast in den if-Anweisungen Vergleiche z.B
wenn t1 gleich t2
wenn t1 gleich t0
wenn t0 gleich t

Die t´s sind Variablen für die Tastennummer?, die müssen ja vor den 
if-Anweisungen Werte haben. Du weist ja nur zu den ADC-Werten die 
Variable t zu.

Deshalb meine Frage: Wie bekommen die Variablen t0, t1, t2 ihre Werte?

Zuerst einen Vergleich machen und hinterher was zuweisen?

Sorry, blick da aber momentan einfach überhaupt nicht durch, was Du da 
machst.

Vielleicht brauch ich ja einfach nur mal ne Pause und etwas Abstand....

In meinem Code weise ich die Tasten-Nr. ja so zu:

button1 = read_button();
warten
button2 = read_button();

button1 == button2 ?
wenn ja equal_counter +1

wieder von vorne beginnen

Gruß Rick

von Rick M. (rick00)


Lesenswert?

Winfried J. schrieb:
> to late
>
> bin schon ewig wieder draußen
>
> Mit dem Schaden muss ich weiterleben, übrigens der typische schaden von
> Programierern meines Alters. Manche haben auch einen BCD- oder Grey-
> star.
>
> Aber mit so einem Spatz lebt sich leicht, so lange man keinen größeren
> Vogel hat.
>
> Irgendwelche Eulen sind nicht hier oder?

Nee, die sind momentan alle bei mir und versuchen sich gerade häuslich 
einzurichten......

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

Rick M. schrieb:
> Sorry, aber ich versteh Dein Denkschema einfach nicht.
>
> Du hast in den if-Anweisungen Vergleiche z.B
> wenn t1 gleich t2
> wenn t1 gleich t0
> wenn t0 gleich t
>
> Die t´s sind Variablen für die Tastennummer?, die müssen ja vor den
> if-Anweisungen Werte haben. Du weist ja nur zu den ADC-Werten die
> Variable t zu.
>

t bekommt die tasten id aus der siebkette
in t0,t1,undt2  werden die tasten werte der letzten drei messungen 
aufbewart
zuerst wird geschaut ob t2==t1
wen ja ob t1==t0
und  zum schluss ob t0==t
dann wird  augegeben
achtung das ist geschachtelt

[pre]
if (t2==t1)
  {
  if (t1==t0)
    {
      if (t2==t)
        {
        PORTD=~t2;  // nach 4 gleichen Mesunngen Ausgabe  des 
Tastencodes PortD
              //Signalinvertierung da LEDs über R-Netz an +5V geführt
werden.
              // hier must du deinen gültige taste in den den 
rückgabewert schreiben. Der funktion schreiben.
        }
    }
  }
[/pr]]

nach diese auswertung

wird t1 nach t2 geschoben
t0 nach t1
und t nach t0

[/pr]
t2=t1; // Hier !!!
t1=t0; //
t0=t; //
[pre]

das heist die letzten 3 werte werden für den nächsten vergleich 
vorbereitet
(um eine position im puffer verschoben) und gerettet
bevor in t der neu Tataturwert eingetragen wird.
das könnte man auch in einem array machen aber das macht es nur 
komplizierte weil du dan die elemente des arrays auch scrolen musst.
bei vier elementen ist die zeigerverwaltung aufwendiger als die diskrete 
umsetzung.und mehr ist hier nicht nötig wür eine Laufschrit bastelt mann 
sich einen ringpuffer.

Wird die taste losgelassen  werden alle t-speischer auf 0 gesetzt

> Deshalb meine Frage: Wie bekommen die Variablen t0, t1, t2 ihre Werte?
>
> Zuerst einen Vergleich machen und hinterher was zuweisen?
>
> Sorry, blick da aber momentan einfach überhaupt nicht durch, was Du da
> machst.
>
> Vielleicht brauch ich ja einfach nur mal ne Pause und etwas Abstand....
>

Sicher, sowas mache ich dann auch mal. Die Liebste schaen und Kaffee und 
wenn nichts mehr geht mal die Festplatte formatieren lassen, ich hoffe 
du weist wie das geht, danach ist man zwar nicht jungfräulich aber der 
Geist wieder leer und fit für neuen müll.

>
> In meinem Code weise ich die Tasten-Nr. ja so zu:
>
> button1 = read_button();
> warten
> button2 = read_button();
>
> button1 == button2 ?
> wenn ja equal_counter +1
>
> wieder von vorne beginnen
>
> Gruß Rick

Du vergleichst nur Paare

Ich vergleiche vier aufeinanderfolgende.

und schiebe sie wie eine Laufschrift weiter
nur schiebe ich nichts im kreis,
sondern stehts vorn rein und hinten fällt das älteste raus (t2 wird 
nicht gerettet sondern einfach überschrieben mit t1)..... zum schluss t0 
mit t.
das heist ich verwerfe injedemschritt nur die älteste Messung.

Dann wird T mit einem neuen Messwert beschrieben und wieder auf vier 
Gleiche getestet. Bis ich vier gleiche Tastaturwerte habe! Der wird dann 
von meiner ISR als Ausgabewert an PORTD gebracht und könnte auch als 
Returnwert zurück an die aufrufende Schicht übergeben werden, oder in 
eine globale Variable geschrieben werden.

Namaste

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

Rick M. schrieb:
> Sorry, aber ich versteh Dein Denkschema einfach nicht.
>
> Du hast in den if-Anweisungen Vergleiche z.B
> wenn t1 gleich t2
> wenn t1 gleich t0
> wenn t0 gleich t
>
> Die t´s sind Variablen für die Tastennummer?, die müssen ja vor den
> if-Anweisungen Werte haben. Du weist ja nur zu den ADC-Werten die
> Variable t zu.
>

t bekommt die TastenID aus der Siebkette
in t0,t1,undt2  werden die TtastenIDs der letzten drei Messungen 
aufbewart
zuerst wird geschaut ob t2==t1
wen ja ob t1==t0
und  zum Schluss ob t0==t
dann wird  ausgegeben
Achtung das ist geschachtelt
1
if (t2==t1)
2
  {
3
  if (t1==t0)
4
    {
5
      if (t2==t)
6
        {
7
        PORTD=~t2;  // nach 4 gleichen Mesunngen Ausgabe  des Tastencodes PortD   
8
              //Signalinvertierung da LEDs über R-Netz an +5V geführt werden. 
9
              // hier must du deinen gültige Taste in den den Rückgabewert schreiben. Der funktion schreiben. 
10
        }
11
    }
12
  }

nach diese auswertung

wird t1 nach t2 geschoben
t0 nach t1
und t nach t0
1
t2=t1; // Hier !!!
2
t1=t0; //
3
t0=t; //

Das heist die letzten 3 werte werden für den nächsten Vergleich 
vorbereitet
(um eine Position im Puffer verschoben) und gerettet,
bevor in t der neu Tastaturwert eingetragen wird.
Das könnte man auch in einem Array machen, aber das macht es nur 
komplizierter, weil du dan die Elemente des arrays auch scrollen musst.
Bei vier Eelementen ist die Zeigerverwaltung aufwendiger als die 
diskrete umsetzung. Und mehr ist hier nicht nötig. Würd man eine 
Laufschriftt basteln, nähme einen Rringpuffer.

Wird die taste losgelassen  werden alle t-speischer auf 0 gesetzt

> Deshalb meine Frage: Wie bekommen die Variablen t0, t1, t2 ihre Werte?
>
> Zuerst einen Vergleich machen und hinterher was zuweisen?
>
> Sorry, blick da aber momentan einfach überhaupt nicht durch, was Du da
> machst.
>
> Vielleicht brauch ich ja einfach nur mal ne Pause und etwas Abstand....
>

Sicher, sowas mache ich dann auch mal. Die Liebste schaen und Kaffee und 
wenn nichts mehr geht mal die Festplatte formatieren lassen, ich hoffe 
du weist wie das geht, danach ist man zwar nicht jungfräulich aber der 
Geist wieder leer und fit für neuen müll.

>
> In meinem Code weise ich die Tasten-Nr. ja so zu:
>
> button1 = read_button();
> warten
> button2 = read_button();
>
> button1 == button2 ?
> wenn ja equal_counter +1
>
> wieder von vorne beginnen
>
> Gruß Rick

Du vergleichst nur Paare

Ich vergleiche vier aufeinanderfolgende.
Und schiebe sie wie eine Laufschrift weiter.
Nur schiebe ich nichts im Kreis,
sondern stehts vorn rein und hinten fällt das älteste raus (t2 wird 
nicht gerettet, sondern einfach überschrieben mit t1)..... zum schluss 
t0 mit t.
Das heist ich verwerfe in jedem Schritt nur den ältesten Tastenwert.

Dann wird T mit einem neuen Messwert beschrieben und wieder auf vier 
Gleiche getestet. Bis ich vier gleiche Tastaturwerte habe! Der wird dann 
von meiner ISR als Ausgabewert an PORTD gebracht und könnte auch als 
Returnwert zurück an die aufrufende Schicht übergeben werden, oder in 
eine globale Variable geschrieben werden.

Namaste

von Hannes L. (hannes)


Lesenswert?

Rick M. schrieb:
>> Irgendwelche Eulen sind nicht hier oder?
>
> Nee, die sind momentan alle bei mir und versuchen sich gerade häuslich
> einzurichten......

Nein, er meint was Anderes. Diese Eulen und ihre Jäger sind aber eher im 
Dummschwätzer-Teil dieses Forums zu finden... ;-)

Ich will Winfried nicht ins Handwerk pfuschen, aber trotzdem diese Frage 
beantworten:

Rick M. schrieb:
> Hannes Lux schrieb:
>> XX Ergebnis auslesen und über den Index in ein Array werfen
>>
>> XX Index erhöhen und auf Anzahl der Mess-Eingänge begrenzen
>>
>> XX Bitmuster für ADMUX für die nächste Messung aus einem anderen Array
>>    holen und in ADMUX schreiben
>>
>> XX ADC starten
>
> Wenn ich das richtig verstanden habe:
>
> Angenommen wir haben 3 Messeingänge für Spannung/Strom + 1 Eingang für
> Tasten.
>
> Das würde jetzt ein 16bit-Array mit 4 Stellen ergeben.
> Ich nenns jetzt mal uint16_t adc_ergebnis[4];

Ja...

>
> und noch mal eins für die Adressen
> uint8_t adc_adresse[] = {0 , 1 , 2 , 3 };

Richtig, darin befinden sich dann die Werte für ADMUX, mit denen 
Mess-Quelle und Referenz eingestellt wird, bei den meisten AVRs auch die 
Ergebnis-Formatierung (ADLAR).

> Das ginge glaub ich auch ohne Array

Dann musst Du aber per If-Orgie die richtigen Werte ermitteln. 
Array-Zugriffe sind nicht nur eleganter, sondern vor Allem schneller. 
Deshalb gönne ich der ADC-Abfrage auch ohne Reue die paar Bytes SRAM, 
die das Array mit den MUX-Werten kostet.

Da ich in ASM programmiere und es die genialen Befehle LDD und STD gibt, 
kann ich beide Arrays über einen Pointer (als Index) ansprechen, was die 
Sache extrem effizient macht. (Ein Pointer ist in ASM nicht dasselbe wie 
in C)

>
> Wenn ich das in die ADC-ISR packen möchte, so muß der Anstoß zur
> Wandlung aber von wo anders erfolgen,

Richtig, und zwar in der Reset-Routine. Dort werden die ersten Parameter 
gesetzt (Index, ADMUX) und die erste Wandlung (Messung) angestoßen.

> wenn ich den ADC nicht frei laufen
> lassen möchte.

Der Freerun-Modus bringt aber nur was, wenn man das im Timer-Interrupt 
nebenher macht. Dann stellt man das Timing so ein, dass der ADC bis zur 
nächsten Abfrage mindestens 2 neue Ergebnisse ermittelt hat, das bringt 
stabilere Ergebnisse weil unter gewissen Bedingungen die erste Messung 
nach der Quellenumschaltung nicht ganz genau sein könnte.

> Z.B. in meiner Timer1-ISR, alle 8msec?

Ich wüsste jetzt nicht warum? 8 ms halte ich für das Messen auf 4 
Kanälen für etwas langsam.

> Von dort muß ich
> aber auch dann die Kanäle wechslen

Nööö, das kann auch der ADC-Interrupt erschlagen. Deshalb die 
Reihenfolge:

- ADC-Wert auslesen und Messwert über den Index ins Array kopieren
- Index erhöhen, bei Überlauf (Array-Größe) Index auf 0 setzen und
  Funktion für die Tastenermittlung aufrufen
- MUX-Wert gemäß Index aus Mux-Array holen und in ADMUX schreiben
- Nächste ADC Einzelmessung mit Interrupt starten

Die Funktion der Tastenermittlung ermittelt über eine LUT, oder über 
eine Switch- oder IF-Orgie den Tastenwert, und vergleicht diesen mit dem 
beim letzten mal ermittelten Tastenwert. Bei Gleichheit wird der 
Prellzähler erhöht, bei Ungleichheit gelöscht. Erreicht der Prellzähler 
(Global bzw. Static) die Prellschwelle, dann ist der Tastenwert gültig 
und wird (falls er nicht 0 ist, was für "keine Taste gedrückt" steht) 
dem Hauptprogramm in eine globale Variable gelegt. Dieses reagiert 
darauf und löscht sie nach Abarbeitung.

Dies wäre die einfache Lösung, die nur Tastendrücke erkennt und nicht 
zwischen kurz und lang unterscheiden kann. Die Lösung mit 
Kurz/Lang-Unterscheidung habe ich oben schon erklärt.

> und die Kanalnummer muß eine globale
> Variable sein, damit ich in der ADC-ISR weiß, in welches Array ich das
> Ergebnis schreiben muß.

Ja sicher doch. Zumindes "Static", falls es in C sowas gibt (in Basic 
kann man lokale Variablen als Static definieren, wodurch sie ihren Wert 
zwischen den Aufrufen behalten).

>
> Habe ich da richtig gedacht?

Teils.

Aber ich will Dir nicht meine Methode aufzwingen, deshalb halte ich mich 
jetzt etwas zurück. Konzentriere Dich also erstmal auf Winfrieds 
Konzept. Denn viele Köche verderben... Hmmm, äähhh, achja, ...die 
Köchin.

...

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

@ Hannes

viele Wege führen nach ROM

und ich sehe das eher als Bereicherung auch für mich. Und wie gesagt war 
das damals sicher auch nicht der Elganz und Weisheit letzer Schluß.
Ich habe damals die Grenzen Vor- und Nachteile des ADC verstehen wollen, 
mehr nicht.

Dabei erkannte ich das Taster und ADC eher eine bescheidene Kombination 
ist, aber mit genügend Redundanz und guter Filterstrategie zum Erfolg 
(20 Tasten bei min 4 Digit Abstand und Serienbauteilen)  führt.

Peter D. packt das Problem wahrscheinlich in 128 byte code und 5 
register

Aber ich war damals noch nicht soweit, genau wie heute ric.
Das Problem war nicht ADC zu bedienen sondern die Werte richtig 
auszuwerten weil: Wer misst misst viel Mist.

if(){}  select case  oder brn.

Es läuft immer auf ein Orgie hinaus.

Also Siebkette und kräftig geschüttelt wichtig ist es die Übersicht zu 
behalten.

Permanenter Stilwechsel ist dem zwar nicht förderlich,
gibt aber neue Impulse und ohne PAP ist es nicht einfach die Struktur 
eines fremden Quellcodes zu lesen. Einfacher ist es den Eigenen zu 
erklären
Wenn das Prinzip dan klar ist muss man das im eigenen Stil umsetzen.

Namaste

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

LUT ist nett erfordert aber für die Tastatur einen definierten 
Übergangswiderstand an den Tasten (unrealistisch) deshalb hier if Orgie 
als Siebkette mit Komperatorschwellen.

Bei mir ein Fensterdiskriminator mit 21 Fenstern

Für ihn 5 gültige Fenster

Namaste

von Hannes L. (hannes)


Lesenswert?

Winfried J. schrieb:
> LUT ist nett erfordert aber für die Tastatur einen definierten
> Übergangswiderstand an den Tasten (unrealistisch)

Damit hatte ich noch keine Probleme. Ich benutze gern die 
Kurzhub-Taster, meist unter einer Laminierfolie mit einlaminiertem 
bedruckten Blatt Papier.
Z.B. hier bei einem Eigenbau-Gerät:
http://www.hanneslux.de/dcc/z1/dccz1b.html
Oder hier ohne eigenen (selbstprogrammierten) AVR als Ersatz für das 
Poti eines Steuerknüppels:
http://www.hanneslux.de/planet5b/planet5-Umbau.html


> deshalb hier if Orgie
> als Siebkette mit Komperatorschwellen.
>
> Bei mir ein Fensterdiskriminator mit 21 Fenstern

Ist auch mit LUT machbar. Jeder Eintrag bekommt 2 Werte, zuerst den 
Schwellenwert, dann die Tastennummer. Die Schwellenwerte liegen dann 
zwischen den per Tasten erreichten ADC-Werten.
In einer Schleife werden beide Werte gelesen und der ADC-Wert mit dem 
Schwellenwert verglichen. Ist der ADC-Wert kleiner als der Schwellenwert 
der Liste, so wird die Schleife verlassen und die zuletzt gelesene 
Tastennummer ist gültig.

>
> Für ihn 5 gültige Fenster

Da ist die If-Orgie billiger...

>

Sorry, da ich in ASM werkele, versuche ich auch den verfügbaren 
Befehlssatz halbwegs effizient zu nutzen. Das hat vielleicht auch damit 
zu tun, dass ich die AVR-Architektur, auf der der Befehlssatz basiert, 
einigermaßen kenne. Meine ersten AVRs waren AT90S1200, ATTiny12 und 
ATTiny15, die hatten kein SRAM und waren mit Hochsprachen nicht oder nur 
sehr schwierig zu programmieren, daher ASM...

> Namaste

Dito...

...

von Peter D. (peda)


Lesenswert?

Rick M. schrieb:
> Ich weiß, daß es eine Komfort-Routine und das Bsp. mit der
> Matrixtastatur am ADC von Peter Dannegger dazu gibt, aber leider ist mir
> das als Anfänger etwas zu hoch....

Wenn ich diesen langen Thread sehe, vermute ich mal, es wäre einfacher 
gewesen, mich zu den Sachen zu fragen, die Dir Probleme beim Verstehen 
bereiten.

In meinem Code ist ja zu sehen, daß ich den Compiler das Ohmsche Gesetz 
selber ausrechnen lasse (Ich bin nämlich stink faul).
Auch wenn Deine Schaltung anders aussieht, kann man dafür bestimmt auch 
eine Formel aufstellen.

Ich bin ein Fan von modularem Programmieren, d.h. ich mache kleinste 
Unterfunktionen für jede einzelne Aufgabe.
Ich kann nur jedem empfehlen, es genauso zu machen.

Gerade Anfänger neigen dazu, alles immer zusammen zu verwursten. Ich 
kann aus Erfahrung davon nur dringend abraten, das ist ne Sackgasse.

Peter

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

hallo

Peter hast du eine Klingel, wenn jemand deinen Namen hier erwähnt?shelt 
es aus dem Forum?

Du erscheinst ja aufs Stichwort.


Ich schrieb:
> Peter D. packt das Problem wahrscheinlich in 128 byte code und 5
> register



Peter Dannegger schrieb:
> (Ich bin nämlich stink faul).

Faulheit ist die antribesfeder der Intelligenz und damit jeder 
Entwicklung.


zu Rick
Man halte ihm zu gute das er sich reedlich durchwurstelt, und das lehrt 
mehr als eine ffertige lösung welche auf anhieb funktioniert.

Namaste

von Rick M. (rick00)


Lesenswert?

Hallo Winfried!

Zu deimen geposteten Code:

Nehmen wir mal an der Code stellt ein Unterprogramm dar, nennen wir es 
"uint8_t read_button(void)".
Zuerst holst Du dir vom ADC 2 neue Messwerte (direkt aufeinander 
folgend?)und ermittelst von beiden den Größeren.
Diesen vergleichst du dann mit einer Maximalschwelle, was bei dir einen 
losgelassenen Taster gleich kommt.
Falls dies der Fall ist, löscht du das komplette Schiebe-Register und 
setzt den Messwert gleichzeitig (wahrscheinlich aus Sicherheitsgründen) 
auf den Maximalwert des ADC (1023).
Ist die Maximal-Schwelle nicht überschritten, so wird der ADC-Max-Wert 
durch deine Vergleichstabelle geschick und die dazugehörige 
Tasten-Nummer ermittelt.
Diese Tasten-Nummer speicherst Du dann in einem 4-Stelligen 
FIFO-Register.
Erst wenn alle 4 Stellen in diesem Register gleich sind liefert das 
Unterprogramm eine Tasten-Nummer zurück.

Warum die if-Verschachtelung, ginge es nicht auch so:
1
if(  t == t0 == t1 == t2 )
2
     return t2;

Das Unterprogramm muß mindestens 4 mal, bei gedrückter Taste, aufgerufen 
werden, um eine Tasten-Nummer ungleich Null zurück zu bekommen.
Somit müßte das Unterprogramm zyklisch, z.B. alle 10msec, aufgerufen 
werden.

Ist das richtig?

Deine LUT gibt mir allerdings noch zu denken, denn wenn ich nur sage
1
 if ( adc_value <= 100 )
Dann umfasst dies auch alle unter dieser Schwelle liegenden Tasten und 
nicht nur diese eine Taste

Gruß Rick

von Rick M. (rick00)


Lesenswert?

Hallo Peter!

Peter Dannegger schrieb:
> Wenn ich diesen langen Thread sehe, vermute ich mal, es wäre einfacher
> gewesen, mich zu den Sachen zu fragen, die Dir Probleme beim Verstehen
> bereiten.

Da müßte ich erst mal konkrete Fragen haben.
Wenn ich mir einen fremden Code ansehe, so suche ich zuerst nach einem 
Grundschema. Detail-Lösungen interessiern mich zu diesem Zeitpunkt noch 
gar nicht.
Änlich einem Blockschaltbild von einem IC-Datenblatt.
Ich frage mich, was für ein Konzept verfolgt er und was sind die 
->Rahmenbedingungen<- ?
Konkret: Woher nimmst Du den ADC-Wert her, wie wird er übergeben?
Wird der ADC-Kanal zyklisch abgefragt? Du hast ja einen Timer am laufen 
(10msec)....
Dein 2bit vertikal Zähler gibt mir ja schon Rätsel auf, aber das gehört 
ja schon wieder zu den Detail-Lösungen.
Du siehst ich habe schlicht weg das Problem, daß ich das Gesamt-Konzept 
und dessen Rahmenbedingungen nicht kenne bzw. nicht verstehe und somit 
weiß ich auch nicht wo ich den Hebel ansetzen soll.

Peter Dannegger schrieb:
> Ich bin ein Fan von modularem Programmieren, d.h. ich mache kleinste
> Unterfunktionen für jede einzelne Aufgabe.
> Ich kann nur jedem empfehlen, es genauso zu machen.

Das bin ich auch und ich versuche dieses Konzept nicht nur in der 
Schaltungtechnik, sondern auch beim Programmieren umzusetzen.
Das einem dies als Anfänger nicht immer gelingt, weil man schlichtweg 
den Überblick verliert, steht außer Frage.

Gruß Rick

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

Rick M. schrieb:
> Hallo Winfried!
>
> Zu deimen geposteten Code:
>
> Nehmen wir mal an der Code stellt ein Unterprogramm dar, nennen wir es
> "uint8_t read_button(void)".
o.k.
voraussetzung pullup an plus, taster schaltet über R mess nach Ground
schau dir mein Schaltbild an Rmess wird durch die Matrix realisiert 
Einzelwiderstände gehen auch (aber nicht bei meiner Tastaturmatrix)

> Zuerst holst Du dir vom ADC 2 neue Messwerte (direkt aufeinander
> folgend?)und ermittelst von beiden den Größeren.


ich habe 2 variablen
nenn wir sie alt und neu alt wird mit max initialisiert
desweiteren habe ich einen tastenwertstapel in dem alle tastenwerte 
gelöscht(0) sind

nun stoße ich die erste messung an warte af das ergebniss
und vergleiche neu mit alt
ist der neue wert kleiner als der alte wird der neue mit dem alten 
überschrieben. Ansonsten wird nichts getan und das Progremm fort 
gesetzt.




> Diesen vergleichst du dann mit einer Maximalschwelle, was bei dir einen
> losgelassenen Taster gleich kommt.
> Falls dies der Fall ist, löscht du das komplette Schiebe-Register und
> setzt den Messwert gleichzeitig (wahrscheinlich aus Sicherheitsgründen)
> auf den Maximalwert des ADC (1023).
richtig

mit diesem jetz ermittelten Wert in alt liegend wird die If Siebkette 
vom größten zur kleinsten maschenweite durchlaufen und in jeder stufe 
wird der aktuelle tastaturcode(ascii)der stufe nach t geschrieben.
so wird jeweis in der folgenden stufe der neue Tastaturwert eingetragen.
fällt der messwert alt nicht mehr weiter durch die maschen der 
darunterliegenden siebe so gleitet das letzte ermittelt askciizeichen in 
t liegend den siebstufen vorbei das ist mein aktueller tastatur wert.

> Ist die Maximal-Schwelle nicht überschritten, so wird der ADC-Max-Wert
> durch deine Vergleichstabelle geschick und die dazugehörige
> Tasten-Nummer ermittelt.
nein auch mit wenn er überschritten wurde , dann bleibt er in dem ersten 
sie hängen und es bleibt 0 in t erhalten
> Diese Tasten-Nummer speicherst Du dann in einem 4-Stelligen
> FIFO-Register.
eher schiebregister (beim fifo wird auch geschoben aber am ausgang kommt 
alles sukzessife wieder raus bei mir kommt nur raus was vier gleich 
zeigt alles andere landet im nirvana)
> Erst wenn alle 4 Stellen in diesem Register gleich sind liefert das
> Unterprogramm eine Tasten-Nummer zurück.
gebnauso

> Warum die if-Verschachtelung, ginge es nicht auch so:
>
1
> if(  t == t0 == t1 == t2 )
2
>      return t2;
3
>
>

das wird warscheinlich gehen wen der compiler kapiert was du willst
da denke ich wahrscheinlich zusehr assembler, den der kann nur 2 werte 
vergleichen und der compiler muss aus deinem therm eh wieder meine if 
veschachtelungsorie machen

> Das Unterprogramm muß mindestens 4 mal, bei gedrückter Taste, aufgerufen
> werden, um eine Tasten-Nummer ungleich Null zurück zu bekommen.
ja und zwar so oft bis es einen gültigen wert hat der auch sein kann das 
viermal hintereinander keine taste gedrückt wurde.

daher würde ich die 4 gleiche zur abruchbedingung einer while schleife 
machen
> Somit müßte das Unterprogramm zyklisch, z.B. alle 10msec, aufgerufen
> werden.
>
wenn du die von mir vorgeschlagene whileschleife nimmst in das 
unterprogramm nimmst liefert es dir gleich eine gültige taste sobald es 
eine hat.
> Ist das richtig?
ansonsten ja
>
> Deine LUT gibt mir allerdings noch zu denken, denn wenn ich nur sage
>
1
 if ( adc_value <= 100 )
> Dann umfasst dies auch alle unter dieser Schwelle liegenden Tasten und
> nicht nur diese eine Taste

es ist ein Sieb mit Bypas alles was nicht durchs sieb passtt wird 
rausgeschütteltund vorbeigeleitet. Beim durchfallen einersiebstufe wird 
t umgestempelt.
Hinter dem sieb ist alt unwichtig und kann verworfen werden da ja jetzt 
ein tastaturcode ermittelt ist
und wenn es 0 ist weil schon das erste sieb zu eng war

es ist wie mit meinen "nicht FiFo"

wie gesagt ich stand am gleichen punkt wie du heute und wollte es testen 
das ist schon ein paar Jahre her und wurde nicht optimiert
aber da der assembler eh nur 2 register vergleichen kann ...

> Gruß Rick

e tu
Namaste

von Rick M. (rick00)


Lesenswert?

Winfried J. schrieb:
>> Diese Tasten-Nummer speicherst Du dann in einem 4-Stelligen
>> FIFO-Register.
> eher schiebregister (beim fifo wird auch geschoben aber am ausgang kommt
> alles sukzessife wieder raus bei mir kommt nur raus was vier gleich
> zeigt alles andere landet im nirvana)

also ein FiFo, daß erst ausgewertet wird, wenn es 4 gleiche Werte 
beinhaltet.
Wenn du einen neuen t-Wert vorne reinschiebst, fällt der alte-t2 Wert 
raus.
Ist aber natürlich reine Ansichtssache... ;-)

Winfried J. schrieb:
> wenn du die von mir vorgeschlagene whileschleife nimmst in das
> unterprogramm nimmst liefert es dir gleich eine gültige taste sobald es
> eine hat.

also
1
 
2
while (  !(t == t0 == t1 == t2) )


Deine LUT auf meine Hardware umgemünzt müßte das so aussehen:


Taster   : adc-Wert
---------------------
Taster 5 : 154
Taster 4 : 307
Taster 3 : 459
Taster 2 : 609
Taster 1 : 760

1
if(adc <= 1000) t=1;
2
if(adc <= 740)  t=2;
3
if(adc <= 589)  t=3;
4
if(adc <= 439)  t=4;
5
if(adc <= 287)  t=5;
6
if(adc <= 134) {t=0; t0=0; t1=0; t2=0;}

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

Rick M. schrieb:
> Winfried J. schrieb:
>>> Diese Tasten-Nummer speicherst Du dann in einem 4-Stelligen
>>> FIFO-Register.
>> eher schiebregister (beim fifo wird auch geschoben aber am ausgang kommt
>> alles sukzessife wieder raus bei mir kommt nur raus was vier gleich
>> zeigt alles andere landet im nirvana)
>
> also ein FiFo, daß erst ausgewertet wird, wenn es 4 gleiche Werte
> beinhaltet.
> Wenn du einen neuen t-Wert vorne reinschiebst, fällt der alte-t2 Wert
> raus.
> Ist aber natürlich reine Ansichtssache... ;-)
>
> Winfried J. schrieb:
>> wenn du die von mir vorgeschlagene whileschleife nimmst in das
>> unterprogramm nimmst liefert es dir gleich eine gültige taste sobald es
>> eine hat.
>
> also
>
1
> while (  !(t == t0 == t1 == t2) )
2
>
>
>
> Deine LUT auf meine Hardware umgemünzt müßte das so aussehen:
>
>
> Taster   : adc-Wert
> ---------------------
> Taster 5 : 154
> Taster 4 : 307
> Taster 3 : 459
> Taster 2 : 609
> Taster 1 : 760
>
>
>
1
> if(adc <= 1000) t=1;
2
> if(adc <= 740)  t=2;
3
> if(adc <= 589)  t=3;
4
> if(adc <= 439)  t=4;
5
> if(adc <= 287)  t=5;
6
> if(adc <= 134)  t=0; 
7
>
das sollte passen

aber auf deine Hw bezogen
muss der vergleich neu alt immer den größeren wert bernehmen
du nach pluss schaltest

ich würde es jedoch auch die HW noch mal umbauen, da dei ADC an einer 
floatenden leitung hängt wenn keine Taste gedrückt ist oder habe ich 
etwas übersehen?

Besser wäre auf jeden Fall bei offener Taste ein definiertes Potential 
am Eingang zu haben und mit der Taste eine Spannugsteiler zu ralisieren.

Sieh dir meine Schaltung noch mal an, falls dich noch niemand darauf 
aufmerksam gemacht hat.

Dann gibt es weniger Fehlmessungen bei offener Tastern
Alternativ die Taster durch einen sehr großen widerstand nach Masse 
ziehen(20-100K).

dann brauchst du natürlich neue schwellwerte


Keines Falles Kondensatoren dort verwenden, das kostet etliche Messungen 
mehr.

Namaste

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

Nachtrag!!!!

 Ohne das floatende Signal auf der ADC Leitung zu beheben wird sich die
das programm regelmäßig im While, aufhängen da du nicht erkennen kannst 
das die Taster alle offen sind das Potential (Spannung der Leitung ist 
dann undefiniert)

Mit deinen Einzelmessungen hättst du alle mögliche tasten vermuten 
können.
Meine Schleife kommt einfach nicht mehr zurück, wenn nicht 4 Messungen 
den selben Tastaturcode liefern!!!!

von Rick M. (rick00)


Lesenswert?

Winfried J. schrieb:
> ich würde es jedoch auch die HW noch mal umbauen, da dei ADC an einer
> floatenden leitung hängt wenn keine Taste gedrückt ist oder habe ich
> etwas übersehen?

siehe meinen ersten Beitrag:

Rick M. schrieb:
> Ich habe zusätzlich den Pin PA7 mit 100k gegen GND gezogen,
> damit der ADC nicht in der Luft hängt.

bzw:

Rick M. schrieb:
> zu beachten ist, daß es sich jeweils um eine Parallelschaltung von  (1
> bis 5k) und 100k handelt.
> So ergebne sich für die einzelnen Tasten folgende Widerstanswerte:
>
> Taster1: 4,76k
>
> Taster2: 3,846k
>
> Taster3: 2,913k
>
> Taster4: 1,961k
>
> Taster1: 990 Ohm

Winfried J. schrieb:
> Sieh dir meine Schaltung noch mal an, falls dich noch niemand darauf
> aufmerksam gemacht hat.

Welche Schaltung, hab ich da was übersehen?
Einen Schaltplan hast Du nie angehängt.

Winfried J. schrieb:
> Keines Falles Kondensatoren dort verwenden, das kostet etliche Messungen
> mehr.

Ist klar, das ergibt eine C-Lade/Entlade-Kennlinie

Winfried J. schrieb:
> ich habe 2 variablen
> nenn wir sie alt und neu alt wird mit max initialisiert
> nun stoße ich die erste messung an warte af das ergebniss
> und vergleiche neu mit alt
> ist der neue wert kleiner als der alte wird der neue mit dem alten
> überschrieben.

1
uint16_t adc_alt = 1023;
2
uint16_t adc_neu = 0;
3
4
//**** Aufruf im Main **************************************
5
6
adc_neu = adc_lesen();   // ADC lesen
7
button = read_button( adc_neu);   // Tastennummer auslesen, 
8
9
10
11
//*******************************************************************
12
13
14
uint8_t read_button(uint16_t adc_neu)
15
{
16
  if (adc_neu < adc_alt)     // adc_alt = 1023!! Bedingung wahr
17
        adc_neu = adc_alt    // gedrückte Taste wird vernichtet!

Eine gedrückte Taste würde bei Dir z.B den ADC-Wert 70 bedeuten.
Da 70 kleiner 1023 wird 70 mit 1023 überschrieben und somit die 
Erkennung der gedückten Taste vernichtet?


Mist hab schon wieder n over flow......

von Hannes L. (hannes)


Lesenswert?

Winfried J. schrieb:
> Ohne das floatende Signal auf der ADC Leitung zu beheben wird sich...

...keine Tastatur ordentlich abfragen lassen, egal ob mit meiner 
Methode, mit Winfrieds Methode, mit Peter Danneggers Methode oder wie 
auch immer.

Entweder, Du baust einen Pull-Down-(Pull-Up-)Widerstand (etwa 20..50k) 
ein, oder Du änderst die Spannungsteilerschaltung so ab, wie ich sie 
weiter oben beschrieben habe.

...

von Peter D. (peda)


Lesenswert?

Ich hab nicht alles gelesen, aber ich habe den Eindruck, daß Du bisher 
nichtmal meinem Rat gefolgt bist und die ADC-Werte ausgibst.

Es hat keinen Zweck, den zweiten Schritt zu tun, bevor man nicht sicher 
ist, daß der erste Schritt klappt.

Schau Dir also die ADC-Werte an, wenn man eine Taste drückt. D.h. wie 
schnell erreichen sie den Endwert, wie weit zappeln sie und wie schnell 
reagieren sie auf das Loslassen.

Ich würde allerdings den 10k rausnehmen und dafür direkt vom ADC-Eingang 
nach VCC legen. Dann hast Du immer maximal 10k Eingangsimpedanz und 
Störungen beim Loslassen sind 10-mal besser unterdrückt, als bei großen 
100k.


Peter

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

zur HW ich hatte das zwar gelesen aber bereits vergessen und mich 
wiederholt im Layout orientiert. Irgendwann ....
das wäre also geklärt

mein Schaltung hatte ich hier verlinkt
Beitrag "Re: 5 Tasten am ADC"

hier als   nochmal Schaltung
http://www.nisch-aufzuege.at/bilder/atmega32_adc_r_tastatur.jpg

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

Rick M. schrieb:
> Winfried J. schrieb:
>> ich habe 2 variablen
>> nenn wir sie alt und neu alt wird mit max initialisiert
>> nun stoße ich die erste messung an warte af das ergebniss
>> und vergleiche neu mit alt
>> ist der neue wert kleiner als der alte wird der neue mit dem alten
>> überschrieben.
>
sorry natürlich umgekehrt der alte wird bedingt überschrieben und der 
wird auch ausgewertet

>
>
>
> uint16_t adc_alt = 1023;
> uint16_t adc_neu = 0;

> //**** Aufruf im Main **************************************

> adc_neu = adc_lesen();   // ADC lesen
>>>  button = read_button( adc_alt);   // Tastennummer auslesen,
>
> //*******************************************************************
>
>
> uint8_t read_button(uint16_t adc_neu)
> {
>>>   if (adc_neu > adc_alt)     // adc_alt = 1023!! Bedingung wahr
>>>        adc_alt = adc_neu    // gedrückte Taste wird vernichtet!
>
>
>
>
> Eine gedrückte Taste würde bei Dir z.B den ADC-Wert 70 bedeuten.
> Da 70 kleiner 1023 wird 70 mit 1023 überschrieben und somit die
> Erkennung der gedückten Taste vernichtet?
> richtig
so das sollte für deine HW  jetzt passen.

Namaste

von Rick M. (rick00)


Lesenswert?

Hannes Lux schrieb:
> Winfried J. schrieb:
>> Ohne das floatende Signal auf der ADC Leitung zu beheben wird sich...
>
> ...keine Tastatur ordentlich abfragen lassen, egal ob mit meiner
> Methode, mit Winfrieds Methode, mit Peter Danneggers Methode oder wie
> auch immer.

ich habe einen Pull down widerstand!!!

Hannes Lux schrieb:
> Entweder, Du baust einen Pull-Down-(Pull-Up-)Widerstand (etwa 20..50k)
> ein, oder Du änderst die Spannungsteilerschaltung so ab, wie ich sie
> weiter oben beschrieben habe.

was ich schon von anfang an habe brauch ich nicht nochmal machen...

Peter Dannegger schrieb:
> Ich hab nicht alles gelesen, aber ich habe den Eindruck, daß Du bisher
> nichtmal meinem Rat gefolgt bist und die ADC-Werte ausgibst.

Die von mir programmierten Tasten-Fenster beruhen darauf, daß ich mir 
die ADC-Werte auf dem LCD ausgeben habe lassen...
es liegt also nicht an meiner faulheit

Peter Dannegger schrieb:
> Schau Dir also die ADC-Werte an, wenn man eine Taste drückt. D.h. wie
> schnell erreichen sie den Endwert, wie weit zappeln sie und wie schnell
> reagieren sie auf das Loslassen.

fast kein zappeln feststellbar.
um die Anstiegszeit bzw. Abfallzeit zu bestimmen ist das LCD zu 
langsam..


Werde über eine Änderung des Layouts nachdenken....

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

Rick M. schrieb:
> Hannes Lux schrieb:
>> Winfried J. schrieb:
>>> Ohne das floatende Signal auf der ADC Leitung zu beheben wird sich...
>>
>> ...keine Tastatur ordentlich abfragen lassen, egal ob mit meiner
>> Methode, mit Winfrieds Methode, mit Peter Danneggers Methode oder wie
>> auch immer.
>
> ich habe einen Pull down widerstand!!!

kein Grund zu schreien

Beitrag "Re: 5 Tasten am ADC"

von Rick M. (rick00)


Lesenswert?

ja, sorry...galt nicht Dir....war nur frustriert....

von Peter D. (peda)


Lesenswert?

Rick M. schrieb:
> fast kein zappeln feststellbar.

Aus der Nase zieh: wie groß ist die Zahl "fast kein"?
2, 4, 10?


Rick M. schrieb:
> um die Anstiegszeit bzw. Abfallzeit zu bestimmen ist das LCD zu
> langsam..

Das LCD ist zumindest deutlich schneller, als Du es ablesen kannst.

Aber Du kannst ja mit der Entprellkonstante (z.B. 10ms) reihum die 
letzten 20 Meßwerte speichern und dann mit der UART untereinander 
ausgeben.
Das Speichern machst Du solange, bis der Wert sich nicht mehr größer 
ändert, als das "fast kein zappeln" und vielleicht noch 5 Werte weiter.
Du kriegst also für jeden Tastendruck/loslassen 25 Werte im 10ms Raster 
angezeigt.
Dann sollte gut zu erkennen sein, wie man das entprellen und auswerten 
kann.

Peter

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

Rick M. schrieb:
> ja, sorry...galt nicht Dir....war nur frustriert....

Schon gut und verständlich, aber bedenke niemand will dich hier ärgern.
Du must bewerten was dir weiter hilft jeder Andere kann nur Empfehlungen 
geben. Und Peter ist hier sicher der Guru. Hans ist auch ein Erfahrener.

Ich habe lediglich mit dem Problem eigenständige Erfahrungen gesammelt,
welche ich Dir gern zur Verfügung stelle.

Schon auf Grund der Länge des Threads geht auch bei mir mal eine 
Information unter zumal das Thema komplexer ist als man glaubt. Noch 
dazu ist mein Experiment über 6 Jahre her ein wunder das ich alles 
sochnell wieder fand.

Und dann gibt es ja noch allgemeine Kommunikationsunsicherheiten.

Also ist das Job oder Hobby?
Wo drückt der Schuh?

Namaste

von Rick M. (rick00)


Lesenswert?

Winfried J. schrieb:
> Schon gut und verständlich, aber bedenke niemand will dich hier ärgern.

ja, dachte Hannes wollte mich nur verar...durch den Beitrag mit dem 
Pull-Down-R, kenne die Menschen hier ja (noch) nicht ....und verstehe da 
vielleicht beiläufige Kommentare vollkommen falsch...wie z.b. 
Programmieren wie n Mädchen.....etc.

Winfried J. schrieb:
> Ich habe lediglich mit dem Problem eigenständige Erfahrungen gesammelt,
> welche ich Dir gern zur Verfügung stelle.

und darüber bin ich Dir, und auch jeden anderen, der mir helfen will, 
sehr dankbar...

Winfried J. schrieb:
> Schon auf Grund der Länge des Threads geht auch bei mir mal eine
> Information unter zumal das Thema komplexer ist als man glaubt.

vollkommen verständlich.
Es ist ja auch nicht gerade sehr lustig, sich in einen so langen Beitrag 
einzuarbeiten, nur um jemand anderen zu helfen. Du opferst ja hier Zeit 
und Energie für andere...

Winfried J. schrieb:
> Und dann gibt es ja noch allgemeine Kommunikationsunsicherheiten

Tja, die Sprache ist eben nur eine sehr unzulängliche 
Kommunikations-Schnittstelle.....

Winfried J. schrieb:
> Also ist das Job oder Hobby?
> Wo drückt der Schuh?

Zum Glück nur Hobby, aber ich wollte mir aus gesundheitlichen Gründen 
ein Gerät bauen und muß eben wieder einmal feststellen, daß ich einfach 
viel zu blauäugig war, was die Umsetzung eines scheinbar einfachen 
Problems mittels MC betrifft.

Also nochmal Danke für eure Zeit und Geduld!

Schönen Abend
Rick

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

Gern auch weiterhin.
Ich hatte etwas Luft, da Strohwitwer und auch sonst etwas Ruhe.
Ab morgen wird es wieder etwas turbulenter und ich werde etwas weniger 
Zeit haben. Aber ich beantworte dir gern weiter fragen wenn ich das 
vermag.
Also keine Sorge.

Namaste

von Hannes L. (hannes)


Lesenswert?

Rick M. schrieb:
> ja, dachte Hannes wollte mich nur verar...

Warum sollte ich das tun?

> durch den Beitrag mit dem
> Pull-Down-R,

In Deinem Schaltbild im ersten Post ist der nicht drin.

Der Thread geht nun schon fast 2,5 Tage, ich habe die einzelnen Beiträge 
zwar alle gelesen, aber nicht in einem Zuge, sondern so, wie sie 
geschrieben wurden und ich Zeit fürs Forum hatte. Dazwischen habe ich 
andere Dinge gemacht und auch andere Threads gelesen. So ist es völlig 
normal, dass ich einige Details vergessen habe, so auch das Detail, dass 
Du einen 100k-PullDown eingesetzt hast.

Wobei ich 100k für etwas hochohmig halte, die Sample&Hold-Stufe arbeitet 
durch Umladung eines Kondensators auf die Spannung des Eingangspins. Und 
dieses "Tor" ist nur sehr kurz offen. Siehe Diagramm im Kapitel ADC des 
Datenblatts. Gut, der Tasten-Spannungsteiler ist niederohmig genug, aber 
für das Erkennen der unbetätigten Tastatur halte ich 100k für 
genzwertig.

...

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

Habe nochmal nachgeschaut ich bin sogar deutlich niederohmiger, fixer

Pullup 7,4 k
0<=Rt<=0.46k

Ich könnte bei meiner ca 160 Tasten an die Matrix hängen.

Allerdings würde ich dafür eher eine PS2 -Tastatur hernehmen.


Namaste

von Rick M. (rick00)


Lesenswert?

Hallo!

Hannes Lux schrieb:
> Wobei ich 100k für etwas hochohmig halte, die Sample&Hold-Stufe arbeitet
> durch Umladung eines Kondensators auf die Spannung des Eingangspins. Und
> dieses "Tor" ist nur sehr kurz offen. Siehe Diagramm im Kapitel ADC des
> Datenblatts. Gut, der Tasten-Spannungsteiler ist niederohmig genug, aber
> für das Erkennen der unbetätigten Tastatur halte ich 100k für
> genzwertig.

Hab nochmal im Datenblatt nachgelesen:
"The ADC is optimized for analog signals with an output impedance of 
approx 10kOhm or less"
Hab mir das sogar mit Leuchtstift angestrichen, ist aber anscheinend 
wieder in Vergessenheit geraten.

Werde den Pull-Down-R von 100k auf 10k verkleinern und alle ADC-Werte 
neu berechnen und zusätzlich anzeigen lassen.

Gruß Rick

von Hannes L. (hannes)


Lesenswert?

Rick M. schrieb:
> Werde den Pull-Down-R von 100k auf 10k verkleinern

Dann liegen aber Deine Werte zu dicht beieinander. Mit um die 22 k bist 
Du besser bedient.

Ich habe (als Ersatz eines Steuerknüppelpotis einer modernen 
RC-Fernsteuerung) 19 Widerstände 510 Ohm in Reihe zwischen GND und +3,3V 
und einen Widerstand 56 k als PullDown. Dies wird vom ADC des Mega8 des 
Fernsteuersenders eingelesen. Die Auswertung der 17 Tasten erfolgt auf 
der Empfängerseite anhand der Kanalimpulsbreite und ist fehlerfrei.

Rick M. schrieb:
> with an output impedance of
> approx 10kOhm or less

Richtig, das wäre "optimal". Ich bevorzuge auch 10 bis 20 k.

In meinem Fall des Funkfernsteuersenders hätte mir ein PullDown von 10 
oder 20 k den Spannungsteiler zu sehr belastet, also die Linearität zu 
sehr beeinträchtigt. Diese war mir aber wichtig, weil sie das Auswerten 
der Tasten enorm erleichtert. Als Differenz zwischen unterer und oberer 
Kanalimpulsbreite hat sich aufgrund des verwendeten Baudratenquarzes und 
des Timer-Vorteilers ein Wert von 136 ergeben. Das macht bei 17 Tasten + 
unbetätigten Tasten, also 18 "Stellungen" 8 Zahlenwerte von Taster zu 
Taster. Also wurde zur Auswertung der ICP-Zahlenwert nach Abzug des 
Offsets durch 8 geteilt und schon war ein Index für die Tasten-Nummer 
ermittelt. Index und LUT deshalb, weil es mehr Freiheit beim Anordnen 
der Taster und des Spannungsteilers bietet und damit die Platine 
vereinfacht.

Manchmal sind eben 10 Zeilen Software billiger als eine unnötig 
komplizierte Platine. Andererseits können ein paar Überlegungen zur 
Hardware und deren Dimensionierung die Software stark vereinfachen.

...

von Rick M. (rick00)


Lesenswert?

Hallo!

Hannes Lux schrieb:
> Rick M. schrieb:
>> Werde den Pull-Down-R von 100k auf 10k verkleinern
>
> Dann liegen aber Deine Werte zu dicht beieinander. Mit um die 22 k bist
> Du besser bedient.

Folgende Werte hab ich für einen 10k Pull-Down-R berechnet:

AREF=2,13V / U_teiler=4,93V

144
263
365
451
527

Bei AREF=AVCC=U_teiler=4,93V

62
114
158
195
228

Als zu eng empfind ich das jetzt nicht.....

Werd aber gerne auf Deine Empfehlung eingehen und einen 22k Pull-Down 
nehmen.

Hannes Lux schrieb:
> Also wurde zur Auswertung der ICP-Zahlenwert nach Abzug des
> Offsets durch 8 geteilt und schon war ein Index für die Tasten-Nummer
> ermittelt.

ICP-Zahlenwert?
Kann Dir da leider nicht ganz folgen..
Daß eine Linearität beim Spannungsteiler die Sache enorm erleichtert is 
mir klar, denn dann kann man z.B. den Präprozessor rechnen lassen, so 
wie es Peter immer gerne macht.
Is ja auch ne schlaue Sache, da eine Änderung der Hardware hierdurch 
sehr leicht übertragen werden kann. Es müssen nur die Werte in der 
Formel geändert werden, die Fenster oder Maschen für die Taster werden 
automatisch berechnet.

MfG Rick

von Peter D. (peda)


Lesenswert?

Rick M. schrieb:
> Daß eine Linearität beim Spannungsteiler die Sache enorm erleichtert is
> mir klar, denn dann kann man z.B. den Präprozessor rechnen lassen, so
> wie es Peter immer gerne macht.

Meine Schaltung ist auch nichtlinear, der obere 
Spannungsteilerwiderstand ist ja fest. Zu höheren Widerständen hin sinkt 
der Spannungsunterschied zwischen 2 Tasten.
Wenn man das ohmsche Gesetz kennt, kann man jede beliebige 
Widerstandsschaltung berechnen lassen.


Peter

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Rick M. schrieb:
> Hab nochmal im Datenblatt nachgelesen:
> "The ADC is optimized for analog signals with an output impedance of
> approx 10kOhm or less"

Das bezieht sich aber nur auf die Umladegeschwindigkeit der
Kondensatoren da drin.

Rein statisch ist der Eingangswiderstand ziemlich hochohmig.  Lass
deine 100 kΩ Pulldown da drin.  Dein eigentlicher Spannungsteiler ist
niedrig genug, und im Vergleich zur ADC-Geschwindigkeit bist du ja
sowieso schnarchlangsam.

von Rick M. (rick00)


Lesenswert?

Jörg Wunsch schrieb:
> Das bezieht sich aber nur auf die Umladegeschwindigkeit der
> Kondensatoren da drin.

Das Drücken und Loslassen der Taster ist ein dymamischer Vorgang


@Winfried


Winfried J. schrieb:
>> uint16_t adc_alt = 1023;
>> uint16_t adc_neu = 0;
>
>> //**** Aufruf im Main **************************************
>
>> adc_alt = adc_lesen();   // ADC lesen
>>>>  button = read_button( adc_alt);   // Tastennummer auslesen,
>>
>> //*******************************************************************
>>
>>
>> uint8_t read_button(uint16_t adc_alt)
>> {
>>>>   if (adc_neu > adc_alt)     // adc_alt = 1023!! Bedingung wahr
>>>>        adc_alt = adc_neu    // gedrückte Taste wird vernichtet!
>>
>>
>>
>>
Bei diesem Code macht der Vergleich gar nichts.
adc_neu ist immer 0 und adc_alt der ADC-Wert von den Tasten
adc_neu kann nie größer adc_alt werden

.... nach meinem Verständnis muß ich vorher 2 ADC-Werte im Abstand von 
8msec abfragen, anschl. das Unterprogramm 4 mal aufrufen, damit ich ne 
gültige Tastennummer zurückbekomme. Das dauert dann minimum 32msec.

Ich steh da aufm Schlauch...Deinen Vergleich mit dem max-Init kapier ih 
ned

Gruß Rick

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

stammt das von mir?

>> adc_alt = adc_lesen();   // ADC lesen

soll natürlch adc_neu heißen
adc_neu = adc_lesen();   // ADC lesen

von Dirk (Gast)


Lesenswert?

Hallo, hier wird gross um die HW diskutiert, aber an der HW sehe ich 
kein Fehler, sondern nur Verbesserungsvorschläge. Die 100kOhm sind im 
gruenen Bereich oder möchtest Du deine Betriebsspannung gerne unnötig 
belasten?

Die Entprellzeit bzw. deine Timerzeit ist ehrlich gesagt Murks. Wozu 
fragst Du den Zustand alle 8ms ab, die Abfrage reicht alle 100ms locker!

Der Code im Thread ist nicht compilierbar, deshalb bitte den richtigen 
Code hier posten.

Wieso benutzt Du den ADC nicht im continues read mode und holst Dir die 
Werte nur zu den entsprechenden Zeiten ab?

Hier ein Pseudo C Code:

1
void adc_init()
2
{
3
// ADC Kanal einstellen, prescaler und continues mode
4
}
5
6
void timer0_init()
7
{
8
//timer 0 prescaler und overflow betrieb
9
//30ms == overflow
10
}
11
12
isr(timer0_ovf)
13
{
14
timer_tick++ // Systemtimer erhöhen
15
}
16
17
int main(void)
18
{
19
volatile u8 timer_tick=0;
20
volatile u8 temp=0;
21
22
adc_init(); //adc einrichten
23
timer0_init(); // timer0 einrichten
24
sei();        //golable interrupt flag aktiviert
25
26
u8 adc_read()
27
{
28
return adc_wert // 
29
}
30
31
32
33
for();;
34
{
35
if (timer_tick) == 3
36
{
37
adc_alt = adc_read()
38
}
39
40
if timer_tick == 6
41
adc_neu = adc_read()
42
if (adc_alt == adc_neu){
43
//wert mit LUT vergleichen und somit die gedrückte Taste auswerten
44
adc_alt=0; // alte werte löschen
45
adc_neu=0;
46
timer_tick=0; // zaehler löschen
47
}
48
} //

Ist kein Super Pseudo Code aber es beinhaltet die wichtigsten Sachen.

von Rick M. (rick00)


Lesenswert?

Dirk schrieb:
> Hallo, hier wird gross um die HW diskutiert, aber an der HW sehe ich
> kein Fehler, sondern nur Verbesserungsvorschläge. Die 100kOhm sind im
> gruenen Bereich oder möchtest Du deine Betriebsspannung gerne unnötig
> belasten?

Ich persönlich finde den Einwand, daß 100k zu hoch sind, für richtig.
Deshab verwende ich jetzt auch fix 22k als Pull-Down-R.
5V/22k ich glaub, daß wird der 7805er verkraften.

Dirk schrieb:
> if (adc_alt == adc_neu)

Das kann alleine schon wegen des Pendelns der Werte bei gedückter Taste 
nicht klappen.
Verglichen können hier höchstens die resultierenden Tastennummern nach 
der LUT werden.

Gruß Rick

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Rick M. schrieb:
>> Das bezieht sich aber nur auf die Umladegeschwindigkeit der
>> Kondensatoren da drin.
>
> Das Drücken und Loslassen der Taster ist ein dymamischer Vorgang

Ja.  Alles außer Gleichspannung ist nach dieser Definition ein
dynamischer Vorgang. ;-)

Deine 8 ms sind saulahm im Vergleich zu dem, was der ADC an
Geschwindigkeit schaffen könnte.  Folglich sind alle kritischen
Kondensatoren spätestens dann umgeladen, wenn du den das zweite Mal
abfragst.

Ich habe gerade den Kollektorwiderstand eines Fototransistors am
ADC-Eingang von 100 kΩ auf 2,2 MΩ vergrößert, weil er mir ansonsten
bei geringer Beleuchtungsstärke zu wenig Auflösung gebracht hat.
Abgefragt wird im Sekundentakt, und eine Änderung von ganz hell auf
ganz dunkel (bei der die 2,2 MΩ ja die Kondensatoren auf Vcc umladen
müssen) ist trotzdem stets mit der nächsten Sekunde erkannt und die
Reaktion (Dimmen der LEDs) erfolgt.

Interessanter Nebeneffekt dabei: anfangs hatte ich versehentlich noch
ADATE aktiv (von vorangegangenen Versuchen), sodass der ADC im free
running mode lief.  Da hat der Sprung von ganz hell nach ganz dunkel
noch ca. 2 s benötigt.  Liegt offenbar daran, dass die S&H-Schaltung
in diesem Falle jeweils nur kurz sampelt, dabei entlädt sie die
Eingangs- und Schaltungskapazität, weil die 2,2 MΩ nicht so schnell
nachladen können.  Nachdem ich das ADATE rausgenommen habe (und damit
die S&H-Schaltung sehr viel länger am Eingang klemmt), war dieser
Effekt jedoch verschwunden.

von Hannes L. (hannes)


Lesenswert?

Rick M. schrieb:
> Dirk schrieb:
>> Hallo, hier wird gross um die HW diskutiert, aber an der HW sehe ich
>> kein Fehler, sondern nur Verbesserungsvorschläge. Die 100kOhm sind im
>> gruenen Bereich oder möchtest Du deine Betriebsspannung gerne unnötig
>> belasten?

Der Spannungsteiler (10k, mehrere 1k) liegt ständig an der 
Betriebsspannung, belastet die Betriebsspannung also ständig. Die 100k 
bzw. 22k wirken nur bei gedrückter Taste.

>
> Ich persönlich finde den Einwand, daß 100k zu hoch sind, für richtig.

Ich inzwischen nicht mehr, ich war da zu voreilig. Denn es geht auch 
ganz gut ohne PullDown.

Der (vorgegebene) Spannungsteiler berücksichtigt die externe 
ADC-Referenz von etwa 2V, deshalb mehrmals 1k auf der GND-Seite und 10k 
auf der Plus-Seite. Nachteil: Bei sich ändernder Betriebsspannung misst 
das Ding falsch, da die Referenz konstanz bleibt. Es ist also keine 
radiometrische Messung. Das ist aber nicht das, worauf ich hinaus will, 
denn bei 5 Werten ist der Abstand immernoch groß genug...

Alles oberhalb der ADC-Referenz wird als "Voll Haus" gemessen, also als 
255 (8 Bit) bzw. 1023 (10 Bit). Somit reicht es aus, den internen PullUp 
einzuschalten, wenn die Tastatur gemessen wird. Und natürlich wieder 
aus, wenn andere Kanäle gemessen werden. Der interne PullUp ist zwar 
recht ungenau (Exemplarstreuungen), aber doch um Einiges hochohmiger als 
der verwendete Spannungsteiler, verfälscht die Werte also nur 
unwesentlich. Und er "zieht" den Pegel nicht nur nach AREF, sondern nach 
Vcc, hat also AREF bei offenen Tastern schnell überschritten. Somit hast 
Du für unbetätigte Taster immer den Maximalwert (also kein Fenster), was 
als Kriterium genutzt werden kann, ob keine Taste gedrückt ist, also 
darüber entscheidet, ob Du den ADC überhaupt auf die Fenster der 
einzelnen Tasten prüfen musst.

> Deshab verwende ich jetzt auch fix 22k als Pull-Down-R.
> 5V/22k ich glaub, daß wird der 7805er verkraften.

Wie ich bereits schrieb, wirkt der PullDown nur bei gedrücktem Taster. 
Die 15k des Spannungsteilers wirken immer, aber auch die verkraftet der 
7805.

>
> Dirk schrieb:
>> if (adc_alt == adc_neu)
>
> Das kann alleine schon wegen des Pendelns der Werte bei gedückter Taste
> nicht klappen.
> Verglichen können hier höchstens die resultierenden Tastennummern nach
> der LUT werden.

Richtig, wobei LUT erst bei mehr Tasten sinnvoll wird, Deine 5 Tasten 
kannst Du mittels IF oder Switch selektieren.

>
> Gruß Rick

...

von Hannes L. (hannes)


Lesenswert?

Jörg Wunsch schrieb:
> Nachdem ich das ADATE rausgenommen habe (und damit
> die S&H-Schaltung sehr viel länger am Eingang klemmt), war dieser
> Effekt jedoch verschwunden.

Danke...

...

von spess53 (Gast)


Lesenswert?

Hi

> Liegt offenbar daran, dass die S&H-Schaltung
>in diesem Falle jeweils nur kurz sampelt, dabei entlädt sie die
>Eingangs- und Schaltungskapazität, weil die 2,2 MΩ nicht so schnell
>nachladen können.  Nachdem ich das ADATE rausgenommen habe (und damit
>die S&H-Schaltung sehr viel länger am Eingang klemmt), war dieser
>Effekt jedoch verschwunden.

Die Länge der Sample-Phase hängt nur vom ADC-Clock ab. Daran ändert 
auch der Free-Running-Mode nichts.

MfG Spess

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

spess53 schrieb:
> Die Länge der Sample-Phase hängt nur vom ADC-Clock ab. Daran ändert
> auch der Free-Running-Mode nichts.

Um die reine Sample-Phase geht es aber nicht, sondern darum, wie
lange die S&H-Kondensatoren bereits am Eingang klemmen.  Das tun
sie ganz offenbar auch bereits vor dem Sampeln, anders ließe sich
der Unterschied zwischen free running mode und explizitem Triggern
einmal pro Sekunde nicht erklären.

Wirklich detailliert beschrieben ist das im Datenblatt ohnehin alles
nicht.

von Rick M. (rick00)


Lesenswert?

Hallo!

Jörg Wunsch schrieb:
> Deine 8 ms sind saulahm im Vergleich zu dem, was der ADC an
> Geschwindigkeit schaffen könnte.  Folglich sind alle kritischen
> Kondensatoren spätestens dann umgeladen, wenn du den das zweite Mal
> abfragst.

Ich glaubte, daß der Kondensator immer nur ganz kurz an der Mess-Spg. 
"anliegt", auch wenn der Kanalwechsel sehr langsam erfolgt (8msec) und 
der ADC im single-shot-Modus läuft.
Deinen Schilderungen entnehme ich, daß dies nicht der Fall ist und der 
S&H Kondensator bei Single-Shot so lange an der Mess-Spg. aniegt bis ein 
anderer Kanal eingestellt wird.
Dann sind die 100k problemlos...

Jörg Wunsch schrieb:
> Interessanter Nebeneffekt dabei: anfangs hatte ich versehentlich noch
> ADATE aktiv (von vorangegangenen Versuchen), sodass der ADC im free
> running mode lief.  Da hat der Sprung von ganz hell nach ganz dunkel
> noch ca. 2 s benötigt.  Liegt offenbar daran, dass die S&H-Schaltung
> in diesem Falle jeweils nur kurz sampelt, dabei entlädt sie die
> Eingangs- und Schaltungskapazität, weil die 2,2 MΩ nicht so schnell
> nachladen können.  Nachdem ich das ADATE rausgenommen habe (und damit
> die S&H-Schaltung sehr viel länger am Eingang klemmt), war dieser
> Effekt jedoch verschwunden.

Also im free-running-Modus liegt der Kondensator nur kurz an der 
Mess-Spg.

Hannes Lux schrieb:
> Nachteil: Bei sich ändernder Betriebsspannung misst
> das Ding falsch, da die Referenz konstanz bleibt.

Nein, da bei meinem Board AREF über einen Spannungsteiler aus der 
Betriebsspg. erstellt wird. Somit ändert sich auch AREF mit der 
Betriebsspg.

spess53 schrieb:
> Die Länge der Sample-Phase hängt nur vom ADC-Clock ab. Daran ändert
> auch der Free-Running-Mode nichts.

??

Gruß Rick

von Peter D. (peda)


Lesenswert?

Hatte ich schon erwähnt, daß man sich die ADC-Werte einfach mal ausgeben 
lassen sollte?

Und danach kann man sich zusätzlich die Bewertung anzeigen, ob die 
Bewertungslogik (if, switch oder LUT) funktioniert.

Erst dann kanns ans Entprellen gehen.

Einfach nur einen Schritt nach dem anderen machen und nicht alles 
gleichzeitig.


Peter

von Rick M. (rick00)


Lesenswert?

Peter Dannegger schrieb:
> Hatte ich schon erwähnt, daß man sich die ADC-Werte einfach mal ausgeben
> lassen sollte?

ja, mach ich auch..


Hab momentan folgendes Problem:

Ich versuche die Tastenerkennung nach dem Schema von Hannes hin zu 
bekommen.

Hab folgende Files:

ADC.h
ADC.c ........... ADC ISR

Timer1.h
Timer1.c  ....... Timer1 ISR

KoSi_Gen.h ........beinhaltet Unterprogramme für Main
KoSi_Gen.c ........beinhaltet Main

Die Variable adc_value_number benutze ich in der Timer1-ISR und ist in 
der Timer1.h deklariert.
Aber diese Variable benutz ich auch in der ADC-ISR.

Nun schreibt mir der Compiler, daß die Variable in ADC.c nicht definiert 
wurde, klar ist ja auch in Timer1.h definiert.
Wenn ich jetzt aber in der ADC.c nicht nur ADC.h sonder auch Timer1.h 
einbinde, hab ich wieder multible definitionen der Variable 
"adc_value_number"

Wie lös ich dieses Problem?

von Rick M. (rick00)


Lesenswert?

Hat sich erledigt, mir ist gerde der FAQ-Artikel wieder eingefallen!
Das Stichwort lautet extern.

von Rick M. (rick00)


Angehängte Dateien:

Lesenswert?

Hallo!

Hab bis jetzt folgendes umsetzen können:

Einfachster Versuchsaufbau: kein Kanalwechsel, Single-Shot

In der Timer1-ISR wird alle 4msec eine ADC-Wandlung angestoßen.
Eine globale Variable hilft mir das 1. und das 2te Wandlungsergebnis in 
der ADC-ISR auseinander halten zu können.

In der ADC-ISR werden 2 aufeinander folgende Tasten-Nummern miteinander 
verglichen und bei Gleichheit beginnt ein Prellzähler zu zählen.

Sobald die Taste wieder losgelassen wird, also der 1. der beiden 
Messwerte wieder null wird und der Prellzähler die Minimalschwelle 
überschritten hat, wird der Tastendruck als gülig gewertet und dem 
Hauptprogramm übergeben.

Folgendes wird am LCD angezeigt:
Erkannte Taste
momentaner ADC-Wert
momentaner Wert des Prellzählers

ADC-Werte der Tasten (berechnet/angezeigt) bei

****AREF = AVCC = U_teiler = 4,93V****

**Pull-Down-R = 22k**

T5: 65/64

T4: 125/125

T3: 180/183

T2: 231/239

T1: 278/294

Wobei sich das Pendeln der Werte lt. LCD auf die Einerstelle begrenzt, 
also kleiner 10 ist.
Komischerweise driften die höheren Werte zw. Berechnung und gemessen 
immer mehr auseinander.
Wenn AREF wieder auf 2,13V reduziert wird, verdoppelt sich dieser Effekt 
sogar.

Wenn ich eine der Tasten betätige kann ich mir schön ansehen, wie der 
Prellzähler hochläuft. Somit funktioniert die LUT für alle Tasten.
Auch der Überlaufschutz des Zählers funktioniert.

Leider wird der Tastendruck immer noch nicht 100% verlässlich erkannt.

Ein weiteres Mysterium ist das Verhalten der LED an PC7, welche 
eigentlich im Sekundentakt an und wieder aus gehen soll. (Sekundentakt 
wird von der Timer1-ISR erzeugt).
Die LED geht für mehrere Takte nicht mehr vollständig aus, sondern 
reduziert die Helligkeit nur um die Hälfte. Dann funktioniert sie für 
ein paar Takte wieder normal und das Spiel beginnt von vorne.
Da die Ausgangspegel ja nur Low oder High sein können, würde dies 
bedeuten, daß der Ausgang schwingt. Wieso weiß ich aber nicht da ich die 
LED bzw. den Ausgang nur toggle.
1
if(second_puls == 1)    // toggle LED7
2
      PORTC ^= (1<<PC7);



Ich hab mal den gesamten Code angehängt und alles überflüssige gelöscht, 
damits übersichtlicher wird.


Gruß Rick

von Rick M. (rick00)


Lesenswert?

Hallo !

Hab jetzt endlich geschafft, meine Tasten anständig auszulesen.

Kann mir jemand erklären warum diese Anweisung nicht funktioniert:
1
if(second_puls == 1)    // LED7 als Sekundenanzeige
2
      PORTC ^= (1<<PC7);

aber diese Anweisung, um die LED blinken zu lassen:
1
if(second_puls == 1)    // LED7 als Sekundenanzeige
2
      PORTC |= (1<<PC7);
3
      
4
if(second_puls == 0)
5
      PORTC &= ~(1<<PC7);

Beim Togglen erlischt die LED nicht immer vollständig, sondern leuchtet 
nur mit halber stärke weiter, was auf ein schwingen des Ausgangs 
hinweist.


Der Grund, warum bisher die Tasten nicht korrekt ausgelesen werden 
konnten, ist, daß das Sichern der gedrückten Taste früher erfolgen 
mußte. Momentan erledige ich das mit einer zusätzlichen Variable 
temp_button.

Gruß Rick

von Hannes L. (hannes)


Lesenswert?

Rick M. schrieb:
> was auf ein schwingen des Ausgangs
> hinweist.

Richtig, denn Du toggelst PC7 bei jedem Hauptschleifendurchlauf, solange 
second_puls 1 ist. Da fehlt eine Flankenerkennung.

...

von Rick M. (rick00)


Lesenswert?

Hallo!

Hannes Lux schrieb:
> Da fehlt eine Flankenerkennung.

Danke, war ein Denkfehler.

Könnte mir bitte jemand erklären, warum ich hier eine mehrfache 
Definition von "adc_channel" habe:
1
uint16_t volatile adc_value [ADC_INDEX_MAX];    // Feld für die Wandlungsergebnisse des ADC = ADC-Ergebnis-Speicher
2
uint8_t volatile adc_channel[] = {7,7};      // Kanalabfolge für das Auslesen der ADC-Werte
3
uint8_t volatile adc_index;            // Index für Kanalwahl und ADC-Speicher

adc_channel wir nur mehr in der Fkt. "adc_init" und in der "adc-ISR" 
verwendet:

"adc_init"
1
ADMUX = ( (ADMUX & ~(0x1F)) | (adc_channel[0] & 0x1F) ); 
2
// 1. Kanal  einstellen

"adc-ISR"
1
ADMUX = ( (ADMUX & ~(0x1F)) | (adc_channel[adc_index] & 0x1F) );
2
 // nächsten Kanal  einstellen

Habe mein Projekt mehrmals mit der Suchfkt. durchsucht, ob der Ausdruck 
"adc_channel" noch wo anders benutzt wird, aber Fehlanzeige.

Gruß Rick

von Rick M. (rick00)


Angehängte Dateien:

Lesenswert?

Hallo!

Meine Tastenerkennung funktioniert jetzt ganz gut.
Momentan wird vom meinem Timer1-ISR alle 4msec eine Wandlung angestoßen.
Möchte ich jedoch meine Wandlungsfrequenz erhöhen, also die nächste 
Wandlung am Ende meiner ADC-ISR anstoßen, weil ich mehrere Messkanäle 
abarbeiten möchte, so funktioniert meine Tastenerkennung auf einmal 
nicht mehr.
Der Prellzähler zählt tadellos hinauf (Anzeige am LCD), auch der 
ADC-Wert stimmt (Anzeige per LCD), die Tasten werden jedoch anscheinend 
nicht mehr richtig ausgewertet.
Hat da vielleicht jemand von euch ne Idee?

Ich hab mal meinen Code angehängt, die Tastenerkennung befindet sich in 
der Datei "adc.c"

Grüße Rick

von Rick M. (rick00)


Lesenswert?

Hallo!

Ich konnte den Fehler bis zur Übergabe der Tasten-Nummer zum 
Hauptprogramm  eingrenzen.
Wenn ich Taste-5 drücke so erhalten die Variablen button_1, button_2 und 
temp_button den Wert 5 und der Prell-Zähler zählt hoch.

Beim Loslassen der Taste wird die Tastennummer (Variable button) aber 
anscheinend dem Hauptprogramm nicht richtig übergeben.

Wenn ich eine Wandlung nur alle 4msec aus der Timer1-ISR anstoße 
funktionierts, wenn ich die nächste Wandlung gleich in der ADC-ISR 
anstoße nicht?
Ich komme einfach nicht auf den Fehler.

Meine ADC-ISR
1
ISR (ADC_vect)
2
{
3
  
4
  //ADMUX = ( (ADMUX & ~(0x1F)) | 0x1F );  // discharge S&H Cap
5
  
6
  adc_value[adc_index] = ADCW;  // Wandlungsergebins auslesen und speichern
7
  
8
9
// ******** ANFANG Tastenabfrage ******************************  
10
  
11
  if (adc_index == 0)              // 1. Wandlungsergebnis für Tasten
12
    button_1 = read_LUT(adc_value[0]);    // Taste zuweisen und speichern
13
      
14
  
15
  
16
  if (adc_index == 1)      // 2tes Wandlungsergebnis für Tasten
17
  {  
18
    button_2 = read_LUT(adc_value[1]);    // Taste zuweisen und speichern
19
    
20
    if (button_1 == button_2)    // wenn 2 gleiche Tasten-Nr. hintereinander
21
    {  
22
      temp_button = button_2;    // Tastennummer sichern
23
      
24
      if(++equal_counter == 65000)  // Prellzähler erhöhen und vor Überlauf schützen
25
        equal_counter = 0;
26
    }
27
  }  
28
  
29
  
30
  if ( (equal_counter < 1000) && (button_1 == 0) )  // Taste losgelassen, kein gültiger Tastendruck  
31
  {
32
    button = 0;
33
    equal_counter = 0;
34
  }
35
  
36
  
37
  if ( (equal_counter > 1000) && (button_1 == 0) )  // Taste losgelassen, gültiger Tastendruck  
38
  {
39
    button = temp_button;            // Tasten-Nr. ausgeben
40
    equal_counter = 0;              // Prellzähler rücksetzen
41
  }
42
  
43
44
45
// ***** ENDE Tastenabfrage  ********
46
47
  
48
  if( ++adc_index == ADC_CHANNELS)  // Index erhöhen und wenn nötig rücksetzen
49
    adc_index = 0;
50
    
51
  ADMUX = ( (ADMUX & ~(0x1F)) | (adc_channel[adc_index] & 0x1F) ); // nächsten Kanal  einstellen  
52
  
53
  ADCSRA |= (1<<ADSC);  //nächste ADC-Wandlung anstoßen
54
  
55
}



In Main:
1
cli();
2
    switch (button)          // Handlung zuweisen
3
    {
4
              
5
      case 0:            // keine Taste gedrückt nix machen
6
        break;  
7
.
8
.
9
.
10
.
11
.
12
sei();

Gruß Rick

von Rick M. (rick00)


Lesenswert?

Zumindest habe ich eine weitere Fehlereingrenzung vornehmen können:
Wenn ich folgende Zeilen
1
if ( (equal_counter < 1000) && (button_1 == 0) )  // Taste losgelassen, kein gültiger Tastendruck  
2
  {
3
    button = 0;
4
    equal_counter = 0;
5
  }
6
  
7
  
8
  if ( (equal_counter > 1000) && (button_1 == 0) )  // Taste losgelassen, gültiger Tastendruck  
9
  {
10
    button = temp_button;            // Tasten-Nr. ausgeben
11
    equal_counter = 0;              // Prellzähler rücksetzen
12
  }



durch folgende ersetze
1
if (equal_counter > 1000)  // Taste losgelassen, gültiger Tastendruck  
2
  {
3
    button = temp_button;            // Tasten-Nr. ausgeben
4
    equal_counter = 0;              // Prellzähler rücksetzen
5
  }

funktioniert die Tastenerkennung wieder, was darauf schließen läßt, daß 
das Loslassen der Taste nicht mehr richtig erkannt wird.
Ich habe bereits versucht die Weitergabe der erkannten Taste erst zu 
machen , wenn button_1 == button_2 == 0 ist. Es findet zwar eine 
Verbesserung statt, (es funktioniert sporadisch) aber eine sichere 
Erkennung ist so auch nicht möglich.

Warum das so ist, verstehe ich allerdings nicht.
Könnte mir hier bitte wer weiterhelfen.

Gruß Rick

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.