Forum: Mikrocontroller und Digitale Elektronik RS485 nach 2,5 Paketen ist schluss


von Christian P. (peterfrosta)


Angehängte Dateien:

Lesenswert?

Hallo Zusammen,

nach 3 Nächten des rum Probierens, versuche ich euch in Anspruch zu 
nehmen.

Bei einem Projekt versuche ich eine RS485 Verbindung zu integrieren.

Das Problem ist, dass ein Board 16 Bytes sendet und eine 16 byte antwort 
bekommt. das funktioniert wenn ich das erste Paket sende. Bei dem 
zweiten kommt keine Rückantwort.
Gesendet wird das zweite Paket ordnungsgemäß (logikanalyser am 
Empfängerboard)

Zig Varianten mit delay habe ich aus probiert:
- delay vor/hinter senden/empfangen Sendempdus aktivieren/deaktivieren

komme nicht weiter und bin am ende ;)

Hardware:
2 Board mit Atmega --> usart --> MAx485... (später mehrere Boards).
Test Distanz: Beide auf einem Tisch.
Masse nicht mit geführt.

Software:
Baud 9600
Board A:
- sende 16 byte
- Empfange 16 byte antwort
- warte 10 ms  (wurde als versuch eingefügt, ging vorher genau so wenig)
- sende 16 byte an Board B
- Empfange 16 byte antwort

Board B:
- Empfange 16 byte
- warte 10 ms  (wurde als versuch eingefügt, ging vorher genau so wenig)
- sende 16 byte antwort
- Empfange 16 byte
- warte 10 ms  (wurde als versuch eingefügt, ging vorher genau so wenig)
- sende 16 byte antwort


Im Anhang ist eine die Ausgabe vom Logiganalyser.
Unten sind die Ausgaben (send16Byte) von Board A und B.
Oben  sieht man wann welches Board in welchem Modus ist.
Dafür ist unmittelbar vor und nach jedem Send16Byte und dem Rec16Byte 
ein Puls auf Portpin programmiert.

Hier die Funktionen:
(Bitte denkt dran, ich hab viel mit delay ausprobiert. Erstens würde ich 
selbst lieber ohne delay auskommen und zweitens habe ich viele Werte 
versucht, dass ich keine Ahnung mehr habe, welche besser wären. Daher 
nehme ich da sehr gerne Empfehlungen entgegen. Blödes rum gemotze weil 
delays im Code stehen, kann man sich sparen. Dann lieber Hinweise wie es 
besser geht :-) )

//___ ein byte empfangen
unsigned int rs485_getc(void)
{
  //___warten auf Receive Complete
  while(bit_is_clear(UCSR0A,RXC0));
  return UDR0;
}

//16 Byte-String empfangen auf USART - Ohne Autolinefeed
void rs485_rec_16Byte(char *s)
{
  uint8_t i = 0;
  while(i<16)
  {
    s[i] = rs485_getc();
    i++;
  }
_delay_ms(1);
}

//___Ein Byte senden für RS485
void rs485_putc(unsigned char byte)
{
  //___warten auf Datenregister "frei"
  while(bit_is_clear(UCSR0A,UDRE0));
  //tue das nur wenn zuvor noch empfangsmodus ist (low)
  if( !(PINH & (1<<PORTH7)) )
  {
    //RS485 auf Sendemodus
    //muss in den anderen Funktionen wieder beendet werden!
    PORTH |= (1<<PORTH7);
    //_delay_ms(1);
  }
  UDR0=byte;

}

//16 Byte-String senden auf USART - Ohne Autolinefeed
void rs485_send_16Byte(char *s)
{
  uint8_t i = 0;
        _delay_ms(10);
  while(i<16)
  {
    rs485_putc(*s);
    s++;
    i++;
  }
  while( bit_is_clear(UCSR0A, TXC0) );
        _delay_ms(5);
  PORTH &= ~(1<<PH7);   //sendemodus beenden - Empfänger aktiv
        _delay_ms(3);
}

Im Screenshot kann mann sehen, dass das erste Paket und die Antwort 
ankommen und danach auch erst der jweilige Empfänger aus der rec_16Byte 
funktion kommt (1. & 2.gestrichelte linie).

