avr_tast.c
/*
Beispielprogramm zur Tastenentprellung und -dekodierung.
Beim æP AT90S8515 werden die Eingaenge von PortA (int. pullup) gegen 0V
geschaltet (aktiv-low). Beim 1. Tastendruck wird der normale Code 'A' - 'H'
erzeugt (bit0 -> bit7). Wird die Taste gedrueckt gehalten, wird der
betreffende repeat Code erzeugt, sofern dieser nicht mit ' ' deaktiviert
ist.
In 'main()' wird auf einen Tastendruck gewartet und eine an PortC geschaltete
LED gegen 0V aktiviert. Weitere Tastendruecke (oder repeat) togglen die LED.
Es wird jeweils nur eine Taste ausgewertet; diese kann aber gedrueckt bleiben,
ohne andere Tasten zu blockieren: n-key-rollover. Schalter und Taster koennen
daher gemischt verwendet werden. Der aktuelle, entprellte Zustand von PortA
findet sich in 'entprellte_tasten'.
Compiler: icca90
Alle Angaben ohne Gewaehr.
Michael Nowak, www.mino-elektronik.de
*/
#include <io8515.h>
#include <ina90.h>
#define MAX_BITS 8 // hier nur ein Port-Byte
#define TASTENWERT unsigned char // auch short oder long
#define T0_NACHLADEWERT -39 // fuer ca. 100 Hz bei 4 MHz
#define ENTPRELL_ZEIT 5 // 5 Zyklen -> 50ms entprellen
#define FIRST_REPEAT 50 // 0,5 Sek. Pause bei gedrueckter Taste
#define NEXT_REPEAT 10 // danach Wiederholung alle 0,1 Sek.
static char taste; // 0 oder Tastencode
static TASTENWERT entprellte_tasten; // zur externen Verwendung
flash char tast_tab[] = "ABCDEFGH"; // 1. Tastencode
flash char rep_tast_tab[] = "a c e g "; // repeatcode teilweise zulassen
char lese_taste()
{
char temp;
TIMSK &= 0xfd; // T0_overflow-interrupt kurz verbieten
temp = taste; // Tastencode lesen
taste=0; // und loeschen
TIMSK |= 0x02; // T0-int wieder freigeben
return(temp);
}
static void dekodiere_taste()
{
char n;
TASTENWERT temp, aenderung;
static TASTENWERT temp_tasten, letzte_aenderung;
static char rep_flag=0, entprell_ctr=0, rep_ctr=0;
temp = PINA; // PortA als aktiv-low Eingang
temp = ~temp; // alle Bits invertieren
if(rep_ctr) rep_ctr--; // repeat-counter dekrementieren
entprell_ctr++; // Entprell-counter inkrementieren
if(temp != temp_tasten) { // Aenderung der Bits ?
temp_tasten=temp; // ja, speichern
entprell_ctr=0; // und neu entprellen
return; // mehr nicht
}
if(entprell_ctr < ENTPRELL_ZEIT) return; // Entprellzeit abwarten
entprell_ctr=0; // und neu starten
// Tasten sind entprellt
// jetzt auf positive Aenderungen testen
aenderung = (temp_tasten ^ entprellte_tasten) & temp_tasten;
entprellte_tasten = temp_tasten; // und letzten Zustand merken
if(aenderung) { // falls neue Tasten aktiviert
letzte_aenderung = aenderung; // Aenderung merken
rep_ctr = FIRST_REPEAT; // und 1.Repeat aktivieren
rep_flag = 0;
}
else if(rep_ctr == 0 && rep_flag) { // keine neue Taste aber repeat aktiv
aenderung = entprellte_tasten & letzte_aenderung; // letzte Aenderung
rep_ctr = NEXT_REPEAT; // wiederholen, mit kurzer repeat-Zeit
}
// Auswertung der Tasten
temp = aenderung;
n=0;
do { // bit suchen
if(temp & 1) { // bit gefunden
if(temp == 1) { // und nur eine Taste
if(!rep_flag) { // kein repeat: normale Codes verwenden
n = tast_tab[n];
rep_flag = 1; // aber beim naechsten Mal repeat !
} else n = rep_tast_tab[n]; // repeat ist schon aktiv
if(n != ' ') taste = n; // repeat nur mit gueltigem Code
else rep_flag = 0; // kein repeat, wenn keine gueltige taste
}
return; // taste erkannt, dekodierung fertig
}
n++;
temp >>= 1;
} while(n < MAX_BITS);
return; // keine taste gefunden
}
void interrupt [TIMER0_OVF0_vect] timer0_int()
{
TIMSK &= 0xfd; // weitere T0_overflow-interrupt verbieten
_SEI(); // und Interrupts global zulassen
TCNT0 = T0_NACHLADEWERT;
dekodiere_taste();
TIMSK |= 0x02; // T0-int wieder freigeben
}
void main()
{
char temp;
TCNT0 = T0_NACHLADEWERT;
TCCR0 = 0x05; // timer0 mit /1024 Vorteiler
TIMSK |= 0x02; // timer0 overflow int
PORTA = 0xff; // PortA pullups einschalten
_SEI();
DDRC = 0xff; // alle LEDs zun„chst eingeschaltet
PORTC = 0; // aktiv-low
for(;;) {
while(!(temp = lese_taste())); // auf Tastendruck warten
switch(temp) {
case 'A':
case 'a':
DDRC ^= 1; // nur LED invertieren
break;
case 'B':
case 'b':
DDRC ^= 2;
break;
case 'C':
case 'c':
DDRC ^= 4;
break;
case 'D':
case 'd':
DDRC ^= 8;
break;
case 'E':
case 'e':
DDRC ^= 16;
break;
case 'F':
case 'f':
DDRC ^= 32;
break;
case 'G':
case 'g':
DDRC ^= 64;
break;
case 'H':
case 'h':
DDRC ^= 128;
break;
}
}
}