Forum: Mikrocontroller und Digitale Elektronik Folientastatur permanente ausgabe


von Franz (Gast)


Lesenswert?

Hallo,
ich möchte mit einer Folinetastatur (3x4) (1-0,*,#) einen Code eingeben. 
Dazu möchte ich zunächst die angegebene Zahl erkennen und ausgeben 
lassen.
1
// Keypad
2
  // column
3
  DDRC |= ((1 << DDC0) | (1 << DDC1) | (1 << DDC2)); // output
4
  PORTC &= ~((1 << DDC0) | (1 << DDC1) | (1 << DDC2)); // low
5
  //row
6
  DDRC &= ~((1 << DDC3) | (1 << DDC4) | (1 << DDC5)); // input
7
  DDRC &= ~(1 << DDD4); // input
8
9
  while (1){
10
  PORTC &= ~((1 << DDC0) | (1 << DDC1) | (1 << DDC2)); // all low
11
  PORTC |= (1 << DDC0); // column 1 high
12
    if ( PINC & (1<<PINC3) ) usart_transmit_string("1 ");
13
    if ( PINC & (1<<PINC4) ) usart_transmit_string("4 ");
14
    if ( PINC & (1<<PINC5) ) usart_transmit_string("7 ");
15
    if ( PIND & (1<<PIND4) ) usart_transmit_string("* ");
16
  PORTC &= ~(1 << DDC0); // column 1 low
17
  PORTC |= (1 << DDC1); // column 2 high
18
    if ( PINC & (1<<PINC3) ) usart_transmit_string("2 ");
19
    if ( PINC & (1<<PINC4) ) usart_transmit_string("5 ");
20
    if ( PINC & (1<<PINC5) ) usart_transmit_string("8 ");
21
    if ( PIND & (1<<PIND4) ) usart_transmit_string("0 ");
22
  PORTC &= ~(1 << DDC1); // column 2 low
23
  PORTC |= (1 << DDC2); // column 3 high
24
    if ( PINC & (1<<PINC3) ) usart_transmit_string("3 ");
25
    if ( PINC & (1<<PINC4) ) usart_transmit_string("6 ");
26
    if ( PINC & (1<<PINC5) ) usart_transmit_string("9 ");
27
    if ( PIND & (1<<PIND4) ) usart_transmit_string("# ");
28
  }

Doch leider kommt permanent eine Ausgabe, obwohl ich gar nichts drücke. 
hauptsächlich kommt die #-Taste. Aber auch 1, 2, 3, 0, * kommen sehr 
häufig vor (alle anderen Zahlen tauchen auch ab und zu auf).

Ich habe die Tastatur durchgemessen, ob vielleicht eine taste dauerhaft 
gedrückt ist, konnte aber niergendwo eine durchkontaktierung messen.

Kann das auch an der Software liegen?

Franz

von Peter II (Gast)


Lesenswert?

Franz schrieb:
> column 3 high

wo ist das column 3 low?

von Tobias (Gast)


Lesenswert?

Das sieht mir sehr nach offenen Eingängen aus. Sorgst du dafür, daß die 
Eingänge einen definierten Pegel sehen? Zum Beispiel mit Pullup's?
Wenn nicht, floaten die Eingänge und du bekommst ein Zufallsmuster.

von Franz (Gast)


Lesenswert?

Peter II schrieb:
> wo ist das column 3 low?

PORTC &= ~((1 << DDC0) | (1 << DDC1) | (1 << DDC2)); // all low

hier werden wieder alle auf low gesetzt. Aber wenn ich es hinter dem 
Block machen würde, wäre es bestimmt übersichtlicher.

Tobias schrieb:
> Sorgst du dafür, daß die
> Eingänge einen definierten Pegel sehen? Zum Beispiel mit Pullup's?

Ich habe die Ausgänge/Eingänge der Tastatur direkt am Mikrocontroller 
gesetzt (Atmega328p). Dieser hat mein ich intern pullups.

Anders müsste ich die Signale von den Reihen (DC3, DC4, DC5, DD4) auf 
einen Transistor legen, welcher dann durchschaltet und die 
Versorgungsspannung durchlässt oder?

von Flip B. (frickelfreak)


Lesenswert?

PORTC |= ((1 << DDC3) | (1 << DDC4) | (1 << DDC5)); // Pullup an

dann alle colums low schalten und auf low prfen. das ist dann dein part

von Stefan F. (Gast)


Lesenswert?

> DDRC &= ~(1 << DDD4); // input

Da wolltest du sicher DDRD schreiben.

Dein Programm erfordert Pull-Down Widerstände an allen Eingängen. Sind 
die vorhanden?

> Dieser hat mein ich intern pullups.

Nur, wenn du sie auch aktivierst. Hast du aber nicht. Abgesehen davon 
würde die Pull-Ups alle Eingänge permanent auf High ziehen. Dann sind 
alle deine if-Bedingungen immer wahr.

von Franz (Gast)


Lesenswert?

Habe jetzt den Code noch einmal ein bisschen umprogrammiert.
Ich habe die internen pullups eingeschaltet (das hatte ich vorher nicht 
gemacht) und ich warte, bis der ausgeschaltete pin für die Reihe 
wirklich auf low ist.
Jetzt ist es aber so, dass ich alle Zahlen nach der Abfrage rausbekomme. 
Also output:
1 4 7 * 2 5 8 0 3 6 9 # 1 4 7...
1
// column
2
  DDRC |= ((1 << DDC0) | (1 << DDC1) | (1 << DDC2)); // output
3
  PORTC &= ~((1 << DDC0) | (1 << DDC1) | (1 << DDC2)); // low
4
  while (( PINC & (1<<DDC0) ) &&
5
      ( PINC & (1<<DDC1) ) &&
6
      ( PINC & (1<<DDC2) )) {}
7
8
  //row
9
  DDRC &= ~((1 << DDC3) | (1 << DDC4) | (1 << DDC5)); // input
10
  DDRD &= ~(1 << DDD4); // input
11
  PORTC |= ((1 << DDC3) | (1 << DDC4) | (1 << DDC5)); // Pullup an
12
  PORTD |= (1 << DDD4); // Pullup an
13
14
  while (1){
15
  while (( PINC & (1<<DDC0) ) &&
16
      ( PINC & (1<<DDC1) ) &&
17
      ( PINC & (1<<DDC2) )) {}
18
  PORTC |= (1 << DDC0); // column 1 high
19
    if ( PINC & (1<<PINC3) ) usart_transmit_string("1 ");
20
    if ( PINC & (1<<PINC4) ) usart_transmit_string("4 ");
21
    if ( PINC & (1<<PINC5) ) usart_transmit_string("7 ");
22
    if ( PIND & (1<<PIND4) ) usart_transmit_string("* ");
23
  PORTC &= ~(1 << DDC0); // column 1 low
24
  while ( PINC & (1<<DDC0) )  {}
25
  PORTC |= (1 << DDC1); // column 2 high
26
    if ( PINC & (1<<PINC3) ) usart_transmit_string("2 ");
27
    if ( PINC & (1<<PINC4) ) usart_transmit_string("5 ");
28
    if ( PINC & (1<<PINC5) ) usart_transmit_string("8 ");
29
    if ( PIND & (1<<PIND4) ) usart_transmit_string("0 ");
30
  PORTC &= ~(1 << DDC1); // column 2 low
31
  while ( PINC & (1<<DDC1) )  {}
32
  PORTC |= (1 << DDC2); // column 3 high
33
    if ( PINC & (1<<PINC3) ) usart_transmit_string("3 ");
34
    if ( PINC & (1<<PINC4) ) usart_transmit_string("6 ");
35
    if ( PINC & (1<<PINC5) ) usart_transmit_string("9 ");
36
    if ( PIND & (1<<PIND4) ) usart_transmit_string("# ");
37
  PORTC &= ~(1 << DDC2); // column 3 low
38
  while ( PINC & (1<<DDC2) )  {}
39
  }

von Franz (Gast)


Lesenswert?

Mit dem Pullup kann ich ja einfach abfragen, ob der pin low ist.
 if ( !(PINC & (1<<PINC3)) ) usart_transmit_string("1 ");

Jetzt ist, dass wenn ich z.B. die 1 drücke, mir die 5 und 6 ausgegeben 
wird. Das wird wahrscheinlich daran liegen, dass ich spalten und zeilen 
falsch verbunden habe. Wenn ich aber z.B. die erste und letzte Leitung 
der Tastatur auf Durchkontaktierung messe und jede Taste drücke, bekomme 
ich nie eine Durchkontatkierung. Wie kann ich denn jetzt ermitteln, 
welche Leitungen für die Spalten und welche für die Zeilen sind?

von Stefan F. (Gast)


Lesenswert?

Die Begründung habe ich Dir schon geschrieben. Wenn du die Pull-Up 
Widerstände aktivierst, ziehen sie alle Eingänge permanent auf High, 
dann sind alle deine if Bedingungen immer wahr.

Dein Ruhepegel (nichts gedrückt) ist jetzt High. Also musst du das alles 
so umprogrammieren, dass einzelne Spalten (Ausgang) auf Low gesetzt 
werden und dann testen, welche Reihe (Eingang) durch den gedrückten 
Taster auf Low gezogen wird.

> ich warte, bis der ausgeschaltete pin für die Reihe wirklich auf low ist.

Das ist unnötig.

von Franz (Gast)


Lesenswert?

Guten Abend,
ich habe noch einmal eine Nachfrage, wegen einem komischen Verhalten.
Code:
1
  // Keypad
2
  // row
3
  DDRC |= ((1 << DDC0) | (1 << DDC1) | (1 << DDC2) | (1 << DDC3)); // output
4
  PORTC &= ~((1 << DDC0) | (1 << DDC1) | (1 << DDC2) | (1 << DDC3)); // low
5
6
  // column
7
  DDRC &= ~((1 << DDC4) | (1 << DDC5)); // input
8
  DDRD &= ~(1 << DDD4); // input
9
  PORTC |= ((1 << DDC4) | (1 << DDC5)); // Pullup an
10
  PORTD |= (1 << DDD4); // Pullup an
11
12
13
  sei(); // Global Interrupts activate
14
  PORTC |= ((1 << DDC0) | (1 << DDC1) | (1 << DDC2) | (1 << DDC3)); // all rows high
15
  //PORTC &= ~(1 << DDC1);
16
  while (1){
17
    PORTC &= ~(1 << DDC0); // row 1 low
18
      if ( !(PINC & (1<<PINC4)) ) usart_transmit_string("1 ");
19
      if ( !(PINC & (1<<PINC5)) ) usart_transmit_string("2 ");
20
      if ( !(PIND & (1<<PIND4)) ) usart_transmit_string("3 ");
21
    PORTC |= (1 << DDC0);
22
    PORTC &= ~(1 << DDC1);
23
      if ( !(PINC & (1<<PINC4)) ) usart_transmit_string("4 ");
24
      if ( !(PINC & (1<<PINC5)) ) usart_transmit_string("5 ");
25
      if ( !(PIND & (1<<PIND4)) ) usart_transmit_string("6 ");
26
    PORTC |= (1 << DDC1);
27
    PORTC &= ~(1 << DDC2);
28
      if ( !(PINC & (1<<PINC4)) ) usart_transmit_string("7 ");
29
      if ( !(PINC & (1<<PINC5)) ) usart_transmit_string("8 ");
30
      if ( !(PIND & (1<<PIND4)) ) usart_transmit_string("9 ");
31
    PORTC |= (1 << DDC2);
32
    PORTC &= ~(1 << DDC3);
33
      if ( !(PINC & (1<<PINC4)) ) usart_transmit_string("* ");
34
      if ( !(PINC & (1<<PINC5)) ) usart_transmit_string("0 ");
35
      if ( !(PIND & (1<<PIND4)) ) usart_transmit_string("# ");
36
    PORTC |= (1 << DDC3);
37
}

Drücke ich jetzt z.B. auf die 2, wird mir die 2 herausgegeben (solange 
wie ich diese gedrückt halte). Allerdings passiert in der ersten Spalte 
nichts (1,4,7,*). Diese Tasten werden nicht erkannt. Zunächst habe ich 
gedacht, dass irgendetwas mit dem Pin PC4 nicht stimmt, da die ganze 
Spalte betroffen ist.
lasse ich allerdings nur einen Block in der while-schleife
1
    PORTC &= ~(1 << DDC0); // row 1 low
2
      if ( !(PINC & (1<<PINC4)) ) usart_transmit_string("1 ");
3
      if ( !(PINC & (1<<PINC5)) ) usart_transmit_string("2 ");
4
      if ( !(PIND & (1<<PIND4)) ) usart_transmit_string("3 ");

Wird mir in diesem Fall die 1 rausgegeben. Gleiches ist auch mit den 
anderen Blocks.

Wieso wird mir die erste Spalte nicht ausgegeben, wenn ich die ganze 
Tastatur abfrage, aber schon, wenn ich nur eine reihe abfrage?

von Franz (Gast)


Lesenswert?

Stefan U. schrieb:
>> ich warte, bis der ausgeschaltete pin für die Reihe wirklich auf low ist.
>
> Das ist unnötig.

Dem ist nicht so.

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

Franz schrieb:
> PORTC &= ~(1 << DDC0);

Auch wenn das vom Wert her egal ist, solltest Du statt DDC0 bitte PC0 
verwenden.

von Franz (Gast)


Lesenswert?

Christian H. schrieb:
> Auch wenn das vom Wert her egal ist, solltest Du statt DDC0 bitte PC0
> verwenden.

Bei allen? Was ist der unterschied? Also theoretisch?

von Karl M. (Gast)


Lesenswert?

Hallo,

Peter Dannegger (peda) hat das sehr schön programmiert und auch gleich 
eine Tasteerentprellung integiert.

von Stefan F. (Gast)


Lesenswert?

> Bei allen? Was ist der unterschied? Also theoretisch?

PC0 und DDC0 sind beides Makros mit dem Wert 2. PC steht für "Port C" 
und DDC steht für "Data Direction C".

Wenn ich auf einem Port etwas ausgebe, wirkt der Begriff "Data 
Direction" an dieser Stelle irritierend auf den Leser des Quelltextes.

>>> ich warte, bis der ausgeschaltete pin für die Reihe
>>> wirklich auf low ist.
>> Das ist unnötig.
> Dem ist nicht so.

Warum denkst du, dass es nötig ist?
Warum hast du das dann trotzdem aus deinem Quelltext entfernt?

> Wieso wird mir die erste Spalte nicht ausgegeben, wenn ich die
> ganze Tastatur abfrage, aber schon, wenn ich nur eine reihe abfrage?

Das liegt an der Synchronisation der Eingänge. Wenn du ein PIN Register 
abfragst, bekommst du nicht die jetzt gerade anliegenden Pegel, sondern 
was einen Takt zuvor angelegen hat.

Der Knackpunkt ist also nicht, dass der Ausgang verzögert auf Low geht, 
sondern dass das PIN Register den tatsächlichen Signalen immer einen 
Takt hinterher läuft. Irgendwo im Datenblatt ist das auch erklärt,.

Nachdem du einen Pin auf Low legst, musst du mindestens einen Takt 
warten. Am Einfachsten stellst du das sicher, indem du einen NOP Befehl 
einfügst.

Also vier mal so:
1
  PORTC &= ~(1 << DDC0); // row 1 low
2
  asm volatile ("nop");
3
      if ( !(PINC & (1<<PINC4)) ) usart_transmit_string("1 ");
4
      if ( !(PINC & (1<<PINC5)) ) usart_transmit_string("2 ");
5
      if ( !(PIND & (1<<PIND4)) ) usart_transmit_string("3 ");

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.