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