Software UART Empfang (ATmega8)

Gast #1275611
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.
#1276061
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?
Gast #1276096
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.
#1276120
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?
Gast #1276145
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.
Gast #1278650
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.
Gast #1278715
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ß
#1278727
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren