Forum: Mikrocontroller und Digitale Elektronik RS485 Übertragung passt nicht


von Chris T. (chris0086)


Angehängte Dateien:

Lesenswert?

Hallo Leute,
ich wollte einen RS485 Bus aufbauen.
Folgender Chip wird verwendet: ADM3485 und Atmega32.

Bisher hab ich nur meine Controller und einen RS485 auf USB Wandler 
dran.
Der wandler funktioniert da ich ihn auch mit anderen Geräten nutze.

Es muss also eher an der Software/Hardware liegen.

Wenn ich RX und TX vor dem ADM abgreife werden auch die richtigen 
Charakters gesendet. Nur auf den Bus kommt nix mehr an.
Folgenden Code verwende ich:
1
/* define CPU frequency in Mhz here if not defined in Makefile */
2
#ifndef F_CPU
3
#define F_CPU 8000000UL
4
#endif
5
6
/* 9600 baud   */
7
#define BAUD1 9600UL          // Baudrate
8
#define UBRR_VAL_UART ((F_CPU+BAUD1*8)/(BAUD1*16)-1)   // clever runden
9
10
//RS485 Definitionen***********************************************
11
12
13
#define TRANSMIT_CONF  DDRA|= (1<<DDA4)
14
#define TRANSMIT_ON    PORTA |= (1<<PA4)
15
#define TRANSMIT_OFF  PORTA &= ~(1<<PA4)
16
17
18
//************** RS485 Funktionen *********************************************************
19
void USART_Transmit( char data )
20
{
21
22
  /* Wait for empty transmit buffer */
23
  while ( !( UCSRA & (1<<UDRE)) )
24
    ;
25
  /* Put data into buffer, sends the data */
26
  UDR = data;
27
}
28
29
30
void USART_SendS(uint8_t *werte, uint8_t rep)
31
{
32
  //receive_string[0] = 1;
33
  uint8_t i;
34
  for(i=0;i<rep;i++)
35
  {
36
    TRANSMIT_ON;
37
    USART_Transmit(werte[i]);
38
  }
39
}
40
41
ISR(USART_TXC_vect)
42
{
43
  TRANSMIT_OFF;
44
}
45
46
void uart_putc(char c)
47
{
48
    TRANSMIT_ON;
49
    USART_Transmit(c);
50
}
51
52
    //USART initialisieren
53
54
    TRANSMIT_CONF; // Transmit Pin als Ausgang
55
  //USART0
56
    UBRRH = UBRR_VAL_UART >> 8;
57
    UBRRL = UBRR_VAL_UART& 0xFF;
58
59
    //USART0
60
    UCSRB |= (1<<TXEN);                // UART TX einschalten
61
    UCSRB |= (1<<RXEN);
62
    UCSRB |= (1<<RXCIE);
63
    UCSRB |= (1<<TXCIE);
64
    UCSRC |= (1<<URSEL)|(1<<UCSZ0)| (1<<UCSZ1);    // Asynchron 8N1
65
66
    //Sensor-Interrupts aktivieren
67
   // MCUCR |= (1<<ISC11) | (1<<ISC01); //fallende Flanke auf INT0 und INT1
68
   // MCUCSR &= ~(1<<ISC2);
69
   // GICR |= (1<<INT0) | (1<<INT1) | (1<<INT2);
70
71
    sei();
72
    uart_putc('O');
73
    uart_putc('K');

Es wird auch zwei Bytes empfangen aber anstatt OK bekomme ich XZ.

Ich sehe leider den Fehler nicht.

Kann mir jemand helfen?

von Robin (Gast)


Lesenswert?

Dein Signal ist invertiert, taush mal deine A und B Leitung am Stecker.

von Chris T. (chris0086)


Lesenswert?

Oh man...
Hatte das schonmal getestet aber dabei wohl noch andere Fehler drin, 
jetzt hab ichs nochmal getauscht und läuft, vielen dank !!!!

von Chris T. (chris0086)


Lesenswert?

Ich muss das Thema leider nochmal hoch holen.
Senden klappt ja soweit,
aber mit dem Empfangen habe ich so meine Probleme.
Das Hauptproblem ist, das ich ja alles was ich sende auch erstmal wieder 
empfange.
Das habe ich versucht schon mal raus zu nehmen.
Aber wenn ich dem Controller was schicke und dann in meiner Main 
auswerte dann kommt da Mist bei raus, bzw. wird mir ein Zählwert nicht 
richtig ausgegeben...
Blöd das ich keine jtag Schnittstelle habe...

