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.
1 | if (PINB &= (1<<PD2)) { |
Das "&=" würde ich nochmal überdenken. ;-)
Ja, das "=" Zeichen hab ich irgendwie übersehen, allerdings funktioniert es ohne es auch noch nicht.
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?
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.
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?
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.
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.
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ß
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.
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ß
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.