ich habe in einem Projekt die Aufgabe 40 Taster und 8 Schieberegler mit Hilfe eines µCs einzulesen.
Die eingelesenen Werte sollen dann via RS232 weitergeschickt werden.
Es sollen dabei auch Tasten erkannt werden, die zur selben Zeit gedrückt wurden.
Jetzt gibt es natürlich mehrere Möglichkeiten dieses Problem anzugehen. Mich interessiert natürlich die optimalste Lösung.
Also interrupt gesteuertes einlesen oder ständiges Multiplexen…hardware oder Softwareentprellung…oder ganz was anderes???
Externe Bausteine (bsp. ADC…) oder alles mit einem µC??
Für zahlreiche Tipps und Vorschläge wäre ich Euch sehr dankbar. Bin noch nicht so fit, was das µC - Programmieren an geht. Habe allerdings zwei C167 Module und würde diese auch gerne einsetzen. Es interessieren mich hier aber eher allgemeine Lösungsansätze.
Ich habe für zahlreiche solche Probleme immer (mindestens) einen timergesteuerten Hintergrundtask eingerichtet mit einem Zeitraster in der Grössenordnung 1 bis 2 msec. In dem führe ich alles aus, was regelmässig geschehen muss, u.a. eben Multiplexing der Tastatur und ev. einer LED-Anzeige. Bei 2 msec kann man z.B. LED-Anzeigen mit 8 Anodentreibern multiplexen, ohne dass die Anzeige flimmert, es wird also pro Interrupt immer nur um eine Leitung weitergeschaltet und die zugehörigen Daten ausgegeben. Mit dem gleichen Zeitraster kann man eine Tastatur-Matrix abfragen, ebenso immer eine Spalte pro Zeitinterrupt.
Entprellen wird gleich miterledigt: die Daten für eine Spalte werden in ein Schieberegister geschoben, eine bestimmte Taste ist 1, wenn die letzten 3 Werte 1 waren, und 0, wenn die 3 letzten Werte 0 waren, die Zahl 3 im Beispiel bestimmt, wie die Tastatur reagiert.
Bei einem Übergang von Aus auf Ein einer Taste wird ein Zeichen in einen FIFO-Speicher geschoben, aus dem übergeordnete Tasks ihre Eingabe entnehmen. Ob mehrere gleichzeitig gedrückte Tasten erkannt werden, hängt von der Matrix ab, dafür sind Entkoppelungsdioden notwendig.
In ähnlicher Weise verarbeite ich in diesem Zeitraster analoge Eingänge: bei jedem Durchgang wird ein Eingang eingelesen und in ein Schieberegister geschrieben, der aktuelle Wert ist dann der Durchschnitt der letzten n Durchgänge, wobei n die Reaktion und anderseits die Störungsunterdrückung bestimmt, das ist also alles leicht skalierbar.
Ist die 2msec-Routine wie beschrieben fertig, habe ich fast schon ein kleines Betriebssystem.
Reinhard
[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]
Reinhard hat ja schon einen Lösungsansatz geschrieben. Wie du die Tasten ansteuerst, hängt von der verwendeten Tastatur ab. Mehrere Tasten gleichzeitig ist bei einer Matrix nur möglich, wenn die Tastenmatrix auch entsprechende Dioden enthält.
Falls möglich, nehmen wird Tastaturen, wo alle 40 Tasten an einem gemeinsamen Ground hängen und an jeder Taste ein µController-Beinchen. Das reduziert die Hardware auf einen Pullup-Widerstand und den Softwareaufwand auf einfaches einlesen. Zudem ist es dann möglich, noch zu jeder Taste parallel eine LED als Rückmeldung zu betreiben (plus Vorwiderstand der LED und geänderter Auswertung).
Also interrupt gesteuertes einlesen oder ständiges
Multiplexen.
meist nur eine Frage des Stromverbrauchs. Bei Interrupt kann der µController zwischendurch schlafen => wenig Strom. Ist er jedoch eh wach, oder ist Strom nicht soooo wichtig, ist pollen oft das vernünftigere (gleichmäßigere, vorhersagbarere Prozessorauslastung) und einfachere.
Beim Pollen ist eine Zeit von 2ms sicherlich gut, es reicht aber auch alle 10ms zu pollen und dann als Softwareentprellung auf 3 Tastenzustände nacheinander gleiches Signal zu warten.
Überschlag: Auf einer Schreibmaschine schafft man max. 600 Tasten pro Minute = 10/Sekunde. Vergleich: Stoppe mal die minimale Zeit auf einer Stoppuhr, mindestens 100ms. Also reichen 30ms für Drücken, 30 für Loslassen aus. (Auch aus Erfahrung.) Tastenprellen sollte niemals so lange dauern (Erfahrung).
Vorgehensweise als Beispiel für 8 Tasten
// pollroutine für ein Byte. Bei z.B. 40 Bytes müssen die Byteoperationen auf ganzen Arrays angewandt werden!
unsigned char PollRoutine(unsigned char aktuelleTasten)
{
static unsigned char Tasten\_puffer[3];
static unsigned char cnt = 0;
static unsigned char TastenImage = 0;
// einfacher Ringpuffer für Tasten
Tasten\_puffer[cnt] = aktuelleTasten;
if(cnt == 2) cnt = 0;
else cnt++;
// eine Taste gilt als gedrückt (1), wenn sie bei allen Tasten\_puffer gedrückt (1) ist
TastenImage |= (Tasten\_puffer[0] & Tasten\_puffer[1] & Tasten\_puffer[2]);
// eine Taste gilt als losgelassen (0), wenn sie bei allen Tasten\_puffer losgeslassen (0) ist.
TastenImage &= (Tasten\_puffer[0] | Tasten\_puffer[1] | Tasten\_puffer[2]);
return TastenImage;
}
Die Funktion ändert TastenImage nur dann, wenn 3 mal nacheinander eine Taste auch wirklich einen neuen Zustand hat.
1. für 40 Tasten brauchst Du z.B. 5 Spalten als
Ausgänge und 8 Zeilen als Eingänge (also max. 2 Ports)
2. Ob Polling oder Interrupt, hängt von den Randbedingungen
und deinen Wünschen ab.
3. Interruptgesteuert ist auch leicht machbar, indem
Du z.B. alle Spalten auf Low legst und die 8 Zeilen
(mit PullUp-Widerständen auf Hihg) mit einem 8-fach-NAND
zusätzlich überwachst (z.B. 74Hc30).
Wenn dann eine beliebige Taste gedrückt wird, spricht
der NAND-Ausgang an -\> auf INT oder NMI legen.
Feines Feature dabei: Eine LED am NAND-Out zeigt Dir
auch noch optisch an, wenn eine Taste gedrückt wird.
4. Wenn Du Open-Kollektorausgänge (od. open-drain) als
Spaltentreiber benutzt, kannst Du auch auf die
Entkopplungsdioden verzichten.
5. Ein mechnischer Kontakt sollte in ca. 5ms sicher schalten.
Ein schlechter Kontakt aber allemal in 10ms.
Zum Entprellen reicht es also, im Abstand von ca. 10ms
2 mal abzufragen (3 mal schadet auch nicht).
Dann also Tasten nur akzeptieren, wenn diese Abfragen
immer mehrfach gleiches Ergebnis liefert.
6. Falls die Prozessorausgänge schwach sind (nur wenig
Treiben können) solltest Du einen Spaltentreiber
spendieren (dann eben am besten Open-Kollektor).
Dies gilt umso mehr, wenn die Leitungen etwas länger
sein sollen und Du dann recht niederohmige
PullUp-widerstände (z.B. 1 KOhm) brauchst, um die
Leistungskapazität schnell genug umzuladen.
7. Für längere Leitungen zur Tastatur
(mehr als ca 10...20cm) möglichst auch
Schutzbeschaltungen an Prozessoreingängen vorsehen.
Wenn Du Open-Kollektorausgänge (od. open-drain) als
Spaltentreiber benutzt, kannst Du auch auf die
Entkopplungsdioden verzichten.
Open Kollektor bzw. Abschaltbare Ausgänge… Es sind aber weiterhin Dioden zur Entkopplung bei Mehrfach-Tastendruck notwendig. Problem: Wenn Drei Tasten gleichzeitg gedrückt sind, kann eine Vierte u.U. fälschlicherweise erkannt werden. (Zum Verständnis einfach an einer 2x2 Matrix durchspielen)
Open Kollektor bzw. Abschaltbare Ausgänge… Es sind aber
weiterhin Dioden zur Entkopplung bei Mehrfach-Tastendruck
notwendig. Problem: Wenn Drei Tasten gleichzeitg gedrückt
sind, kann eine Vierte u.U. fälschlicherweise erkannt werden.
(Zum Verständnis einfach an einer 2x2 Matrix durchspielen)
Naja, bei 3-fach Tastendruck kann das dann passieren.
Ansonsten ist die Entkopplung ja auch primär wichtig,
damit es nicht zum Kurzschluß zwischen parallelen
Ausgängen kommt.
Ansonsten kommt es natürlich drauf an, ob Mehrfachtastendruck
ausgewertet werden soll, oder ob nur unterschieden
werden soll zwischen 1-Taste (=OK)und mehrere-Tasten (#OK).
Gruß Uwi