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
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.
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.
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