RS485 empfang und senden

Gast #3252215
Lesenswert?

Hallo,
Empfänger:
Mµ:Atmega8-16 mit 16MHz Quarz

Mein Sendestring sieht so aus  uart_puts("0xA4\r" );

Ich versuche nun meine RS485 Test-Routiene zum laufen zu bringen
aber ich kann nur einmal etwas empfangen.
Das Senden geht überhauptnich.



Wenn ich anstelle von den RS485 Baustein ein Max232 anschliese 
funktioniert alles.

Vielleicht könnte mir einer Weiterhelfen

mfg

1
#define UART_MAXSTRLEN 10
2
 
3
volatile uint8_t uart_str_complete = 0;     // 1 .. String komplett empfangen
4
volatile uint8_t uart_str_count = 0;
5
volatile char uart_string[UART_MAXSTRLEN + 1] = "";
6

7
ISR(USART_RXC_vect)
8
{
9
  unsigned char nextChar;
10
 
11
  // Daten aus dem Puffer lesen
12
  nextChar = UDR;
13
  if( uart_str_complete == 0 ) {  // wenn uart_string gerade in Verwendung, neues Zeichen verwerfen
14
 
15
    // Daten werden erst in uart_string geschrieben, wenn nicht String-Ende/max Zeichenlänge erreicht ist/string gerade verarbeitet wird
16
    if( nextChar != '\n' &&
17
        nextChar != '\r' &&
18
        uart_str_count < UART_MAXSTRLEN ) {
19
      uart_string[uart_str_count] = nextChar;
20
      uart_str_count++;
21
    }
22
    else {
23
      uart_string[uart_str_count] = '\0';
24
      uart_str_count = 0;
25
      uart_str_complete = 1;
26
    }
27
  }
28
}
29

30

31
void uart_puts (char *s)
32
{
33

34
UCSRA |= (1<<TXC);                  // clear txc flag
35

36
    while (*s)
37
    {   /* so lange *s != '\0' also ungleich dem "String-Endezeichen(Terminator)" */
38
        UDR = *s;
39
        s++;
40
    }
41
  
42
  
43
}
44

45

46
void setTransmitMode( void )
47
{
48
 PORT_UART_OUT |= ( 1 << PIN_UART_OUT );
49
}
50

51
void setReceiveMode( void )
52
{
53
  while ( !( UCSRA & (1<<TXC)) );    // Wait for empty transmit buffer
54
  //UCSRA |= (1<<TXC);                  // clear txc flag
55

56
  PORT_UART_OUT &= ~( 1 << PIN_UART_OUT );
57
}
58

59
uint8_t c;
60
uint8_t c1;
61

62
//mainloop:
63
 for (;;)
64
 {   
65

66
   if (uart_str_complete == 1)
67
      {  
68
        uart_str_complete = 0;
69
        c =    uart_string[0];           //Hole Daten vom UART ab 
70

71

72
         if (c==0xA4)          
73
          {
74
           c1=uart_string[1];
75
           setTransmitMode();     //Sende-Pin auf HIGH schalten
76
           uart_puts("TEST OK" ); 
77
           setReceiveMode();       //Sende-Pin auf LOW schalten
78
          }
79

80
      }
81
      
82
 }
83
}
Gast #3252250
Lesenswert?

runtastic schrieb:
> Ist der RS485 Baustein auf senden gestellt?
1
//Port init
2
//AUSGÄNGE PORTD
3
#define PORT_UART_OUT     PORTD
4
#define DDR_UART_OUT      DDRD
5
#define PIN_UART_OUT      PD2
6

7
DDR_UART_OUT  |= ( 1 << PIN_UART_OUT );

ja klar setTransmitMode(); schaltet auf high DE und RE
und setReceiveMode(); schaltet dann wieder auf low
Gast #3252267
Lesenswert?

denken die Funktionen:

setTransmitMode();
setReceiveMode();

auch an eine Zeitliche Verzögerung?

Ich würde folgendes Testen:

setTransmitMode();     //Sende-Pin auf HIGH schalten
delay_ms(5);           // eine Verzögerung
uart_puts("TEST OK" );
Gast #3252297
Lesenswert?

