mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Entprellung mit Dannegger-Code auf unterschiedlichen Ports


Autor: M.B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute,

ich beutze zur Entprellung meiner taster den genialen Code von Peter 
Dannegger. Ich habe u.a. gestern den ganzen Tag hier im Forum verbracht 
um mich nochmal in den Code einzuarbeiten.

Ich habe nun bei mir Taster an unterschiedlichen Ports (Port C und Port 
B). Jetzt versuche ich die beiden Ports in den Code von PD zu 
verbasteln. Ich bin sicher das ich das hier mal gelesen habe, aber ich 
finde es nicht mehr.
Ich muss irgendwie die unterschiedlichen Ports mit den entsprechenden 
Pins mit "KEY_PIN" verheiraten. Aber ich weiß nicht mehr wie das geht.

Vielleicht hilft mir mal jemand auf die Sprünge oder gibt mir den Link 
zum entsprechendem Thema.
/* C-Code für ATmega 88 */

[...]
//#define KEY_PIN    PINB // Version PD
#define KEY_PINB    PINB
#define KEY_PINC    PINC

#define _Taster1    0x01    //PB0
#define _Taster2    0x02    //PC1

[...]

ISR(TIMER2_OVF_vect)
{
  static uint8_t ct0, ct1;
  uint8_t i;

  TCNT2 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5);  // preload for 10ms

//  i = key_state ^ ~KEY_PIN;           // key changed ? PD's Version
  i = key_state ^ ~((KEY_PINB & _Taster1) | (KEY_PINC & _Taster2)) // wäre jetzt mein Ansatz
// aber stimmt die Richtung, in die ich mich bewege?
//Ich könnte mir auch einen Zwischenschritt über eine Variable vorstellen:

KEY_PIN_neu = ((PORTB |= _Taster1) | (PORTC |= _Taster2));
i = key_state ^ ~KEY_PIN_neu;

[...]

Könnt ihr das nachvollziehen?

Autor: ziegel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo, hab das mal so gelöst (Codeteile hängen zusammen als Teil der 
Interrupt-Service-Routine, hier nur vereinzelt zum Kommentieren):

Erstmal Portrichtung für die Taster setzen. Bei mir in der 
Interrupt-Service-Routine selber, da die Port-Pins auch als 
LCD-Datenausgang genutzt werden, das delay ist dann nötig für stabile 
Verhältnisse beim Einlesen:
  KEY_DIR_RS &= ~ALL_KEYS;                // Portrichtung setzen auf Eingang
  KEY_PORT_RS |= ALL_KEYS;                // PullUp's Ein
  KEY_PORT_RS &= ~KEY_PIN_RS;             // Tasten an RS abfragen: RS auf low ziehen
  _delay_us(2);    //2us

Als nächstes 3 Digitale Inputs einlesen (DIN), liegen auf anderem Port 
als die Tasten, Portrichtung ist anderswo gesetzt:
  din_state = (~DIN_PIN_C )& 14;            // DIN Bits 1,2,3 einlesen,  ~ da Optokoppler gegen GND und interner Pull-Up-Widerstand ein, Rest rausmaskieren

Hier noch ne kleine Notaus-Abfrage, die direkt ohne Entprellung aus der 
ISR heraus die Maschine abstellt:
  if ( din_state & (D_IN_2) ) {            // wenn D_IN_2 (NOTAUS) gesetzt,
    D_OUT_1_off;
  }

Jetzt die eingelesenen DIN-Zustände mit den Taster-Zuständen in ein Bit 
verheiraten (hier liegen die einzelnen Bits günstig, falls nicht, dann 
noch zurechtschieben):

    i = key_state ^ ( din_state |((~KEY_PIN) & 240));  // key changed ? ~ da Signal gegen GND und interner Pull-Up-Widerstand ein,
                              // DIN sind Bits 1,2,3, Tasten sind Bits 4,5,6,7, dort Rest rausmaskieren

dann der "normale" Peter Dannegger Code (4-fach Entprellung, hier mit 
10ms Takt):

    ct0 = ~( ct0 & i );              // reset or count ct0, Signale CT0 und CT1 sind invertiert
    ct1 = ct0 ^ (ct1 & i);           // reset or count ct1
    i &= ct0 & ct1;                  // count until roll over ?
    key_state ^= i;                  // then toggle debounced state
    key_press |= key_state & i;      // 0->1: key press detect, "speichern"*/

