USART tx-timing Problem

OP #7774617
Lesenswert?

altes Problem - aber ich finde die Lösung nicht:

1
(mega328)
2
serial_read(0x01030000000184ff);
3

4

5
.....
6

7

8
uint8_t status_0tx_1rx = 0;
9
void serial_read(uint64_t x) {
10
//for (uint8_t i=14;i-=2;i<254)
11
  {
12

13
  PORTC|=(1<<2);
14
  ct_tx_isr=0;
15

16
    UCSR0A &=~ (1<<TXC0);
17
    serial_char((x>>(14*4)) & 0xff);
18
    while(!(UCSR0A & (1<<TXC0)));
19

20
    UCSR0A &=~ (1<<TXC0);
21
    serial_char((x>>(12*4)) & 0xff);
22
    while(!(UCSR0A & (1<<TXC0)));
23

24
    UCSR0A &=~ (1<<TXC0);
25
    serial_char((x>>(10*4)) & 0xff);
26
    while(!(UCSR0A & (1<<TXC0)));
27

28
    UCSR0A &=~ (1<<TXC0);
29
    serial_char((x>>(8*4)) & 0xff);
30
    while(!(UCSR0A & (1<<TXC0)));
31

32
    UCSR0A &=~ (1<<TXC0);
33
    serial_char((x>>(6*4)) & 0xff);
34
    while(!(UCSR0A & (1<<TXC0)));
35

36
    UCSR0A &=~ (1<<TXC0);
37
    serial_char((x>>(4*4)) & 0xff);
38
    while(!(UCSR0A & (1<<TXC0)));
39

40
    UCSR0A &=~ (1<<TXC0);
41
    serial_char((x>>(2*4)) & 0xff);
42
    while(!(UCSR0A & (1<<TXC0)));
43
    
44
    UCSR0A &=~ (1<<TXC0);
45
    serial_char((x>>(0*4)) & 0xff);
46
    while(!(UCSR0A & (1<<TXC0)));
47

48
>>>>    _delay_ms(2);  <<<<<
49

50
    PORTC &= ~(1<<2);
51
status_0tx_1rx = 1;
52

53
  while (status_0tx_1rx) 
54
  {
55
    if ( (UCSR0A & (1<<RXC0)) )
56
    {
57
      // Zeichen wurde empfangen, jetzt abholen
58
      uint8_t c;
59
      c = uart_getc();
60
      // hier etwas mit c machen z.B. auf PORT ausgeben
61
    
62
    if( 
63
  //nextChar != '\n' &&
64
    //    nextChar != '\r' &&
65
        uart_str_count < UART_MAXSTRLEN ) 
66
  {
67
      uart_string[uart_str_count] = c;
68
      uart_str_count++;
69
    }
70
    else {
71
      uart_string[uart_str_count] = '\0';
72
      uart_str_count = 0;
73
      uart_str_complete = 1;
74
  led1_blink; 
75
  
76
  lcd_goto(3,7);//
77
  lcd_int(c);// 
78
    lcd_int(uart_string[0]);
79
    lcd_int(uart_string[1]);
80
    lcd_int(uart_string[2]);
81
    lcd_int(uart_string[3]);
82
    lcd_int(uart_string[4]);
83
wait;
84
wait;
85
wait;
86
wait;
87
              
88
  lcd_clear(3);//              =
89

90
    status_0tx_1rx=0;
91
    }
92
   
93
  }
94
    else
95
    {
96
      // Kein Zeichen empfangen, Restprogramm ausführen...
97
    }
98
  }
99
  }
100
}

Ohne _delay_ms(2); werden Werte beim tx verschluckt.

Was ist bei der Wartefunktion falsch??

1
    UCSR0A &=~ (1<<TXC0);
2
    serial_char((x>>(0*4)) & 0xff);
3
    while(!(UCSR0A & (1<<TXC0)));

Danke für Unterstützung

OP #7774641
Lesenswert?

Das Programm soll - irgendwann - einen Wechselrichter per RS485 - steuern.

serial_read(0x01030000000184ff);

Sendet eine bestimmte Zeichenfolge auf die der WR antworten muss.

Zur Zeit ist der Empfänger ein c#-Programm auf dem PC.

Die Zeichenfolge wird im Prinzip richtig gesendet. Nur ohne das delay werden die letzten beiden Zeichen mit '0' ausgegeben. D.h. Die Übertragung wird durch den auf den Sende-Befehl folgenden Befehl vorzeitig abgebrochen.

Eigentlich müsste doch das Setzen des TXCO-Bits abgewartet werden?

#7774645
Lesenswert?

Lothar M. schrieb:

Der Code an sich ist eigentlich gar nicht mal so lang wenn man die unnötigen Leerzeilen rauslöscht. Hab ich mal gemacht...

Wenn der Code nicht mehr auf eine Seite passt, der Zeilenzähler dreistellig wird und damit die Forensoftware die Formatierung nicht mehr sauber hin bekommt, fühlt sich das lang an.

Karl K. schrieb:

Ohne _delay_ms(2); werden Werte beim tx verschluckt.

