Forum: Mikrocontroller und Digitale Elektronik Software UART Empfang (ATmega8)


von Mento (Gast)


Lesenswert?

Ich versuche momentan - auf einem ATmega8 - mit einem Software-UART 
Daten von einem anderen ATmega8 zu empfangen und auf PortC auszugeben, 
allerdings kommt nur Kauderwelsch raus.
Die Baudrate ist genau ein Timer durchlauf mit Vorteiler 1024, bei 16 
MHz Takt. Also sehr sehr langsam.

Hier der Code:

void init_SoftUART(void)
{
  MCUCR  |= (1<<ISC01);      //Bei Fallender Flanke.
  GICR  |= (1<<INT0);        //INT0 aktivieren.
  GIFR   = (1<<INTF0);      //Interrupt Flag zur sicherheit löschen.

  //Timer2 für Software-UART.
  TCCR2 = (1<<CS02) | (1<<CS00); //Vorteiler auf 1024.

}


ISR (INT0_vect)
{
  TCNT2 = 170; //Timer2 auf die Mitte der Bits sezten.
  GICR  &= ~(1<<INT0); //INT0 deaktivieren.
  TIFR = (1<<TOV2);
  TIMSK |= (1<<TOIE2);  //Timer2 interrupt aktivieren.
}


ISR (TIMER2_OVF_vect)
{
  static int8_t curBit = -1;
  static uint8_t receiveByte = 0;
  static uint8_t curByte = 0;

  switch (curBit) {
    case -1:
      break;
    case 8:
      curBit = -2;

      PORTC = receiveByte;

      UARTreceiveBytes[curByte] = receiveByte;
      receiveByte = 0;

      curByte = !curByte;

      GICR  |= (1<<INT0); //INT0 aktivieren.
      TIMSK &= ~(1<<TOIE2);  //Timer2 interrupt deaktivieren.
      break;
    default:
      receiveByte >>= 1;
      if (PINB &= (1<<PD2)) {
        receiveByte |= (1<<7);
      }
      break;
  }
  curBit++;
}


Könnt ihr mir helfen oder müsst ihr noch mehr wissen?
Ach ja: Das senden Funktioniert einwandfrei, hab ich mit einem Oszi 
überprüft.

von Stefan E. (sternst)


Lesenswert?

1
      if (PINB &= (1<<PD2)) {
Das "&=" würde ich nochmal überdenken. ;-)

von Mento (Gast)


Lesenswert?

Ja, das "=" Zeichen hab ich irgendwie übersehen, allerdings funktioniert 
es ohne es auch noch nicht.

von Stefan E. (sternst)


Lesenswert?

Mento schrieb:
> Ja, das "=" Zeichen hab ich irgendwie übersehen, allerdings funktioniert
> es ohne es auch noch nicht.

Beim Wiederaktivieren des INT0 Interrupts muss auch das entsprechende 
Flag gelöscht werden.

Wenn es dann immer noch nicht geht, poste bitte mal, was genau gesendet 
und was genau statt dessen empfangen wird.

PS: Wieso ist eigentlich 170 die Mitte?

von Mento (Gast)


Lesenswert?

Es funktioniert noch immer nicht. Das mit 170 war zu Testzwecken, 
ursprünglich ist dort 128 gestanden und steht auch jetzt wieder dort.