Und zuletzt die Tasten-Ports wieder auf Ausgang schalten:

  KEY_DIR_RS |= ALL_KEYS;            // Portrichtung setzen auf Ausgang
  KEY_PORT_RS |= ~ALL_KEYS;          // PullUp's aus

Hoffe, das hilft weiter, Gruß!

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
//  i = key_state ^ ~KEY_PIN;           // key changed ? PD's Version
  i = key_state ^ ~((KEY_PINB & _Taster1) | (KEY_PINC & _Taster2)) // wäre jetzt mein Ansatz

Das müsste so funktionieren. An Stelle eines EingangsPorts setzte du dir 
das Byte aus zwei Ports zusammen. Vorassetzung ist natürlich, das deine 
Tasten an "aufeinanderfolgenden" Bist hängen - mit jeweisl einer Taste 
an Bit 0 von PORTB und PORTC ginge das nicht so einfach.
KEY_PIN_neu = ((PORTB |= _Taster1) | (PORTC |= _Taster2));
i = key_state ^ ~KEY_PIN_neu;

????

Damit komme ich nicht klar. Dazu finde ich auch keine Entsprechung im 
Originalcode, zumindest nicht in dem hier:
http://www.mikrocontroller.net/attachment/highlight/36986

Abgesehen davon hasse ich solche Kontruktionen mit Zuweiseungen 
innerhalb der rechten Seite eines Ausdrucks. Das ist eher was für den 
Obfuscated C Contest.

Oliver

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oliver schrieb:

> ????
>
> Damit komme ich nicht klar. Dazu finde ich auch keine Entsprechung im
> Originalcode, zumindest nicht in dem hier:
> http://www.mikrocontroller.net/attachment/highlight/36986

Ist doch simpel.
Das Einlesen des kompletten Tastenports geschieht im Originalcode hier
  i = key_state ^ ~KEY_PIN;    // key changed ?

Anstatt das Pin Register direkt auszulesen, kannst du das auch so machen
  tmp = KEY_PIN;
  i = key_state ^ ~tmp;
  ...

Noch hat sich nichts geändert.

Jetzt sagt aber kein Mensch, dass du tmp als ganzes von KEY_PIN befüllen 
musst. Du kannst das auch nach Lust und Laune aus mehreren Pin Registern 
zusammensetzen ... komplette Pins nehmen ... einzelne Bits ausmaskieren, 
was immer du willst. Hauptsache jeder Taster hat in tmp sein eigenes Bit
  tmp = ( PINB & 0x01 ) | ( PINC & 0x02 ) | ( PINC & 0x01 ) << 2;
  i = key_state ^ ~tmp;
  ...

Wenn man es hochgestochen ausdrücken will, dann baust du dir damit ein 
'virtuelles Pin Register' zusammen, in dem jedes Bit einem Taster 
entspricht.

>
> Abgesehen davon hasse ich solche Kontruktionen mit Zuweiseungen
> innerhalb der rechten Seite eines Ausdrucks.

Dann machs ganz einfach nicht :-)

Autor: M.B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zunächst erst mal vielen Dank für Eure Antworten.

Wie ich sehe, kann ich es so ähnlich machen, wie ich es vorgeschlagen 
hatte:
Mein Vorschlag war:
KEY_PIN_neu = ((PORTB |= _Taster1) | (PORTC |= _Taster2));
i = key_state ^ ~KEY_PIN_neu;


kbuchegg's Vorschlag war:
tmp = ( PINB & 0x01 ) | ( PINC & 0x02 ) | ( PINC & 0x01 ) << 2;
  i = key_state ^ ~tmp;

Aus
PORTB |= 0x01
 muss ich nur
PINB & 0x01
 machen?

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab das schon verstanden,

bis darauf, daß dieser Teil hier alternativ zu den Zeilen davor gedacht 
war:
//Ich könnte mir auch einen Zwischenschritt über eine Variable vorstellen:

KEY_PIN_neu = ((PORTB |= _Taster1) | (PORTC |= _Taster2));
i = key_state ^ ~KEY_PIN_neu;