Aber hier mal der Code, wahrscheinlich kann man das viel besser lösen 
aber ich habe leider keinen Ansatz...
1
//RS485 Definitionen***********************************************
2
3
4
#define TRANSMIT_CONF  DDRA|= (1<<DDA4)
5
#define TRANSMIT_ON    PORTA |= (1<<PA4)
6
#define TRANSMIT_OFF  PORTA &= ~(1<<PA4)
7
8
volatile uint8_t uart_transmit_progress = 0;
9
volatile uint8_t uart_r_array[10];
10
volatile uint8_t uart_back_read = 0;
11
volatile uint8_t u_rx_start = 0;
12
volatile uint8_t receive_max = 6;
13
volatile char u_receive_string[15];
14
volatile uint8_t u_r_c = 0; //Daten an UART empfangen
15
16
//************** RS485 Funktionen *********************************************************
17
18
19
void USART_Transmit( char data )
20
{
21
22
  /* Wait for empty transmit buffer */
23
  while ( !( UCSRA & (1<<UDRE)) )
24
    ;
25
  /* Put data into buffer, sends the data */
26
  UDR = data;
27
}
28
29
void uart_puts(char *s,uint8_t count)
30
{
31
32
  uint8_t i;
33
  uart_transmit_progress = 1;
34
    for (i=0;i<count;i++)
35
    {
36
      TRANSMIT_ON;
37
        USART_Transmit(s[i]);
38
        while(!(uart_back_read))
39
          ;
40
        uart_back_read = 0;
41
        u_rx_start=0;
42
    }
43
    uart_transmit_progress= 0;
44
45
}
46
47
ISR(USART_TXC_vect)
48
{
49
  TRANSMIT_OFF;
50
}
51
52
void uart_putc(char c)
53
{
54
    TRANSMIT_ON;
55
    USART_Transmit(c);
56
}
57
58
ISR(USART_RXC_vect)
59
{
60
  uint8_t i;
61
  if(uart_transmit_progress)
62
  {
63
    uart_r_array[u_rx_start] = UDR;
64
    uart_back_read=1;
65
66
    u_rx_start++;
67
  }
68
  else
69
  {
70
71
72
    //USART_Transmit(receive_string[i]);
73
    //USART_Transmit(i);
74
    i = u_rx_start;
75
    u_receive_string[i] = UDR;
76
    //lcd_putc(i);
77
    /*if (i==1)
78
        {
79
          if((u_receive_string[i]>>4)== 16)
80
          {
81
            receive_max = 10;
82
          }
83
          else
84
          {
85
            receive_max = 9;
86
          }
87
        }
88
        */
89
    if(i == receive_max)
90
    {
91
      u_rx_start=0;
92
      LED3_ON ;
93
      u_r_c = receive_max;
94
      //USART_Transmit('Z');
95
96
    }
97
    else
98
    {
99
100
      i++;
101
      u_rx_start = i;
102
    }
103
  }
104
}
105
106
int main(void)
107
{
108
109
  //Interrupt-Eingänge konfigurieren
110
  PORTD |= (1<<2);
111
  PORTD |= (1<<3);
112
  PORTB |= (1<<2) | (1<<3);
113
114
115
  //Taster pullup akitivieren
116
  TASTER_PULLUP |= (1<<TASTER_PIN);
117
118
  //LED-Ausgänge konfigurieren
119
  DDRA |= (1<<DDA7) | (1<<DDA6) | (1<<DDA5);
120
121
122
    //USART initialisieren
123
124
    TRANSMIT_CONF; // Transmit Pin als Ausgang
125
  //USART0
126
    UBRRH = UBRR_VAL_UART >> 8;
127
    UBRRL = UBRR_VAL_UART& 0xFF;
128
129
    //USART0
130
    UCSRB |= (1<<TXEN);                // UART TX einschalten
131
    UCSRB |= (1<<RXEN);
132
    UCSRB |= (1<<RXCIE);
133
    UCSRB |= (1<<TXCIE);
134
    UCSRC |= (1<<URSEL)|(1<<UCSZ0)| (1<<UCSZ1);    // Asynchron 8N1
135
136
    //Sensor-Interrupts aktivieren
137
   // MCUCR |= (1<<ISC11) | (1<<ISC01); //fallende Flanke auf INT0 und INT1
138
   // MCUCSR &= ~(1<<ISC2);
139
   // GICR |= (1<<INT0) | (1<<INT1) | (1<<INT2);
140
141
    sei();
142
    //uart_putc((uint8_t) receive_max);
143
    //uart_putc('O');
144
    //uart_putc('K');
145
    //Master_send_command(1,16,12312);
146
147
148
149
150
151
152
153
  /*********************************************************************/
154
155
  // Messung der Interruptdauer
156
      tmp =0;
157
      tmp =0;
158
      tmp =0;
159
160
  // Debug
161
162
163
      int16_t be3;
164
      uint8_t testv;
165
      testv = 0;
166
      uint8_t direction;
167
      direction = 1;
168
169
while(1)
170
{
171
  if(u_r_c) //Es wurden Daten empfangen
172
  {
173
174
175
176
    uart_putc((uint8_t) u_r_c);
177
    u_r_c = 0;
178
  }
179
}
180
}

