ATmega8 - PC billentyűzet kezelés

2013-02-02

 

Néha jól jöhet, ha nem kell külön billentyűzetet építsünk a mikrovezérlőnkhöz. Akkor is jó megoldásnak tűnik, ha sok billentyűre lenne szükségünk, mert egy PC billentyűzet ára egyszerűen verhetetlen. A billentyűzetekben általában egy maszkprogramozott i8051 vagy valami hasonló mikrovezérlő van, az gondoskodik a gombok figyeléséről, pergésmentesítéséről, autorepeat-jéről és tulajdonképpen szinkron half duplex soros vonalon a lenyomott gombok kódjának a PC felé való továbbításáról.

Itt látható a nem túl bonyolult kapcsolás. A billentyűzet órajel vezetékét az egyik külső megszakítás lábra (INT0 vagy INT1) kell kötni, az adat vezeték tetszőleges bemenő lábra köthető.

Egy régi alaplapból kiműtöttt PS2 aljzatot hanyatt vágtam, ráforrasztottam egy kis maradék NYÁK-ra, és motázs szallaggal (kétoldalt ragacsos habgumi) a deszkapanelemre ragasztottam. A billentyű már szintúgy régóta porosodott a szekrényem tetején, arra várt, hogy egyszer felhasználjam ehhez a kapcsoláshoz.

Kicsit jobban látható a csati. Ha valakinek éppen ilyet sikerülne szereznie (valószínűleg szabványos a kiosztásuk, de az is lehet, hogy a világon egyedül egyetlen kínai gyár állítja elő az összeset :), akkor a narancssárgás vezeték a +5V, a zöldes a föld, a fekete csíkos - sárga az órajel, és a sárga az adat.

Én kicsit bizalmatlan vagyok, nem utoló sorban magammal szemben is, ezért szétcsavaroztam a billentyűzetet, és nem is tévedtem, a benne lévő kis panelen fel volt iratozva a beforrasztott vezeték. Doksi ide vagy oda, szépen végigcsöngettem a vezetékeket.

 

Így néz ki a billentyűzet adása a PC, illetve most a mikrovezérlőnk felé. Ez egy szinkron soros adatátvitel, olyan mint azt az USART-nál láthattuk. A feladat, hogy elkapdossuk a biteket, szép sorban egymás után tegyük, és így előálljon a küldött adat byte. A start, a parity meg a stop biteket egyszerűen eldobjuk. A program úgy működik, hogy az órajel lefutó élére van beállítva az INT0 megszakítás. A lefutó élre induló INT0 megszakítást kezelő függvény számlálja hanyadik bitnél tartunk, és 0..7 biteket szépen betárolja. A végén alapba teszi a változókat. Na most akkor lenne igazán szép az életünk, ha a billentyűzet ASCII kódokat küldene. Nem azt küld, hanem úgynevezett scan kódokat, meg minden egyebet, van olyan gomb, amire több byte hosszú kombinációt válaszol. Most nem akartam potosan minden betü, szám, vezérlőgomb összes lehetőségét lekezelni, megelégedtem annyival, hogy a leggyakoribb adalék kódokat elyomtam, és általában a kapcsolás szimplán a gomb scan kódját küldi el a soros vonalon. Akinek részletesebben kell lekezelnie a billentyűzetet, annak is jól használható ez a program, a gombokat nyomogatva a terminál képernyőjére kiírja a lenyomott gomb scan kódját. Az alábbi ábrákon láthatók az angol PC AT billentyűzet scan kódjai.

Követ ne vessetek rám, de nyugodtan vádoljatok elfogódottsággal, ha azt állítom, eléggé olvashatóra sikeredett a programom, ezért tovább nem akarom magyarázgatni. Általában a programjaim nem világelsőként születnek meg, de törekszem, hogy ne legyenek bennük felesleges dolgok, és legyenek jól követhetőek.



/*******************************************************************************
*   Author       -  Kiraly Tibor
*                   http://www.tkiraaly.hu
*   Date         -  2013.02.02.
*   Chip         -  Atmel ATmega8
*   Compiler     -  avr-gcc (WinAVR )
*
*   PC AT (PS2) billentyuzet kezelese.
*   A prg. a scan kodokat a soros portra irja ki.
*
********************************************************************************
*   AVR PB0 14 - LED - 470R - +5V
*
*   AVR INT0 4 - KBD CLOCK 5 
*   AVR PD3  5 - KBD DATA  1
*                KBD +VCC  4 - +5V
*                KBD GND   3 - GND
*
*******************************************************************************/