Beides nacheinander, so wie es oben wörtlich steht, macht es eben keinen 
Sinn.

>> Abgesehen davon hasse ich solche Kontruktionen mit Zuweiseungen
>> innerhalb der rechten Seite eines Ausdrucks.

>Dann machs ganz einfach nicht :-)

Tue ich auch nicht :-)

Oliver

Autor: ziegel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo nochmal,

das mit den nicht "aufeinanderfolgenden" Bits lässt sich leicht durch 
Bit-Schieben (>>) lösen.

Bei mir habe ich das Zusammenführen über eine Zwischenvariable din_state 
gelöst, da ich noch eine Notaus-Funktion brauche, die direkt reagiert.

Ihr müsst darauf achten, alle nicht relevanten Bits rauszumaskieren (die 
werden ja sonst wie gedrückte Tasten interpretiert), also definierte 
Zustände zu schaffen. Und genau aufpassen, welche Bits/Bytes wann 
negiert (~) sein wollen.

Das Konstrukt KEY_PIN_neu = ... funktioniert so daher nicht.

hier noch meine Defines zu obigem Code:
//D-IN Ports
  #define  DIN_PORT_C   PORTC
  #define  DIN_DIR_C    DDRC
  #define  DIN_PIN_C    PINC
  #define D_IN_0      (1 << PC3)
  #define D_IN_1      (1 << PC2)
  #define D_IN_2      (1 << PC1)  // NOTAUS

// KEY-Ports
  #define KEY_PIN   PIND
  #define KEY1      (1 << PD4)
  #define KEY2      (1 << PD5)
  #define KEY7      (1 << PD6)
  #define KEY8      (1 << PD7)

  #define KEY_PORT_RS   PORTD
  #define KEY_DIR_RS    DDRD
  #define KEY_PIN_RS    (1 << PD3)  // LCD_RS_PD3

  #define ALL_KEYS      (KEY1 | KEY2 | KEY7 | KEY8)


Den KEY_..._RS setze ich, da wie geschrieben die Tasten mit der 
LCD-Anzeige gemultiplext sind. Ich habe eigentlich noch eine 
Repeat-Funktion für einzelne Taster eingebaut, die ich hier im Code 
weggelassen habe.

Gruß!

Autor: M.B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

ich hab es jetzt gerade mal ausprobiert!

Mit folgender Version von kbuchegg funktioniert es:
tmp = ( PINB & 0x01 ) | ( PINC & 0x02 ) | ( PINC & 0x01 ) << 2;
  i = key_state ^ ~tmp;

Ich habe aber es folgendermaßen abgewandelt: Ist das Gleiche nur ohne 
Zwischenschritt tmp
i = key_state ^~((KEY_PINB & _Taster1) | (KEY_PINC & _Taster2));

>> Oliver wrote:
>> Abgesehen davon hasse ich solche Kontruktionen mit Zuweisungen
>> innerhalb der rechten Seite eines Ausdrucks.

Du musst es ja nicht übernehmen. Es hat halt jeder seinen eigenen 
Programmierstil. ich arbeite gerne mit "sprechenden Variablen" In diesem 
Fall muss man aber wissen was man tut: nicht das die beiden Taster auf 
dem gleichen Bit liegen.

Viele Grüße und Danke nochmal

Autor: M.B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ach noch was:

Falls diese Schreibweise Nebenwirkungen hat, die in meinem Fall nicht 
bzw noch nicht aufgetreten sind, bitte kommentieren und posten!

Autor: Ahnungslos_0815 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  M.B. (Gast)

>ich beutze zur Entprellung meiner taster den genialen Code von Peter
>Dannegger.

Sorry mal, bin hier noch relativ neu, wo finde ich den Code?

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Falls diese Schreibweise Nebenwirkungen hat, die in meinem Fall nicht
>bzw noch nicht aufgetreten sind, bitte kommentieren und posten!

KEY_PIN_neu = ((PORTB |= _Taster1) | (PORTC |= _Taster2));

Nun ja, du schaltest mit dieser Zeile auch die Pull-Ups der 
Tastereingänge ein. Das ist vermutlich sinnvoll, machst du das bewusst?

Oliver

Autor: M.B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Ahnungslos_0815 (Gast)

