Forum: Mikrocontroller und Digitale Elektronik Atmega8 PS2 Protokoll


von cygar (Gast)


Lesenswert?

Hallo Leute,

bin noch relativ neu im µC Bereich und wollte nun zu Lernzwecken eine 
ps2 Tastatur an den AVR schließen und die Signale per UART an einen PC 
schicken.

Klappt auch theoretisch ganz gut, jedoch scheine ich falsche Daten zu 
bekommen

Hier ertsmal mein code:
1
ISR(SIG_INTERRUPT1)       
2
{
3
  PORTB = (1<<PB0);   //LED
4
  
5
      while(PIND & (1<<PIND3));  // wait for low clock
6
7
  int i;
8
  char data;
9
  //read 8 bit
10
  for (i=0; i<8; i++) 
11
  {
12
     while(!(PIND & (1<<PIND3)));   // wait for clock high
13
       while(PIND & (1<<PIND3));  // wait for low clock
14
     
15
       if ( PIND & (1<<PIND0) ) 
16
     {
17
      //PORTB = (1<<PB0);   //LED
18
       send_string("1");
19
    }
20
    else
21
    {
22
      send_string("0");  
23
    }        } 
24
}
25
 
26
27
int main(void)
28
{
29
  init_uart(UBRR_VAL);
30
 
31
  DDRB = (1<<PB0);      
32
  DDRD &= ~(1<<PD0);  
33
  DDRD &= ~(1<<PD3);
34
35
  //activate Pull up Resistor
36
  PORTD |= (1<<PD0); 
37
  PORTD |= (1<<PD3);
38
  
39
   //falling edge for INT1
40
  MCUCR |= (1<<ISC11);
41
  MCUCR &= ~(1<<ISC10);
42
  
43
  //Allow INT1
44
  GICR |= (1<<INT1);
45
  
46
  //Allow global interrupt
47
  sei();
48
  
49
  while (1)
50
  {
51
  }
52
  
53
  return 0;
54
}

Wenn ich die A Taste drücke empfange ich z.B "00000000" und beim Q 
"01000000"

Kann mir da jemand Sagen was ich Falsch mache?

von Dominik H. (dominikh)


Lesenswert?

Zu allererst macht der Interrupt so eher wenig Sinn. Pro Interrupt 
solltest du genau ein Bit lesen, ohne das rumgetue mit den whiles. 
Vermutlich verpasst du mit deiner "Lösung" einige Bits.

Bei jedem low der Clock gibt es einen Bit. Wenn du dann nach dem low 
erst auf ein low, ein high und ein low wartest, ist schonmal mindestens 
ein Bit flöten, je nach Ausführungsgeschwindigkeit auch mehr.

Auch das Senden per UART sollte nicht im Interrupt geschehen. Das nimmt 
nämlich wieder Zeit in Anspruch, während derer der Interrupt nicht 
erneut feuern kann -> wieder verlorene Bits.

von Michael H. (michael_h45)


Lesenswert?

cygar schrieb:
> Kann mir da jemand Sagen was ich Falsch mache?
Vermutlich brauchen deine send_strings im Interrupt zu lange.
Du kannst entweder die Uart wesentlich schneller als die PS2 machen, 
oder dir überlegen, die du deine 0en und 1en am geschicktesten erst 
irgendwo ablegst und dann erst schickst, wenn die ganze Empfangsaktion 
schon gelaufen ist.

Siehe: Bitmanipulation

p.s.: KEIN array zum Speichern =)

p.p.s.: Wo hast du denn das mit dem SIG_INTERRUPT her? Das ist 
steinalter, sogar veralteter Kram. Falls das aus einem Tutorial ist, 
such dir ein anderes!
Zum Beispiel das AVR-GCC-Tutorial von hier.

von cygar (Gast)


Lesenswert?

Danke schonmal für eure Hilfe, hole jetzt jedes Bit einzeld per 
Interrupt. Jedoch das mit der Bitmanipulation bekomme ich noch nicht hin

Vielen Danke
cygar

von cygar (Gast)


Lesenswert?

So hatte etwas wenig zeit aber mich jetzt noch mal ran gesetzt...

Frage jetzt pro interrupt nur 1 bit aber bekomme leiter komplett falsche 
daten.