Spess53 schrieb:
> Hi
>
>>UCSRA |= (1<<TXC);                  // clear txc flag
>
>>    while (*s)
>>    {   /* so lange *s != '\0' also ungleich dem "String->
>>        UDR = *s;
>>        s++;
>>    }
>
> Damit überfährst du die UART gnadenlos.
>
> MfG Spess

Das ist eindeutig
void uart_puts (char *s)
{

UCSRA |= (1<<TXC);                  // clear txc flag

    while (*s)
    {

         while (!(UCSRA & (1<<UDRE)))  /* warten bis Senden moeglich */
         {
         }

  /* so lange *s != '\0' also ungleich dem 
"String-Endezeichen(Terminator)" */
        UDR = *s;
        s++;
    }


}



Trotzdem bekomme ich nur ab und zu den String empfangen
#3252340
Lesenswert?

@Tim (Gast)

>Welche Optimierungsstufe nutzt du vom gcc?
>ggf schmeisst das der ggc nämlich raus:

Nö, Zugiffe auf IO-Register sind volatile und damit nicht entfernbar.

while (!(UCSRA & (1<<UDRE)));  /* warten bis Senden moeglich */

mit Semikolon am Ende reicht.
Gast #3252429
Lesenswert?

@Falk Brunner:
Ok, Danke für den Hinweis.

@Sven (Gast):
Ich habe mir nochmal den Code angesehen und der passt soweit.

>Wenn ich anstelle von den RS485 Baustein ein Max232 anschliese
>funktioniert alles.

Also doch eher Richtung Hardware.
Mal Dauerhaftes senden versucht?

Was hast du auf der anderen Seite? Einen PC?
Kann es sein das der nicht schnell genug von senden
auf empfangen umschaltet? Also im µC mal ein delay
vor dem umschalten zum Senden einbauen.

Kannst du mit einem 3 Teilnehmer der Bus belauschen?

Hast du eine Aktive Terminierung am bus damit
der sich nicht jeden Müll einfängt?
(+5V 620R A 120R B 620R GND)
Gast #3252458
Lesenswert?

Tim schrieb:
> @Falk Brunner:
> Ok, Danke für den Hinweis.
>
> @Sven (Gast):
> Ich habe mir nochmal den Code angesehen und der passt soweit.
>
>>Wenn ich anstelle von den RS485 Baustein ein Max232 anschliese
>>funktioniert alles.
>
> Also doch eher Richtung Hardware.
> Mal Dauerhaftes senden versucht?
>
> Was hast du auf der anderen Seite? Einen PC?
> Kann es sein das der nicht schnell genug von senden
> auf empfangen umschaltet? Also im µC mal ein delay
> vor dem umschalten zum Senden einbauen.
>
> Kannst du mit einem 3 Teilnehmer der Bus belauschen?
>


also ich verwende ein Stm32F103 Board(3.3V) als Master der sendet dan 
uart_puts("0xA4\r" ) das wird auch vom Slave(atmega8 5V) auch jedesmal 
erkannt.

wenn ich nun vom slave etwas zurück senden will wird nur manchmal etwas 
empfangen.

> Hast du eine Aktive Terminierung am bus damit
> der sich nicht jeden Müll einfängt?
> (+5V 620R A 120R B 620R GND)
Ich hab nur zwischen A 120R B

aber es sind ja nur 2Teilnehmer soll sich da die Terminierung so sehr 
auswirken??
Gast #3252506
Lesenswert?

Probiert mal folgendes:

Nachdem das letzte byte ins UDR geschickt wird das "send complete" Flag 
pollen. Und erst wenn das Byte komplett auf dem Bus liegt den receive 
mode einschalten.

Im Moment wird das letzte Byte einfach abgeschnitten.
Gast #3252512
Lesenswert?

Wenn du nur 120Ohm dran hast dann mal schauen ob der RS485 Baustein 
failsafe ist. 0V sind bei RS485 nicht definiert, also weder logisch 1 
noch 0. Damit haben dann die nicht failsafe Transceiver ein Problem das 
Startbit  zu erkennen.
Gast #3252525
Lesenswert?