Das zweite Paket hingegen wird nicht richtig empfangen. Board B verlässt 
die rec_16Byte funktion, obwohl nicht alle Byte auf dem Bus waren...

Wie kann das sein? Eigentlich dürfte Board B zuvor nichts empfangen bis 
Board A sendet. Empfänger Controller scheint dann aber noch nicht 
"abgestürzt" zu sein.

HILFEEEE!  :-)

: Bearbeitet durch User
von Bernhard S. (dl9rdw)


Lesenswert?

Ist PH7 bei Dir das gleiche wie PORTH7?

Wenn dem so ist, kann ich im Moment auf den ersten Blick nichts 
erkennen, warum das nicht öfter als 1x funktionieren sollte.

von spess53 (Gast)


Lesenswert?

Hi

>  //___warten auf Datenregister "frei"
>  while(bit_is_clear(UCSR0A,UDRE0));

Du solltest auf TXC0 prüfen. UDRE0 gibt nur an, das der Puffer leer ist, 
aber nicht, das das Byte schon fertig gesendet wurde.

MfG Spess

von Christian P. (peterfrosta)


Lesenswert?

Bernhard Schröcker schrieb:
> Ist PH7 bei Dir das gleiche wie PORTH7?

Sollte so sein. AtmelStudion schimpft nicht...

spess53 schrieb:
> Du solltest auf TXC0 prüfen. UDRE0 gibt nur an, das der Puffer leer ist,
> aber nicht, das das Byte schon fertig gesendet wurde.

Sowas hatte ich mal aufgenschappt und in die send16Byte eingebaut.
Also ist die 1Byte ebene put_c der richtige ort dafür??

Kann ich nicht sofort testen :-/ erst gleich...

man kann leider von iphone nicht auf "absenden" drücken!

danke schon mal und grüße!

von spess53 (Gast)


Lesenswert?

Hi

>Also ist die 1Byte ebene put_c der richtige ort dafür??

Der richtige Ort ist die Stelle, an der deine Übertragung beendet ist.

MfG Spess

von Kaj (Gast)


Lesenswert?

spess53 schrieb:
> Hi
>
>>  //___warten auf Datenregister "frei"
>>  while(bit_is_clear(UCSR0A,UDRE0));
>
> Du solltest auf TXC0 prüfen. UDRE0 gibt nur an, das der Puffer leer ist,
> aber nicht, das das Byte schon fertig gesendet wurde.

Aus einem ATmega-Datenblatt:
1
C Code Example 
2
void USART_Transmit( unsigned char data )
3
{
4
  /* Wait for empty transmit buffer*/
5
  while( !( UCSRnA & (1<<UDREn)) )
6
    ;
7
  /* Put data into buffer, sends the data*/
8
  UDRn = data;
9
}

Bernhard Schröcker schrieb:
> Ist PH7 bei Dir das gleiche wie PORTH7?
PH7 ist nichts anderes als ein
1
# define PH7    7

von spess53 (Gast)


Lesenswert?

Hi

>Aus einem ATmega-Datenblatt:

>C Code Example
>void USART_Transmit( unsigned char data )
>{
>  /* Wait for empty transmit buffer*/
>  while( !( UCSRnA & (1<<UDREn)) )
>    ;
>  /* Put data into buffer, sends the data*/
>  UDRn = data;
>}

Und was heißt das? UDRE zeigt an das der USART-Puffer  ein neues Byte 
aufnehmen kann. Das ist aber schon so, wenn das letzte Byte von UDR in 
das Schieberegister transferiert wurde und gerade gesendet wird.

Mfg Spess

von Christian P. (peterfrosta)


Lesenswert?

spess53 schrieb:
> Der richtige Ort ist die Stelle, an der deine Übertragung beendet ist.

das beantwortet meine frage nicht.
für mich ist die übertragung nach 16 Byte zu ende... aber das Register 
reagiert ja nicht nach meinen wünschen.
Aber ich habe die funktionen nun geändert und die Tx0 abfrage in die 
put_c gepackt.

leider keine besserung. das zweite paket wird vom Board b noch immer zu 
früh als empfangen erkannt...

