PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : PS/2 Maus am PIC16F886



stumpi_8
27.03.2009, 14:11
Hallo,
ich bin noch ein relativ unerfahrener Bastler und möchte mittels einer PS/2 Maus und eines PIC16F886 die Bewegung der Maus erfassen und auf einem DEM16217 Display ausgeben. Das Display habe ich weils nur für den Moment ist parallel an den PIC angeschlossen. Die Ansteuerung Funktioniert auch so weit. Die Clock und Datenleitung der Maus habe ich über 2 4k7 Pullups gegen 5V an 2 Ports des PICS angeschlossen. So weit so gut, doch ich bekomme die Kommunkikation zwischen PIC und Maus nicht so recht zum Laufen, deshalb möchte ich euch bitten mal ein Auge auf meinen Code zu werfen.
Gruß stumpi

radbruch
27.03.2009, 14:43
Hallo

Ich beschäftige mich zur Zeit mit dem Anschluß einer PC-Tastatur an einen AVR. Da Maus und Tastatur die selben Protokolle verwenden kann dir vielleicht dieser Link hilfreich sein:

http://www.marjorie.de/ps2/ps2_protocol.htm

Ich habe das zwar noch nicht selbst ausprobiert, aber einige Stellen in deinem Code scheinen danach nicht ganz richtig zu sein:


unsigned char readByte(void){
signed char i;
unsigned char daten=0;

delay_us(3); //Sensor Zeit lassen um die Daten aus dem Register zu holen

for (i=7; i>-1; i--){
while (0==INPUT(clk)); // SCK =0 Sensor bereitet Daten auf fallender Flanke vor !

delay_us(1); //Sensor kurz Zeit lassen

if(INPUT(data)==1){ //BIT einlesen
daten |= (1<<i);
}
else{
daten &=~ (1<<i);
}

}
return data;
}
Die Wartezeiten erscheinen mir zu kurz. Das LSB kommt zuerst! Start/Stop/Parity wird ignoriert. Das Taktende wird nicht abgewartet. Und schließlich sind die Daten bei fallender Flanke des Taktes (von 1 nach 0) gültig.

Achtung! Auch beim Schreiben gibt die Maus den Takt vor. Der Takteingang am Kontroller muss wohl immer hochohmig sein.

Viel Erfolg.

mic