Es wird mir dann zwar ein Byte gesendet, da steht aber 240 drin und 
nicht 6.
Ich übergebe ja in der Receive ISR einfach den Wert von receive_max und 
der ist mit 6 festgelegt.

von Purzel H. (hacky)


Lesenswert?

Du empfaengst was du sendest, weil der RxInterupt waehrend dieser Zeit 
laeuft. Eine Eigenschaft des RS485.

Ich wuerd diesen Wert grad wegschmeissen und nicht speichern. Egal.
Das Senden wuerde ich auch per Interrupt machen.

von Chris T. (chris0086)


Lesenswert?

Das Problem ist, selbst wenn ich noch nichts gesendet habe, sondern nur 
empfangen dann kommt in meiner Main schon nicht das richtige an...

von A. S. (Gast)


Lesenswert?

Chris T. schrieb:
> Es wird mir dann zwar ein Byte gesendet, da steht aber 240 drin und
> nicht 6.

Das sieht nach abgeschaltetem Empfänger oder falsche Baudrate aus.

Wenn das Senden noch nicht klappt, hat es wenig Sinn, Empfangen zu 
wollen.

Bei manchen Controllern gibt es 1 Flag (mit Interrupt) für 
Transmit-Buffer leer (und damit ist der 1Byte-Fifo gemeint), und noch 
ein weiteres Flag für "jetzt ist das zeichen wirklich komplett mit allem 
versendet, mit Stopp und Pi pa po". Wenn du letzteres nicht hasst, 
brauchst Du eine Pause!

von spess53 (Gast)


Lesenswert?

Hi

>Wenn du letzteres nicht hasst, brauchst Du eine Pause!

Der Atmega32 hat einen TXC-Interrupt.
Und den kann man auch benutzen, selbst wenn man ihn hasst.

MfG Spess

von Chris T. (chris0086)


Lesenswert?

Den TXC Interrupt nutze ich ja schon um den Transmitpin wieder 
umzuschalten...

Senden klappt doch auch schon

: Bearbeitet durch User
von Hmmm (Gast)


Lesenswert?

Was erwartest Du, wenn Du !RE auf GND legst? Wenn der Receiver immer 
aktiv ist, bekommst Du logischerweise alle gesendeten Daten zurück.

von Chris T. (chris0086)


Lesenswert?

Ja ich weis, aber das muss sich doch per Software bewerkstelligen 
lassen, dass es trotzdem funktioniert.

von EdiR (Gast)


Lesenswert?

Chris T. schrieb:
> Ja ich weis, aber das muss sich doch per Software bewerkstelligen
> lassen, dass es trotzdem funktioniert.

Ignorier doch einfach alle empfangenen Zeichen, solange du selber 
sendest.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Es ist sogar prinzipiell sinnvoll, die gesendeten Daten gleich wieder zu 
empfangen - die kann man nämlich wunderbar mit den tatsächlich 
gesendeten Daten vergleichen, und so Übertragungsfehler bzw. Störungen 
auf dem RS485-Bus erkennen. Wenn nämlich zur gleichen Zeit zwei 
Busteilnehmer senden, stören sie sich gegenseitig.

von A. S. (Gast)


Lesenswert?

Chris T. schrieb:
> Es wird mir dann zwar ein Byte gesendet, da steht aber 240 drin und
> nicht 6.

Chris T. schrieb:
> Senden klappt doch auch schon

??? Was ist denn dann Dein Problem?

von Bastian W. (jackfrost)