//___Ein Byte senden für RS485
void rs485_putc(unsigned char byte)
{
  //___warten auf Datenregister "frei"
  while(bit_is_clear(UCSR0A,UDRE0));
  //tue das nur wenn zuvor noch empfangsmodus ist (low)
  if( !(PINH & (1<<PORTH7)) )
  {
    //RS485 auf Sendemodus
    //dieser muss in den anderen Funktionen wieder beendet werden!
    PORTH |= (1<<PORTH7);
    //_delay_ms(1);
  }
  UDR0=byte;
  while( bit_is_clear(UCSR0A, TXC0) );

}



//16 Byte-String senden auf USART - Ohne Autolinefeed
void rs485_send_16Byte(char *s)
{
  uint8_t i = 0;
_delay_ms(10);
  while(i<16)
  {
    rs485_putc(*s);
    s++;
    i++;
  }
  //while( bit_is_clear(UCSR0A, TXC0) );
_delay_ms(5);
  PORTH &= ~(1<<PH7);    //sendemodus beenden - Empfänger aktiv
_delay_ms(3);
}

habt ihr noch weitere ideen?
gruß

von Christian P. (peterfrosta)


Lesenswert?

spess53 schrieb:
> Der richtige Ort ist die Stelle, an der deine Übertragung beendet ist.

das beantwortet meine frage nicht.
für mich ist die übertragung nach 16 Byte zu ende... aber das Register 
reagiert ja nicht nach meinen wünschen.
Aber ich habe die funktionen nun geändert und die Tx0 abfrage in die 
put_c gepackt.

leider keine besserung. das zweite paket wird vom Board b noch immer zu 
früh als empfangen erkannt...

//___Ein Byte senden für RS485
void rs485_putc(unsigned char byte)
{
  //___warten auf Datenregister "frei"
  while(bit_is_clear(UCSR0A,UDRE0));
  //tue das nur wenn zuvor noch empfangsmodus ist (low)
  if( !(PINH & (1<<PORTH7)) )
  {
    //RS485 auf Sendemodus
    //dieser muss in den anderen Funktionen wieder beendet werden!
    PORTH |= (1<<PORTH7);
    //_delay_ms(1);
  }
  UDR0=byte;
  while( bit_is_clear(UCSR0A, TXC0) );

}



//16 Byte-String senden auf USART - Ohne Autolinefeed
void rs485_send_16Byte(char *s)
{
  uint8_t i = 0;
_delay_ms(10);
  while(i<16)
  {
    rs485_putc(*s);
    s++;
    i++;
  }
  //while( bit_is_clear(UCSR0A, TXC0) );
_delay_ms(5);
  PORTH &= ~(1<<PH7);    //sendemodus beenden - Empfänger aktiv
_delay_ms(3);
}

habt ihr noch weitere ideen?
gruß

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Christian Peskov schrieb:
> das zweite paket wird vom Board b noch immer zu
> früh als empfangen erkannt...

Was genau meinst Du damit?

von spontan (Gast)


Lesenswert?

>für mich ist die übertragung nach 16 Byte zu ende...

Die Übertragung ist zu Ende, wenn das letzte Byte den UART verlassen 
hat, nicht, wenn der UART für das 17. Byte bereit wäre (siehe auch oben)


> aber das Register reagiert ja nicht nach meinen wünschen.

Wie soll es auch, die Art, wie das Register reagiert ist im Dateblatt 
festgelegt, Deine Wünsche spielen da keine große Rolle.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

* In welchen Pegel springt denn dein Bus, wenn du nichts sendest? Wird 
das von der Gegenstelle evtl. als Startbit interpretiert?
* Oszillografier doch mal Daten und die SE/RE Signale der Transceiver. 
Dann weisst du, ob evtl. die Senderoutine zu früh auf RE umschaltet, 
oder ob da noch was auf SE steht, wenn doch eigentlich empfangen werden 
soll.

Übrigens, im Datenblatt zum Mega8 steht der folgende Hinweis:

The TXC Flag can be used to check that the Transmitter has completed all 
transfers, and the RXC Flag can be used to check that there are no 
unread data in the receive buffer. *Note that the TXC Flag must be
cleared before each transmission (before UDR is written) if it is used 
for this purpose*.

: Bearbeitet durch User
von Christian P. (peterfrosta)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Was genau meinst Du damit?

siehe screenshot oben - 3. gestrichelte linie.

