Forum: Mikrocontroller und Digitale Elektronik RS485 empfang und senden


von Sven (Gast)


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
}

von runtastic (Gast)


Lesenswert?

Ist der RS485 Baustein auf senden gestellt?

von Sven (Gast)


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

von aevo (Gast)


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

von Spess53 (Gast)


Lesenswert?

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

von Guest (Gast)


Lesenswert?

Du musst Pin4 des MAX485 mit Pin7 des ATMega verbinden.

von Sven (Gast)


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

von Tim (Gast)


Lesenswert?

Welche Optimierungsstufe nutzt du vom gcc?
ggf schmeisst das der ggc nämlich raus:
1
while (!(UCSRA & (1<<UDRE)))  /* warten bis Senden moeglich */
pack da mal ein volatile asm("nop") in die {}

von Sven (Gast)


Lesenswert?

Optimierungsstufe = s
auch mit dem nop bekomm ich nur sporadisch was empfangen

von Falk B. (falk)


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.

von Tim (Gast)


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)

von Sven (Gast)


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

von Hatte ich einmal (Gast)


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.

von Spess53 (Gast)


Lesenswert?

Hi

Du hast hoffentlich einen Quarz am ATMega.

MfG Spess

von Hatte ich einmal (Gast)


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.

von Hatte ich einmal (Gast)


Lesenswert?

Sorry die UART hat ein Problem das Startbit zu erkennen, weil der 
Transceiver den Ausgang die ganze Zeit auf 0v hält.

von Tim (Gast)


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.

von Tim (Gast)


Lesenswert?

@Hatte ich einmal (Gast):
>Im Moment wird das letzte Byte einfach abgeschnitten.

Nope. Er pollt brav in setReceiveMode().

von Hatte ich einmal (Gast)


Lesenswert?

Sorry übersehen.

Dann sind die 620R und ein evtl. Loopback die vielversprechendsten 
Ansätze.

von René B. (reneb)


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.

von Spess53 (Gast)


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

von René B. (reneb)


Lesenswert?

Natürlich sind die ISRs dahinter gemeint, braucht aber nicht viel um das 
zu erkennen...
- Die ISR (USART_TXC_vect), welche mit TXCIE eingeschaltet wird, (usw. 
s.o.)
- Die ISR (USART_UDRE_vect), welche mit UDRIE eingeschaltet wird, (usw. 
s.o.)

von Spess53 (Gast)


Lesenswert?

Hi

>Natürlich sind die ISRs dahinter gemeint, braucht aber nicht viel um das
>zu erkennen...

Und mir welchen Flanken werden die ausgelöst?

MfG Spess

von Sven (Gast)


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

von René B. (reneb)


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.

von Tim (Gast)


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?

von Sven (Gast)


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

von Sven (Gast)


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

von Falk B. (falk)


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

von René B. (reneb)


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.

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.