Hier noch der aktuelle Code:
1
void init_SoftUART(void)
2
{
3
  MCUCR  |= (1<<ISC01);      //Bei Fallender Flanke.
4
  GICR  |= (1<<INT0);        //INT0 aktivieren.
5
  GIFR   = (1<<INTF0);      //Interrupt Flag zur sicherheit löschen.
6
  
7
  //Timer2 für Software-UART.
8
  TCCR2 = (1<<CS02) | (1<<CS00); //Vorteiler auf 1024.
9
  
10
}
11
12
13
ISR (INT0_vect)
14
{
15
  TCNT2 = 128; //Timer2 auf die Mitte der Bits sezten.
16
  GICR  &= ~(1<<INT0); //INT0 deaktivieren.
17
  TIFR = (1<<TOV2);
18
  TIMSK |= (1<<TOIE2);  //Timer2 interrupt aktivieren.
19
}
20
21
22
ISR (TIMER2_OVF_vect)
23
{
24
  static int8_t curBit = -1;
25
  static uint8_t receiveByte = 0;
26
  static uint8_t curByte = 0;
27
  
28
  switch (curBit) {
29
    case -1:
30
      break;
31
    case 8:
32
      curBit = -2;
33
      
34
      PORTC = receiveByte;
35
      
36
      UARTreceiveBytes[curByte] = receiveByte;
37
      receiveByte = 0;
38
      
39
      curByte = !curByte;
40
      
41
      GIFR = (1<<INTF0);
42
      GICR  |= (1<<INT0); //INT0 aktivieren.
43
      TIMSK &= ~(1<<TOIE2);  //Timer2 interrupt deaktivieren.          
44
      break;
45
    default:
46
      receiveByte >>= 1;
47
      if (PINB & (1<<PD2)) {
48
        receiveByte |= (1<<7);
49
      }
50
      break;
51
  }
52
  curBit++;
53
}

Und noch der Code des Senders:
1
ISR (TIMER2_OVF_vect) {
2
  static int8_t curBit = -1;
3
  if (UARTsendBytes[0]) {
4
    switch (curBit) {
5
      case -1: //Start-Bit
6
        UARTPort &= ~(1<<UARTPin);
7
        break;
8
      case 8: //Stop-Bit
9
        UARTPort |= (1<<UARTPin);
10
        break;
11
      default: //Daten-Bit
12
        if (UARTsendBytes[0] & (1<<curBit)) {
13
          UARTPort |= (1<<UARTPin);
14
        } else {
15
          UARTPort &= ~(1<<UARTPin);
16
        }
17
        break;
18
    }
19
    curBit++;
20
    if (curBit > 8) {
21
      curBit = -1;
22
      
23
      UARTsendBytes[0] = UARTsendBytes[1]; //Nächstes Byte zum versenden. 
24
      UARTsendBytes[1] = 0;
25
    }
26
  }
27
}

Es werden jeweils zwei Bytes versandt, das erste gibt die Art der 
Nachricht an und das zweite die Daten.

von Stefan E. (sternst)


Lesenswert?

Mento schrieb:

> Es werden jeweils zwei Bytes versandt, das erste gibt die Art der
> Nachricht an und das zweite die Daten.

Ich will nicht wissen, was die Daten bedeuten (das ist völlig 
irrelevant), ich will wissen, wie die Daten aussehen.
Was wird empfangen, wenn du 0x55 sendest?
Was wird empfangen, wenn du 0xf0 sendest?
Was wird empfangen, wenn du 0x0f sendest?

von Mento (Gast)


Lesenswert?

Tut mir leid, ich hab dich falsch verstanden.

Hier die Ergebnisse (ich hab jeweils viermal gesendet, und jedes mal ist 
etwas anderes herausgekommen):
Bei 0x55:
100011
011111
000111
111111

Bei 0xF0:
001111
100011
011111
110001

Bei 0x0F:
100011
100001
111000
001111

Ich glaub aber nicht, dass du daraus schlau wirst.
Ich hab nur immer die ersten 6 Bits da PortC nicht mehr Pins hat.

von Stefan E. (sternst)


Lesenswert?

