Hallo zusammen, ich möchte mir ein paar Port PINs sparen und 9 Schalter mit einer 3x3 Matrix abfragen. Ich habe hier im Forum und im Web auch einige Beispiele gefunden und die Matrix entsprechend zusammengelötet. 1N4148 Dioden sind in Reihe zu den Schaltern gelötet, keine weiteren Widerstände. Wenn ich die Matrix ohne AVR (in diesem Fall ein Mega 8) mit LEDs teste, sieht alles richtig aus. Lasse ich den AVR die Matrix auslesen kommt nur Blödsinn bei rum. Wie das Programm arbeitet: Die 3 Eingänge haben PullUps aktiviert. Die Ausgänge sind anfangs alle 1. Jetzt wird ein ein Ausgang auf 0 gesetzt. Alle Eingänge, die über Schalter mit dem Ausgang verbunden sind, sollen in der Theorie jetzt auf 0 bzw. GND gezogen werden. In der Praxis bzw. als Ergebnis im Code siehts leider anders aus. Wenn ich parallel zu den Ein- und Ausgängen LEDs über ULN2803 anschließe, leuchten diese auch wieder richtig. Das Ergebnis mit angeschlossenen LEDs sieht auch wieder anders aus als ohne. In beiden Fällen aber falsch. Was kann ich nochmal überprüfen um den Fehler zu finden? Gruß Joachim
Joachim J schrieb: > Alle Eingänge, die über Schalter mit dem Ausgang verbunden sind, sollen > in der Theorie jetzt auf 0 bzw. GND gezogen werden. In der Praxis bzw. > als Ergebnis im Code siehts leider anders aus. Dann ist entweder an der Theorie praktisch etwas falsch oder Schaltplan/Programm setzen das gewünschte theoretische Verhalten nicht richtig in die Praxis um. Kurz: Zeige deinen Schaltplan und dein Programm
Deinem Wunsch komme ich sofort nach :-) Initialisierung der Schalter:
1 | //Ausgänge für DIP Schalter Matrix
|
2 | DDRD |=(1<<DDD2)|(1<<DDD3)|(1<<DDD4); |
3 | //Eingänge für DIP Schalter Matrix
|
4 | DDRD &=~((1<<DDD5)|(1<<DDD6)|(1<<DDD7)); |
5 | //Pull-Ups an Port D5 bis D7 aktivieren
|
6 | PORTD |= (1<<PD5)|(1<<PD6)|(1<<PD7); |
7 | //Ausgänge auf 1 setzen, Abfrage der Schalter ist invertiert
|
8 | PORTD |= (1<<PD2)|(1<<PD3)|(1<<PD4); |
Abfrage der Schalter:
1 | PORTD |= ((1<<PD2)|(1<<PD3)|(1<<PD4));//Ausgänge auf High |
2 | |
3 | //-------- ersten 3 bits --------
|
4 | PORTD &= ~(1<<PD2); //Ausgang PD2, für die ersten 3 bits auf low |
5 | |
6 | Pin_status = bit_is_set(PIND, 5) ? 0 : 1; |
7 | temp_DMXadress|=(Pin_status<<0); |
8 | |
9 | Pin_status = bit_is_set(PIND, 6) ? 0 : 1; |
10 | temp_DMXadress|=(Pin_status<<1); |
11 | |
12 | Pin_status = bit_is_set(PIND, 7) ? 0 : 1; |
13 | temp_DMXadress|=(Pin_status<<2); |
14 | |
15 | //-------- zweiten 3 bits --------
|
16 | PORTD |= ((1<<PD2)|(1<<PD3)|(1<<PD4));//Ausgänge auf High |
17 | PORTD&=~(1<<PD3); |
18 | Pin_status = bit_is_set(PIND, 5) ? 0 : 1; |
19 | temp_DMXadress|=(Pin_status<<3); |
20 | |
21 | Pin_status = bit_is_set(PIND, 6) ? 0 : 1; |
22 | temp_DMXadress|=(Pin_status<<4); |
23 | |
24 | Pin_status = bit_is_set(PIND, 7) ? 0 : 1; |
25 | temp_DMXadress|=(Pin_status<<5); |
26 | |
27 | |
28 | //-------- dritten 3 bits, zu Testzwecken 9. weggelassen --------
|
29 | PORTD |= ((1<<PD2)|(1<<PD3)|(1<<PD4));//Ausgänge auf High |
30 | PORTD&=~(1<<PD4); |
31 | |
32 | Pin_status = bit_is_set(PIND, 5) ? 0 : 1; |
33 | temp_DMXadress|=(Pin_status<<6); |
34 | |
35 | Pin_status = bit_is_set(PIND, 6) ? 0 : 1; |
36 | temp_DMXadress|=(Pin_status<<7); |
Gruß Joachim
Zum Thema prellen: Die Schalter "lege ich einmal um" und dann wars das. Prellen kann man hier vernachlässigen.
Joachim J schrieb: >
1 | > //Ausgänge auf 1 setzen, Abfrage der Schalter ist invertiert |
2 | > PORTD |= (1<<PD2)|(1<<PD3)|(1<<PD4); |
3 | >
|
Kommentar erzeugt Endlosschleife bei mir. Code ist nicht komplett.
Hallo, was genau meinst du mit "Kommentar erzeugt Endlosschleife bei mir." ? Der Code der Abfrage liegt in read_dips(), der Rest in der Main. Ich habe mir die Ergebnisse dann per RS232 ausgegeben. Gruß Joachim
Joachim J schrieb: > Pin_status = bit_is_set(PIND, 5) ? 0 : 1; > temp_DMXadress|=(Pin_status<<0); > > Pin_status = bit_is_set(PIND, 6) ? 0 : 1; > temp_DMXadress|=(Pin_status<<1); > > Pin_status = bit_is_set(PIND, 7) ? 0 : 1; > temp_DMXadress|=(Pin_status<<2); Das ist ja von hinten durch die Brust ins Auge. Wie wärs einfach mit:
1 | temp_DMXadress |= 0x07 & (~PIND >> 5); |
Und davor natürlich noch mindestens ein NOP, da die Eingänge im vorherigen Zyklus gelatcht werden.
:
Bearbeitet durch User
Hallo Peter, mit einer großzügingen Menge an _delay_ms gehts. :-) Danke! Die Abfrage geschieht nur einmal und ist alles andere als zeitkritisch. Kannst du mir vielleicht auch noch etwas näher erklären warum es da "klemmt" oder mir sagen wo ich das nachlesen kann? So tief bin ich noch nicht in AVR und C und das "latchen" ist mir als Fehler noch nicht untergekommen. Gruß Joachim
Hallo Joachim, das "latchen" steht im Datenblatt deines µC, nicht direkt zu finden, aber als Anmerkung ist es vorhanden. Und bedeutet, etwas salopp geschrieben: eine Portänderung, z.B. PullUP "on", dauert länger, als bis zum Ende des Befehls.
:
Bearbeitet durch User
9 Taster bekommt man auch an einem einzigen Analogeingang sauber ausgewertet. Nachteil: man braucht auch 9 Widerstände.
Hi Nun, es ist nicht selten der Fall, das die negative Logik durch die 0-Abfrage bedingt durch den Pullup etwas Verwirrung bringt.Aus diesem Grund lege ich Eingänge immer in logischer Lage zum Schalter in Variablen ab. treu nach dem EVA-Prinzip. Einlesen - Verarbeiten - Ausgeben. Da ich C nicht beherrsche, versuche ich es einfach mal zu erläutern. Du selektierst Reihe 1 durch Ausgabe einer 0. Anschließend liest du deie Eingänge ein, drehst die Bits, maskierst die relevanten Bits aus und legst das Ergebnis in Variable Input_1 ab. In Asembler in etwas so:
1 | Read_IO: |
2 | In r16, PortD |
3 | ORI r16, 0b00011100 ; Alle Reihen auf "1" |
4 | ANDI r16, 0b11111011 ; selektiere Reihe 1 |
5 | OUT PortD, r16 |
6 | In r16, PortD ; Eingänge lesen |
7 | COM r16 |
8 | ANDI r16, 0b11100000 ; Eingänge ausmaskieren |
9 | ROR r16 |
10 | SWAP r16 ; Eingänge auf bits 0 bis 2 schieben |
11 | STS Input_1, r16 ; und in Variable Input_1 ablegen |
12 | In r16, PortD |
13 | ORI r16, 0b00011100 ; Alle Reihen auf "1" |
14 | ANDI r16, 0b11110111 ; selektiere Reihe 2 |
15 | OUT PortD, r16 |
16 | In r16, PortD ; Eingänge lesen |
17 | COM r16 |
18 | ANDI r16, 0b11100000 ; Eingänge ausmaskieren |
19 | ROR r16 |
20 | SWAP r16 ; Eingänge auf bits 0 bis 2 schieben |
21 | STS Input_2, r16 ; und in Variable Input_2 ablegen |
22 | In r16, PortD |
23 | ORI r16, 0b00011100 ; Alle Reihen auf "1" |
24 | ANDI r16, 0b11101111 ; selektiere Reihe 3 |
25 | OUT PortD, r16 |
26 | In r16, PortD ; Eingänge lesen |
27 | COM r16 |
28 | ANDI r16, 0b11100000 ; Eingänge ausmaskieren |
29 | ROR r16 |
30 | SWAP r16 ; Eingänge auf bits 0 bis 2 schieben |
31 | STS Input_3, r16 ; und in Variable Input_3 ablegen |
32 | RET |
Sieht zwar gewaltig aus, ist es aber nicht. Ich habe nun das tganze Programm, um den Inhalt von Input 1-3 auszuwerten und genau nach der Logik: Ist ein Taster gedrückt, dann ist das Bit "1". Bei einer Taktfrequenz von 1 MHz braucht diese Routine rd. 30 µs. Noch eine Bemerkung zur Entprellung. Da in den Variablen Input_1 bis Input_3 die aktuellen Eingänge liegen, kannst du mit einem EOR (Exclusiv-Oder) und einem alten Wert feststellen, ob eine Änderung eingetreten ist, oder ob die Eingänge eine Zeitlang stabil waren
1 | Debounce_IO: |
2 | LDS r16, Input_1 ; Akt. Eingänge |
3 | LDS r17, Old_In_1 ; Stand beim letzten Durchlauf |
4 | EOR r17, r16 ; Ergebnis in r17 |
5 | BREQ Chk_Time ; ist gleich, Entprellzeit prüfen, evtl.reduzieren |
6 | STS Old_In_1, r16 ; aktuelle Eingänge ablegen |
7 | LDS r17, 50 ; Entprellzeit neu setzen |
8 | STS Deb_Time_1, r17 ; und merken |
9 | RJMP Row_2 |
10 | LDS r17, Deb_Time_1 ; Restzeit laden |
11 | CPI r17, 0 ; schon abgelaufen? |
12 | BREQ Row_2 |
13 | DEC r17 ; Zeit reduzieren |
14 | STS Deb_Time_1, r17 ; und merken |
15 | BRNE BREQ ; Zeit nicht abgelaufen, dann weiter |
16 | STS Akt_In_1, r16 ; r16 hat noch den gültigen Wert der Eingänge |
17 | Row_2: ; nächste Reihe prüfen und entprellen |
18 | .... |
19 | Row_3: |
20 | .... |
21 | RET |
Auch hierist genau berechenbar, wie lange die Entprellroutine bei einem Durchlauf braucht. Etwa 60 µs. Die Bits in akt_In_x sind nun entprellte gültige Signale. Sicherlich wird es dir keine große Mühen machen, diese Programmteile in C nachzubauen. Gruß oldmax
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.