spontan schrieb:
> Die Übertragung ist zu Ende, wenn das letzte Byte den UART verlassen
> hat, nicht, wenn der UART für das 17. Byte bereit wäre (siehe auch oben)

ok also nicht nach jedem byte sondern nach dem letzten. dem 16. Byte. 
Steht das nciht so 3 kommentare weiter oben??
Christian Peskov schrieb:
> //16 Byte-String senden auf USART - Ohne Autolinefeed
> void rs485_send_16Byte(char *s)
> {
>   uint8_t i = 0;
> _delay_ms(10);
>   while(i<16)
>   {
>     rs485_putc(*s);
>     s++;
>     i++;
>   }
>   //while( bit_is_clear(UCSR0A, TXC0) );
> _delay_ms(5);
>   PORTH &= ~(1<<PH7);    //sendemodus beenden - Empfänger aktiv
> _delay_ms(3);
> }

Matthias Sch. schrieb:
> * Oszillografier doch mal Daten und die SE/RE Signale der Transceiver.
> Dann weisst du, ob evtl. die Senderoutine zu früh auf RE umschaltet,
> oder ob da noch was auf SE steht, wenn doch eigentlich empfangen werden
> soll.
Da komm ich so schlecht dranne, aber gute idee, werde ich heute  tun!

Matthias Sch. schrieb:
> * In welchen Pegel springt denn dein Bus, wenn du nichts sendest? Wird
> das von der Gegenstelle evtl. als Startbit interpretiert?
das muss ich überprüfeni ch glaube die waren in der tag auf high pegel. 
schau ich nach!

Matthias Sch. schrieb:
> The TXC Flag can be used to check that the Transmitter has completed all
> transfers, and the RXC Flag can be used to check that there are no
> unread data in the receive buffer. *Note that the TXC Flag must be
> cleared before each transmission (before UDR is written) if it is used
> for this purpose*.

das hatte ich gstern nicht richtig interpretieren können (vllt zu spät) 
jetzt liest es sich recht deutlich :-)

Also vor  dem senden "cleare" ich TX0 und warte danach auf TX =1.
dann stellt sich folgende Frage wieder:
Vor und nach jedem Byte?
Oder vor und nach jedem 16 Byte paket?
jede nachricht soll ja 16 Byte lang sein.

ich danke euch!

von Christian P. (peterfrosta)


Lesenswert?

was zum Screenshot vllt wichtig ist und bisher unwerähnt...

das was unter A und B als gesendete Bytes in den unteren beiden Reihen 
zu sehen ist wurde jeweils auf dem Board B zwischen dem MAX485 und dem 
Atmega abgegriffen. ist also schon vom MAX485 auf atmega usart 
umgesetzt.

Also kommt auch das zweite Paket sauber durch den MAX485 an Board B, an 
Rx an?!

Durch die Peaks sieht man ja, dass Board B in die empfangs routine geht 
und sie zu früh verlässt.


Das erste Paket kommt an und die erste Antwort geht fehlerfrei raus.
Board B geht das zweite Mal in die Empfangsroutine und empfängt nicht 
vorhandene Daten und stoppt deshalb bevor alle 16 Byte des zweiten 
Pakets überhaupt aus Board A raus sind.

Also werden doch zuvor  schon Daten von der Empfangroutine get_c 
erkannt??!
Gibt es typische Ursachen dafür?

Wenn ich später usart, RS485 und SE/RE aufnehme werde ich mal noch 
peacks in
  //___warten auf Receive Complete
  while(bit_is_clear(UCSR0A,RXC0));

einfügen, um zu sehen wann er die while verlässt.

Im Screenshot sieht man noch, dass die pegel von Rx und Tx (am atmega) 
zwischen allesn paketen auf HIGH ist. ist das in Ordnung?

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Christian Peskov schrieb:
> Im Screenshot sieht man noch, dass die pegel von Rx und Tx (am atmega)
> zwischen allesn paketen auf HIGH ist. ist das in Ordnung?

Jo, high auf den seriellen Leitungen bedeutet inaktiv.

Christian Peskov schrieb:
> Also vor  dem senden "cleare" ich TX0 und warte danach auf TX =1.
> dann stellt sich folgende Frage wieder:
> Vor und nach jedem Byte?