hier mein code:
1
ISR(INT1_vect)       
2
{
3
  PORTB = (1<<PB0);   //LED
4
5
  bit++;
6
      //read bit
7
  if (bit <= 11 && bit >= 1)
8
  {
9
     if ( PIND & (1<<PIND0) ) 
10
     { 
11
       a = (1<<bit);
12
    }
13
  }
14
  if (bit == 11)
15
  {
16
    bit = 0; 
17
                ausgabe=1;
18
  
19
  }
20
21
}

von cygar (Gast)


Lesenswert?

Okay, ich seh schon selbst da muss ja ne und verknüpfung hin sonst wird 
a ja jedes mal neu beschrieben

also
1
 a |= (1<<bit);

so funktioniert es auch endlich!!

von Christopher G. (cbg)


Lesenswert?

Shifting per Variable sollte man vermeiden. Bei Fällen wie diesem hier 
kann man ganz leicht Zyklen sparen, indem man es so programmiert.
1
ISR(INT1_vect)
2
{
3
  static uint16_t tmp;
4
  PORTB = (1<<PB0);   //LED
5
6
  bit++;
7
  //read bit
8
  if (bit <= 11 && bit >= 1)
9
  {
10
     tmp <<= 1;
11
     if ( PIND & (1<<PIND0) )
12
       tmp |= 1;
13
  }
14
  if (bit == 11)
15
  {
16
    a = tmp;
17
    ausgabe=1;
18
    bit = 0;
19
    tmp = 0;
20
  }
21
22
}
tmp habe ich hinzugefügt, da ich annehme, dass a global ist und du 
damit die Datenübergabe ans Hauptprogramm realisierst. bit braucht 
übrigens nicht global sein, falls es sonst nicht verwendet wird. Wenn 
doch, dann aber volatile setzen, selbiges gilt für a und ausgabe.

von cygar (Gast)


Lesenswert?

Hallo Christopher,

danke für deinen Code, scheint bei mir aber noch nicht ganz zu klappen. 
Die Werte die ich empfange scheinen falsch zu sein und sind auch nur 
9bit land und nicht 11.

Bei meinem Code habe ich aber auch noch ein Problem hier habe ich 12 
bits statt 11.
1
IST:
2
100001110000
3
SOLL:
4
10000111000

Man sieht das das 0. bit hier zu viel ist. Bei meiner Interruptroutine 
zähle ich aber auch gleich am anfang den bit zähler hoch. Daran müsste 
es liegen oder?
Wenn ich nun aber am ende der Routine den Zähler erhöhe, bekomme ich ich 
zwar ab und zu den richtigen Wert beim drücken der A taste, jedoch 
zwischendurch auch immer falsche Werte.. woran liegt das?

Vielen Danke!!

von Christopher G. (cbg)


Lesenswert?

Poste mal deinen aktuellen Code als Anhang.

von cygar (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

Mein Code funktioniert jetzt soweit wie er soll. Shifte aber immer noch 
immer jedesmal wieder von vorne.

von Christopher G. (cbg)


Lesenswert?

Dass du a gleichzeitig als temporäre Variable in der ISR und auch als 
Übergabevariable verwendest ist schlecht. Je nachdem, wie schnell dein 
Signal ist, kanns sein, dass du mit /a = 0/ nach send_string dir einen 
Teil des ankommenden Signals löscht. Shiftest nun doch per Variable, 
nagut, von mir aus.
Hab mir PS2 noch nie angeschaut aber du empfängst 11 Bit, verundest mit 
Bits 9:1, shiftest dann um 1 nach rechts und hast dann Bits 9:1 des 
Signals in den untersten 8 Bit von a. Schaut merkwürdig aus, aber 
wenns passt, dann gut.

Was geht jetzt nicht?

cygar schrieb:
> Mein Code funktioniert jetzt soweit wie er soll. Shifte aber immer noch
> immer jedesmal wieder von vorne.

Den zweiten Satz kapier ich nicht.


PS: Übrigens wäre es besser, mit dem Input Capture eines Timers 
zusätzlich zu den Signalflanken auch noch die Zeit zwischen 2 Flanken zu 
messen. Somit kannst du schauen, ob das Signal von der Zeit her gültig 
ist.

von cygar (Gast)


Lesenswert?

Hey,

alles funktionieren tut alles nur wurde mir auch von anderer Seite 
gesagt das das shiften per Variable nicht so gut ist. Die Methode die du 
gepostet hast scheint nicht ganz zu funktionieren und verstehe ich nicht 
ganz.

Danke!!

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.