Wie stellst du das fest? Was sagt der LA, was sagt der Debugger?

Wieso erwartest du überhaupt, dass eine Funktion namens serial_read() irgendetwas mit tx zu tun hat ;-)

Moderator (Firma: Titel) Persönliche Seite #7774647
Lesenswert?

Karl K. schrieb:

serial_read() .... Sendet

Ja, das ist in der Tat verwirrend...

Nur ohne das delay werden die letzten beiden Zeichen mit '0' ausgegeben.

  1. siehst du die beiden "Nullwerte" auch so mit einem Oszi auf der Leitung?
  2. was passiert, wenn du nochmal zusätzlich 2 Bytes ausgibst?

Zur Zeit ist der Empfänger ein c#-Programm auf dem PC.

  1. kannst du da mal ein "übliches" Terminalprogramm" verwenden?
  2. welche Hardware verwendest du? Es gibt mir zu denken, dass du RS485 schreibst. Da muss zum richtigen Zeitpunkt der Treiber von "Senden" auf "Empfangen" umgeschaltet werden...
#7774654
Lesenswert?

Karl K. schrieb:

altes Problem - aber ich finde die Lösung nicht:

Schon mal was von einer Schleife gehört? Oder wirst du nach Programmzeilen bezahlt?

Hat es einen Grund, warum das so äußerst merkwürdig machen willst? Eine Halbduplex-Sendefunktion baut man anders. Außerdem löscht man das TXC0 Flag, indem man eine 1 reinschreibt! Klingt komisch, ist aber so! RTFM!

UCSR0A &=~ (1<<TXC0);

Damit wird TCX0 NICHT gelöscht! Eher so.

UCSR0A |= (1<<TXC0);

Ja, so!

Außerdem prüft man für das Senden meistens UDRE0, denn damit kann man lückenlos senden. Das ist ja der Witz des Sendepuffers. Nur beim letzten Byte prüft man TXC0, um dann den Tranceiver wieder auf Empfangen bzw. Tristate zu schalten. Siehe Anhang. Solche Daten übergibt man aber besser als Pointer auf ein Bytearray, nicht als 64 Bit Zahl.

Angehängte Dateien:
OP #7774731
Lesenswert?

Lothar M. schrieb:

  1. welche Hardware verwendest du? Es gibt mir zu denken, dass du RS485 schreibst. Da muss zum richtigen Zeitpunkt der Treiber von "Senden" auf "Empfangen" umgeschaltet werden...

M328-Nano + RS485-Adapter, ich mach heute abend mal ein Foto.

Mit PORTC &= ~(1<<2); wird von Senden auf Empfangen umgeschaltet.

Terminalprogramm ist eine gute Empfehlung.

Falk B. schrieb:

Außerdem löscht man das TXC0 Flag, indem man eine 1 reinschreibt! Klingt komisch, ist aber so! RTFM!

Das wird es sein - Ich habe extra ins fucking Manual geguckt - aber da war wohl noch was an anderer Stelle.

Falk B. schrieb:

Schon mal was von einer Schleife gehört?

//for (uint8_t i=14;i-=2;i<254) Hatte ich zuerst probiert - ging aber nicht. Wenn das Ganze erst mal funktioniert werde ich das noch layouten - wobei die Auflösung der Schleife durchaus Sinn ergeben kann weil die Steuerung der Schleife wegfällt.

Danke für alle Hinweise - insbesondere TXC0-Flag. Ich werde das heute abend probieren und berichten.

Moderator (Firma: Titel) Persönliche Seite #7774756
Lesenswert?

Karl K. schrieb:

M328-Nano + RS485-Adapter, ich mach heute abend mal ein Foto.

Wenn du kein Oszi hast, dann teste deine Software mal mit einer normalen RS232-Schnitte, da muss der Treiber nicht umgeschaltet werden und du siehst was der µC tatsächlich sendet.

Karl K. schrieb:

Falk B. schrieb:

Außerdem löscht man das TXC0 Flag, indem man eine 1 reinschreibt!

Das wird es sein - Ich habe extra ins fucking Manual geguckt

An der falschen Stelle. Da wunderst es eher, dass überhaupt was sinnvolles übertragen wird...

Angehängte Dateien:
#7774791
Lesenswert?

Karl K. schrieb:

M328-Nano + RS485-Adapter, ich mach heute abend mal ein Foto.

Was ist ein M328-Nano? Selbst Google ist da etwas hilflos.

Karl K. schrieb:

Mit PORTC &= ~(1<<2); wird von Senden auf Empfangen umgeschaltet.

Karl K. schrieb:

PORTC|=(1<<2); ... PORTC &= ~(1<<2);

Magic Numbers machen den Code nicht gerade lesbarer. Spätestens wenn der Pin woanders hin gelegt werden soll - viel Spaß in längerem Quellcode.

#7774983
Lesenswert?

Karl K. schrieb:

Das Programm soll - irgendwann - einen Wechselrichter per RS485 - steuern.

serial_read(0x01030000000184ff);

Sendet eine bestimmte Zeichenfolge auf die der WR antworten muss.