Das sieht ja eher zufällig aus. Sicher, dass du überhaupt den richtigen 
Pin einließt? Die dazugehörige Zeile sieht ja auch etwas verdächtig aus.
1
if (PINB & (1<<PD2)) {
Tatsächlich einlesen tust du PB2. Dem Code nach könntest du aber auch 
eigentlich PD2 einlesen wollen.

von Gast (Gast)


Lesenswert?

Hallöchen,

was soll das

curByte = !curByte;

bewirken? Eine logische Negation deines Emfangszählers!?!

Und

(PINB & (1<<PD2))

ist zwar nicht verkehrt, aber Port B und ein Pin von Port D sollte man 
nicht mischen!
Außerdem, kann es sein, dass deine SoftUART am Port D angeschlossen ist?


Gruß

von Mento (Gast)


Lesenswert?

Ich hab es jetzt hinbekommen, es waren mehrere Sachen falsch. Unter 
anderem das mit PinB statt PinD und auch der Vorteiler des Timers da ich 
zuerst Timer0 verwendet hatte, bei welchem der Vorteiler anders ist als 
beim Timer2.

Hier der Code, falls es irgendjemanden interessiert:
1
void init_SoftUART(void)
2
{
3
  MCUCR  |= (1<<ISC01);      //Bei Fallender Flanke.
4
  GICR  |= (1<<INT0);        //INT0 aktivieren.
5
  GIFR   = (1<<INTF0);      //Interrupt Flag zur sicherheit löschen.
6
  
7
  //Timer2 für Software-UART.
8
  TCCR2 = (1<<CS22) | (1<<CS21) | (1<<CS20); //Vorteiler auf 1024.
9
  
10
}
11
12
13
ISR (INT0_vect)
14
{
15
  TCNT2 = 128; //Timer2 auf die Mitte der Bits sezten.
16
  GICR  &= ~(1<<INT0); //INT0 deaktivieren.
17
  TIFR = (1<<TOV2);
18
  TIMSK |= (1<<TOIE2);  //Timer2 interrupt aktivieren.
19
}
20
21
22
ISR (TIMER2_OVF_vect)
23
{
24
  static int8_t curBit = -1;
25
  static uint8_t receiveByte = 0;
26
  static uint8_t curByte = 0;
27
  
28
  switch (curBit) {
29
    case -1:
30
      break;
31
    case 8:
32
      curBit = -2;
33
      
34
      UARTreceiveBytes[curByte] = receiveByte;
35
      receiveByte = 0;
36
      
37
      curByte = !curByte;
38
      
39
      GIFR = (1<<INTF0);
40
      GICR  |= (1<<INT0); //INT0 aktivieren.
41
      TIMSK &= ~(1<<TOIE2);  //Timer2 interrupt deaktivieren.          
42
      break;
43
    default:
44
      receiveByte >>= 1;
45
      if (PIND & (1<<PD2)) {
46
        receiveByte |= (1<<7);
47
      }
48
      break;
49
  }
50
  curBit++;
51
}

Danke an euch alle.

von Gast (Gast)


Lesenswert?

Hallo,

nochmal die Frage:
Was soll das

curByte = !curByte;

bewirken? Eine logische Negation deines Emfangszählers!?!

Ich halte diese Zeile für falsch, mindestens aber gefährlich da 
'curByte' static ist und als Arrayindex benutzt wird.

Meines Wissens ist !0 im C "Quasi" Standard nicht eindeutig definiert 
außer, das es nicht Null ist. Es kann also 0x01 oder 0xFF oder sonstwas 
sein, ganz nach belieben des Compilers.

Oder liege ich falsch, mal so an die wahren C Experten gerichtet?

Gruß

von Stefan E. (sternst)


Lesenswert?

Gast schrieb:

> Ich halte diese Zeile für falsch, mindestens aber gefährlich da
> 'curByte' static ist und als Arrayindex benutzt wird.

Sie ist weder falsch noch gefährlich. Sie sorgt dafür, dass immer 
abwechselnd UARTreceiveBytes[0] und UARTreceiveBytes[1] beschrieben 
werden.

> Meines Wissens ist !0 im C "Quasi" Standard nicht eindeutig definiert
> außer, das es nicht Null ist.

Ich weiß ja nicht, was bei dir dieses "Quasi" ist, aber im richtigen 
Standard ist das Ergebnis des !-Operators eindeutig definiert.

Zitat C-Standard ISO99:
1
The result of the logical negation operator ! is 0 if the value of
2
its operand compares unequal to 0, 1 if the value of its operand
3
compares equal to 0.

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.