Forum: Mikrocontroller und Digitale Elektronik USART tx-timing Problem


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Karl K. (leluno)


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

: Bearbeitet durch Moderator
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Karl K. schrieb:
> Ohne _delay_ms(2); werden Werte beim tx verschluckt.
Wie sieht der Aufbau aus? Wer ist der Sender? Wer ist der Empfänger? 
Welche Werte werden verschluckt? Immer die selben oder beliebige?

Oder kurz: was soll das Programm machen und was macht es stattdessen?

von Rainer W. (rawi)


Lesenswert?

Karl K. schrieb:
> altes Problem

Es gibt ein noch viel älteres:

Wichtige Regeln - erst lesen, dann posten!
...
Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Rainer W. schrieb:
> Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang
Der Code an sich ist eigentlich gar nicht mal so lang wenn man die 
unnötigen Leerzeilen rauslöscht. Hab ich mal gemacht...

von Karl K. (leluno)


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?

von Rainer W. (rawi)


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 ;-)

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


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...

: Bearbeitet durch Moderator
von Falk B. (falk)


Angehängte Dateien:

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.

von Falk B. (falk)


Lesenswert?

So mit einem Pointer auf ein Bytearray.
1
void serial_read(uint8_t *x)
2
{
3
    uint8_t tmp;
4
5
    PORTC|=(1<<2);      // Sender aktiv
6
    ct_tx_isr=0;
7
    for (uint8_t i=0; i < 8; i++)
8
    {
9
        while(!(UCSR0A & (1<<UDRE0));        
10
        serial_char(*x++);
11
    }

von Karl K. (leluno)


Lesenswert?

Lothar M. schrieb:
> 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...

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.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Angehängte Dateien:

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...

: Bearbeitet durch Moderator
von Rainer W. (rawi)


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.

: Bearbeitet durch User
von Falk B. (falk)


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

von Falk B. (falk)


Lesenswert?

Rainer W. schrieb:
> Was ist ein M328-Nano? Selbst Google ist da etwas hilflos.

ATmega328 auf dem Arduino Nano. Ok, diese Wortschöpfung ist unnötig und 
verwirrend.

von Falk B. (falk)


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.

von Karl K. (leluno)


Lesenswert?

Falk B. 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.

von Falk B. (falk)


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.

von Karl K. (leluno)


Angehängte Dateien:

Lesenswert?

Vielen dank für die Hilfe. Fehler war tatsächlich txc0 1 statt 0 zum 
löschen. Ich hatte offenbar nur bis >cleared by writing< gelesen und mir 
den Rest falsch gedacht.

von Karl K. (leluno)


Angehängte Dateien:

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?

von Mi N. (msx)


Lesenswert?

Karl K. schrieb:
> Empfang M328-WR(Bild 2 +3)kommt kein brauchbares Signal.

Das kann man auf den Fotos ja auch ganz deutlich sehen :-(

von Rainer W. (rawi)


Lesenswert?

Mi N. schrieb:
> Das kann man auf den Fotos ja auch ganz deutlich sehen :-(

Wozu mag diese komische USB-Schnittstelle beim Hantek DSO2D15 wohl gut 
sein? ;-)

von Mi N. (msx)


Lesenswert?

Rainer W. schrieb:
> Wozu mag diese komische USB-Schnittstelle beim Hantek DSO2D15 wohl gut
> sein? ;-)

In diesem Fall nur, um Krabben- von Feldsalat zu unterscheiden.

von Falk B. (falk)


Lesenswert?

Mi N. schrieb:
>> Wozu mag diese komische USB-Schnittstelle beim Hantek DSO2D15 wohl gut
>> sein? ;-)
>
> In diesem Fall nur, um Krabben- von Feldsalat zu unterscheiden.

I shot the sherif, but I did'nt shoot the screeeeeen, ohhh noooooo . . . 
;-)

von Falk B. (falk)


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.

von Karl K. (leluno)


Angehängte Dateien:

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.

von Falk B. (falk)


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.

von Karl K. (leluno)


Lesenswert?

Noch ne Frage:

low-level ist laut Oszi 1,72Volt bei 4,72 Volt Vcc. Das reicht wohl 
nicht ganz, dass der uc das als low erkennen kann.

Was tun? pull-down? wie groß?

von Falk B. (falk)


Lesenswert?

Karl K. schrieb:
> Noch ne Frage:
>
> low-level ist laut Oszi 1,72Volt bei 4,72 Volt Vcc. Das reicht wohl
> nicht ganz, dass der uc das als low erkennen kann.
>
> Was tun? pull-down? wie groß?

Welches Signal an welchem IC? Schaltplan? Siehe Netiquette!

von Karl K. (leluno)


Lesenswert?

Signal an der Stelle x gemessen:


adapter GND----x-----GND M328
        RXD----x-----RX
        TXD----------Tx
        VCC----------Vin

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.