Ganz schlechter Stil. Eine Funktion sollte nur genau DAS machen, was der Name besagt! Bei dir solltest du senden und empfangen in getrennte Funktionen packen.

Strukturierte Programmierung auf Mikrocontrollern

#7774987
Lesenswert?

Rainer W. schrieb:

Karl K. schrieb:

PORTC|=(1<<2); ... PORTC &= ~(1<<2);

Magic Numbers machen den Code nicht gerade lesbarer. Spätestens wenn der Pin woanders hin gelegt werden soll - viel Spaß in längerem Quellcode.

Stimmt. Ein Macro ist hier das mittel der Wahl, den es ist selbsterklärend.

1
#define RS485_TRANSMIT PORTC |=  (1<<2)
2
#define RS485_RECEIVE  PORTC &= ~(1<<2)
3

4
...
5

6
RS485_TRANSMIT;
7
RS485_RECEIVE;

Ob man die Semicolons in die Macros packt oder nicht ist eine Glaubensfrage.

#7775014
Lesenswert?

Karl K. schrieb:

Ganz schlechter Stil.

aber trotzdem richtig, denn der Wechselrichter soll ausgelesen werden. Die write-Funktion gibt es auch. Da soll in das Register des WR geschrieben werden.

Dann nennt man es aber readRegister oder ähnlich. Und wieso braucht ein LESEfunktion einen 64 Bit Parameter? Dort gehört eher eine Registeradresse rein.

OP #7775374
Lesenswert?

jetzt bräuchte ich doch noch mal Hilfe:

Ich habe drei rs485-terminals: WR, PC, M328

Senden M328-PC und M328-WR und PC-WR geht.

Empfangen PC-WR, M328-PC(Bild1) geht.

Empfang M328-WR(Bild 2 +3)kommt kein brauchbares Signal.

Woran kann das liegen? Ist der Adapter unbrauchbar?

Angehängte Dateien:
#7775405
Lesenswert?

Karl K. schrieb:

jetzt bräuchte ich doch noch mal Hilfe:

Ich habe drei rs485-terminals: WR, PC, M328

Senden M328-PC und M328-WR und PC-WR geht.

Wer sagt das? Wie hast du das gemessen?

Empfangen PC-WR, M328-PC(Bild1) geht.

Glaub ich nicht. Das kann alles Mögliche sein.

Nutze dein Steuersignal für den Tranceiver (PC2) als Trigger zur Messung mit dem Oszi (Kanal 1). Dann siehst du die Sendedaten vom Arduino zum Wechselrichter und dessen Antwort (Kanal 2). Damit kannst du eine systematische Fehlersuche starten.

Woran kann das liegen? Ist der Adapter unbrauchbar?

Nö. Es ist deine Software.

OP #7775583
Lesenswert?

Falk B. schrieb:

Senden M328-PC und M328-WR und PC-WR geht. Wer sagt das? Wie hast du das gemessen?

Ich sende die Zeichenfolge (0x010300000001840a) an den Wechselrichter. Wenn der Wechselrichter "0x0103020005 + 2byte crc" antwortet, funktioniert die Kommunikation in beide Richtungen.

Die Oszi-Bilder 2+3 sehen erkennbar anders aus als Bild 1. Die dreieckigen Zacken können nicht als eindeutige digitale rs485-Signale ausgewertet werden - Hardwareproblem. Der Adapter ist in der Lage, Signale vom PC umzuformen - nicht jedoch Signale vom WR. Die sind vermutlich ein bisschen anders und daher in einem Grenzbereich, den der Adapter nicht auswerten kann.

Ich hab den Adapter gewechselt und sehe jetzt die richtige Antwort des WR - 01-03-02-00-05 zumindest auf dem Oszi (Bild 4/ mangels Kabel per Camera). Das Signal kommt jetzt richtig auf dem rx Pin an. Den Rest bekomm ich dann - wahrscheinlich - irgendwie hin.

Jedenfalls Danke für die wirklich hilfreiche Unterstützung.

Angehängte Dateien:
#7775591
Lesenswert?

Karl K. schrieb:

Ich sende die Zeichenfolge (0x010300000001840a) an den Wechselrichter. Wenn der Wechselrichter "0x0103020005 + 2byte crc" antwortet, funktioniert die Kommunikation in beide Richtungen.

Die Oszi-Bilder 2+3 sehen erkennbar anders aus als Bild 1.

Mal in Ernst. Was soll das? Dein Oszi kann DIGITALE, SCHARFE Screenshots auf USB ausgeben. NUTZE DAS! Nicht diesen verwaschenen Mist mit dem Handy!

Die dreieckigen Zacken können nicht als eindeutige digitale rs485-Signale ausgewertet werden - Hardwareproblem.

Ja welches Signal sehen wird denn da wirklich? An welchem IC an welchem Pin wurde gemessen?

Der Adapter ist in der Lage, Signale vom PC umzuformen - nicht jedoch Signale vom WR. Die sind vermutlich ein bisschen anders und daher in einem Grenzbereich, den der Adapter nicht auswerten kann.

Glaub ich nicht. Ist eher ein Schaltungsfehler deinerseits.

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