stumpi_8
30.03.2009, 15:02
@radbruch vielen dank für den link und die prompte antwort
ich habe meinen code verbessert (hoffe ich) doch ich kann immer noch keine daten von der maus empfangen :(
funktioniert deine kommunikation zwischen tastatur und avr??

radbruch
01.04.2009, 15:30
Hallo

Inzwischen funktioniert es mit einer Tastatur ganz gut:


// PS/2-Schnittstelle am ATMega32 1.4.2009 mic
// RP6 liest AT-Tastatur am I2C-Port

// http://www.marjorie.de/ps2/ps2_protocol.htm
// http://www.beyondlogic.org/keyboard/keybrd.htm

#include "RP6RobotBaseLib.h"

uint8_t i, scancode;

int main(void)
{
initRobotBase();
DDRC &= ~3; //SDA und SCL sind Eingänge
PORTC &= ~3; // ohne interne PullUps (extern sind 4k7 PullUps angeschlossen)

while(1)
{
i=0;
scancode=0;
while(PINC & 1); // Warten auf Startbit
while(!(PINC & 1)); // Ende Startbit
do
{
while(PINC & 1); // Tastatur bereitet die Daten vor
if(PINC & 2) scancode |= (1<<i); // Bit einlesen
i++;
while(!(PINC & 1)); // gelesen, auf nächstes Bit warten
}while(i<8);

while(PINC & 1); // Warten auf Paritybit
while(!(PINC & 1)); // Ende Paritybit
while(PINC & 1); // Warten auf Stopbit
while(!(PINC & 1)); // Ende Stopbit

writeInteger(scancode, 16);
writeChar('\n');
}
return(0);
}

Mit der Maus funktioniert das seltsamerweise nicht. Dein Programm habe ich nicht getestet. Ich bin aber noch dran.

Gruß

mic

radbruch
01.04.2009, 18:35
Und nochmals hallo

Es funktioniert! Zwar mit einem AVR, aber das sollte ein PIC auch können. Ich weiß allerdings nicht ob die PICs auch Tristatepins besitzen, ich gehe aber davon aus.

Das Problem: Entgegen den meisten Dokus muss man der PS/2-Maus wohl ein Kommando senden um sie zum Senden der Daten zu überreden. Alle meine Testmäuse wurden aktiv nachdem sie ein 0xf4 (enable) erhalten hatten:

// PS/2-Schnittstelle am ATMega32 1.4.2009 mic
// RP6 liest PS/2-Maus am I2C-Port

// http://www.marjorie.de/ps2/ps2_protocol.htm
// http://www.beyondlogic.org/keyboard/keybrd.htm
// http://instruct1.cit.cornell.edu/courses/ee476/FinalProjects/s2004/jcc72/index.html

// Hihi: http://www.mikrocontroller.net/topic/130824

#include "RP6RobotBaseLib.h"

#define Clock_Low {DDRC |=1; PORTC &=~1;} // clock low aktiv
#define Data_Low {DDRC |=2; PORTC &=~2;} // data low aktiv
#define Clock_High {DDRC &=~1; PORTC &=~1;}// Eingang mit externem 4K7-PullUp)
#define Data_High {DDRC &=~2; PORTC &=~2;}// Eingang mit externem 4K7-PullUp)
#define Data_Out {DDRC |=2; PORTC |=2;} // data high aktiv
#define Clock_In (PINC & 1) // Eingang abfragen
#define Data_In (PINC & 2) // Eingang abfragen

void send(uint8_t kommando)
{
uint8_t i, parity;
parity=0;

Clock_Low; // Clock auf Low und kurz warten -> Bus übernehmen
sleep(2);
Data_Low; // Datenleitung auf Low
Clock_High; // Clock auf high -> Takt wieder freigeben
while(!Clock_In); // Warten bis Maus den Takt ausgibt

for(i=0; i<8; i++) // 8 Bit Daten senden
{
while(Clock_In); // Warten bis schreiben erlaubt
if(kommando & (1<<i)) { Data_Out; parity++; } else Data_Low
while(!Clock_In); // Daten bereitgestellt, warten bis Maus liest
}

while(Clock_In); // Warten bis schreiben wieder erlaubt, dann Parity ausgeben
if(!(parity & 1)) Data_Out else Data_Low // Parity richtig senden
//if(parity & 1) Data_Out else Data_Low // Parityfehler erzwingen
while(!Clock_In); // Maus liest Parity
while(Clock_In); // Stopbit abwarten (wird scheinbar nicht geprüft)
while(!Clock_In); // Maus liest Stopbit

Data_High; // Datenleitung freigeben

while(Data_In); // ack von Maus abwarten
while(!Data_In); // Das war's
}
uint8_t read(void)
{
uint8_t i, scancode, parity;
scancode=0;
parity=0;
while(Clock_In); // Warten auf Startbit
while(!Clock_In); // Ende Startbit
for(i=0; i<8; i++) // 8 Bits einlesen
{
while(Clock_In); // Maus bereitet die Daten vor
if(Data_In) scancode |= (1<<i); // Bit einlesen
while(!Clock_In); // gelesen, auf nächstes Bit warten
}

while(Clock_In); // Warten auf Paritybit
if(Data_In) parity=1; // Parity einlesen
while(!Clock_In); // Ende Paritybit
while(Clock_In); // Warten auf Stopbit
while(!Clock_In); // Ende Stopbit
return(scancode);
}

int main(void)
{
initRobotBase();
Clock_High;
Data_High;

send(0xff); // reset
writeInteger(read(), 16);
writeChar('\n');
writeInteger(read(), 16);
writeChar('\n');
send(0xff); // reset
writeInteger(read(), 16);
writeChar('\n');
writeInteger(read(), 16);
writeChar('\n');
send(0xf4); // enable
writeInteger(read(), 16);
writeChar('\n');
mSleep(500);
writeString_P("\nBitte Maus bewegen!\n\n");

while(1)
{
writeInteger(read(), 16);
writeChar('\n');
}
return(0);
}
Achtung! Auch beim Senden von Kommandos gibt die Maus den Takt vor! Das Protokoll stimmt zwar anscheinend immer noch nicht mit der Doku überein, aber die Maus sendet Daten die man jetzt mal dekodieren kann. Es gibt noch viel zu erforschen ;)

Gruß

mic

[Edit]
btw. sind Mäuse zur Wegerfassung nicht geeignet:
https://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=421528#421528
Der erste Absatz gilt auch für Kugelmäuse.

stumpi_8
03.04.2009, 15:10
also mit meinem code konnte ich zwar daten senden aber irgendwie gibts da noch nen kleinen fehler
ich habs jetzt mal dein code so angepasst das er auf dem pic läuft
die maus antwortet jetzt auf 0xFF und 0xF4 mit 0xFA wie gewünscht bin aber noch nicht dazu gekommen die gesendeten daten auszuwerten.
bei jeder bewegung sendet die maus 3 byte oder?

radbruch
03.04.2009, 15:43
Ist doch schon prima wenn es funzt. Ja, es sind drei Bytes: Overflow- und Richtungsbits für Deltax/-y und die Statusbits der Tasten im ersten Byte, gefolgt vom 8Bit-Zweierkomlement (Kehrwert-1?) für Deltax und Deltay.

Das Protokoll stimmt übrigends doch. Das Problem ist die serielle Ausgabe während das PS/2-Gerät sendet. Dadurch werden gelegentlich Daten verbummelt. Ich hab'noch ein bisschen rumgespielt, inzwischen meldet sich sogar eine USB-Funkmaus mit PS/2-Adapter brav mit FA AA 00 :)

Die blockierenden Funktionen sind nicht wirklich befriedigend, zumal nicht mal ein Timeout vorgesehen ist. Besser wäre ein interruptfähiger Eingang an Clock mit entsprechender ISR. Das habe ich aber nicht zur Verfügung deshalb untersuche ich mal ob man nicht das TWI-Modul im AVR dazu überreden kann die Tastatur-/Mausdaten einzulesen. PICs können vermutlich auch TWI, oder?

Gruß

mic

stumpi_8
03.04.2009, 16:42
also der pic hat interupt pins und auch 2 I²C pins
ich denke ich werde es mal mit interrupts versuchen
kannst du die 3 gesendeten bytes gescheit abspeichern?