Du setzt TXC vor dem Senden des Byte zurück (1 reinschreiben). Dann UDR 
beschreiben. TXC wird gesetzt, wenn das Byte komplett gesendet wurde. 
Also vor jeden Byte zurücksetzen, bei dem du wissen willst, wann es 
fertig gesendet ist.

: Bearbeitet durch User
von Christian P. (peterfrosta)


Lesenswert?

Also... ich habe nun mit allen möglichen Pin den logic anlayser nochmal 
drüber gelassen. Alles sah gut aus und funktionierte totzdem nicht.
Dann habe ich mal das übrige Projekt aus geklammert und mehrer hin und 
her sendungen funktionierten gut. mit verschieden pausenlängen.

Werde also mal den code aufräumen müssen. Irgendwas im übrigen code 
fuscht da wohl rein. ist mir bisher unerklärlich... ich werde was melde 
wenn ich es herausfinde oder weitere probleme kommen.

Danke schon mal an alle!

von Christian P. (peterfrosta)


Lesenswert?

dummheit gehört bestraft :-/
oder verlorener überblick.

problem war, dass Board B vor der Antwort Bytes vom Payload änderte.
Board A schickte das übernommene Payload dann im zweiten Package zu 
Board B,
wo es die Prüfung nicht bestand und deshalb keine zweites Mal gesendet 
wurde! Ziemlich dämlich so weit unten zu suchen wo der Fehler doch erst 
durch Änderungen in obere Ebene auftrat.
Leider hat mich der Logic Analyser gleich auf die Bit-Ebene gedrängt.

Auch dadurch habe ich nicht bemerkte, dass mein Code nicht in jedem Fall 
eine Antwort zu lässt bzw ich das Payload ändern lasse und dadurch die 
Bedingungen nicht mehr passen.

jedenfalls trotzdem danke an alle.

Meine RS485 Routinen sind durch eure Vorschläge jedenfalls nicht 
schlechter geworden! bzw sind optimierter.

grüße!

ps: kann ich das hier irgendwie als gelöst makieren?

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Christian Peskov schrieb:
> Leider hat mich der Logic Analyser gleich auf die Bit-Ebene gedrängt.

Es war ja nicht vorherzusehen und deswegen gut, das du nachgeschaut 
hast. Es hat dich ja per Ausschlussverfahren zur Lösung gelenkt.

Christian Peskov schrieb:
> wo es die Prüfung nicht bestand und deshalb keine zweites Mal gesendet
> wurde!

Diesen Fehler musst du natürlich abfangen, denn im wahren Leben kann das 
auch passieren. Ein Signal a la 'Was war das denn, da war was faul' 
könnte dem Sender helfen, das Päckchen nochmal zu verschicken oder 
anderweitig sauber auszusteigen.

: Bearbeitet durch User
von Christian P. (peterfrosta)


Angehängte Dateien:

Lesenswert?

Danke Matthias.


leider  ist da immer noch der wurm drin...

hatte hier schon nen riesen roman geschrrieben aber versuche es nun mit 
bilder kürzer.