>wenn ich nun vom slave etwas zurück senden will wird nur manchmal etwas
>empfangen.

Wie gesagt lass den slave mal eine kurze Pause machen bevor er 
antwortet.

>aber es sind ja nur 2Teilnehmer soll sich da die Terminierung so sehr
>auswirken??

Der Trick sind 2x 620R.
Dadurch wird der Bus auf einem Definierten Pegel gehalten
und hängt nicht frei in der Luft wenn beide im Empfangsmodus sind.

Andere Sache: Dein Master schaltet den Empfänger aus wenn er sendet?
Nicht das er sich selbst hört und dadurch die Software aus dem Tritt 
kommt.
#3252543
Lesenswert?

Hab gerade den max1487 erfolgreich am laufen. Daher kurz folgendes 
beachten:

- Wenn du den max485 auf transmit setzt, dann schicke gleich mal zwei 
0x00 Bytes vorweg, damit die nachfolgenden Start/Stop-Bits korrekt 
erkannt werden können. Das produziert schlimmstenfalls einen oder zwei 
Frame-Error beim Empfänger, aber dafür kommt der Rest dann auch an.
z.B. bei DMX wird auch erstmal für eine bestimmte Zeit (88µS?) die 
Leitung auf einen festen Pegel gesetzt, zum einen für die Startkennung, 
zum anderen eben um die StartBits sauber erkennen zu können.

- Wenn du Daten in UDR raufschiebst ist die Verwendung von UDRIE 
optimal, damit die nächsten Daten bereitgestellt werden noch bevor das 
vorangegangene Byte abgesetzt wurde. Aber eben nicht um nach dem letzten 
Byte den transciever wieder umzuschalten...

- ,denn du musst auch TXCIE nutzen um beim letzten zu sendenden Byte den 
transciever auf "recieve" umzuschalten, NACHDEM das letzte Byte komplett 
inkl. Stop-Bit abgesetzt wurde.

- Verdrahtung mit ordentlichem Massebezug und Terminierung (2x120Ohm) 
vorrausgesetzt...

Hinweis zu TXCIE und UDRIE. TXCIE ist flankengesteuert und kommt nur 
einmal nachdem ein Byte erfolgreich gesendet wurde, aber UDRIE blockiert 
so lange, bis man entweder ein neues Byte in UDR schiebt oder eben UDRIE 
deaktiviert.
Meine Lösung ist momentan nicht dolle und für 9Bit, aber tut. Ggf. kann 
ich sie dir schicken.
Gast #3252579
Lesenswert?

Hi

>Hinweis zu TXCIE und UDRIE. TXCIE ist flankengesteuert und kommt nur
>einmal nachdem ein Byte erfolgreich gesendet wurde, aber UDRIE blockiert
>so lange, bis man entweder ein neues Byte in UDR schiebt oder eben UDRIE
>deaktiviert.

xxxIE heißt, Interrupt Enable. Was soll da flankengesteuert sein?

MfG Spess
Gast #3252630
Lesenswert?

1.ich hab mal in einer endlosschleife 2 strings mit jeweils 1secunde 
pause dazwischen gesenden
das kommt auch grössten teils an.

2.habe auch mal die uart lib von P.Fleury benutzt wo auch für das senden 
der Interrupt benuzt wird,das gleiche Ergebniss.


3.wie muss die Terminierung bei 5V und bei 3.3V sein

Vielleicht kann mir denn jemand von ihnen einen Link zeigen
oder sagen wie mann das senden korrekt macht.


Mfg
#3252644
Lesenswert?

Nehmen wir mal den mega8:
TXC_vect mit steigender Flanke auf das Bit TXC in UCSRA. Dann wird die 
ISR einmal betreten und fertig. Danach erst wieder, wenn 0 und dann 1 
kam.
UDRE_vect auf Pegel von UDRE in UCSRA. Wenn die ISR kommt und verlassen 
wird, geht es direkt dort wieder rein, wenn UDRE nicht verschwindet oder 
der Interrupt deaktiviert wird.