#define F_CPU          4000000                   // orajel 4MHz
#define BAUDRATE       9600
#define MYUBRR         F_CPU/ 16UL/ BAUDRATE - 1




#include "tkiraaly_atmega8.h"




#define LED                  0
#define LED_ENABLE           BS( DDRB, LED)
#define LED_BE               BC( PORTB, LED)
#define LED_KI               BS( PORTB, LED)




#define KBD_DATA             BTS( PIND, 3)       // billentyuzetrol bejovo adat bit

// MCUCR beallitasai
#define INT0_0               0                   // IT 0 szintnel
#define INT0_1               0B00000001          // IT 1 szintnel
#define INT0_LEFUTO          0B00000010          // IT 1->0 elre
#define INT0_FELFUTO         0B00000011          // IT 0->1 elre
#define INT0_ENABLE          GICR|= 0B01000000   // INT0 engedelyezese
                                                 
#define INT1_0               0                   // IT 0 szintnel
#define INT1_1               0B00000100          // IT 1 szintnel
#define INT1_LEFUTO          0B00001000          // IT 1->0 elre
#define INT1_FELFUTO         0B00001100          // IT 0->1 elre
#define INT1_ENABLE          GICR|= 0B10000000   // INT1 engedelyezese




UC volatile kbd= 0;                              // vett billentyu scan kodja
UC kbd_prev= 0;                                  // elozo billentyu scan kodja
UC kbd_input= 0;                                 // bitek -> kod
UC kbd_count= 11;                                // bit szamlalo




void usart_putc( UC);                            // USART egy karakter kuldese
void usart_hex( UC);                             // USART 1 byte kuldese hexadecimalisan
UC num2hexc( UC);                                // szam hexadecimalis szamjeggye alakitasa
void kbd_decoder( void);




ISR( INT0_vect)                                  // INT0 megszakitas kezelese
{
   if( kbd_count < 11 && kbd_count > 2)          // csak 3..10 bit az adat, tobbi eldobasa
   {
      kbd_input=( kbd_input >> 1);
      if( KBD_DATA) kbd_input|= 0B10000000;      // '1' eltarolasa
   }
   if( --kbd_count == 0)                         // osszes bit bejott
   {
      if( ( kbd_input != 0xE0) &&                // 0xE0 elnyomas
          ( kbd_input != 0xF0) &&                // 0xF0 es ismetles elnyomas
          ( kbd_prev  != 0xF0)) kbd= kbd_input; 
      kbd_prev= kbd_input; 
      kbd_count= 11;
   }
}




int main( void)
{
   UBRRL= MYUBRR;                                // USART inicializalasa
   UBRRH= ( MYUBRR)>> 8;
   UCSRC= SET_UCSRC+ ASYNCRON+ BIT_8+ PARITY_NO+ STOPBIT_1;
   UCSRB= TX_ENABLE;

   MCUCR= INT0_LEFUTO;                           // billentyuzet kezeleshez
   INT0_ENABLE;

   IT_ENABLE;
  
   LED_ENABLE;
   LED_BE;

   for(;;)
   {
      if( kbd)                                   // ha nyomtak le billentyut
      {
         usart_hex( kbd);
         kbd= 0;
         usart_putc( ' ');
      }
   }
}




void usart_putc( UC c)                           // USART egy karakter kuldese
{
    while( BTC( UCSRA, UDRE));                   // 1, ha kesz az adat fogadasara
    UDR= c;
}




void usart_hex( UC c)                            // USART 1 byte kuldese hexadecimalisan
{
   usart_putc( num2hexc(c >> 4));
   usart_putc( num2hexc(c));
}




UC num2hexc( UC c)                               // szam hexadecimalis szamjeggye alakitasa
{
   c&= 0x0F;
   if( c < 10) c+= '0';
   else        c+= 'A'- 10;
   return c;
}

Itt a vége, fuss el véle, legytek az én vendégeim, innen letölthetitek a hozzávalókat összecsomagolva.