ich empfange die zweite Antwort noch immer nicht richtig.
Die zweite Rückantwort ist um 3 Bytes nach hinten verschoben. Das 
eigentliche Byte0 ist auf Stelle von Byte3. Die ersten 3 Bytes sind 
falsch und die Werte mir unbekannt :-(
Wie soooo? Das nervt....

Ich stelle fest:
Wenn der Empfänger das erste Mal Antwortet und auf Empfang umschaltet, 
werden umnittelbar 3 Bytes empfangen.

Wie kann ich das verursacht haben??
die nächste nachricht ist da noch "längst" nicht in sicht!!

Bild 1 zeigt die Übersicht
Bild 2 zoomt auf die pseudo Bytes nach dem ersten Antwort des Empfängers
Bild 3 zeigt die folgenden "kaputt" empfangenen 16 Bytes.

zeigt das jemanden die Ursache auf??

Hiiilfe!

zur Anschauung noch mal die verwendeten Funktionen:
//___Ein Byte senden für folge funtkionen
void rs485_putc(uint8_t byte)
{
  while(bit_is_clear(UCSR0A,UDRE0));    //___warten auf Datenregister 
"frei"
  UDR0=byte;
//   PORTB |= (1<<PORTB3);
//   PORTB &= ~(1<<PORTB3);
  while( bit_is_clear(UCSR0A, TXC0) );  //___warten bis Sendung 
abgeschlossen
}


//16 Byte-String senden auf USART - Ohne Autolinefeed
void rs485_send_16Byte(uint8_t *s)
{
  uint8_t i = 0;

  _delay_ms(15);
  PORTC |= (1<<PORTC4);    //RS485 auf Sendemodus
  _delay_ms(5);
  while(i<16)
  {
    rs485_putc(*s);
    s++;
    i++;
  }
_delay_ms(5);
  PORTC &= ~(1<<PORTC4);    //sendemodus beenden - Empfänger aktiv
_delay_ms(5);
}


//___ ein byte empfangen
unsigned int usart_getc(void)
{
  //___warten auf Receive Complete
  while(bit_is_clear(UCSR0A,RXC0) );
    PORTB |= (1<<PORTB3);
    PORTB &= ~(1<<PORTB3);
  return UDR0;
}

//16 Byte-String empfangen auf USART - Ohne Autolinefeed
void rs485_rec_16Byte(uint8_t *s)
{
  uint8_t i = 0;

  PORTB |= (1<<PORTB3);
  PORTB &= ~(1<<PORTB3);

  _delay_ms(5);
  while(i<16)
  {
    s[i] = usart_getc();
    i++;
  }
}

: Bearbeitet durch User
von Christian P. (peterfrosta)


Angehängte Dateien:

Lesenswert?

vllt ist das die lösung?!

von spess53 (Gast)


Lesenswert?

HI

>  //___warten auf Receive Complete
>  while(bit_is_clear(UCSR0A,RXC0) );

So etwas wäre für mich ein absolutes No-Go. Wenns mit dem Empfang 
hapert, bleibt das Programm hängen.

MfG Spess

von Christian P. (peterfrosta)


Lesenswert?

spess53 schrieb:
> HI
>
>>  //___warten auf Receive Complete
>>  while(bit_is_clear(UCSR0A,RXC0) );
>
> So etwas wäre für mich ein absolutes No-Go. Wenns mit dem Empfang
> hapert, bleibt das Programm hängen.
>
> MfG Spess

Bleibt so auch nicht... timeout ist nur aktuell aus geklammert bei der 
fehler suche ausgeklammert...

spess du scheinst doch ahnng zu haben...
Hast du eine Meinung zu dem Hinweis aus dem anderen Thread?

Das gehört sich mit Pull-Ups oder?

mfg

von spess53 (Gast)


Lesenswert?

Hi

>Das gehört sich mit Pull-Ups oder?

Das ist die übliche Failsave Beschaltung. Näheres findest du hier (S.8):

http://www.ti.com/lit/pdf/snla049

MfG Spess

von F. H. (Gast)


Lesenswert?

In

> void rs485_putc(uint8_t byte)
> {
>   while(bit_is_clear(UCSR0A,UDRE0));
>   UDR0=byte;
>   while( bit_is_clear(UCSR0A, TXC0) );
> }

wurde das

> The TXC Flag can be used to check that the Transmitter has completed all
> transfers, and the RXC Flag can be used to check that there are no
> unread data in the receive buffer. *Note that the TXC Flag must be
> cleared before each transmission (before UDR is written) if it is used
> for this purpose*.

noch nicht beachtet!

von Christian P. (peterfrosta)


Lesenswert?

auch mit den definierten Pegeln an den Busleitungen, werden die 3 
Pseudobyte  zu früh empfangen.



ich weiß es nicht was ich noch machen soll.
Muss immer ein MAX485 auf "Sender" eingestellt sein?

muss ich den usart Empfänger zwischen durch mal abschalten oder 
"flushen"?

danke. ich bin echt am ende ^^

von Christian P. (peterfrosta)


Lesenswert?

Christian Peskov schrieb:
> auch mit den definierten Pegeln an den Busleitungen, werden die 3
> Pseudobyte  zu früh empfangen.
>
>
>
> ich weiß es nicht was ich noch machen soll.
> Muss immer ein MAX485 auf "Sender" eingestellt sein?
>
> muss ich den usart Empfänger zwischen durch mal abschalten oder
> "flushen"?
>
> danke. ich bin echt am ende ^^

danke bau ich sofort ein....

von Christian P. (peterfrosta)


Lesenswert?

/___Ein Byte senden für RS485
uint8_t rs485_putc(unsigned char byte)
{
       //___warten auf Datenregister "frei"
  while(bit_is_clear(UCSR0A,UDRE0));
  //Timeout fehlt!

  UCSR0A &= ~(1<<TXC0);

  UDR0=byte;
  PORTK |= (1<<PK0);
  PORTK &= ~(1<<PK0);

        //___warten bis Sendung abgeschlossen
  while( bit_is_clear(UCSR0A, TXC0) );
}


bringt leider keine Besserung...
habe den bus aktuell so beschaltet:

5V -(620Ohm)- A -(120Ohm)- B -(620Ohm)- GND

: Bearbeitet durch User
von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Christian Peskov schrieb:
> UCSR0A &= ~(1<<TXC0);

Nee, du musst beim AVR, um ein Bit zu löschen, eine 1 reinschreiben. 
Wäre zumindest das erste mal für mich, das es bei einem AVR umgekehrt 
wäre.

Du hast ja bis jetzt tunlichst vermieden, uns den genauen Typ deines 
Mega zu nennen. Mach das bitte mal. Also, welcher Mega hat PORT K ?

Christian Peskov schrieb:
> peterfrosta

Du unterschlägst übrigens den Adelstitel. M.W. heisst das 'Peter von 
Frosta' :-)

: Bearbeitet durch User
von spess53 (Gast)


Lesenswert?

Hi

>Also, welcher Mega hat PORT K ?

Z.B. ATmega640/1280/2560

MfG Spess

von Christian P. (peterfrosta)


Lesenswert?

Matthias Sch. schrieb:
> Christian Peskov schrieb:
>> UCSR0A &= ~(1<<TXC0);
>
> Nee, du musst beim AVR, um ein Bit zu löschen, eine 1 reinschreiben.
> Wäre zumindest das erste mal für mich, das es bei einem AVR umgekehrt
> wäre.

Ist das so? ist mir ja bisher nie aufgefallen.... ist das speziel für 
flag register so?
habs aber gefunden:

"The TXCn Flag bit is automatically cleared when a transmit complete 
interrupt is executed, or it
can be cleared by writing a one to its bit location."

Werde ich später unbedingt versuchen!

> Du hast ja bis jetzt tunlichst vermieden, uns den genauen Typ deines
> Mega zu nennen. Mach das bitte mal. Also, welcher Mega hat PORT K ?
Das ist aber ohne Grund so heimlich ;)
Board A (Sender) ist ein Atmega2560.
Board B Empfänger (der mit den Pyseudo-Bytes) ist ein Atmega88.