Jetzt aber genug der SpAesse, das war schließlich kein Einsteiger-Threat 
und da setz ich ein bissl Mitdenken mal vorraus und nicht dass ich 
wieder beim µC-Alphabet anfangen muss.
Gast #3252661
Lesenswert?

>3.wie muss die Terminierung bei 5V und bei 3.3V sein

Die 620R passen für 5V.
Du Brauchst das auch nur an einer stelle, soll ja nur
verhindern dass der bus einen undefinierten Pegel hat.
Ob du da jetz 620R ider 1K nimmst ist bei kurzen
Strecken egal.
Wenn du was längeres vorhast guck dir mal den LT1785 an.

Welche Baudrate fährst du eigentlich?
Die schon mal reduziert?

Zum lesen:
RS-485

Und zum Rechnen:
http://www.ti.com/lit/an/slla036d/slla036d.pdf

Bild vom Aufbau?
(Speicher-) Oszie Vorhanden?
Gast #3252677
Lesenswert?

Tim schrieb:
>
> Die 620R passen für 5V.
Die muss ich dann noch einbauen bis jetz hab ich nur zwischen A 120R B 
drin
> Welche Baudrate fährst du eigentlich?
76800
> Die schon mal reduziert?
Ja von 9600 bis 250000

> (Speicher-) Oszie Vorhanden?
Nicht Vorhanden
Gast #3253479
Lesenswert?

So die Terminierung hab ich jezt so wies Vorgeschlagen wurde.
Verwende die Uart-Lib von P.Fleury , der Empfang klapt wunderbar aber 
wenn ich mein "TEST OK" sende kommt ohne die Delays nie komplett an mit 
den Delays klapt dies.

Es wird doch in setReceiveMode while ( !( UCSRA & (1<<TXC)) );
abgefragt ob senden möglich ist.

komisch?
1
void setTransmitMode( void )
2
{
3
 PORT_UART_OUT |= ( 1 << PIN_UART_OUT );
4
}
5

6
void setReceiveMode( void )
7
{
8
  while ( !( UCSRA & (1<<TXC)) );    // Wait for empty transmit buffer
9
  PORT_UART_OUT &= ~( 1 << PIN_UART_OUT );
10
}
11

12
 setTransmitMode();      //Sende-Pin auf HIGH schalten
13
 Delay1ms(1000);         //Warte 1Sekunde 
14
 uart_puts("TEST OK" ); 
15
 Delay1ms(1000);         //Warte 1Sekunde 
16
 setReceiveMode();       //Sende-Pin auf LOW schalten
#3253498
Lesenswert?

@ Sven (Gast)

>Es wird doch in setReceiveMode while ( !( UCSRA & (1<<TXC)) );
>abgefragt ob senden möglich ist.

Nö, ob das letzte Zeichen im Buffer gesendet wurde.

>void setReceiveMode( void )
>{
>  while ( !( UCSRA & (1<<TXC)) );    // Wait for empty transmit buffer
>  PORT_UART_OUT &= ~( 1 << PIN_UART_OUT );

Hier muss TXC gelöscht werden, damit es beim nächsten Mal nich vorzeitig 
als gesetzt erkannt wird.
 UCSRA = (1<<TXC);    // clear TXC
#3253528
Lesenswert?

Funktioniert es auch noch, wenn du das letzte Delay raus nimmst?
Ich nehme mal an dass das erste Delay notwendig ist um das StartBit 
ordentlich zu erkennen. So weit so gut...
Aber das letzte Delay in deinem Code ist wohl notwendig, weil deine 
bisherige Version von setReceiveMode nicht erkennt, wann das LETZTE Byte 
aus dem Puffer aus ist.
Die müsstest du so abändern, dass du auch auf einen leeren Puffer (der 
lib-eigene Ringpuffer, nicht der HW-Buffer) der UART-lib prüfst. Sonst 
bricht er nach dem erfolgreichen senden irgendeines Bytes ab. Evtl. 
klappt es sogar manchmal, denn in der PFleury lib werden die Daten auf 
UDRE_vect schon nachgeschoben.

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