Schau mal hier:
[[Beitrag "Universelle Tastenabfrage"]]

@ Oliver

Sollte natürlich PINB und PINC heißen und nicht PORT

Sorry, hatte mich vertippselt

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
M.B. schrieb:
>
/* C-Code für ATmega 88 */
> //#define KEY_PIN    PINB // Version PD
> #define KEY_PINB    PINB
> #define KEY_PINC    PINC
> 
> #define _Taster1    0x01    //PB0
> #define _Taster2    0x02    //PC1
>   i = key_state ^ ~((KEY_PINB & _Taster1) | (KEY_PINC & _Taster2)) //
> 

Das ist vollkommen korrekt so.


>
> KEY_PIN_neu = ((PORTB |= _Taster1) | (PORTC |= _Taster2));
> 

Das ist Bullshit (auch mit PINB,PINC) und funktioniert daher nicht.


Peter

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ziegel schrieb:
> Hier noch ne kleine Notaus-Abfrage, die direkt ohne Entprellung aus der
> ISR heraus die Maschine abstellt:


Du bist sicher, daß der Notaus auch darauf reagieren muß, wenn jemand 
elektrostatisch aufgeladen dem Taster näher kommt oder bei sonstigen 
Störungen?

Du bist sicher, daß ein Notaus 30ms später wirklich eine Rolle spielt?


Peter

Autor: ziegel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

@ Peter, das kommt natürlich auf die Anwendung an. Es handelt sich hier 
um einen schnell laufenden Antrieb, der µC realisiert über eine Rampe 
und Frequenzumrichter das langsame anlaufen und abbremsen. Notaus ist 
ein Öffner-Stromkreis gegen GND, der durch verschiedene Bedingungen 
unterbrochen wird. Prellen und statische Ladung sind hier also 
uninteressant. Es ist außerdem völlig egal, ob der Notaus zu oft 
Auftritt, wichtig ist, daß der Antrieb schellstmöglich gebremst wird, um 
Schäden zu vermeiden. Außerdem, um die Entprell-Diskussion anzuheizen, 
ich habe immerhin die Info, daß der Zustand aufgetreten ist, und das zu 
einem diskreten Zeitpunkt.
Mir ging es hier aber primär ums Prinzip, vor der "Entprellung" noch 
eine zusätzliche Abfrage zu realisieren. Sonst brauchts auch keine 
Zwischenvariable.

Und Vielen Dank für die hervorragende Entprell-Routine! Gruß!

Autor: East (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ist zwar ein  bischen her, aber habe ein Problem das diese Routine auf 
Unterschiedlichen Ports nicht funzt. Habe soweit auch verstanden, wie 
das mit dem Maskieren der unterschiedlichen Ports funzt. Problem ist 
noch das in getkeypress() nur die variable des PINs (1 oder 2) an 
Keypress übergeben wird. Wenn jetzt aber gleiche >PINs aus 
unterschiedlichen Ports abgefragt werden sollen ( PINC1 oder PINB1 ), 
wie wird das dann in der getkeypress gemacht. Muss man dann nicht zwei 
variblen übergeben?

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
East schrieb:
> Wenn jetzt aber gleiche >PINs aus
> unterschiedlichen Ports abgefragt werden sollen

Dann schiebe den einen Wert auf freie Bits oder nimm 16Bit Variablen:
uint16_t i = PINB | (PINC<<8);

Autor: East (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Könntest Du vielleicht mal einen Blick drauf werfen. Habe es zwar zum 
laufen gebracht. Aber das Programm macht faxen. Heisst wenn ich mit der 
Hand ohne Berührung über den MC fahre, löst das immerwieder einen 
Eingang aus.

Autor: East (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Habe es etwas anders gelöst. Habe zwei Variblen für die Routine.

Vielen Dank schonmal im Voraus.

Dennis

Autor: East (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nach erfolgreicher Fehlersuche, habe ich vielleicht noch eine Frage.

Wie sieht nach der beschaltung der unterschiedlichen Ports, die Übergabe 
in getkeypress(x) aus?

Wird einfach nur wie zuvor, der Wert des Pins übergeben? Oder reicht 
einfach nur Name der Deklaration (_taster1) aus.?

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.