Hatte das nicht unterschieden, um es euch nicht noch komplizierter zu 
machen. Die 4 Funktionen sind auf beiden Boards identisch bis auf die 
Portnamen natürlich.
Die


> Du unterschlägst übrigens den Adelstitel. M.W. heisst das 'Peter von
> Frosta' :-)
tut mir leid matthias :-) ich weiß leider nicht wer der/die  M.W is...

von Peter D. (peda)


Lesenswert?

Matthias Sch. schrieb:
> Übrigens, im Datenblatt zum Mega8 steht der folgende Hinweis:
>
> The TXC Flag can be used to check that the Transmitter has completed all
> transfers, and the RXC Flag can be used to check that there are no
> unread data in the receive buffer. *Note that the TXC Flag must be
> cleared before each transmission (before UDR is written) if it is used
> for this purpose*.

Auweia, das gibt ne dicke Race-Condition.

Nach dem Löschen von TXC kann just das vorherige Byte fertig sein und 
TXC wird gesetzt. Dann schreibst Du ins UDR und testest das bereits 
gesetzte TXC, d.h. das letzte Byte wird abgewürgt.

Du mußt erst in UDR schreiben und danach TXC löschen und falls 
Interrupts enabled sind, muß das atomar erfolgen.

von Christian P. (peterfrosta)


Lesenswert?

Danke für die Hinweise!
Wenn ich Sie unten richtig umgesetzt habe, war das leider nocht nicht 
dir Hauptursache :-(

alles wie gehabt...


//___Ein Byte senden für folge funtkionen
void rs485_putc(uint8_t byte)
{
  while(bit_is_clear(UCSR0A,UDRE0)); //warten auf Datenregister "frei"
  UDR0=byte;
  UCSR0A |= (1<<TXC0);  //1schreiben um flag-tx fertig zuLÖSCHEN!!

  while( bit_is_clear(UCSR0A, TXC0) );  //___warten bis Sendung 
//                                                 abgeschlossen
}

von Peter D. (peda)


Lesenswert?

1
#include <util/atomic.h>
2
3
void rs485_putc(uint8_t byte)
4
{
5
  ATOMIC_BLOCK(ATOMIC_FORCEON){
6
    UDR0=byte;
7
    UCSR0A = UCSR0A;  //1schreiben um flag-tx fertig zuLÖSCHEN!!
8
  }
9
  while( bit_is_clear(UCSR0A, TXC0) );  //___warten bis Sendung 
10
//                                                 abgeschlossen
11
}

von Christian P. (peterfrosta)


Lesenswert?

Peter Dannegger schrieb:
> #include <util/atomic.h>
>
> void rs485_putc(uint8_t byte)
> {
>   ATOMIC_BLOCK(ATOMIC_FORCEON){
>     UDR0=byte;
>     UCSR0A = UCSR0A;  //1schreiben um flag-tx fertig zuLÖSCHEN!!
>   }
>   while( bit_is_clear(UCSR0A, TXC0) );  //___warten bis Sendung
> //                                                 abgeschlossen
> }

Danke für den code!
aber könntest du mir das vllt erläutern?

 ATOMIC_BLOCK(ATOMIC_FORCEON).... sorgt dafür, dass

>  UDR0=byte;
>  UCSR0A = UCSR0A;

ausgeführt  bitweise oder atomar ausgeührt wird. Im Zusammenhang mit den 
Interrupt de- und aktivierung von Atomic. sorgt es wohl dafür, dass kein 
interrupt zwischen in diese beiden Zeilen fuscht.

aber was soll
UCSR0A = UCSR0A;
bewirken??

Desweiteren... der Empfänger  hatte mit dem Senden nicht die Probleme 
(denke ich). Nach dem er vom senden wieder auf Empfang umstellt, kommen 
die Speudo bytes. Allerdings ist da auch der RS485 schon 
deaktiviert(SE). und Dass passiert ja erst nach einer delay von 
Millisekunden. Da dprfte doch keine vergessenen Byte mehr abhol breit 
sein... und warum auch noch bis zu 3?
Hm....

ich mache jetzt neue nackte Projekte auf und mache dort die 
Schnittstelle von grund auf :-(

von Sascha W. (sascha-w)


Lesenswert?

Hallo,

schaltest du am MAX485 den Empfänger während des Sendens aus (RE=1)?
Wenn ja, dann wird der Receiver-Ausgang hochohmig, d.h. du must am AVR 
den Pullup am RX-Pin einschalten, oder extern einen Pullup vorsehen - 
sonst kann sich da was einschleichen.

Sascha

von Christian P. (peterfrosta)


Lesenswert?

Sascha Weber schrieb:
> schaltest du am MAX485 den Empfänger während des Sendens aus (RE=1)?

ja, da ich RS und SE gebrückt habe...
Dann kann ich  keinen Pull up dran löten, sehe ich doch richtig?!



5V -(620Ohm)- A -(120Ohm)- B -(620Ohm)- GND
kommt wird doch nur an einem teilnehmer realisiert oder?

dank vielmals für eure mühen!!

von Peter D. (peda)


Lesenswert?

Christian Peskov schrieb:
> dass kein
> interrupt zwischen in diese beiden Zeilen fuscht.

So isses.
Mag vielleicht hier noch nicht nötig sein, aber Programme werden größer 
und größer und dann denkt man nicht mehr daran.

Christian Peskov schrieb:
> aber was soll
> UCSR0A = UCSR0A;
> bewirken??

Das | ist nicht nötig, ist es gesetzt, wird es gelöscht.
Alle anderen Bits bleiben erhalten bzw. sind read-only.

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.