Lesenswert?

Hi,

Die Zeile
1
uart_r_array[u_rx_start] = UDR;

Bringt nichts wenn du u_rx_start
In deiner Sendeschleife nach jedem Zeichen wieder auf 0 setzt.

Gruß JackFrost

von Chris T. (chris0086)


Lesenswert?

Mein Problem ist ganz einfach das ich nichts richtig empfange.
Das Senden klappt.
Wie würde die Empfangsroutine aussehen damit ich das was ich empfangen 
habe in meiner Main Schleife wieder zurück senden kann...

Das ist das Problem.

Mit
1
u_r_c = receive_max;

wird ja einfach eine konstante in der Empfangsroutine auf die Variable 
geschrieben.

In meiner Main soll mir der Wert zurück gesendet werden, es wird aber 
ein anderer Wert als übergeben gesendet...

: Bearbeitet durch User
von Chris T. (chris0086)


Lesenswert?

Hat niemand ein eIdee woran es liegen könnte das mir der Wert nicht 
korrekt zurück gesendet wird?

Also eigenartig ist, wenn ich einzelne Zeichen mit Hterm sende, dann 
wird mir irgendwann wenn receive_max erreicht ist auch die passend 
eAntwort geliefert.
Wenn ich die Zeichen aber hinterienander eingebe und dann Enter drücke 
damit alle gesendet werden klappt das nicht, als ob er die nicht 
mitbekommt...

Muss irgendwie mit der Hardware zusammen hängen, jemand Ideen? Der 
Controller und RS485 Chip werden mit 3,3V versorgt.

: Bearbeitet durch User
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Chris T. schrieb:
> Hat niemand ein eIdee woran es liegen könnte das mir der Wert nicht
> korrekt zurück gesendet wird?

Hast Du Beitrag "Re: RS485 Übertragung passt nicht" überlesen?

Du setzt u_rx_start=0; nach jedem gesendeten Zeichen, obwohl u_rx_start 
der Index auf Deinen Receive-Buffer ist.

Wenn Du Dich sowieso nicht dafür interessierst, ob die gesendeten Daten 
identisch mit den empfangenen sind, dann ist die Lösung ganz einfach:

1. Verbindung von /RE zu GND unterbrechen
2. /RE mit DE verbinden

Dann kann der Transceiver während des Sendens nichts empfangen.

von Chris T. (chris0086)


Lesenswert?

Frank M. schrieb:
> Du setzt u_rx_start=0; nach jedem gesendeten Zeichen, obwohl u_rx_start
> der Index auf Deinen Receive-Buffer ist.

Ich weis das aber wenn ich nichts sende dann wird da auch nichts auf 
Null gesetzt. Ich empfange ja erstmal nur, und wenn die empfangenen 
Zeichen = receive_max sind dann wird ein Zeichen gesendet...


Also nach Reset sende ich das erste mal:
01 01 01 01 01 01 01 01 01 01
das sind 10 Zeichen
darauf hin kommt erstmal nichts zurück obwohl theoretisch receive_max 
erreicht sein sollte.

Dann sende ich nochmal
01 01 01 01 01 01 01 01 01 01

jetzt kommt als antwort: 7F

Dann sende ich nochmal:
01 01 01 01 01 01 01 01 01 01

jetzt kommt als Antwort endlich 09 was receive_max entspricht.

Wenn ich jetzt wieder sende dann kommt erst wieder nichts, dann 7F und 
dann wieder 09

...

: Bearbeitet durch User
von Chris T. (chris0086)


Lesenswert?

Okay wenn ich meinen Programmer auf 5V umstelle dann tut alles was es 
soll, ich muss mal mit dem Oszi die Spannung messen, eventuell bricht 
die ein...

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Chris T. schrieb:
> Hat niemand ein eIdee woran es liegen könnte das mir der Wert nicht
> korrekt zurück gesendet wird?

Chris T. schrieb:
> Ich weis das aber wenn ich nichts sende dann wird da auch nichts auf
> Null gesetzt.

Drück Dich mal klarer aus. Ersteres hört sich so an, als ob der µC sein 
eigenes Echo nicht empfängt: "nicht korrekt zurück gesendet wird".

Letzteres hört sich so an: "µC1 sendet, µC2 empfängt nichts."

Was denn nun? Wenn letzteres: A & B vertauscht?

Was wird empfangen? Nichts oder nur wenig oder nur Schrott?

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.