Folientastatur permanente ausgabe

Gast #4623730
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
Gast #4623735
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.
Gast #4623750
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?
Gast #4623781
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.
Gast #4623783
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
  }
Gast #4623799
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?
Gast #4623817
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.
Gast #4624804
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?
Gast #4626310
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 ");

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren