-         

Ergebnis 1 bis 10 von 10

Thema: Auslesen einer PS/2-Schnittstelle

  1. #1
    Neuer Benutzer Öfters hier
    Registriert seit
    24.11.2005
    Ort
    Bochum
    Alter
    35
    Beiträge
    5

    Auslesen einer PS/2-Schnittstelle

    Anzeige

    Hallo !

    Ich würde gerne eine ps/2-Maus auslesen, um daraus einen Odometer zu basteln. Ich brauche hierzu eine detallierte Dokumentation des Protokolls.
    Kann mir da jemand helfen ?

    Danke und Gruß,

    Thommy

  2. #2
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    01.03.2004
    Ort
    Bielefeld (JA, das gibt es!)
    Alter
    29
    Beiträge
    1.614
    schwer, sehr sehr schwer, selbst schonmal versucht, habs nich hinbekommen, versuch dein glück möglichst an einer maus, die nicht direkt ps/2 nur ausgibt sondern lieber quadratur-signale, die lassen sich tausend mal besser auslesen, das ps/2 protokoll findeste aber auch im netz, und es wurde im forum auch schon mehrmals diskutiert, also benutz einfach mal die forumsuche
    Ich will Microsoft wirklich nicht zerstören. Das wird nur ein gänzlich unbeabsichtigter Nebeneffekt sein.
    Linus Torvalds, Entwickler von Linux

  3. #3
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    30.10.2005
    Ort
    Mönchengladbach
    Alter
    47
    Beiträge
    114
    Hi,

    ist nicht schwer, ist eigentlich super simpel, wenn man mal verstanden hat, wie's läuft.

    Anbei mein Code für den WINAVR in C:

    Code:
    // ************************************************************************************************************************
    //
    // PS/2 Mouse Communication
    //
    // (c) 2005 Chris Hendricks
    //
    // ************************************************************************************************************************
    
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <avr/signal.h>
    #include <string.h>
    
    #define u8  unsigned char
    #define u16 unsigned int
    
    // ************************************************************************************************************************
    
    // 16 MHz Clock
    
    #define TIMER0_25US             TCNT0 = 206; TCCR0 = (1<<CS01)
    #define TIMER0_50US             TCNT0 = 156; TCCR0 = (1<<CS01)
    #define TIMER0_75US             TCNT0 = 106; TCCR0 = (1<<CS01)
    #define TIMER0_100US            TCNT0 = 56;  TCCR0 = (1<<CS01)
    #define TIMER0_500US            TCNT0 = 131; TCCR0 = (1<<CS01) | (1<<CS00)
    
    #define TIMER0_1MS              TCNT0 = 6;   TCCR0 = (1<<CS01) | (1<<CS00)
    #define TIMER0_5MS              TCNT0 = 178; TCCR0 = (1<<CS02) | (1<<CS00)
    #define TIMER0_10MS             TCNT0 = 100; TCCR0 = (1<<CS02) | (1<<CS00)
    
    #define TIMER0_RUNNING          (TCCR0)
    #define NOOP                    asm volatile (";")
    
    // ************************************************************************************************************************
    
    #define URXBUFSIZE 255                                              // Größe des UART Empfangspuffers
    #define UTXBUFSIZE 255                                              // Größe des UART Sendepuffers
    
    // ************************************************************************************************************************
    
    u8 urxbuf[URXBUFSIZE];                                              // UART Empfangspuffer
    u8 utxbuf[UTXBUFSIZE];                                              // UART Sendepuffer
    u8 urxl = 0;                                                        // Anzahl Zeichen im UART Empfangspuffer
    u8 utxl = 0;                                                        // Anzahl Zeichen im UART Sendepuffer
    
    volatile u8 timcntdwn;
    
    // ************************************************************************************************************************
    
    void uart_prstr (char * string)                                     // * UART-TX-PUFFER: STRING ABLEGEN *
    {
      memcpy (&utxbuf[utxl],string,strlen(string));                     // String an den Puffer anhängen
      utxl += strlen(string);                                           // Länge des Pufferinhalts erhöhen
    }
    
    // ************************************************************************************************************************
    
    void uart_prchr (char chr)                                          // * UART-TX-PUFFER: CHARACTER ABLEGEN *
    {
      utxbuf[utxl++] = chr;                                             // Character an den Puffer anhängen
    }
    
    // ************************************************************************************************************************
    
    void uart_prhex (u8 val)                                            // * UART-TX-PUFFER: HEX-WERT ABLEGEN *
    {
      u8 ln, hn;                                                        // Variablen
      hn = (val & 0xF0)>>4;                                             // HiNibble Wert
      ln = (val & 0x0F);                                                // LoNibble Wert
      utxbuf[utxl++] = '$';                                             // Dollarzeichen anhängen
      utxbuf[utxl++] = hn>9 ? hn+0x37 : hn+0x30;                        // HiNibble an den Puffer anhängen
      utxbuf[utxl++] = ln>9 ? ln+0x37 : ln+0x30;                        // LoNibble an den Puffer anhängen
    }
    
    // ************************************************************************************************************************
    
    u8 uart_havebyte (void)                                             // * UART-RX-PUFFER: ZEICHEN VORHANDEN? *
    {
      return (urxl);                                                    // Anzahl Zeichen im Empfangspuffer zurückgeben
    }
    
    // ************************************************************************************************************************
    
    u8 uart_getbyte (void)                                              // * UART-RX-PUFFER: ZEICHEN LESEN *
    {
      u8 c;                                                             // Hilfsvariable
      c = urxbuf[0];                                                    // Zeichen aus dem FIFO lesen
      urxl--;                                                           // Anzahl Zeichen verringern
      memmove (&urxbuf[0],&urxbuf[1],urxl);                             // Puffer shiften
      return (c);                                                       // Zeichen zurückgeben
    }
    
    // ************************************************************************************************************************
    
    SIGNAL (SIG_UART_RECV)                                              // * UART EMPFANGSINTERRUPT *
    {
      if (urxl < URXBUFSIZE)                                            // noch Kapazität im Empfangsbuffer
      {
        urxbuf[urxl] = UDR;                                             // neues Zeichen anhängen
        if (urxbuf[urxl] == 0x0D) 
        {                                                               // Empfangenes Zeichen ist ein CR
          uart_prstr ("\r\n");                                          // CR+LF als Echo zurücksenden
        }
        else
        {                                                               // Empfangenes Zeichen ist kein CR
          uart_prchr(urxbuf[urxl]);                                     // Echo ans Terminal zurücksenden
        }
        urxl++;                                                         // Anzahl vorhandener Zeichen im FIFO erhöhen
      }
    }
    
    // ************************************************************************************************************************
    
    SIGNAL (SIG_INTERRUPT0)
    {
      if (PIND & (1<<PD3))
        uart_prchr ('1');
      else
        uart_prchr ('0');
    }
    
    // ************************************************************************************************************************
    
    SIGNAL (SIG_INTERRUPT1)
    {
      if (PIND & (1<<PD3))
        uart_prchr ('1');
      else
        uart_prchr ('0');
    }
    
    // ************************************************************************************************************************
    
    SIGNAL (SIG_OUTPUT_COMPARE0)
    {
      if (timcntdwn)          timcntdwn--;                              // timcntdwn runterzählen wenn > 0
    } 
    
    SIGNAL (SIG_OVERFLOW0)
    {
      TCCR0 = 0x00;
    }
    
    // ************************************************************************************************************************
    
    #define PS2_CLCK_IS_HI    (PINC & (1<<PC0))
    #define PS2_DATA_IS_HI    (PINC & (1<<PC1))
    #define PS2_CLCK_LO       DDRC |= (1<<PC0)
    #define PS2_CLCK_HI       DDRC &= ~(1<<PC0)
    #define PS2_DATA_LO       DDRC |= (1<<PC1)
    #define PS2_DATA_HI       DDRC &= ~(1<<PC1)
    
    // ************************************************************************************************************************
    
    u8 ps2_wait_long_for_clck_lo ()
    {
      TIMER0_10MS;
      while (TIMER0_RUNNING)
      {
        if (!PS2_CLCK_IS_HI) return 0x00;
      }
      return (0xFF);
    }
    
    // ************************************************************************************************************************
    
    u8 ps2_wait_for_clck_lo ()
    {
      TIMER0_50US;
      while (TIMER0_RUNNING)
      {
        if (!PS2_CLCK_IS_HI) return 0x00;
      }
      return (0xFF);
    }
    
    // ************************************************************************************************************************
    
    u8 ps2_wait_for_clck_hi ()
    {
      TIMER0_50US;
      while (TIMER0_RUNNING)
      {
        if (PS2_CLCK_IS_HI) return 0x00;
      }
      return (0xFF);
    }
    
    // ************************************************************************************************************************
    
    u8 ps2_send (u8 val)
    {
      u8 i = -1;
      u8 pb = 0;
      
      PS2_CLCK_LO;                                                      // setze CLCK LO
      TIMER0_100US; while (TIMER0_RUNNING) NOOP;                        // warte 100µs
      PS2_DATA_LO;                                                      // setze CLCK LO, DATA LO
      TIMER0_25US; while (TIMER0_RUNNING) NOOP;                         // warte 25µs
      PS2_CLCK_HI;                                                      // setze CLCK HI, DATA LO
    
      if (ps2_wait_long_for_clck_lo()) goto ps2_send_error;             // 10ms auf fallende Flanke (CLCK) warten
    
      for (i=0; i<8; i++)
      {                                                                 // Datenbits LSB->MSB
        if (val & 0x01)
        {                                                               // Bit ist 1
          pb++;                                                         // Parityzähler erhöhen
          PS2_DATA_HI;                                                  // Datenleitung HI sezen
        }
        else
        {                                                               // Bit ist 0
          PS2_DATA_LO;                                                  // Datenleitung LO setzen
        } 
        if (ps2_wait_for_clck_hi()) goto ps2_send_error;                // 50µs auf steigende Flanke (CLCK) warten
        if (ps2_wait_for_clck_lo()) goto ps2_send_error;                // 50µs auf fallende Flanke (CLCK) warten
        val = val >> 1;
      }
      
      if (pb & 0x01)                                                    // PB ungerade?
        PS2_DATA_LO;                                                    // -> kein Parity Bit
      else                                                              // PB gerade?
        PS2_DATA_HI;                                                    // -> Parity Bit
      if (ps2_wait_for_clck_hi()) goto ps2_send_error;                  // 50µs auf steigende Flanke (CLCK) warten
      if (ps2_wait_for_clck_lo()) goto ps2_send_error;                  // 50µs auf fallende Flanke (CLCK) warten
      
      i++;
      PS2_DATA_HI;                                                      // CLCK und DATA freigeben
      PS2_CLCK_HI;                                                      // CLCK und DATA freigeben
      if (ps2_wait_for_clck_hi()) goto ps2_send_error;                  // 50µs auf steigende Flanke (CLCK) warten
      if (ps2_wait_for_clck_lo()) goto ps2_send_error;                  // 50µs auf fallende Flanke (CLCK) warten
    
      PS2_CLCK_LO;                                                      // CLCK LO setzen (Bus blockieren)
      return (0);                                                       // Fehlerfrei
    
      ps2_send_error:                                                   // Fehlerhandling
      PS2_CLCK_LO;                                                      // CLCK LO setzen (Bus blockieren)
      return (i);                                                       // Fehlernummer zurückgeben
    
    }
    
    // ************************************************************************************************************************
    
    u8 ps2_read (u8 * buffer, u8 len, u8 bytes_read)
    {
      u8 i;
      bytes_read = 0;                                                   // Anzahl gelesener Zeichen
      PS2_CLCK_HI;                                                      // CLCK freigeben
    
      while (bytes_read < len)
      {
        buffer[bytes_read] = 0;
        for (i=1; i<=11; i++)
        {
          if (i==1)                                                     // beim Startbit
            { if (ps2_wait_long_for_clck_lo()) goto ps2_read_error; }   //   10ms auf fallende Flanke (CLCK) warten
          else                                                          // sonst
            { if (ps2_wait_for_clck_lo()) goto ps2_read_error; }        //   50µs auf fallende Flanke (CLCK) warten
    
          if (i>=2 && i<=9)
          {                                                             // wenn Datenbit
            if (PS2_DATA_IS_HI)                                         // HI
              buffer[bytes_read] = (buffer[bytes_read]>>1) | 0x80;
            else                                                        // LO
              buffer[bytes_read] = (buffer[bytes_read]>>1) | 0x00;
          }
          if (ps2_wait_for_clck_hi()) goto ps2_read_error;              // 50µs auf steigende Flanke (CLCK) warten    
        }
        bytes_read++;                                                   // Bytezähler erhöhen
      }
    
      PS2_CLCK_LO;                                                      // CLCK LO setzen (Bus blockieren)
      return (0);                                                       // Fehlerfrei
    
      ps2_read_error:                                                   // Fehlerhandling
      PS2_CLCK_LO;                                                      // CLCK LO setzen (Bus blockieren)
      return (i);                                                       // Fehlernummer zurückgeben
    }
    
    // ************************************************************************************************************************
    
    int main (void)                                                     // * HAUPTPROGRAMM *
    {
                                                                        // Variablen
      u8 c,i;                                                           // Hilfsvariablen
      u8 rbuf[10];                                                      // Empfangspuffer
    
                                                                        // RS232 Bus initialisieren
      UBRRL=16;                                                         // 57k6 @ 16MHz
      UCSRB=_BV(TXEN) | _BV(RXEN) | _BV(RXCIE);                         // Sender, Empfänger und EmpfangsIRQ einschalt
    
      TIMSK |= (1<<TOIE0);                                              // Overflow Interrupt für Timer0 einschalten
    
      sei();                                                            // Interrupts starten
    
      for (i=0; i<255; i++) asm volatile (";");                         // ein kurzes Nickerchen
      
      uart_prstr ("\r\n");                                              // Welcome Text ausgeben
      uart_prstr ("*******************\r\n");                           // Welcome Text ausgeben
      uart_prstr ("* PS/2 started... *\r\n");                           // Welcome Text ausgeben
      uart_prstr ("*******************\r\n");                           // Welcome Text ausgeben
    
      PORTC = 0x00;
      DDRC  |= 0x00;
    
      while (1)                                                         // Hauptschleife
      {
        
        // --------------------------------------------------------------------------------------------------------------------
    
        if (utxl && (UCSRA & (1<<UDRE)))
        {                                                               // Bereit zum Versand eines Zeichens über UART
          cli();                                                        // Interrupts abschalten
          UDR = utxbuf[0];                                              // erstes Zeichen aus dem FIFO ins Senderegister
          utxl--;                                                       // Länge der Warteschlange verringern
          memmove (&utxbuf[0],&utxbuf[1],utxl);                         // FIFO shiften
          sei();                                                        // Interrupts einschalten
        }
        
        // --------------------------------------------------------------------------------------------------------------------
        
        if (uart_havebyte())
        {
          i = 0;
          switch (uart_getbyte())
          {
            case 'a': { i=ps2_send(0xF6); break; }
            case 'b': { i=ps2_send(0xF4); break; }
            case 'z': { i=ps2_send(0xFF); break; }
            case 'r': { i=ps2_send(0xE8); break; }
            case '1': { i=ps2_send(0x00); break; }
            case '2': { i=ps2_send(0x01); break; }
            case '4': { i=ps2_send(0x02); break; }
            case '8': { i=ps2_send(0x03); break; }
            case '+': { DDRC = 0x00;      break; }
            case '-': { DDRC = 0x01;      break; }
            case '#': { i=ps2_read(rbuf,1,c); if (!i) uart_prhex (rbuf[0]);      break; }
          }
          if (i) 
          {
            uart_prstr ("RES=");
            uart_prhex(i);
            uart_prstr ("\r\n");
          }
        }
    
      }                                                                 // Ende Hauptschleife
    
    }                                                                   // Ende main
    Das Programm ist für das RNControl 1.4 mit 16MHz Quarz geschrieben.

    Es wird ein Serielles Terminal (HyperTerm) erwartet mit 57600 8N1.

    Die CLCK-Leitung der Maus muss an PC0, die DATA Leitung an PC1.

    RNControl meldet sich mit einer Hallo-Meldung und erwartet dann einen Tastendruck, der dann ein entsprechendes Kommando an die Maus schickt.

    Die Projektdoku ist noch nicht fertig. Wenn Interesse besteht, erzähle ich gerne mehr...

    Gruß,
    Chris

  4. #4
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    16.05.2005
    Alter
    32
    Beiträge
    137
    Ja, das würde mich auch interessieren, hast du noch mehr Wissen das du uns gerne zu verfügung stellen würdest?
    Gruß, Majus

  5. #5
    Gast
    vielen dank für die infos!
    ich selbst kann auch noch was dazu beitragen. Ich habe noch eine Beschreibung für RS232-Mäuse gefunden unter:
    http://seth.positivism.org/man.cgi/4/mouse

    gruß
    Richard

  6. #6
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    30.10.2005
    Ort
    Mönchengladbach
    Alter
    47
    Beiträge
    114
    Ich gebe zu bedenken, dass sich bei seriellen Mäusen ein Problem einstellt: es wird ohne Handshaking gearbeitet. Wenn du zwischendurch ein Zeichen verpasst, kommst du aus dem Tritt und hast wenig Möglichkeiten.

    Bei PS/2 blockiert man einfach den Datenfluss dann muss die Maus sich selber merken, was passiert ist, bis sie wieder senden darf.

  7. #7
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    10.03.2005
    Alter
    28
    Beiträge
    967
    Machst du dich mal ans Doku schreiben? *lechz*
    Ich würde ja gern die Welt verändern..., doch Gott gibt mir den Quellcode nicht!

  8. #8
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    30.10.2005
    Ort
    Mönchengladbach
    Alter
    47
    Beiträge
    114
    Wenn ich mich am WE aufraffen kann, dann mach ich's

  9. #9
    Gast
    Danke, wär auf jedenfall sehr sehr nett

  10. #10
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    30.10.2005
    Ort
    Mönchengladbach
    Alter
    47
    Beiträge
    114
    Tja, ich hab's immer noch nicht geschafft, mal die PS/2 Maus zu dokumentieren und einen Wiki-Artikel zu schreiben. Wenigstens hat sich der Code weiter entwickelt, ich poste ihn hier einfach mal (wegen einer Anfrage in einem anderen Thread).

    In der main() wird zunächst ein Reset ausgelöst und die Rückgabewerte werden geprüft. Danach wird die Auflösung hoch gesetzt und der Continous Reporting Mode eingeschaltet.

    Code:
    // ************************************************************************************************************************
    
    #include <avr/io.h>
    #include <avr/signal.h>
    #include <avr/interrupt.h>
    #include <string.h>
    #include <stdlib.h>
    
    #define u8  unsigned char
    #define s8  signed char
    #define u16 unsigned int
    #define s16 signed int
    
    // ************************************************************************************************************************
    
    typedef struct {
      u8 head;
      s8 rwheel;
      s8 lwheel;
    } ps2_movement_type;
    
    // ************************************************************************************************************************
    
    #define TIMER0_25US             TCNT0 = 231; TCCR0 = (1<<CS01)
    #define TIMER0_50US             TCNT0 = 206; TCCR0 = (1<<CS01)
    #define TIMER0_75US             TCNT0 = 181; TCCR0 = (1<<CS01)
    #define TIMER0_100US            TCNT0 = 156; TCCR0 = (1<<CS01)
    #define TIMER0_500US            TCNT0 = 193; TCCR0 = (1<<CS01) | (1<<CS00)
    
    #define TIMER0_1MS              TCNT0 = 131; TCCR0 = (1<<CS01) | (1<<CS00)
    #define TIMER0_2MS              TCNT0 =   6; TCCR0 = (1<<CS01) | (1<<CS00)
    #define TIMER0_5MS              TCNT0 = 217; TCCR0 = (1<<CS02) | (1<<CS00)
    #define TIMER0_10MS             TCNT0 = 178; TCCR0 = (1<<CS02) | (1<<CS00)
    #define TIMER0_20MS             TCNT0 = 100; TCCR0 = (1<<CS02) | (1<<CS00)
    
    #define TIMER0_RUNNING          (TCCR0)
    #define NOOP                    asm volatile (";")
    
    #define SLEEP_10MS              TIMER0_10MS; while (TIMER0_RUNNING) NOOP
    #define SLEEP_20MS              TIMER0_20MS; while (TIMER0_RUNNING) NOOP
    
    
    #define PS2_CLCK_IS_HI          (PINC & (1<<PC0))
    #define PS2_DATA_IS_HI          (PINC & (1<<PC1))
    #define PS2_CLCK_LO             DDRC |= (1<<PC0)
    #define PS2_CLCK_HI             DDRC &= ~(1<<PC0)
    #define PS2_DATA_LO             DDRC |= (1<<PC1)
    #define PS2_DATA_HI             DDRC &= ~(1<<PC1)
    
    
    // ************************************************************************************************************************
    
    SIGNAL (SIG_OVERFLOW0)                                              // * TIMER0 ÜBERLAUF *
    {
      TCCR0 = 0x00;                                                     // Timer 0 ausschalten
    }
    
    // ************************************************************************************************************************
    
    u8 ps2_wait_long_for_clck_lo ()                                     // PS/2: Bis zu 10ms auf CLCK=LO warten
    {
      TIMER0_10MS;                                                      // Timer0 Preload 10ms
      while (TIMER0_RUNNING)
      {                                                                 // wenn der Timer läuft
        if (!PS2_CLCK_IS_HI) return 0x00;                               // und CLCK geht auf LO -> Return OK
      }
      return (0xFF);                                                    // Timer abgelaufen -> Return Timeout
    }
    
    // ************************************************************************************************************************
    
    u8 ps2_wait_for_clck_lo ()                                          // PS/2: Bis zu 50µs auf CLCK=LO warten
    {
      TIMER0_50US;                                                      // Timer 0 Preload  50µs
      while (TIMER0_RUNNING)
      {                                                                 // wenn der Timer läuft
        if (!PS2_CLCK_IS_HI) return 0x00;                               // und CLCK geht auf LO -> Return OK
      }
      return (0xFF);                                                    // Timer abgelaufen -> Return Timeout
    }
    
    // ************************************************************************************************************************
    
    u8 ps2_wait_for_clck_hi ()                                          // PS/2: Bis zu 50µs auf CLCK=HI warten
    {
      TIMER0_50US;                                                      // Timer 0 Preload  50µs
      while (TIMER0_RUNNING)
      {                                                                 // wenn der Timer läuft
        if (PS2_CLCK_IS_HI) return 0x00;                                // und CLCK geht auf LO -> Return OK
      }
      return (0xFF);                                                    // Timer abgelaufen -> Return Timeout
    }
    
    // ************************************************************************************************************************
    
    u8 ps2_send (u8 val)
    {
      u8 i = -1;
      u8 pb = 0;
      
      PS2_CLCK_LO;                                                      // setze CLCK LO
      TIMER0_100US; while (TIMER0_RUNNING) NOOP;                        // warte 100µs
      PS2_DATA_LO;                                                      // setze CLCK LO, DATA LO
      TIMER0_25US; while (TIMER0_RUNNING) NOOP;                         // warte 25µs
      PS2_CLCK_HI;                                                      // setze CLCK HI, DATA LO
    
      if (ps2_wait_long_for_clck_lo()) goto ps2_send_error;             // 10ms auf fallende Flanke (CLCK) warten
    
      for (i=0; i<8; i++)
      {                                                                 // Datenbits LSB->MSB
        if (val & 0x01)
        {                                                               // Bit ist 1
          pb++;                                                         // Parityzähler erhöhen
          PS2_DATA_HI;                                                  // Datenleitung HI sezen
        }
        else
        {                                                               // Bit ist 0
          PS2_DATA_LO;                                                  // Datenleitung LO setzen
        } 
        if (ps2_wait_for_clck_hi()) goto ps2_send_error;                // 50µs auf steigende Flanke (CLCK) warten
        if (ps2_wait_for_clck_lo()) goto ps2_send_error;                // 50µs auf fallende Flanke (CLCK) warten
        val = val >> 1;
      }
      
      if (pb & 0x01)                                                    // PB ungerade?
        PS2_DATA_LO;                                                    // -> kein Parity Bit
      else                                                              // PB gerade?
        PS2_DATA_HI;                                                    // -> Parity Bit
      if (ps2_wait_for_clck_hi()) goto ps2_send_error;                  // 50µs auf steigende Flanke (CLCK) warten
      if (ps2_wait_for_clck_lo()) goto ps2_send_error;                  // 50µs auf fallende Flanke (CLCK) warten
      
      i++;
      PS2_DATA_HI;                                                      // CLCK und DATA freigeben
      PS2_CLCK_HI;                                                      // CLCK und DATA freigeben
      if (ps2_wait_for_clck_hi()) goto ps2_send_error;                  // 50µs auf steigende Flanke (CLCK) warten
      if (ps2_wait_for_clck_lo()) goto ps2_send_error;                  // 50µs auf fallende Flanke (CLCK) warten
    
      PS2_CLCK_LO;                                                      // CLCK LO setzen (Bus blockieren)
      return (0);                                                       // Fehlerfrei
    
      ps2_send_error:                                                   // Fehlerhandling
      PS2_CLCK_LO;                                                      // CLCK LO setzen (Bus blockieren)
      return (i);                                                       // Fehlernummer zurückgeben
    
    }
    
    // ************************************************************************************************************************
    
    u8 ps2_read (u8 * buffer, u8 len, u8 bytes_read)
    {
      u8 i;
      bytes_read = 0;                                                   // Anzahl gelesener Zeichen
      PS2_CLCK_HI;                                                      // CLCK freigeben
    
      while (bytes_read < len)
      {
        buffer[bytes_read] = 0;
        for (i=1; i<=11; i++)
        {
          if (i==1)                                                     // beim Startbit
            { if (ps2_wait_long_for_clck_lo()) goto ps2_read_error; }   //   10ms auf fallende Flanke (CLCK) warten
          else                                                          // sonst
            { if (ps2_wait_for_clck_lo()) goto ps2_read_error; }        //   50µs auf fallende Flanke (CLCK) warten
    
          if (i>=2 && i<=9)
          {                                                             // wenn Datenbit
            if (PS2_DATA_IS_HI)                                         // HI
              buffer[bytes_read] = (buffer[bytes_read]>>1) | 0x80;
            else                                                        // LO
              buffer[bytes_read] = (buffer[bytes_read]>>1) | 0x00;
          }
          if (ps2_wait_for_clck_hi()) goto ps2_read_error;              // 50µs auf steigende Flanke (CLCK) warten    
        }
        bytes_read++;                                                   // Bytezähler erhöhen
      }
    
      PS2_CLCK_LO;                                                      // CLCK LO setzen (Bus blockieren)
      return (0);                                                       // Fehlerfrei
    
      ps2_read_error:                                                   // Fehlerhandling
      PS2_CLCK_LO;                                                      // CLCK LO setzen (Bus blockieren)
      return (i);                                                       // Fehlernummer zurückgeben
    }
    
    // ************************************************************************************************************************
    
    void fatal_error (u8 errcode, u16 addinfo)
    {
        // Fehlerbehandlung hier rein....
        while (1) {}
    }
    
    // ************************************************************************************************************************
    
    int main (void)
    {
                                                                        // Variablen
      u8  c,i;                                                          // Hilfsvariablen
      ps2_movement_type moved;                                          // Bewegungsmeldung
    
      TIMSK |= (1<<TOIE0);                                              // Overflow Interrupt für Timer0 einschalten
      sei();                                                            // Interrupts einschalten
    
      for (i=0;i<50;i++) { SLEEP_20MS; }                                // 1s warten (50*20ms)
      if (ps2_send(0xFF))   fatal_error(0x01,0x00);                     // PS/2 Cmd: Reset
      SLEEP_20MS;                                                       // 20ms warten
      if (ps2_read(&c,1,i)) fatal_error(0x02,0x00);                     // auf Lesefehler von PS/2 prüfen
      if (c != 0xFA)        fatal_error(0x03,c);                        // auf Quittung (ACK/$FA) prüfen
      for (i=0;i<50;i++) { SLEEP_10MS; }                                // 1s warten (50*20ms)
      if (ps2_read(&c,1,i)) fatal_error(0x04,0x00);                     // auf Lesefehler von PS/2 prüfen
      if (c != 0xAA)        fatal_error(0x05,c);                        // auf BAT-Quittung ($AA) prüfen
      if (ps2_read(&c,1,i)) fatal_error(0x06,0x00);                     // auf Lesefehler von PS/2 prüfen (Device ID überspringen)
    
      for (i=0;i<25;i++) { SLEEP_10MS; }                                // 1s warten (50*20ms)
      if (ps2_send(0xE8))   fatal_error(0x07,0x00);                     // PS/2 Cmd: Set Resolution
      SLEEP_20MS;                                                       // 20ms warten
      if (ps2_read(&c,1,i)) fatal_error(0x08,0x00);                     // auf Lesefehler von PS/2 prüfen
      if (c != 0xFA)        fatal_error(0x09,c);                        // auf Quittung (ACK/$FA) prüfen
    
      for (i=0;i<25;i++) { SLEEP_10MS; }                                // 1s warten (50*20ms)
      if (ps2_send(0x02))   fatal_error(0x0A,0x00);                     // Resolution 2 = 4 counts/mm = 2 Impulse pro Zahn
      SLEEP_20MS;                                                       // 20ms warten
      if (ps2_read(&c,1,i)) fatal_error(0x0B,0x00);                     // auf Lesefehler von PS/2 prüfen
      if (c != 0xFA)        fatal_error(0x0C,c);                        // auf Quittung (ACK/$FA) prüfen
    
      for (i=0;i<25;i++) { SLEEP_10MS; }                                // 1s warten (50*20ms)
      if (ps2_send(0xF4))   fatal_error(0x0D,0x00);                     // PS/2 Continuous Reporting Mode einschalten
      SLEEP_20MS;                                                       // 20ms warten
      if (ps2_read(&c,1,i)) fatal_error(0x0E,0x00);                     // auf Lesefehler von PS/2 prüfen
      if (c != 0xFA)        fatal_error(0x0F,c);                        // auf Quittung (ACK/$FA) prüfen
    
      // ----------------------------------------------------------------------------------------------------------------------
    
      mainloop:                                                         // Sprungmarke für Hauptschleife
    
      // ----------------------------------------------------------------------------------------------------------------------
    
      if (!ps2_read((char*)&moved,3,c))                                 // Maus lesen
      {
        // hier kann mit den Inkrementalgeberwerten und den Keys gearbeitet werden
      }
    
      // ----------------------------------------------------------------------------------------------------------------------
    
      goto mainloop;
    
    }
    Er ist für einen Atmega8 mit 8 MHz. Bei anderer Taktung müssen die Timer-Makros natürlich angepasst werden.

    PS2 CLCK ist an PC0, DATA ist an PC1. Das kann in den Makrodefinitionen geändert werden.

    Bei mir sind Encoder für das linke und das rechte Hinterrad angeschlossen. Durch die gewählte Auflösung erhalte ich Zähleveränderungen mit jeder Flanke, d.h. bei jedem "Farbwechsel" wird der Zähler erhöht bzw. verringert je nach Drehrichtung.

    Durch den Continous Reporting Mode muss man in der Hauptschleife nur immer wieder drei Bytes vom PS/2 Bus abholen und erhält damit die gezählten Impulse seit dem letzten Auslesen.

    So long,
    Chris

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •