Forum: Mikrocontroller und Digitale Elektronik RS485 bus mit Fleury Uart


von M. W. (mw73)


Angehängte Dateien:

Lesenswert?

Hallo Community!

Ich arbeite gerade an einem RS485 Bus. Der Bus besteht aus vier Mega48 
und Max485 als Busbaustein. Ein Master und 3 Slaves werden im 
half-duplex-mode betrieben. Ich möchte den multi prozessor communication 
mode zum Einsatz bringen. So weit so gut.
Der Busaufbau entspricht der beigefügten Grafik. Die Busleitungen 
enthalten zwei 120 ohm Terminierungswiderstände sowie an einem Busende 
Biaswiderstände mit je 1k. Ich denke dass der Aufbau soweit in Ordnung 
ist (momentan am Steckbrett).

Ich hätte mir folgende Übertragung vorgestellt:
Die Uart (Fleury) wird im 9-bit Modus betrieben.
Der Master sendet mit gesetztem Adressbit eine Slaveadresse (zb. 0x44)
und dannach einen Datenstring mit dem jeweiligen Kommando.
Die Slaves haben alle das MPCM-bit gesetzt.
Der Slave mit der richtigen Adresse setzt jetzt sein MPCM-bit zurück und 
empfängt die Daten. Das funktionier auch recht gut.

zum Problem:
Auslesen der empfangenen Datenstrings.
Der Master sendet ein Kommando zb. led! (Das Rufzeichen ist das 
Stringende).
zusammen mit der Adresse wird jetzt folgendes übertragen Mled! (M = 0x44 
Adresse). Ein Slave gibt zur Kontrolle auf ein lcd aus. Bei der ersten 
Übertragung wird aber MMled!übertragen (zumindest laut lcd). Die 
nächsten paar Male passt es wieder. und dann zb. MMed! oder !led! oder 
irgend sowas. Und dann passt es wieder.

Kann mir da jemand auf die Sprünge helfen?
Ich hab echt schon viele Stunden damit verbracht aber ich finde den 
Fehler nicht. Ziel ist natürlich dass der richtige String ankommt bzw. 
richtig ausgelesen werden kann.

anbei der code:

Master:
1
#ifndef F_CPU
2
#define F_CPU 8000000UL
3
#endif
4
5
6
#include <avr/io.h>
7
#include <avr/interrupt.h>
8
#include <util/delay.h>
9
#include <stdio.h> 
10
#include <stdlib.h>
11
#include <string.h> 
12
#include "uart.h"
13
14
15
16
int main(void)
17
{
18
  DDRB = (1<<PINB0) | (1<<PINB2); // Set PB0 and PB2 as output
19
  PORTB &= ~(1<< PINB2); // set PB2 to zero and listen to incoming data - 0 = listen, 1 = send
20
  
21
  DDRD &= ~(1<<PIND5) | (1<<PIND6) | (1<<PIND7); // set PD5 PD6 and PD7 as input 
22
  PORTD = (1<<PIND5) | (1<<PIND6) | (1<<PIND7); // activate pull-up at PD5 PD6 and PD7
23
  
24
  //uart init select baud-rate and cpu-clock
25
  uart0_init(UART_BAUD_SELECT(9600, F_CPU));
26
  
27
  _delay_ms(100);
28
  sei();
29
  
30
31
    while(1)
32
    {
33
      
34
  _delay_ms(1000);
35
  UCSR0B |= (1<< TXB80); //set adressbit
36
  PORTB |= (1<< PINB2); // set bit to send data
37
     
38
  //send adress
39
  RS485_transmit(0x44);
40
  _delay_ms(100); 
41
  
42
  UCSR0B &= ~(1<< TXB80); // set adressbit to zero so data can be transmit
43
  
44
  uart0_puts("led!");
45
  _delay_ms(500); 
46
  PORTB &= ~(1<< PINB2); // switch back to zero and listen to incoming data     
47
     
48
    }
49
}


Slave:
1
#ifndef F_CPU
2
#define F_CPU 8000000UL
3
#endif
4
5
6
7
#include <avr/io.h>
8
#include <avr/interrupt.h>
9
#include <util/delay.h>
10
#include <stdio.h> 
11
#include <stdlib.h>
12
#include <string.h> 
13
#include "RS485_Routines.h"
14
#include "lcd-routines.h"
15
16
17
uint8_t received=0; // to store adress
18
char buf[]; // Buffer for lcd
19
char comp[] = ("Dled!");
20
21
22
void uart0_gets(char *test)
23
{
24
  unsigned int c;
25
26
  c = uart_getc();
27
  if(!(c & UART_NO_DATA))
28
  {
29
    *test = c;
30
    test++;
31
32
    do {
33
      c = uart_getc();
34
      if(!(c & UART_NO_DATA))
35
      {
36
        *test = c;
37
        test++;
38
      }
39
    } while( c != '!');  
40
              
41
  
42
  }
43
}
44
45
int main(void)
46
{
47
  DDRB = (1<<PINB0) | (1<<PINB2); // set PINB0 and PINB2 as output
48
  PORTB &= ~(1<< PINB2); // switch PB2 to zero and listen to incoming data
49
  
50
  lcd_init();
51
  lcd_clear();
52
  lcd_setcursor(0,1);
53
  lcd_string("RS485 Test");
54
  
55
  
56
  //uart init select baud-rate and cpu-clock
57
  uart0_init(UART_BAUD_SELECT(9600, F_CPU));
58
  
59
  UCSR0A |= (1<< MPCM0);
60
  _delay_ms(200);
61
  sei();
62
63
    while(1)
64
    {
65
         
66
     
67
     char test[8] = "";  
68
     
69
     
70
     
71
     received = UDR0;
72
     if (received == 0x44) {  // this is my adress
73
      UCSR0A &= ~(1<< MPCM0);
74
      //blink_led();
75
      
76
      lcd_setcursor(0,2);
77
      sprintf(buf,"My adress = 0x%x",received);
78
      lcd_string(buf);
79
      received = 0;
80
      
81
      uart0_gets(test);
82
      
83
      lcd_setcursor(0,4);
84
      lcd_string(test);
85
      
86
      if (strcmp(comp, test) == 0){
87
        blink_led();
88
      }
89
    
90
      
91
    }//if
92
  
93
  } //while       
94
    
95
} //main


Ich bitte euch nochmals um Hilfe, da ich mit meinem Latein am Ende bin 
und das noch ziemlich neu für mich ist.

Solltet Ihr noch Info benötigen gebt mir bitte bescheid.

Danke im Voraus!

Grüße
mw73

von Purzel H. (hacky)


Lesenswert?

Ist etwas viel auf's mal.

Mit einem Oszilloskop wuerde man nun einen Pin togglen.

Und nie blockierend implementieren ... du weisst ja nicht mal wo das 
Programm am Warten ist.

Und wenn man sich Arbeit sparen will, verwendet man einen zweiten UART 
zum Debuggen.

Der einfachere Ansatz, auch wenn er schwieriger erscheint, ist eine 
Statusmaschine, und ein, zwei oder mehrere Pins fuer das Oszilloskop.
Und dann programmiert man nicht blockierend.

Blockierend bedeutet, die Rechenzeit wird verballert, da geschieht sonst 
nichts. Macht man nicht.

von Sabberlotte (Gast)


Lesenswert?

Die Fail-Save Widerstände sind mit 1k u.U. zu groß.
Die internen Pullup am RxD auch. Mit 10k an VCC probieren?
Ein LA ist manchmal Gold wert!

von ms (Gast)


Lesenswert?

HAllo,

hier mal ein paar Tips.
1. Ich habe mir angewöhnt Übertragungsfehler zu zulassen. Wichtig ist 
dabei die Fehlerbehandlung (CRC,ACK,NACK, FrameError....)
2. Das Senden und Empfangen in einer ISR verlegen.
3. Empfänger und Sender sollten die gleiche Sprache sprechen (Protokoll) 
z.b. EmpfängerAdr,SenderAdr,LängeDaten,Daten....,CRC.

4. Nach dem Empfangen solltest du das MPCM bit wieder setzen.

ms

von Jim M. (turboj)


Lesenswert?

1
while(1) {
2
  received = UDR0;

Da fehlt jeglicher Test, ob überhaupt ein neuer (gültiger) Wert im UDR 
drin ist.

Du liesst da u.U. Zwischenwerte aus, falls die Bits von der Hardware 
einzeln gesetzt/gelöscht werden. Was ja nicht komplett unwahrscheinlich 
ist, schließlich kommen die einzeln an.

von M. W. (mw73)


Lesenswert?

Hallo Zusammen,

zuerst einmal Danke für eure schnellen Antworten!!!

@Zwölf Mal Acht:
Ich bin mir jetzt nicht sicher wie Du das genau meinst mit "blockierend 
implementieren" bzw. wie ich das jetzt anders machen könnte. Ich hab 
mich auf alle Fälle mit dem Konverter an die RX/TX Leitungen des 
angesprochenen Slaves gehängt und mittels Terminal überprüft ob der 
String ankommt. Wie gesagt, der String kommt an RX des Slaves an. Am 
Terminal steht Mled!
Also der String geht zum Empfänger und zwar richtig geschrieben, egal 
wie oft ich ihn sende.

@Sabberlotte:
Danke für den Tipp, werde ich gleich ausprobieren. Meinst Du die 10k 
auch an VSS oder nur VCC? und die 120ohm passen aber oder?

@MS:

So weit bin ich eigentlich noch gar nicht, denn so wie es aussieht, wird 
ja nicht einmal der einzige String der momentan gesendet wird richtig 
übertragen bzw. richtig eingelesen denn wenn ich mich mit dem Konverter 
an die RX Leitung des Slaves hänge, steht am Terminal immer der richtige 
Text.
Das fehlende MPCM bit werde ich gleich überprüfen ober ich glaube das 
habe ich beim kopieren übersehen.

@Jim Meba:

Hier wird die Adresse ausgelesen. Das funktioniert aber einwandfrei im 
Gegensatz zum Auslesen des Strings.
Ich habe schon versucht nur in Schleifen alle Slaves über die Adressen 
nacheinander anzusprechen. Das funktioniert wirklich gut. Jeder 
angesprochene Slave meldet sich per LED.

Ich werde jetzt die Widerstände tauschen und testen, ob ich das MPCM bit 
wieder gesetzt habe. Ich melde mich dann wieder.

Ich denke aber, dass das Problem beim Einlesen des Strings besteht. Da 
hatten die meisten Leute Probleme mit Fleurys uart (hab ich in den 
ganzen alten Postings gelesen).

Grüße
Markus

von ms (Gast)


Lesenswert?

Hallo Makus,

Zeigt dein Konverter auch Parity error an den Adresse ist MARK und Daten 
sind SPACE.

gruß aus dem Schwabenland.

von M. W. (mw73)


Lesenswert?

Hallo Zusammen,

melde mich zurück

@ms:
Nein, ich kann ja damit nur Text vom uC aufs Terminal übertragen.

Also es sieht so aus:

Ich habe die Bias-Widerstände getauscht - von 1k auf 10k
hat aber nichts gebracht oder verändert.

@ms:
Danke für die Aufmerksame Beobachtung mit dem fehlenden setzen des 
MPCM-Bits.
Ich hatte es wahrscheinlich durchs viele herumtesten übersehen.

Das ganze hat jetzt folgende Auswirkungen:
in ca. 90% wird jetzt folgender String gesendet: DDled!
Ich verstehe aber nicht warum er D (die Adresse) zweimal im String 
stehen hat, sollte ja nur einmal drin stehen??

alle paar mal sendet er dann !led! --> hier wird die Adresse verschluckt 
und dafür ein Rufzeichen vor dem eigentlichen String gesetzt.

Hat hier jemand eine Idee?

Grüße
Markus

von Sabberlotte (Gast)


Lesenswert?

Markus W. schrieb:
> @Sabberlotte:
> Danke für den Tipp, werde ich gleich ausprobieren. Meinst Du die 10k
> auch an VSS oder nur VCC? und die 120ohm passen aber oder?

10k nur an VCC (Pullup)!

Markus W. schrieb:
> Ich habe die Bias-Widerstände getauscht - von 1k auf 10k
> hat aber nichts gebracht oder verändert.

VCC > 560 Ohm > A > 120 Ohm > B > 560 Ohm > GND ...
... aber nur an einer Seite / die andere nur 120 Ohm zwischen A und B.

von M. W. (mw73)


Lesenswert?

Danke Sabberlotte für den Tipp,
ich werde es morgen testen und bescheid geben.

Grüße
Markus

von ms (Gast)


Lesenswert?

Hallo Markus,

kannst ja mal den Code testen.
Ja ist mit ISR aber MPC macht nur mit Interrupt sinn.
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <util/delay.h>
4
#include <stdio.h>
5
#include <stdlib.h>
6
#include <string.h>
7
#include "RS485_Routines.h"
8
#include "lcd-routines.h"
9
10
#ifndef F_CPU
11
#define F_CPU 8000000UL
12
#endif
13
14
#define UART_BAUD_CALC(UART_BAUD_RATE,F_OSC) \
15
  ( ( F_OSC ) / ( ( UART_BAUD_RATE ) * 8UL ) - 1 )
16
17
#define NET_UCSRA             UCSR0A
18
#define NET_UCSRB             UCSR0B
19
#define NET_UCSRC             UCSR0C
20
#define NET_UDR               UDR0
21
#define NET_ADRESS        0x44
22
#define UART_BAUD_RATE        9600
23
24
25
26
uint8_t received=0; // to store adress
27
char buf[256]; // Buffer for lcd
28
char comp[] = ("Dled!");
29
30
unsigned char ucRxCount;
31
bool DataOk;
32
33
char test[10];
34
35
void NetInit() {
36
  char c;
37
  UBRR0H = (unsigned char)(UART_BAUD_CALC(UART_BAUD_RATE, F_CPU) >> 8);
38
  UBRR0L = (unsigned char)UART_BAUD_CALC(UART_BAUD_RATE, F_CPU);
39
40
  NET_UCSRA = (1 << U2X0) | (1 << MPCM0);
41
  NET_UCSRB = (1 << UCSZ02) | (1 << RXCIE0) | (1 << RXEN0) | (1 << TXEN0) |
42
    (1 << TXCIE0);
43
  NET_UCSRC = (0 << UMSEL0) | (1 << UCSZ01) | (1 << UCSZ00);
44
45
  c = NET_UDR;
46
}
47
48
SIGNAL(SIG_UART_RECV) {
49
  static unsigned char ucRxByte;
50
51
  if (NET_UCSRA & ((1 << FE0) + (1 << DOR0))) // Fehler
52
  {
53
    ucRxByte = NET_UDR; // Rx Buffer leeren
54
    NET_UCSRA |= (1 << MPCM0); // MPCM Mode einschalten
55
    DataOk = false;
56
    return;
57
  }
58
59
  if (NET_UCSRB & (1 << RXB80)) // OK mit 9. bit
60
  {
61
62
    ucRxByte = NET_UDR;
63
    if (ucRxByte == NET_ADRESS) {
64
      NET_UCSRA &= ~(1 << MPCM0); // MPCM Mode ausschalten
65
      ucRxCount = 0; // Zähler auf 0
66
      test[ucRxCount] = ucRxByte; // Adresse speichern an Byte 0
67
      ucRxCount++; // Zähler +1
68
      DataOk = false;
69
      return;
70
    }
71
72
  }
73
74
  ucRxByte = NET_UDR;
75
76
  if (ucRxByte != '!') // EndZeichen  empfangen
77
  {
78
    test[ucRxCount] = ucRxByte;
79
    ucRxCount++;
80
    return;
81
  }
82
  else {
83
    NET_UCSRA |= (1 << MPCM0); // MPCM Mode einschalten
84
    test[ucRxCount] = '\n';
85
    ucRxCount = 0;
86
    DataOk = true;
87
    return;
88
  }
89
90
}
91
92
int main(void) {
93
  DDRB = (1 << PINB0) | (1 << PINB2); // set PINB0 and PINB2 as output
94
  PORTB &= ~(1 << PINB2); // switch PB2 to zero and listen to incoming data
95
96
  lcd_init();
97
  lcd_clear();
98
  lcd_setcursor(0, 1);
99
  lcd_string("RS485 Test");
100
101
  // Neu *************************************************
102
  NetInit();
103
104
  _delay_ms(200);
105
  sei();
106
107
  while (1) {
108
109
    if (DataOk) {
110
      lcd_setcursor(0, 2);
111
      sprintf(buf, "My adress = 0x%x", test[0]);
112
      lcd_string(buf);
113
      lcd_setcursor(0, 4);
114
      lcd_string(&test[1]);
115
116
      if (strcmp(comp, test) == 0) {
117
        blink_led();
118
      }
119
120
      DataOk = false;
121
    }
122
123
  } // while
124
125
} // main



ms

von M. W. (mw73)


Lesenswert?

Hallo ms!

wow, danke, voll nett von Dir!!

Ich werden den code gleich am Nachmittag testen und gebe heute abend 
bescheid.

Vielen Dank noch mal!

Grüße
Markus

von ms (Gast)


Lesenswert?

Hallo Markus,

habe ich gerne gemacht da RS485 mein "Steckenpferd" ist.
Der Code ist zum Teil aus einem Produktivsystem.
Es fehlt aber noch eine TimeOut,Prüfsumme und CallBack Funktion.


ms

von M. W. (mw73)


Lesenswert?

Hallo ms!

Ich bin noch am testen, hab den code aber leider noch nicht zum laufen 
gebracht.
Nach einfügen der stdbool.h konnte ich den code zwar kompilieren, es 
läuft allerdings nicht einmal das lcd an.
Die Ausgabe "RS485 test" ist ja die erste Anweisung in de main. Die 
sollte doch zumindest kommen?

Ich hab Deinen code noch nicht ganz durchschaut aber so wie ich es 
verstanden habe, ist die Fleury uart jetzt nicht mehr erforderlich denn 
Baudrate und die Register werden ja jetzt im Hauptprogramm festgelegt.

SIGNAL(SIG_UART_RECV) --> ist das die alte Konvensation für den Aufruf 
der ISR ? in der ersten Fleury Uart habe ich diesen Aufruf schon einmal 
gelesen. Wurde aber dann geändert in ISR(UART0_RECEIVE_INTERRUPT).

Ich teste weiter und hoffe es zum Laufen zu bekommen.

Grüße
Markus

Danke Sabberlotte für den Tipp mit den Widerständen, hab jetzt die 
richtigen eingesetzt - Danke!

von M. W. (mw73)


Lesenswert?

Hallo ms!

Nur so eine Idee, würde es Sinn machen, Deine Programmteile in die ISR 
der Fleury Lib zu implementieren? Diese hat ja eine eigene ISR welche 
ausgelöst wird, wenn ein byte empfangen wurde.

...oder würdest Du mir raten mein Vorhaben auf Deinem Code aufzubauen 
und die Lib gar nicht mehr zu verwenden?

Ich bin jetzt etwas verunsichert.


Grüße
Markus

von M. W. (mw73)


Lesenswert?

achja, eines noch,

heute morgen hab ich noch an meiner version gearbeitet und sie soweit 
lauffähig gebracht, dass der Master immer den selben slave über seine 
Adresse anspricht und immer den selben String "led!" sendet. Der String 
kommt jetzt auch fehlerfrei an.

hier der code des slaves:
1
#ifndef F_CPU
2
#define F_CPU 8000000UL
3
#endif
4
5
6
7
#include <avr/io.h>
8
#include <avr/interrupt.h>
9
#include <util/delay.h>
10
#include <stdio.h> 
11
#include <stdlib.h>
12
#include <string.h> 
13
14
#include "RS485_Routines.h" // Fleury uart
15
#include "lcd-routines.h"
16
17
18
uint8_t received=0;   // to store address
19
uint16_t counter = 0; // counts received messages
20
uint16_t errcounter = 0; // counts errormessages != comp
21
22
23
24
char buf[]; //buffer for lcd ADDRESS
25
char bufc[]; // buffer for sprintf counts
26
char bufec[]; // buffer for sprintf error counts
27
28
char Line[5]; // for function get string
29
unsigned int c; // for function get string   
30
char comp[] = ("led"); // testmode: master always sends the same string - ADDRESS(0x44) + String(led!) ! = end of string
31
32
// for debug
33
void blink_led(void){
34
  
35
  PORTB |= (1<<PINB0);
36
  _delay_ms(500);
37
  PORTB &= ~(1<<PINB0);
38
  _delay_ms(500);
39
}
40
41
42
43
// helper function for get string - this is a waiting function
44
uint8_t uart_getc_wait()
45
{
46
unsigned int c;
47
48
do {
49
    c = uart0_getc();
50
  } while( c == UART_NO_DATA );
51
52
return (uint8_t)c;
53
}
54
55
56
// function to receive a whole string
57
void uart_gets( char* Buffer, uint8_t MaxLen )
58
{
59
uint8_t NextChar;
60
uint8_t StringLen = 0;
61
62
NextChar = uart_getc_wait();         
63
64
while( NextChar != '!'&&StringLen<MaxLen - 1 ) {
65
    *Buffer++ = NextChar;
66
StringLen++;
67
NextChar = uart_getc_wait();
68
}
69
70
// put a zero at the end of string
71
  *Buffer = '\0';
72
}
73
74
75
76
int main(void)
77
{
78
  DDRB = (1<<PINB0) | (1<<PINB2); // set PINB0 and PINB2 as output
79
  PORTB &= ~(1<< PINB2); // switch PB2 to zero and listen to incoming data
80
  
81
  lcd_init();
82
  lcd_clear();
83
  lcd_setcursor(0,1);
84
  lcd_string("RS485 Test");
85
  
86
  
87
  //uart init select baud-rate and cpu-clock (fleury uart)
88
  uart0_init(UART_BAUD_SELECT(9600, F_CPU));
89
  
90
  UCSR0A |= (1<< MPCM0); // slave: set the MPCM-bit
91
  _delay_ms(200);
92
  sei(); // enable interrupts
93
  
94
95
96
    while(1)
97
    {
98
         
99
     
100
     
101
     received = UDR0;
102
     if (received == 0x44) {  // this is my adress
103
      UCSR0A &= ~(1<< MPCM0); // now set MPCM zero and receive data
104
      //blink_led();
105
           
106
          
107
      lcd_setcursor(0,2);
108
      sprintf(buf,"My adress = 0x%x",received);
109
      lcd_string(buf);
110
      received = uart0_getc(); // empty rxbuffer (address isn't used in data)
111
      received = 0; 
112
      
113
      
114
      
115
      c = uart_getc(); // receive data
116
      uart_gets( Line, sizeof( Line ) );
117
      
118
      UCSR0A |= (1<< MPCM0); // set MPCM-bit
119
      
120
      
121
      lcd_setcursor(0,3);
122
      lcd_string(Line);
123
      
124
      counter +=1;
125
      lcd_setcursor(0,4);
126
      lcd_string("cnt:");
127
      sprintf(bufc,"%4d", counter);
128
      lcd_setcursor(5,4);
129
      lcd_string(bufc);
130
      
131
      lcd_setcursor(11,4);
132
      lcd_string("err:");
133
      sprintf(bufec,"%4d", errcounter);
134
      lcd_setcursor(16,4);
135
      lcd_string(bufec);
136
      
137
      
138
      
139
      if (strcmp(comp, Line) == 0){
140
        blink_led();
141
        lcd_setcursor(0,2);
142
        lcd_string("                    ");
143
        lcd_setcursor(0,3);
144
        lcd_string("                    ");
145
      
146
      }
147
      else {
148
        
149
        errcounter +=1;
150
        
151
        lcd_setcursor(11,4);
152
        lcd_string("err:");
153
        sprintf(bufec,"%4d", errcounter);
154
        lcd_setcursor(16,4);
155
        lcd_string(bufec);
156
      }
157
      
158
  
159
      
160
      }//if
161
  
162
     
163
     
164
    
165
      
166
  
167
  } //while   
168
     
169
     
170
     
171
    
172
    
173
} //main

soweit so gut.

Jetzt kommt das Problem:

wenn jetzt der Master einen anderen Slave mit seiner Adresse anspricht 
und andere Daten sendet (zb. "aus!") und danach wieder der andere slave 
mit der 0x44er Adresse angesprochen wird, empfängt dieser Daten des 
vorher angesprochenen.

Du hast mir ja bereits gesagt, dass MPCM nur mittels ISR funktioniert.

Normalerweise dürfte der 0x44er Slave den String des 0x43er gar nicht 
empfangen, da MPCM zu diesem Zeitpunkt gesetzt ist und der Master ja nur 
mit gesetztem Adressbit die Adresse sendet.

Grüße
Markus

von ms (Gast)


Lesenswert?

Hallo Markus,

Markus W. schrieb:
> SIGNAL(SIG_UART_RECV) --> ist das die alte Konvensation für den Aufruf
ja (ist schon Jahre her das ich meine Lib geschrieben habe)

Markus W. schrieb:
> ...oder würdest Du mir raten mein Vorhaben auf Deinem Code aufzubauen
> und die Lib gar nicht mehr zu verwenden?

Die Entscheidung kann ich dir nicht abnehmen.Es kommt darauf an was Du 
machen willst.

Markus W. schrieb:
> (zb. "aus!")
Noch ein Tip: Versuche keine "Texte" für kommandos zu nehmen das macht 
dir später das leben schwer.

ms

von ms (Gast)


Lesenswert?

Hallo Makus,

Markus W. schrieb:
> Normalerweise dürfte der 0x44er Slave den String des 0x43er gar nicht
> empfangen

Doch darf er deine Lib verwendet einen RingBuffer.Die Lib ist echt gut 
aber du hast da wenig kontrolle.

Dein Master sendet ca. alle 600ms einen Frame.Ist die LCD-Lib so schnell
dass Du das MPC-Bit rechtzeitig setzen kannst bevor das Frame vom 
anderen in den Ringbuffer gelangt.

ms

von M. W. (mw73)


Lesenswert?

Hallo ms!

Danke für die Antworten.
Ich werde erstmal versuchen Deine Version zum Laufen zu bekommen.
Ich habe mich jetzt etwas damit auseinander gesetzt und ich denke dass
sie wirklich perfekt ist.

Kannst Du mir noch eine Verständnisfrage beantworten, wenn ich Deinen 
Code verwende, brauche ich die Fleury Lib nicht mehr oder?.

Grundsätzlich soll dieses Projekt keine große Sache werden. Der Master 
soll lediglich zu bestimmten Zeiten Kommandos an die Slaves schicken. 
Diese sollen die jeweiligen Kommandos mit der Liste vergleichen und 
diese dann ausführen. Dannach eine Rückmeldung an den Master.

Du meintest, ich solle die Texte mit Kommandos austasuchen. Meinst Du 
damit zb. Zahlen in einer uint_8t Variable oder in einen String 
umwandeln? Wie könnte denn da die Überprüfung aussehen ob die Zahl zu 
ende eingelesen wurde?

Kannst Du mir noch kurz erklären, wie ein kompletter Frame aussieht. 
Also Ziel soll es sein, alle Informationen in ein Array zu schreiben 
(char Test[10]. An Stelle null kommt die Adresse, an Stelle 1, die 
Adresse vom Master, an Stelle 3 die Länge der Daten, dann an Stelle 4 
das Kommando und zum Schluss die checksumme. Ist das so richtig?

Der Master sendet dann diese Informationen der Reihe nach oder

zb. uart_transmit(0x44) //Zieladresse
    uart_transmit(0x01) //Adresse Master
    usw.

wäre dass so richtig.


... ich hoffe ich nerve Dich nicht mit meinen Fragen aber ich bin noch 
Anfänger. Ich habe zwar versucht mich in die Thematik mit dem RS485 
einzulesen aber ich habe sehr wenig Informationen darüber gefunden, wie 
man so eine Bus richtig aufbaut.

Danke für Deine Hilfe

Grüße
Markus

von ms (Gast)


Lesenswert?

Hallo Markus

Markus W. schrieb:
> Kannst Du mir noch eine Verständnisfrage beantworten, wenn ich Deinen
> Code verwende, brauche ich die Fleury Lib nicht mehr oder?.
nein die brauchst du nicht mehr

Markus W. schrieb:
> Du meintest, ich solle die Texte mit Kommandos austasuchen.

ja z.B. LED(_1) AN ist bei mir 0x10 0x01, LED(_1) AUS = 0x11 0x01; 
LED(_1) toggel = 0x12 0x01.

aber dazu am Wochenende mehr.

ms

von M. W. (mw73)


Lesenswert?

Hallo ms!

Danke einstweilen, ich versuche erstmal Deinen Code bei mir zum laufen 
zu bringen.

Lg
Markus

von ms (Gast)


Lesenswert?

Hallo Markus,

klammer mal TXEN0 und TXCIE0 aus.
1
NET_UCSRB = (1 << UCSZ02) | (1 << RXCIE0) | (1 << RXEN0);  /* | (1 << TXEN0) | (1 << TXCIE0);*/

in Main NetInit(); vor Lcd_init();

für das weiter vorgehen, hast du dich schon mal mit Struct,Zeigern und 
Funktionszeigern beschäftigt?

ms

von M. W. (mw73)


Lesenswert?

Hallo ms!

Ich hab gestern dran gearbeitet. Der Code "läuft jetzt an".
Die erse Zeile am lcd erscheint.
Allerdings gibt es Probleme beim einlesen der Adresse. Diese wird 
scheinbar
nicht erkannt. Ich hab mit der debug led folgendes festgestllt:

in der ISR wird die erste if-Abrage durchlaufen
1
if (NET_UCSRA & ((1 << FE0) + (1 << DOR0)))

geht in die nächste if-Abfrage rein
1
if (NET_UCSRB & (1 << RXB80)) // OK mit 9. bit
und bleibt schließlich bei der Adressabfrage hängen
1
if (ucRxByte == NET_ADRESS)


Ich hab testweise versucht ucRXByte mit einer uint8_t variable zu 
ersetzten
und an dieser Stelle eine lcd-Ausgabe durchgeführt. Es wird jetzt 0x80 
ausgegeben???

Ich werde heute weiter testen.

Achja
>für das weiter vorgehen, hast du dich schon mal mit Struct,Zeigern und
>Funktionszeigern beschäftigt?

struct hatte ich noch nie benötigt, mit Zeigern habe ich mich etwas 
beschäftigt.

Grüße
Markus

von ms (Gast)


Lesenswert?

Hallo Markus,

ich habe was vergessen.
1
if (NET_UCSRB & (1 << RXB80)) // OK mit 9. bit
2
  {
3
4
    ucRxByte = NET_UDR;
5
    if (ucRxByte == NET_ADRESS) {
6
      NET_UCSRA &= ~(1 << MPCM0); // MPCM Mode ausschalten
7
      ucRxCount = 0; // Zähler auf 0
8
      test[ucRxCount] = ucRxByte; // Adresse speichern an Byte 0
9
      ucRxCount++; // Zähler +1
10
      DataOk = false;
11
      return;
12
    }else    // Packet ist nicht für mich gedacht.
13
    {
14
      NET_UCSRA |= (1<<MPCM0);
15
      return;
16
    }
17
18
  }
für den fall dass das Packet nicht für mich ist

ms

von M. W. (mw73)


Lesenswert?

Hallo ms!

Danke für den Hinweis!!!

Ich hab es jetzt zum Laufen bekommen.

Du kannst Dir ja gar nicht vorstellen was mir passiert ist,

Ich hatte die define F_CPU die ganze Zeit unterhalb der include 
util/delay.h

Als ich testweise die debug-led in der while-schleife blinken lassen hab 
bin ich drauf gekommen.

Jetzt funtioniert das Senden und empfangen wie gewollt auch mit mehreren 
Teilnehmern.


... Glaubst Du dass Du das Wochenende noch einmal ein paar Minuten Zeit 
findest und mir noch etwas die Zusammensetzung eines kompletten Packets 
erklären könntest?

Auf alle Fälle vielen vielen Dank für Deine kompetente Hilfe!!!!!!!!!!!
Ich hab durch Deinen Code viel zu diesem Thema dazu gelernt.

Schönen Abend und LG

Markus

von ms (Gast)


Lesenswert?

Hallo Markus,

hier noch ein Stück code nicht zum Testen sondern zum analysieren.
Daraus ergibt sich schon das komplette Packet.
Sieht schlimm aus ist es aber nicht.
1
#define CRC_BIT     0x10
2
#define INCLUDE_CRC(x)        (((x) & (CRC_BIT)) !=0) ? (2):(0)
3
4
#define MAX_DATA_LENGTH 10
5
#define CRC16_POLYNOM   0x1002
6
7
typedef struct {
8
  unsigned char RxAddress;
9
  unsigned char InfoByte;
10
  unsigned char TxAddress;
11
  unsigned char DataLength;
12
  unsigned char Data[MAX_DATA_LENGTH];
13
} st_protokoll_Data;
14
15
bool DataOk;
16
17
st_protokoll_Data stRxData;
18
//st_protokoll_Data stTxData;
19
20
unsigned char RxHeader;
21
unsigned char RxBody;
22
unsigned int RxCrc16;
23
unsigned int crc16;
24
25
void NetSetTxEnable(bool enable) {
26
  if (enable) {
27
    PORTB |= (1 << PINB2);
28
  }
29
  else {
30
    PORTB &= ~(1 << PINB2);
31
  }
32
}
33
34
void NetInit() {
35
  char c;
36
37
  UBRR0H = (unsigned char)(UART_BAUD_CALC(UART_BAUD_RATE, F_CPU) >> 8);
38
  UBRR0L = (unsigned char)UART_BAUD_CALC(UART_BAUD_RATE, F_CPU);
39
40
  NET_UCSRA = (1 << U2X0) | (1 << MPCM0);
41
  NET_UCSRB = (1 << UCSZ02) | (1 << RXCIE0) | (1 << RXEN0);
42
  /* | (1 << TXEN0) | (1 << TXCIE0); */
43
  NET_UCSRC = (1 << UCSZ01) | (1 << UCSZ00);
44
  NetSetTxEnable(false);
45
  c = NET_UDR; // Rx Buffer leeren und verwerfen
46
}
47
48
void InitCRC(void) {
49
  crc16 = 0xffff;
50
}
51
52
void CalcCRC(unsigned char data) {
53
  unsigned char bitCount;
54
  unsigned char PolynomFlag;
55
  for (bitCount = 0; bitCount < 8; bitCount++) {
56
    PolynomFlag = (crc16 & 0x8000) != 0;
57
    crc16 <<= 1;
58
    if (data & 0x80) {
59
      crc16 |= 1;
60
    }
61
    data <<= 1;
62
    if (PolynomFlag)
63
      crc16 ^= CRC16_POLYNOM;
64
  }
65
}
66
67
void Net_NewFrameStart(void) {
68
  DataOk = false;
69
  RxHeader = 0x00;
70
  RxBody = 0x00;
71
  RxCrc16 = 0;
72
  InitCRC();
73
  stRxData.TxAddress = NULL;
74
75
}
76
77
ISR(USART_RX_vect) {
78
  static unsigned char ucRxByte;
79
80
  if (NET_UCSRA & ((1 << FE0) + (1 << DOR0))) // Fehler
81
  {
82
    ucRxByte = NET_UDR; // Rx Buffer leeren
83
    NET_UCSRA |= (1 << MPCM0); // MPCM Mode einschalten
84
    DataOk = false;
85
    return 0;
86
  }
87
88
  if (NET_UCSRB & (1 << RXB80)) // OK mit 9. bit
89
  {
90
91
    ucRxByte = NET_UDR;
92
    if (ucRxByte == NET_ADRESS) {
93
      NET_UCSRA &= ~(1 << MPCM0); // MPCM Mode ausschalten
94
      stRxData.RxAddress = ucRxByte;
95
      Net_NewFrameStart();
96
      CalcCRC(ucRxByte);
97
      RxHeader++;
98
      return;
99
    }
100
    else // Packet ist nicht für mich gedacht.
101
    {
102
      NET_UCSRA |= (1 << MPCM0);
103
      return;
104
    }
105
106
  }
107
  // ab hier geht es weiter mit 8 bit
108
  ucRxByte = NET_UDR;
109
110
  if (RxHeader == 1) // Info BYTE
111
  {
112
    stRxData.InfoByte = ucRxByte;
113
    RxHeader++;
114
    CalcCRC(RxByte);
115
    return;
116
  }
117
  if (RxHeader == 2) // Sender ADR
118
  {
119
    stRxData.TxAddress = ucRxByte;
120
    RxHeader++;
121
    CalcCRC(ucRxByte);
122
    return;
123
  }
124
  if (RxHeader != 0xFF) // DATA Länge
125
  {
126
127
    RxHeader = 0xFF;
128
    stRxData.DataLength = ucRxByte;
129
    CalcCRC(ucRxByte);
130
    return;
131
  }
132
133
  if (RxBody < (stRxData.DataLength - (INCLUDE_CRC(stRxData.ModeByte)))) // DATA
134
  {
135
136
    stRxData.Data[RxBody] = ucRxByte;
137
    CalcCRC(ucRxByte);
138
    RxBody += 1;
139
    if (!INCLUDE_CRC(stRxData.ModeByte) &&
140
      (RxBody == stRxData.DataLength)) // Keine CRC nötig
141
    {
142
      NET_UCSRA |= (1 << MPCM0);
143
      DataOk = true;
144
    }
145
    return;
146
  }
147
  if (RxBody == (stRxData.DataLength - 2)) // CRC16 High
148
  {
149
    RxCrc16 = ucRxByte << 8;
150
    stRxData.Data[RxBody] = ucRxByte;
151
    RxBody++;
152
    return;
153
  }
154
  if (RxBody == (stRxData.DataLength - 1)) // CRC16 Low
155
  {
156
157
    RxCrc16 |= ucRxByte;
158
    stRxData.Data[RxBody] = ucRxByte;
159
    CalcCRC(0);
160
    CalcCRC(0);
161
    RxBody = RxHeader = 0;
162
    if (crc16 != RxCrc16) // fehler CRC
163
    {
164
      NET_UCSRA |= (1 << MPCM0);
165
      return;
166
    }
167
    else // alles OK
168
    {
169
      NET_UCSRA |= (1 << MPCM0);
170
      DataOk = true;
171
      return;
172
    }
173
  }
174
175
  if (RxBody>=MAX_DATA_LENGTH)
176
  {
177
  NET_UCSRA |= (1 << MPCM0);
178
  return;
179
  }
180
181
}

am Wochendende mehr.

ms

von M. W. (mw73)


Lesenswert?

Hallo ms,

danke für den Code, ich werd mich da heut abend gleich
durcharbeiten.

Danke

LG
Markus

von ms (Gast)


Lesenswert?

Hallo Markus,

wie sieht es mit der Hardware aus??
Brauchst Du da auch Hilfe?
Ich hätte da auch ne schöne Lösung.

ms

von M. K. (sylaina)


Lesenswert?

Er vielleicht nicht aber ich wäre da nicht abgeneigt. Lese bisher nur 
mit aber ich entwickle auch grad ein Gerät u.a. mit mehrere uCs (geplant 
sind bisher Atmega328er) die verschiedene Motoren/Aktuatoren/Sensoren 
steuern/auswerten sollen. Als Kommunikation möchte ich gerne einen 
RS485-Bus benutzen, bisher dachte ich daran einen MAX485 zu verwenden um 
damit den Bus aufzubauen.

von ms (Gast)


Lesenswert?

Hallo,

O.k. können wir machen.
Wird es kommerziell genutzt?

ms

von Peter D. (peda)


Lesenswert?

ms schrieb:
> Noch ein Tip: Versuche keine "Texte" für kommandos zu nehmen das macht
> dir später das leben schwer.

Ganz im Gegenteil, Texte kann man sehr einfach vergleichen und debuggen 
(sniffen). Außerdem lassen sie sich leicht merken.

Kryptische Binärwerte nimmt man nur dann, wenn es auf maximale Datenrate 
ankommt. Und dann muß man sich beim Debuggen immer ne Tabelle daneben 
legen, was sie bedeuten. Oder man schreibt ein extra Programm, was sie 
wieder in verstehbare Texte umsetzt.

von ms (Gast)


Lesenswert?

Hallo Peter,

Peter D. schrieb:
> wenn es auf maximale Datenrate
> ankommt.

Das stimmt nicht ganz es kommt nicht auf die maximal Datenrate an 
sonderen das der Prozessor nicht viel zeit zum Parsen verschwenden soll.
Er sollte lieber so viel Zeit für seinen eigentliche Arbeiten verwenden 
die er bekommen kann.
Ich sehe die kommunikation nicht als Hauptaufgabe des Prozessors!!!

Peter D. schrieb:
> Oder man schreibt ein extra Programm
das gehört nun mal dazu und ist auch nicht schwer.

ms

von M. K. (sylaina)


Lesenswert?

ms schrieb:
> Hallo,
>
> O.k. können wir machen.
> Wird es kommerziell genutzt?
>
> ms

Nutzung ist für meinen Hobbyraum gedacht. Ich will mir so eine Art CNC 
und/oder Laser-Gravierer bauen (um schlicht und ergreifend zu lernen). 
Eigentlich könnte also die komplette Steuerung auch ein einziger uC 
übernehmen, ich will mir aber auch mal die Kommunikation zwischen uCs 
anschaun bzw. damit arbeiten und hab mich hier für RS485 entschieden. 
Daher habe ich mir überlegt: Ein uC steuert nur die Motoren an, ein uC 
wertet die Positionen aus, ein weiterer kümmert sich um die restlichen 
Sensoren (beim Lasergravierer z.B. die Steuerung der Energie des 
Lasers). Ein vierter uC soll sich um die Kommunikation mit einem PC 
kümmern, sodass das System vom PC aus steuerbar ist. Das Ganze ist noch 
in der Entwicklung (auf Papier und in meinem Kopf), nichts in Stein 
gemeißelt und der Hintergrund ist einfach nur, dass ich das mal 
ausprobieren möchte wobei das Hauptaugenmerk auf dem Bussytem, hier 
RS485, liegt, sprich also der Weg ist hier eigentlich das Ziel.

ms schrieb:
> Das stimmt nicht ganz es kommt nicht auf die maximal Datenrate an
> sonderen das der Prozessor nicht viel zeit zum Parsen verschwenden soll.

Ich nehme hier auch immer Klartext-Kommandos. Binärwerte, so denke ich 
mir, waren in der Vergangenheit u.a. auch deswegen benutzt worden, weil 
sie Speicherplatz (neben CPU-Load beim Parsen) sparten, oder?

: Bearbeitet durch User
von ms (Gast)


Lesenswert?

Hallo Köhler

M. K. schrieb:
> Ich nehme hier auch immer Klartext-Kommandos. Binärwerte, so denke ich
> mir, waren in der Vergangenheit u.a. auch deswegen benutzt worden, weil
> sie Speicherplatz (neben CPU-Load beim Parsen) sparten, oder?

könnte auch eine Rolle spielen.
Anderes Beispiel:
Dein uC muss ein Sensorsignal auswerten in der Regel mit y=m*x+b da 
kommt
ein float für maximale Genauigkeit raus (geht aber auch mit long).
Jetzt muss du diesen wert übertragen mit 6 Nachkommastellen.
Das sind Vorkomma+6 Byte.
Binär sind es immer 4 Byte.

ms

von M. W. (mw73)


Lesenswert?

Hallo ms!

Würdest Du mir auch Deine Hardware Lösung zur verfügung stellen, da die 
sicher viel besser ist als meine Standard Lösung. Natürlich auch für 
rein private Nutzung.

Ich analysiere gerade Deinen crc-code und melde mich zum Wochenende.
Danke nochmal für den Code.

Danke auch an Peter für Deinen Beitrag.

Schönen Abend und LG

Markus

von M. K. (sylaina)


Lesenswert?

ms schrieb:
> Jetzt muss du diesen wert übertragen mit 6 Nachkommastellen.
> Das sind Vorkomma+6 Byte.
> Binär sind es immer 4 Byte.

Na na na, Wert und Befehl sind jetzt aber zwei unterschiedliche paar 
Schuhe, oder?
Aber du hast recht, das macht schon Sinn einen Float so zu übertragen, 
ich übertrage Floats auch oft so ;)

von ms (Gast)


Lesenswert?

guten morgen M.K.

M. K. schrieb:
> Na na na, Wert und Befehl sind jetzt aber zwei unterschiedliche paar
> Schuhe, oder?

Da mach ich keinen unterschied. Die art und weise wie man das umsetzt 
sollte durchgängig gleich sein (sonst braucht man 2 Tabellen zum 
debuggen ;-))

m.s

von M. K. (sylaina)


Lesenswert?

Das ist sicherlich auch nicht verkehrt es durchgängig gleich zu machen, 
es kommt halt drauf an was man machen will. Ich finde halt bei Befehlen 
Klartext nicht falsch weil man dann sich die Sache auch in drei Jahren 
nochmal anschaun kann und weiß was da passiert ohne einen Blick in eine 
Codetabelle werfen zu müssen. ;)

Aber genug davon, meine erste Idee mit dem MAX485 schaut so aus, dass 
ich Rx/Tx entsprechend aufgelegt habe und DE bzw. !RE auf einen freien 
Portpin. Defaultmäßig werde ich wohl immer nur auf den Bus lauschen es 
sei denn der Master sagt, dass ich auch quatschen darf. Im Moment fehlt 
mir noch die Idee wie ich es handhaben soll wenn zwei Slaves 
gleichzeitig quatschen wollen. Lasse ich den Master regelmäßig fragen ob 
jemand was zu sagen hat oder soll ich die Slaves regelmäßig den Master 
fragen lassen ob sie ihre Informationen weiter reichen dürfen. Spontan 
finde ich die erste Variante schöner aber auch nicht optimal.

von ms (Gast)


Lesenswert?

Hallo M.K.

Jetzt komms pas auf :-)
Nimm dir das Leben als Beispiel.
In der Schule hat der Lehrer das sagen. Der schüler antwortet nur nach 
auforderung und das in einer angemessen zeit ohne um drum herum zu 
quatschen.
Das ist die Autoritäre Art.

Es gibt auch Lehrer die eine Art Redenstock haben die die Schüler immer 
durchgeben nur der mit dem Stock(Token) darf Reden.
Das ist die Laissez-faire Art.

Je nach System und Anforderung muss man auswählen welche Art sich am 
besten eignet

ms

von M. K. (sylaina)


Lesenswert?

Die Idee mit dem Redestock gefällt mir für meinen Fall am besten jetzt 
wenn ich so drüber nachdenke, kann aber sein dass das für mich völliger 
Mumpitz ist und ich besser die Reihe durchgehe und immer frage...da muss 
ich mich nochmal schlau machen was bei mir schlauer wäre.

von ms (Gast)


Lesenswert?


von ms (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

Ich habe mal mein Bus-System angehängt.
Der Grundaufbau ist bei Master und Slave immer gleich (OK unnötig aber 
kostet ja nicht die Welt).
Der Bus geht über normales Netzwerkkabel oder Patchkabel.
Es gibt ein Y-Verteiler der Verteilt den Bus zum Slave und zum nächten 
Y-Verteiler oder End-Slave.
Beim Master ist es möglich den zweiten Abschlußwiderstand zu setzen 
(Achtung da verdoppelt sich die Leitungslänge).
Bei einem End-Slave wird halt der R dort gesetzt und beim Master 
nicht(Jumper).
Das einfügen eines neuen Slave in das bestehende System ist dadurch kein 
Problem (neues Dachfenster).


ms

von ms (Gast)


Lesenswert?

Hallo Leute,

jetzt nochmal zu meinem Aufbau.
Die Grundschaltung ist nichts neues man könnte sie noch aufblusten mit 
Würth und Co. Ist aber aus meiner erfahrung nicht nötig. Genau dieser 
Aufbau wurde bei einer Testphase beim DLR in Köln verwendet. Da habe ich 
für einen Tag die Langarmzentriefuge gemietet. Ich musste die 
Stromaufnahme eines Lüfters bei verschiedene G-Kräfte messen (bis ca 
10G). Der Bus wurde über ein (zwei) Koaxkabel zu einem Schleifring in 
die Gondel übertragen. Das war nun mal die einzige möglichkeit in die 
Gondel zu kommen.
Ich kann euch sagen es gab keine Problem.Ich kann euch nicht sagen wie 
lang das Koax war aber ich gehe von ca. 200m aus.

Es ist keinem aufgefallen das der Schirm nicht angeschlossen ist.Muss 
natürlich sein.GND->100 Ohm-> Schirm.

ms

von M. W. (mw73)


Lesenswert?

Hallo ms!

Danke nochmal für alle Unterlagen bis jetzt. Den Aufbau werde ich mir 
später genauer ansehen. Ich versuch erst mal den Packetaufbau und den 
crc check auf die Reihe zu bekomen. Ich melde mich zum WE und hoffe dass 
ich bis da hin soweit bin.

Sag mal, wie viel kostet die Tagesmiete für die Langarmzentrifuge?
Bin sehr beeindruckt von dem was Du machst.

LG
Markus

von ms (Gast)


Lesenswert?

Hallo Markus,

Markus W. schrieb:
> Sag mal, wie viel kostet die Tagesmiete für die Langarmzentrifuge?
so genau kann ich dir das nicht sagen ist schon echt lange her. Aber die 
waren glaub ich froh dass sich das Ding mal wieder dreht. Es war 
garnicht mal so teuer 2000-2500,- glaube ich noch zu wissen.

Markus W. schrieb:
> crc check auf die Reihe zu bekomen

Da gibt es auch viel zum nachlesen es gibt aber auch verschieden Arten. 
Halte Dich nicht zu lange damit auf. Es fehlt ja noch das Senden und die 
Kommando Auswertung.

ms

von M. W. (mw73)


Lesenswert?

Hallo ms!

Ich hab mich jetzt soweit mit dem Code beschäftigt. Einiges ist soweit 
auch klar, vieles jedoch nicht und teilweise fehlen mir noch die 
Zusammenhänge.

Darf ich Dir einige konkrete Fragen stellen?

Ich hab mich soweit in die Theorie des crc-checks eingelesen und das 
soweit auch verstanden. Allerdings is mir Deine Umsetzung nicht so ganz 
klar.

void CalcCRC(unsigned char data)
könntest Du mir die in zwei drei Sätzen erklären (die Bildung vom Flag 
und die weiteren zwei if-Abfragen).

Dann zur ISR

... dort wo zb. die Adresse eingelesen wird ist mir soweit klar.
Die Adresse geht einmal in RXAdress.
Dann startet ein neuer Frame.
Es wird die Checksumme berechnet
und in den Header geschrieben --> was wird hier hinein geschrieben?

könntest Du mir auch noch die folgenden if-Anweisungen kurz erklären
(wo der header einmal auf 1,2 oder ungleich 0xff geprüft wird?)
Was ist eigentlich das Info Byte?

Oje, mit dem Body sieht's nicht viel besser aus.

Tut mir leid, aber mit diesen Einträgen in header und body kann ich 
nicht viel anfangen.

...oder muss da die Senderoutine schon dementsprechend angepasst sein?
wann wurde überhaupt in den header geschrieben, wenn dieser auf zwei 
geprüft wird. Wenn die RxAdresse eingelesen wird, wird ja der header auf 
0 gesetzt?

so viele Fragen :-(

Ich hoffe das wird Dir nicht zuviel.

LG
Markus

von ms (Gast)


Lesenswert?

Hallo Markus,

Markus W. schrieb:
> void CalcCRC(unsigned char data)
> könntest Du mir die in zwei drei Sätzen erklären (die Bildung vom Flag
> und die weiteren zwei if-Abfragen).

Können wir das bis zum schluß aufheben.
https://de.wikipedia.org/wiki/Zyklische_Redundanzpr%C3%BCfung

Markus W. schrieb:
> Tut mir leid, aber mit diesen Einträgen in header und body kann ich
> nicht viel anfangen.

Du must dir klar machen dass die ISR bei jedem Byte ausgelösst wir.
Zwischen den einzelnen Bytes macht der uC irgend was anderes.
RXHeader und RXBody sind Hilfsvariablen in denen wir die Positionen 
speichern.
Am Anfang Senden wir ja die Adresse im 9bit Format das ist der 
eindeutige Start von einem Frame (die ISR wird nur bei einem 9Bit Byte 
Ausgelöst bei einem 8 bit Byte passiert nichts). Ist das Frame für mich 
gedacht schalten wir um in den 8 bit Modus(ab jetzt wird die ISR bei 8 
bit ausgelöst). Gleichzeitig werden alle Hilfsvariablen 
initalisiert.RXHeader wird um ein erhöht da ich weis das nächste Byte 
ist das InfoByte.
1
if (RxHeader == 1) // Info BYTE
2
  {
3
    stRxData.InfoByte = ucRxByte;
4
    RxHeader++;// RxHeader um eins erhöhen!!!!!!!!!!!!!!!!
5
    CalcCRC(RxByte);
6
    return;
7
  }
Nachdem das InfoByte empfangen ist wird der RXHeader nochmal um ein 
erhöht
da jetzt die SenderAdr kommt.
1
if (RxHeader == 2) // Sender ADR
2
  {
3
    stRxData.TxAddress = ucRxByte;
4
    RxHeader++;// RxHeader um eins erhöhen!!!!!!!!!!!!!!!!
5
    CalcCRC(ucRxByte);
6
    return;
7
  }
Jetzt wird RXHeader nochmal erhöht
Beim nächsten Byte werden die zwei ersten IF abfragen mit RXHeader nicht 
mehr durchlaufen sondern die nächste.
1
if (RxHeader != 0xFF) // DATA Länge
2
  {
3
4
    RxHeader = 0xFF;// RxHeader auf das Maximum setzen!!!!!!!!
5
    stRxData.DataLength = ucRxByte;
6
    CalcCRC(ucRxByte);
7
    return;
8
  }
Hier wird die länge der Nutzdaten übertragen (+ 2Byte CRC16)
Ab jetzt muss ich sorge tragen dass die ganze Header Geschichte nicht 
mehr durchlaufen wird also RXHeader = 0xff
RXBody ist 0 beim Start haben wir die Variable so initalisiert.
Da ich weiss dass jetzt die Nutzdaten kommen muss ich die nach der reihe 
in meinen Buffer schreiben (stRxData.Data[RxBody] = ucRxByte;)
Aber nur die Nutzdaten die zwei letzten sind CRC16. Um diese raus zu 
filtern gibt es das MAKRO INCLUDE_CRC(stRxData.InfoByte) (<-- da war ein 
fehler). Das Makro überprüft ob der Sender eine CRC16 mitgeschickt hat 
oder nicht. der Sender Signalisiert das mit dem InfoByte sobald da 0x10 
drin steht gibt das Makro 2 zurück ansonsten 0.
Ist keine CRC nötig wird eingelsen bis RxBody == stRxData.DataLength 
ist.
Danach wir dem MainThread eine Info gegeben dass neue Daten verfügbar 
sind DataOK = true (wird aber noch eine CallBack funktion).
Ist eine CRC berechnung nötig werden die zwei letzten Byte eingelesen 
und mit der Lokal berechneten CRC (crc16)verglichen. Ist alles OK Signal 
an MainThread.

ms

von ms (Gast)


Lesenswert?

Hallo Markus,

noch was das InfoByte benutze ich um während dem Emfangen entscheidungen 
zu treffen um dass sich das Haupprogramm sich nicht kümmern soll.
Z.B. kann der Sender einen einfache Antwort (ACK oder NACK) anforden 
oder eine qualifizierte(antwort mit messdaten). Die einfache wird 
automatisch an den sender gesendet sobald der Frame kompett eingelesen 
ist. Die andere muss das Hauptprogramm zusammenstellen.
Es könnte ja auch mal sein das Infomationen in Fragmente aufgeteilt 
werden müssen im InfoByte könnte man die FragmendID mittschicken und dem 
Hauptprogramm erst Info geben sobald alle Fragmente empfangen sind.

ms

von M. W. (mw73)


Lesenswert?

Hallo ms!

Vielen Dank für Deine ausführlichen Erklärungen.
Das waren jetzt die Zusammenhänge die ich noch benötigt habe.

Ich hab zwar gestern abend den Teil der ISR, wo die Adresse empfangen 
wird ins Visual Studio geschrieben und mit printf ausgeben lassen. Dabei 
ist mir auch schon aufgefallen, dass der Header auf 1 gesetzt wurde.

Das heißt jetzt, ich kann mein Programm dementsprechend abändern.
Ich muss dazu meine Senderoutine anpassen auf Adresse, Infobyte, 
Nutzdaten

Ich werde mich gleich dran machen und melde mich wenn ich soweit bin.

Vielen Danke noch einmal, dass Du mir das so aufbereitest, dass ich für 
mich eine einzigartige Chance komplexere Dinge zu lernen.

LG
Markus

von ms (Gast)


Lesenswert?

Hallo Markus,

Markus W. schrieb:
> Das heißt jetzt, ich kann mein Programm dementsprechend abändern.

ja kannst du.

Ich gehe jetzt nachhause leg mich hin und heute mittag werde ich eine 
Senderoutine zusammen stellen. Die kannst du in ruhe analysieren und 
Ideen daraus entwickeln.

ms

von ms (Gast)


Lesenswert?

Hallo Markus,

hier mal mein Testcode für den Master
1
#ifndef F_CPU
2
#define F_CPU 16000000UL
3
#endif
4
5
#include <avr/io.h>
6
#include <avr/interrupt.h>
7
#include <util/delay.h>
8
#include <stdio.h>
9
#include <stdbool.h>
10
#include <stdlib.h>
11
#include <string.h>
12
13
14
#define UART_BAUD_CALC(UART_BAUD_RATE,F_OSC) \
15
( ( F_OSC ) / ( ( UART_BAUD_RATE ) * 8UL ) - 1 )
16
17
#define NOP asm volatile ("nop" ::)
18
19
#define NET_UCSRA             UCSR0A
20
#define NET_UCSRB             UCSR0B
21
#define NET_UCSRC             UCSR0C
22
#define NET_UDR               UDR0
23
#define NET_ADRESS        0x01
24
#define UART_BAUD_RATE        9600
25
#define CRC_BIT         0x10
26
#define INCLUDE_CRC(x)        (((x) & (CRC_BIT)) !=0) ? (2):(0)
27
28
#define MAX_DATA_LENGTH 10
29
#define CRC16_POLYNOM   0x1002
30
31
typedef struct {
32
  unsigned char RxAddress;
33
  unsigned char InfoByte;
34
  unsigned char TxAddress;
35
  unsigned char DataLength;
36
  unsigned char Data[MAX_DATA_LENGTH];
37
} st_protokoll_Data;
38
39
volatile bool DataOk;
40
41
st_protokoll_Data stRxData;
42
st_protokoll_Data stTxData;
43
44
unsigned char RxHeader;
45
unsigned char RxBody;
46
unsigned int RxCrc16;
47
unsigned int crc16;
48
/* neu******************************/
49
unsigned char *NetTxPtr;
50
unsigned char NetTxCount;
51
unsigned char NetTxCount_temp;
52
53
void NetSetTxEnable(bool enable) {
54
  if (enable) {
55
    PORTB |= (1 << PINB2);
56
  }
57
  else {
58
    PORTB &= ~(1 << PINB2);
59
  }
60
}
61
62
void NetInit() {
63
  char c;
64
65
  UBRR0H = (unsigned char)(UART_BAUD_CALC(UART_BAUD_RATE, F_CPU) >> 8);
66
  UBRR0L = (unsigned char)UART_BAUD_CALC(UART_BAUD_RATE, F_CPU);
67
68
  NET_UCSRA = (1 << U2X0) | (1 << MPCM0);
69
  NET_UCSRB = (1 << UCSZ02) | (1 << RXCIE0) | (1 << RXEN0) | (1 << TXEN0) | (1 << TXCIE0); 
70
  NET_UCSRC = (1 << UCSZ01) | (1 << UCSZ00);
71
  NetSetTxEnable(false);
72
  c = NET_UDR; // Rx Buffer leeren und verwerfen
73
}
74
75
void InitCRC(void) {
76
  crc16 = 0xffff;
77
}
78
79
void CalcCRC(unsigned char data) {
80
  unsigned char bitCount;
81
  unsigned char PolynomFlag;
82
  for (bitCount = 0; bitCount < 8; bitCount++) {
83
    PolynomFlag = (crc16 & 0x8000) != 0;
84
    crc16 <<= 1;
85
    if (data & 0x80) {
86
      crc16 |= 1;
87
    }
88
    data <<= 1;
89
    if (PolynomFlag)
90
    crc16 ^= CRC16_POLYNOM;
91
  }
92
}
93
94
void Net_NewFrameStart(void) {
95
  DataOk = false;
96
  RxHeader = 0x00;
97
  RxBody = 0x00;
98
  RxCrc16 = 0;
99
  InitCRC();
100
  stRxData.TxAddress = NULL;
101
102
}
103
104
void Net_SendFrame(void)
105
{
106
  int i, loop;
107
  i = 0;
108
  InitCRC();
109
  CalcCRC(stTxData.RxAddress);
110
  i++;
111
  CalcCRC(stTxData.InfoByte);
112
  i++;
113
  CalcCRC(stTxData.TxAddress);
114
  i++;
115
  CalcCRC((stTxData.DataLength += (INCLUDE_CRC(stTxData.InfoByte))));
116
  i++;
117
  for (loop = 0; loop < (stTxData.DataLength - (INCLUDE_CRC(stTxData.InfoByte))); loop++) // Framedaten
118
  {
119
    CalcCRC(stTxData.Data[loop]);
120
    i++;
121
  }
122
  CalcCRC(0);
123
  CalcCRC(0);
124
  stTxData.Data[loop++] = (crc16>>8)&0xff;
125
  stTxData.Data[loop] = (crc16)&0xff;
126
  NetTxCount = i+(INCLUDE_CRC(stTxData.InfoByte));
127
  NetTxCount_temp = NetTxCount;
128
  NetTxPtr = &stTxData.RxAddress;
129
  NetSetTxEnable(true);
130
  NET_UCSRB |= (1<< TXB80); // nur beim Master
131
  NET_UCSRB |= (1<<UDRIE0); // Tx Empty einschalten
132
  
133
}
134
135
void Net_SendChar(unsigned char ptr_RXAddress,unsigned char *val,
136
unsigned int len)
137
{
138
  int loop;
139
  stTxData.RxAddress = ptr_RXAddress;
140
  stTxData.TxAddress = NET_ADRESS;
141
  stTxData.InfoByte = CRC_BIT;
142
  stTxData.DataLength = len;
143
  for(loop = 0; loop < len; loop++){
144
    stTxData.Data[loop] = *val++;
145
  }
146
  Net_SendFrame();
147
}
148
149
ISR(USART_UDRE_vect) // Tx Buffer ist leer und braucht nachschub
150
{
151
  
152
  if (NetTxCount)
153
  {
154
    if(NetTxCount != NetTxCount_temp)NET_UCSRB &= ~(1<< TXB80); 
155
    NET_UDR = *NetTxPtr;
156
    NetTxPtr++;
157
    NetTxCount--;
158
    
159
  }
160
  else
161
  NET_UCSRB &= ~(1<<UDRIE0); // Tx Empty abschalten
162
}
163
164
165
ISR(USART_TX_vect)  // Leztes Byte wurde gesendet
166
{
167
  NetSetTxEnable(false);
168
  NOP;
169
  NOP;
170
  
171
}
172
173
ISR(USART_RX_vect) {
174
    unsigned char ucRxByte;
175
  
176
  if (NET_UCSRA & ((1 << FE0) + (1 << DOR0))) // Fehler
177
  {
178
    ucRxByte = NET_UDR; // Rx Buffer leeren
179
    NET_UCSRA |= (1 << MPCM0); // MPCM Mode einschalten
180
    DataOk = false;
181
    return;
182
  }
183
184
  if ((NET_UCSRB & (1 << RXB80)) ) // OK mit 9. bit
185
  {
186
187
    ucRxByte = NET_UDR;
188
    if (ucRxByte == NET_ADRESS) {
189
      NET_UCSRA &= ~(1 << MPCM0); // MPCM Mode ausschalten
190
      stRxData.RxAddress = ucRxByte;
191
      NET_UDR = ucRxByte;
192
      Net_NewFrameStart();
193
      CalcCRC(ucRxByte);
194
      RxHeader++;
195
      return;
196
    }
197
    else // Packet ist nicht für mich gedacht.
198
    {
199
      NET_UCSRA |= (1 << MPCM0);
200
      return;
201
    }
202
203
  }
204
  // ab hier geht es weiter mit 8 bit
205
  ucRxByte = NET_UDR;
206
207
  if (RxHeader == 1) // Info BYTE
208
  {
209
    stRxData.InfoByte = ucRxByte;
210
    RxHeader++;
211
    CalcCRC(ucRxByte);
212
    return;
213
  }
214
  if (RxHeader == 2) // Sender ADR
215
  {
216
    stRxData.TxAddress = ucRxByte;
217
    RxHeader++;
218
    CalcCRC(ucRxByte);
219
    return;
220
  }
221
  if (RxHeader != 0xFF) // DATA Länge
222
  {
223
224
    RxHeader = 0xFF;
225
    stRxData.DataLength = ucRxByte;
226
    CalcCRC(ucRxByte);
227
    return;
228
  }
229
230
  if (RxBody < (stRxData.DataLength - (INCLUDE_CRC(stRxData.InfoByte)))) // DATA
231
  {
232
233
    stRxData.Data[RxBody] = ucRxByte;
234
    CalcCRC(ucRxByte);
235
    RxBody += 1;
236
    if (!INCLUDE_CRC(stRxData.InfoByte) &&
237
    (RxBody == stRxData.DataLength)) // Keine CRC nötig
238
    {
239
      NET_UCSRA |= (1 << MPCM0);
240
      DataOk = true;
241
    }
242
    return;
243
  }
244
  if (RxBody == (stRxData.DataLength - 2)) // CRC16 High
245
  {
246
    RxCrc16 = ucRxByte << 8;
247
    stRxData.Data[RxBody] = ucRxByte;
248
    RxBody++;
249
    return;
250
  }
251
  if (RxBody == (stRxData.DataLength - 1)) // CRC16 Low
252
  {
253
254
    RxCrc16 |= ucRxByte;
255
    stRxData.Data[RxBody] = ucRxByte;
256
    CalcCRC(0);
257
    CalcCRC(0);
258
    RxBody = RxHeader = 0;
259
    if (crc16 != RxCrc16) // fehler CRC
260
    {
261
      NET_UCSRA |= (1 << MPCM0);
262
      return;
263
    }
264
    else // alles OK
265
    {
266
      NET_UCSRA |= (1 << MPCM0);
267
      DataOk = true;
268
      return;
269
    }
270
  }
271
272
  if (RxBody==MAX_DATA_LENGTH)
273
  {
274
    NET_UCSRA |= (1 << MPCM0);
275
    return;
276
  }
277
278
}
279
280
281
int main(void) {
282
  unsigned char buf[20];
283
  DDRB = (1 << PINB5) | (1 << PINB2); // set PINB0 and PINB2 as output
284
285
  NetInit();
286
  _delay_ms(200);
287
  sei();
288
289
  while (1) {
290
    
291
    
292
    _delay_ms(1000);
293
    sprintf(buf,"LED");
294
    Net_SendChar( 0x44,&buf[0],3);
295
    
296
297
  } // while
298
299
} // main

ab jetzt sollte man den Code in Dateien aufteilen.
Du siehts es ist garnicht so schwer.
Im nächsten Kapitel werden wir uns mit den Kommandos beschäftigen.

ms

von M. W. (mw73)


Lesenswert?

Hallo ms!

Danke Dir erneut für den Code.
Ich hatte heute vormittag keine Zeit zum testen, bin aber
jetzt wieder voll dabei und mach mich gleich ans Werk.

Ich melde mich später wie ich zurecht kommme.

LG
Markus

von M. W. (mw73)


Lesenswert?

Hallo ms!

ich hab jetzt mal beide Codes am laufen (den Mastercode muss ich noch 
genauer studieren)

Da ja das ganze System jetzt anders funktioniert hab ich noch eine 
Frage.

Die If-Abfrage nach dem Rufzeichen (Stringende) ist ja jetzt hinfällig.
1
  if (ucRxByte != '!') // EndZeichen  empfangen
2
  {
3
    test[ucRxCount] = ucRxByte;
4
    ucRxCount++;
5
    return;
6
  }

Diese hab ich auch in der ISR weg gelassen. Ich lasse mir die Nutzdaten 
(im jetztigen Fall LED) auf das Lcd ausgeben. Es kommen aber hinterher 
noch zwei Hieroglyphen. Kann es an der fehlenden Null-Terminierung 
liegen?

ich lese die Nutzdaten jetzt in der while schleife aus
1
While(1){
2
_delay_ms(1); // testweise, um am lcd was zu sehen
3
if (DataOk) {
4
      lcd_setcursor(0, 2);
5
      sprintf(buf, "My adress = 0x%x", stRxData.RxAddress); // Slave Add
6
      lcd_string(buf);
7
    
8
    lcd_setcursor(0, 3);
9
    sprintf(buf, "MA adress = 0x0%x", stRxData.TxAddress); // Master Add
10
    lcd_string(buf);
11
    
12
          lcd_setcursor(0, 4);
13
          lcd_string(&stRxData.Data); // Nutzdaten
14
15
     DataOk = false;
16
  }
17
}

Ist das richtig die Daten so auszulesen oder muss ich die ISR noch 
anpassen bzw. warum hab ich die Hieroglyphen am ende des Strings?

LG
Markus

von ms (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Markus,

Markus W. schrieb:
> warum hab ich die Hieroglyphen am ende des Strings?

sorry mein fehler habe vor lauter hin und her kopieren immer diese Zeile 
mit kopiert
1
if (RxBody == (stRxData.DataLength - 2)) // CRC16 High
2
  {
3
    RxCrc16 = ucRxByte << 8;
4
    // -- > stRxData.Data[RxBody] = ucRxByte;
5
    RxBody++;
6
    return;
7
  }
8
  if (RxBody == (stRxData.DataLength - 1)) // CRC16 Low
9
  {
10
11
    RxCrc16 |= ucRxByte;
12
    // --> stRxData.Data[RxBody] = ucRxByte;

ich habe mal meine Datei angehängt schau sie Dir mal an.

Und ja! Sollte jemand mal nachfragen. Über den RS485-BUS mit MPCM Mode 
ist es möglich einen Bootloader mit einzubauen das hat den vorteil dass 
die anderen Slaves garnicht mitbekommen das ein ander gerade geflasht 
wird da der Loader ja nur im 8bit modus läuft. Einziger knackpunkt ist 
das umschalten von TXEnable.

ms

von M. W. (mw73)


Lesenswert?

Hallo ms!

Danke, jetzt funktioniert es !!

Sag mal, ich bin gerade am durchsehen und vergleichen des Master Codes 
mit der Version die Du mir heute geschickt hast.

Da ist mir aufgefallen, und ich hab es auch schon öfters gelesen, dass 
die Adresse optional aus dem EEProm gelesen werden kann.

Wie sinnvoll ist das überhaupt die Adresse ins EEProm zu verfrachten?

Du betreibst Deine Controller mit Bootloader? Geht es Dir hierbei 
hauptsächlich ums flashen während des Betriebs?

Ich werde jetzt den Master Code besser studieren und etwas Code hin und 
her schicken.

LG
Markus

von ms (Gast)


Lesenswert?

Hallo Markus,

Markus W. schrieb:
> Wie sinnvoll ist das überhaupt die Adresse ins EEProm zu verfrachten?

ja oder willst Du für jeden Slave den Compiler neu anschucken.
Ich mach das immer so. Slave flashen. EEProm an stelle x lesen ist das 
0xff
ist das ein neuer slave und bekommt die Adresse 0x00. Der Master scan 
zyklisch den Bus ab ob ein neuer Slave da ist. Ist einer da kann ich mit 
dem kommando SET_NET_ADR ihm eine ADR zuweisen (ins EEProm schreiben).

Markus W. schrieb:
> Geht es Dir hierbei
> hauptsächlich ums flashen während des Betriebs?

Ja. Stell dir vor deine Teile sind irgend wo in der Welt verteilt. Und 
du sollst einen neue Firmware aufspielen. Da ist doch ein Bootloader 
doch nicht schlecht. Meist habe ich ein Linux System als Master auf dass 
ich von der ferne zugreifen kann. Da muss ich nur das Hex hinüber 
schieben und den Bootloader starten.

ms

von M. W. (mw73)


Lesenswert?

Hallo ms!

wow, ich bin wirklich sehr beeindruckt!!!!
Du lässt also die Adressen vergeben.

... Wie gesagt als Anfänger hab ich mir über so etwas keine Gedanken 
gemacht.
In meinem Mini-System hab ich einen Master und drei Slaves. Da ist die 
Vergabe kein Problem.

Aber der Ansatz ist wirklich sehr Interessant.
Vollprofi eben !!!!

LG
Markus

von ms (Gast)


Lesenswert?

Hallo Markus,

ich empfehle dir für deinen Master eine größere Platform. Für kleinere 
Aufgaben ist ein ATmega noch i.O. Ich habe keine Ahnung was du vor hast.
Ich teste gerade eine Himbeere mit Win10 als Master sieht bis jetzt 
nicht schlecht aus.

ms

von ms (Gast)


Lesenswert?

Hallo Markus,

die Lib ist noch nicht Wasserdicht.Die Kommunikation ist im moment nur 
einseitig (der Master sendet und der Slave empfängt) es sollte aber sein 
dass der Slave den empfang bestätigt. Auch ganz wichtig es muss eine 
Timeout funktion oder ähnlich beim Senden eingebaut werden da ich die 
Erfahrung gemacht habe dass das TXEnable PIN bei kleinen Atmegas nicht 
zuverlässig zurück geshalten wird (deswegen die zwei NOPs).Du kannst dir 
ja bis zum WE mal gedanken machen (auch die anderen sind gerne 
Eingeladen) wie man sowas mit einbauen kann.

ms

von nicht“Gast“ (Gast)


Lesenswert?

Hiho

Die Adresse würde ich eher in Hardware setzen und über gpio auslesen. 
Dann brauchst du gar nichts mehr programmieren und kannst die Teile 
einfach aus dem Lager nehmen.

Da musst du aber natürlich die Pins über haben und einen DIP Switch dran 
packen.

Grüße

von ms (Gast)


Lesenswert?

Hallo,

das geht natürlich auch 8fach dip mit schieberegister und 3 port pin.

ms

von M. W. (mw73)


Lesenswert?

Hallo ms!

Danke für die weiteren Gedankenansätze. Ich hab es ja noch gar nicht 
erwähnt, ich möchte mit diesem System einmal meine Rolläden steuern.
Es handelt sich daher um eine geringe Anzahl an controllern. Es soll 
einen Master und fünf Slaves geben. Zusätzlich soll das System von einer 
einfachen Wetterstation beeinflusst werden (Wind, Lichtstärke, Uhrzeit 
usw.).

Ich habe mir auch schon mal Gedanken über den Einsatz eines Rasp 
gemacht, bin aber fürs erste froh, wenn das mit den Mega soweit 
funktioniert.

Ich möchte mir jetzt wirklich, wie Du es vorgeschlagen hast in den 
nächsten Tagen Gedanken über einen erweiterten Kommunikationsablauf, 
sowie Timeouts und Codeauslagerung Gedanken machen und Dir diese bis zum 
nächsten WE mitteilen.

Vielen Danke für die Unterstützung bis jetzt.

LG
Markus

von ms (Gast)


Lesenswert?

Hallo Markus,

das ist mal ein gutes Projekt um den Bus zu erreichen. Meine 
Technikerarbeit habe ich mit einer Wetterstation gemacht (WXT510 
Vaisala) die hängt noch bei mir an der Hütte. Ich glaube daher stammt 
auch die crc Routine.

ms

von M. W. (mw73)


Lesenswert?

Hallo ms!

Ich hätte eben vor, das Projekt langsam wachsen zu lassen. Zuerst eine 
einfache Zeitsteuerung, bei der der Master die Rolläden Öffnungs- und 
Schließbefehle zu bestimmten Zeiten gibt. Wenn das soweit läuft, soll 
die Wetterstation mit ins Spiel kommen und eben zb. bei starkem Wind die 
Rolläden öffnen oder bei dunkelheit unabhängig von der Uhrzeit 
schließen.

Auch eine kleine Alarmanlage soll integriert werden (Fensterabsicherung 
durch Glasbruchsensor, Reedkontakt und Ultraschallsensor).

Ich hab die Rolläden vor ein paar Monaten bekommen, hab sie 
zwischenzeitlich über einen Webserver gesteuert (2560+W5100). Das hat 
auch sehr gut funktioniert, war aber nur testweise ein kleines 
Spaßprojekt.

LG
Markus

von M. W. (mw73)


Lesenswert?

Hallo ms!

ich würde morgen gerne beginnen, den Code in auszulagern. Wie würdest Du 
das managen? Machst Du für Master und Slave jeweils eigene Routinen oder 
machst Du eine gemeinsame Routine die beide verwenden können. Reicht 
eine Datei für alle bis jetzt vorkommenden Routinen zb. RS485.c (und .h)

LG
Markus

von ms (Gast)


Lesenswert?

Hallo Markus,

ich würde alles was mit der Uart zu tun hat in eine Datei packen 
(Driver).
Alles was mit der Aktion zu tun hat in eine eigene (Service).
Tools wie crc usw. in eine eigene.

Master und Slave benutzen den gleichen Code.

ms

von M. W. (mw73)


Lesenswert?

ah, alles klar,

dann werd ich mich so versuchen.

Danke und schönen abend

LG
Markus

von M. W. (mw73)


Lesenswert?

Hallo ms!

Ich bin gerade noch mit dem Auslagern beschäftigt. Ist etwas viel für 
mich.
Würde es Sinn machen, sämtliche globale Variablen in einen eigenen 
Header "Globals.h" auszulagern?
Mit den includes könnte man ja das selbe machen - oder?

Bin da noch ziemlich viel am tüfteln.

Grüße
Markus

von M. K. (sylaina)


Lesenswert?

Markus W. schrieb:
> Würde es Sinn machen, sämtliche globale Variablen in einen eigenen
> Header "Globals.h" auszulagern?

Das mache ich in der Tat immer so. Grundgerüst meiner Header-Files:
1
#ifndef globals_h
2
#define globals_h
3
4
//meine variablen
5
6
#endif /* globals_h */
Mit dem #ifndef wird verhindert, dass man den Header mehrfach einbindet 
aber ich denke, dass das bekannt ist, oder?

von M. W. (mw73)


Lesenswert?

Hallo M.Köhler,

danke für die Info.
Ja, ist soweit bekannt.

Danke
Markus

von M. W. (mw73)


Angehängte Dateien:

Lesenswert?

Hallo ms!

so, ich hab jetzt eine lauffähige Version des ausgelagerten Codes. 
Könntest Du einmal kurz einen Blick drauf werfen. Ich bin mir bei 
einigen Dingen nicht sicher. Speziell bei den Includes. Wie gesagt es 
läuft zwar und wurde fehlerfrei compiliert, was aber nicht heisst, dass 
es gut ist.
Vielleicht kannst Du kurz drüber schauen. Ich hab da sehr lange 
gebraucht dafür, hab aber sowas noch nie vorher gemacht.

LG
Markus

von M. K. (sylaina)


Lesenswert?

Uh, meinst du jetzt mich oder ms? However, ich werd am WE leider nicht 
dazu kommen mir das genau anzuschaun, frühestens nächstes WE komm ich 
dazu. Ich zieh nämlich am Montag um. Aber ich werde einen Blick 
wagen...oder zwei oder drei ;)
EDIT: Ich habs nur mal kurz überflogen: Die ISR des USART ist für meinen 
Geschmack zu lange, die Checks würde ich auslagern in die Mainloop und 
in der ISR nur das empfangene Zeichen wegspeichern.

: Bearbeitet durch User
von ms (Gast)


Lesenswert?

Hallo Markus,

erst einmal respect. Ich habe da noch ein paar Anmerkungen. Ich stehe 
nicht auf globale Variablen da besteht die Versuchung diese irgendwo im 
Code zu manipulieren. Es ist immer besser die Variable explizit 
anzuforden. Gibt es keine möglichkeit diese Variable anzufordern hat das 
einen Grund. In C++ ist das einfacher. Auch solltest du genaue 
Schnittstellen definieren zwischen den einzelenen Units. So ist es 
einfacher z.B. die Unit Service in eine Desktopanwendung oder sogar in 
eine Android App zu verwenden ohne diese neu schreiben zu müssen.

ich werde mich heute mal mit deinem Code beschäftigen. Welchen Konverter 
hast du? In welcher Sprache programmierst Du in VS C++ oder C#.

ms

von M. W. (mw73)


Lesenswert?

Hallo ms!

Danke für die schnelle Antwort!!
Ich beschäftige mich zur Zeit ausschließlich mit Mikrocontrollern und 
verwende daher C und Atmel Studio. Wenn ich mehr Erfahrung gesammelt 
habe kann ich mich auch einmal in andere Bereiche vorwagen aber momentan 
bin ich schon sehr zufrieden, wenn ich meine uC-Projekte einigermaßen 
realisieren kann. Könntest Du mich hierbei noch etwas unterstützen, um 
wirklich eine RS485 Master-Slave-Kommunikation aufzubauen.

@M.Köhler, Danke auch für Deinen Beitrag und Hilfe!!

LG
Markus

von ms (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Markus,

klar helfe ich dir weiter. Da mein Code schon ca.12 Jahre alt ist und 
ich mich auch weiter entwickelt habe sehe ich noch einige 
Verbesserungen.
Ich habe mal mit der CRC Angefangen. Das Senden geht jetzt so:
1
void Net_SendFrame(void)
2
{
3
  uCRC16_t CRC;
4
  if(INCLUDE_CRC(stTxData.InfoByte))
5
  {
6
    
7
    stTxData.DataLength += (INCLUDE_CRC(stTxData.InfoByte));      // + 2 Byte CRC
8
    CRC = CalcCRCBuffer(&stTxData.RxAddress,stTxData.DataLength +2);  // + 2 Byte Header (normal 4 aber da CRC schon +2 ist aber nicht berechnet wird reichen 2 aus)
9
    stTxData.Data[stTxData.DataLength-(CRC_HI+1)] = CRC.cCRC16[CRC_HI]; // CRC Hi einfügen
10
    stTxData.Data[stTxData.DataLength-(CRC_LO+1)] = CRC.cCRC16[CRC_LO]; // CRC lo einfügen
11
  }
12
  NetTxCount = 4 + stTxData.DataLength;
13
  NetTxCount_temp = NetTxCount;
14
  NetTxPtr = &stTxData.RxAddress;
15
  NetSetTxEnable(true);
16
  if(Dev_Config->MasterMode)NET_UCSRB |= (1<< TXB80); // nur beim Master
17
  NET_UCSRB |= (1<<UDRIE0); // Tx Empty einschalten
18
  
19
}

In der Bild Datei sieht man dass die CRC gleich bleibt (CRC1 ist die 
alte version CRC2 die neue)

ms

von ms (Gast)


Lesenswert?

Hallo Markus,

hier nochmal eine erweiterung damit kannst du ganz einfach int,Float
übertragen ohne Bits hin und her zu schieben. Es gibt hier ein Beitrag 
bei dem man versucht eine int zu übertragen(bin mal gespannt wie das 
ausgeht). Für uns ist das ganz einfach und sogar sicher!!!
1
typedef union{
2
  float     fVal;
3
  unsigned int   iVal;
4
  unsigned char    cVal[4];
5
}multiVal_t;
6
7
8
9
void Send_Interger(unsigned char ptr_RXAddress,unsigned int *val)
10
{
11
  multiVal_t multiVal;
12
  multiVal.iVal = *val;
13
  Net_SendChar(ptr_RXAddress,&multiVal.cVal[0],2);
14
  
15
}
16
17
void Send_Float(unsigned char ptr_RXAddress,float *val)
18
{
19
  multiVal_t multiVal;
20
  multiVal.fVal = *val;
21
  Net_SendChar(ptr_RXAddress,&multiVal.cVal[0],4);
22
}

von M. W. (mw73)


Lesenswert?

Hallo ms!

Danke für die Erweiterungen, ich mach mich gleich an die Arbeit, diese 
zu implementieren.

LG
Markus

von M. W. (mw73)


Lesenswert?

Hallo ms!

hat perfekt funktioniert!!

Allerdings hab ich eine Frage.

Du hast Dir wahrscheinlich irgendwo eine Config oder eine Funktion 
geschrieben, wo Du festlegst, ob Du den Code für einen Master oder Slave 
verwendest.
1
if(Dev_Config->MasterMode)NET_UCSRB |= (1<< TXB80); // nur beim Master

Ich habe das TXB80 jetzt einfach ohne Abfrage für Master gesetzt.

Als nächstes teste ich ob ich den code als Slave verwenden kann. bis 
jetzt habe ich ja für den Slave Deinen Code verwendet, den Du ganz zu 
Beginn gepostet hast.
In weiterer Folge soll ja der Slave zurück senden können.

Ich mach mich gleich an die Arbeit.

LG
Markus

von ms (Gast)


Lesenswert?

Hallo Markus,

Master und Slave verwenden zwar den gleichen Code zum senden und 
empfangen
aber beide haben unterschiedliche Aufgaben. Deswegen mein hinweis so zu 
programmieren dass man ganz einfach gerätespezifische dateien 
austauschen kann. Ein Lichttaster hat andere Funktionen wie eine 
Rolladensteuerung.
1
typedef struct{
2
  unsigned char MyAdr;      // meine Adr
3
  bool MasterMode;        // Ich bin Master??
4
  unsigned int speed;        // Baud
5
  fptrNetTask  fptrCallBackOnOk;  // CallBack bei neue Daten
6
}st_Dev_Config;
7
8
/*
9
// Slave Main
10
int main(void) {
11
  unsigned char buf[20];
12
  DDRB = (1 << PINB5) | (1 << PINB2); // set PINB0 and PINB2 as output
13
  DDRC =0xff;
14
  st_Dev_Config my_Dev_config;
15
  
16
  my_Dev_config.fptrCallBackOnOk = NetAktion;
17
  my_Dev_config.MasterMode = false;  // Jetzt bin ich nur ein Slave <-------------------------------------------
18
  my_Dev_config.MyAdr = 0x44;      // oder aus EEProm auslesen
19
  my_Dev_config.speed = 9600;
20
21
  NetInit(&my_Dev_config);
22
  _delay_ms(200);
23
  sei();
24
25
  while (1) {
26
    
27
    if(LCD_Update)
28
    {
29
    //lcd_string(&LCD_buf);   // da ich deine LCD Lib nicht habe ist das ausgeklammert.
30
    LCD_Update = false;  
31
    }
32
    
33
    
34
35
  } // while
36
37
} // main
38
*/
39
// Master Main
40
41
42
43
int main(void) {
44
  unsigned char buf[20];
45
  DDRB = (1 << PINB5) | (1 << PINB2); // set PINB0 and PINB2 as output
46
  DDRC =0xff;
47
  st_Dev_Config my_Dev_config;
48
  
49
  my_Dev_config.fptrCallBackOnOk = NetAktion;
50
  my_Dev_config.MasterMode = true;  // Jetzt bin ich der Master im Bus <--------------------------------------------------
51
  my_Dev_config.MyAdr = 0x01;      // oder aus EEProm auslesen
52
  my_Dev_config.speed = 9600;
53
54
  NetInit(&my_Dev_config);
55
  _delay_ms(200);
56
  sei();
57
58
  while (1) {
59
    
60
    _delay_ms(1000);
61
    buf[0] = WRITE_LCD_BUFFER;
62
    sprintf(&buf[1],"LED");
63
    Net_SendChar( 0x44,&buf[0],4);
64
    
65
    
66
67
  } // while
68
69
} // main

ms

von M. W. (mw73)


Lesenswert?

Hallo ms!

Danke vielmals,ich werde das gleich studieren und durchtesten.

LG
Markus

von M. W. (mw73)


Lesenswert?

Hallo ms!

ich hab's bis jetzt noch nicht zum Laufen gebracht.
Wenn ich es heute nicht mehr schaffe, melde ich mich morgen zurück.

Wünsch Dir noch einen schönen Abend.

LG
Markus

von M. W. (mw73)


Lesenswert?

Hallo ms!

so, jetzt läuft es wie gewünscht und die Zusammenhänge werden immer 
klarer.
Die größten Probleme hatte ich mit der My_Dev_config, da ja teilweise 
noch im Code die defines für Baudrate und Adresse vorhanden waren. Auch 
in anderen Codeteilen waren Referenzen auf "NET_ADDRESS" usw. vorhanden.

Einige Fragen hätte ich trotzdem noch denn ich musste einiges 
auskommentieren um den Code lauffähig zu bekommen.
1
my_Dev_config.fptrCallBackOnOk = NetAktion; //auf NetAktion habe ich keine Referenz
2
3
4
typedef void (*fptrNetTask)(st_protokoll_Data*) // --> gehört das überhaupt rein?
5
6
7
8
typedef struct{
9
  unsigned char MyAdr;      // meine Adr
10
  bool MasterMode;        // Ich bin Master??
11
  unsigned int speed;        // Baud
12
  //fptrNetTask  fptrCallBackOnOk;  // CallBack bei neue Daten --> hab ich aus auskommentiert, lief sonst nicht
13
}st_Dev_Config;

Vielleicht könnstest Du Dir das bei Gelegenheit ansehen.

LG
Markus

von M. W. (mw73)


Lesenswert?

Hallo ms!

Ich habe jetzt den Code in beiden Varianten (Master & Slave) bis auf die 
oben genannten Punkte soweit am Laufen.

Denkst Du wir könnten uns am Wochenende darüber unterhalten?

LG
Markus

von ms (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Markus,

Ich habe mal mein Test Projekt hochgeladen. Da habe ich einen Master und 
zwei Slaves. Der Slave 0x44 ist ein Taster der 0x45 ist eine Lampe.
Die Funktion: bei einem kurzem Click auf den Taster wird die Lampe(LED) 
langsam hoch gedimmt nochmal kuzer Click wird die Lampe langsam runter 
gedimmt. Bei long Click geht die Lampe sofort an/aus.
Der Master regelt das ganze.
Es gibt da noch einen schönheitsfehler aber ist bei zwei Slaves nicht so 
wichtig.Mein Aufbau ist auch im Anhang.

ms

von M. W. (mw73)


Lesenswert?

Hallo ms!

Danke für das Beispiel, ich werd mir das gleich ansehen und melde mich 
zurück

LG
Markus

von ms (Gast)


Lesenswert?

Hallo Markus,

noch eine Info.Der Slave fragt ständig den Taster ab gibt es eine 
Änderung wird der Status zwischen gespeichert bis der Master den Status 
abfragt. Danach wird der Status gelöscht. Also Master fragt ab --> Slave 
Antwortet braucht aber eine Bestätigung vom Master das er die Daten 
bekommen hat --> Master sendet ein ACK --> Status wird gelöscht.Beim 
LightService sendet das Slave nur ein ACK beim setzen der LED. Eine 
Antwort mit Daten zählt als Positiv ACK für den Master.

Der nächste Schritt ist das einfügen einer TimeOut funktion und der 
beschäftigung mit Mutex und Semaphore. Je nach Auslegung sind bei der 
kummunikation Prioritäten zu setzen. Bei einem Rauchmelder ist das 
erfassen der Umgebungsluft wichtiger wie das abhandeln einer anfrage.

ms

von M. W. (mw73)


Lesenswert?

Hallo ms!

Danke für diese Info. ich bin gerade beim Durcharbeiten - absoluter 
Proficode!!!
Einiges ist für mich noch sehr verwirrend. Ich muss mich eben 
einarbeiten.
Ich werde versuchen das innerhalb der kommenden Woche zu erledigen und 
am Wochenende meine Erkenntnisse posten. Ich wäre Dir sehr dankbar, wenn 
Du kommendens WE wieder rein schauen könntest.

LG
Markus

von ms (Gast)


Lesenswert?

Hallo Markus

Markus W. schrieb:
> absoluter
> Proficode!!!

nee nee da sind wir noch weit weg!!

ms

von M. W. (mw73)


Lesenswert?

Hallo ms!

So, melde mich wieder zurück.
Ich hatte zwar diese Woche nicht so viel Zeit (Stress wegen Studium) 
aber es ist für mich absolut interessant Deinen Code zu studieren.
Für mich ist der Code nicht mehr ganz so trivial und es bedarf daher 
einiges an Zeit, die Verweise und Funktionen nach zu vollziehen.

Ich hätte da auch eine Frage.

Der Slave (und auch der Master) rufen ja im Modul Scheduler folgende 
Funktion auf:

void dispatchTasks(void)

Welche Funktion hat hier das "delay" und welchen Wert bezw. von wo 
erhält es seinen Wert?
1
if( !task_list[i].delay &&
2
    task_list[i].status == RUNNABLE )

aha jetzt hab ich noch was gefunden
Der Slave übergibt ja die einzelnen Tasks
1
// adds a new task to the task list
2
// scans through the list and
3
// places the new task data where
4
// it finds free space
5
void addTask(uint8_t id, task_t task,
6
uint16_t period)
7
{
8
  uint8_t idx = 0, done = 0x00;
9
  while( idx < MAX_TASKS )
10
  {
11
    if( task_list[idx].status == STOPPED )
12
    {
13
      task_list[idx].id = id;
14
      task_list[idx].task = task;
15
      task_list[idx].delay = period;
16
      task_list[idx].period = period;
17
      task_list[idx].status = RUNNABLE;
18
      done = 0x01;
19
    }
20
    if( done ) break;
21
    idx++;
22
  }
23
24
}

delay ist der Wert von period
was ist dann period, welche Bedeutung hat es? (in dem Fall wird für 
jeden Task 10 übergeben)

Das ist mir noch etwas unklar.

lg
Markus

von ms (Gast)


Lesenswert?

Hallo Markus,

delay ist die zählvariable periode ist Merkervariable.
Jede ms wird die funktion schedulerMainTask aufgerufen die zählt delay 
um 1 nach unten. In dispatchTasks wird nachgeschaut ob delay 0 ist wen 
ja wird die funktion Task aufgerufen. Danach wird delay auf den wert von 
Periode gesetzt und das Spiel fängt von vorne an. Bei einer ID >= 50 
wird nur einmal die Taskfunktion aufgerufen (single shot).

ms

von M. W. (mw73)


Lesenswert?

Guten Morgen,

Na Du bist ja ein echter Frühaufsteher!

Danke für die Erklärung, die hat geholfen.
Ich hätte allerdings noch eine Frage.

Der Slave initiert ja seine Tasks.

addTask(1, floorLightTask, 10);
addTask(2,buttonTask,10);


Dann werden die Tasks ja der Liste hinzugefügt und schließlich in 
dispatch tasks aufgerufen.

// call the task
(*task_list[i].task)();

Wenn ich jetzt im Modul floorlightservice nachsehe, gibt es da nur eine
Funktion floorlight (ohne Task) aber ich denke, dass das die Funktion 
ist, die aufgerufen werden soll.

lg
Markus

von ms (Gast)


Lesenswert?

Hallo Markus,

floorlightask ist ein "hintergrund Task" aus der floorlight.c. die 
regelt das dimmen. Der service wird unten bei jedem durchlauf 
aufgerufen.

ms

von M. W. (mw73)


Lesenswert?

Hallo ms!

jetzt hab ich's gesehen. Ich hab den Aufruf immer in
der floorlightservice gesucht.
Ich seh mir das jetzt weiter an.

lg
Markus

von M. W. (mw73)


Lesenswert?

Hallo ms!

Da hab ich noch was wichtiges gefunden.

Du hast ja folgende typedef enum angelegt:

eine in button.h --> button_state_t;

und eine in floorlight.h --> floorLight_state_t;

Beide beinhalten aber unterschiedliche Aufzählungskonstanten.


Die floorlightservice.c beginnt jetzt mit folgender Deklaration:
1
button_state_t buttonStateFloorLightService;

Im selben Modul kommt dann folgede Funktion (ich hab nur die ersten zwei 
Zeilen eingefügt):
1
 void floorLight(void) // wird in der while-schleife von main aufgerufen
2
 {
3
   if(buttonStateFloorLightService == STATE_OFF)buttonStateFloorLightService = getButtonState();

Müsste das nicht heissen if(buttonStateFloorLightService == B_STATE_OFF)

Also "B_STATE_OFF" nicht "STATE_OFF", da ja in der typdef enum 
button_state_t das so festgelegt wurde.

Tut leid, ich bin gerade etwas confused.

lg
Markus

von ms (Gast)


Lesenswert?

Hallo Markus,

du hast recht. Ich habe auf die warnung nicht geachtet.
Die Zahl die dahintersteckt ist aber beidesmal 0;

ms

von M. W. (mw73)


Lesenswert?

Hallo ms!

Danke!

Ich werde diese Woche wohl noch benötigen um den Code zu studieren.
Ich melde mich dann kommendes WE zurück.

lg
Markus

von M. W. (mw73)


Lesenswert?

Hallo ms!

meld mich wieder zurück.

Ich hab mir diese Woche den Slave-Code weiter durchgesehen. Ich weis 
jetzt soweit bescheid, wie sich die verschiedenen Statuswerte ergeben. 
Später hätte ich zum Slave-Code noch ein paar geziehlte Fragen.

...Nein, eigentlich müsste ich Dich gleich fragen.
Du hattest am Anfang geschrieben dass der Ablauf so ist:

Ein Master, ein Slave (Taster 0x44), ein Slave (Lampe 0x45)

Wenn ich jetzt den Code durchspiele hab ich folgendes Problem:
Der Slavecode hat ja die Adresse 0x45, also die Lampe. In der 
while-Schleife des Codes wird ja  ständig die Funktion floorlight() aus 
dem Modul floorlightservice.c aufgerufen.

Diese wiederum ruft gleich in der ersten Zeile folgendes auf:
1
if(buttonStateFloorLightService == B_STATE_OFF)buttonStateFloorLightService = getButtonState(); // getButtonState() wird in button.c aufgerufen

Für mich sieht das aus, wie wenn die Funktion getButtonState() (aus dem 
Modul Button.c) direkt aufgerufen wird. Da es aber ein anderer Slave 
ist, sollte ja die Anfrage über den Bus laufen? - oder sehe ich das 
falsch?

Könntest Du mir das kurz erklären?

Ich bin jetzt wieder beim Master Code und überlege mir gerade das 
Zusammenspiel zwischen Master und Slave.

Meiner Meinung nach stellt ja (muss ja eigentlich auch so sein) der 
Master die erste Anfrage. und zwar:

In der while-schleife des Masters wird über die Funktion Masterservice() 
(im Modul Masterservice.c) die Funktion SlaveButtonState() aufgerufen.

Diese sendet eine Anfrage eben über den Buttonstate des Slaves.
Kannst Du mir den Senderahmen dieser Funktion und der Funktion 
SlaveSetLight() kurz erklären.

SlaveButtonState()
mit buf legst Du ja ein array für die Nutzdaten fest.
Was bedeuten die Daten in buf[0] (0x02)?
und jetzt der frame:
1
Net_SendChar(device[0].adr,&buf[0],1,CRC_BIT);
also device[0].adr = 0x44 (Slave mit Taster)
&buf[0] sind ja die Daten (bitte noch um Erklärung)
dann kommt 1 (bitte um Erklärung)
und dann CRC_Bit --> sollte das nicht ein Aufruf sein?

Ich hab mir auch die Argumente in der Funktion angesehen.

Der Funktion NetSendChar zufolge sollten ja die Übergabeargumente 
folgendes bedeuten:
1, RX Adresse (ist klar)
2, sind wohl die Daten
3, aha, unsigned int len (in der for schleife werden wohl die Nutzdaten 
eingelesen bis len oder?)
4, bleibt noch das Info Byte.

Könntest Du mir bitte diese Routinen noch etwas genauer erklären in 
Bezug auf die Sendeargumente.
SlaveButtonState
SlaveSetLight --> diese hat andere Argumente

LG
Markus

von ms (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Markus,

Markus W. schrieb:
> Ein Master, ein Slave (Taster 0x44), ein Slave (Lampe 0x45)

Beide Slave haben die gleiche funktionen. Der Master aber fragt nur beim 
0x44 den Taster Status ab und gibt ihn an den 0x45 weiter. FloorLight 
und Button haben KEINE Verbindung zueinander!!!

Markus W. schrieb:
> also device[0].adr = 0x44 (Slave mit Taster)
> &buf[0] sind ja die Daten (bitte noch um Erklärung)
> dann kommt 1 (bitte um Erklärung)
> und dann CRC_Bit --> sollte das nicht ein Aufruf sein?

&buf[0] ist die Adresse im Speicher vom ersten Byte der Daten.
1 bedeutet 1 Byte von buf soll übertragen werden. 2 sind 2 Byte von buf 
usw
CRC_Bit = im Info Byte wird das bit für CRC wird mit übertragen gesetzt.

im Anhang eine Beschreibung (ist auf das was wir jetzt erarbeitet haben 
beschränkt).

ms

von M. W. (mw73)


Lesenswert?

Hallo ms!

Vielen Dank, jetzt ist mir wieder einiges klarer.
Die Framelist ist sehr hilfreich.
Ich arbeite gerade weiter und da ist mir was aufgefallen.

Könntest Du mal einen Blick auf die Typedef Master_state_t 
(Masterservice.h) werfen. Du hast für STATE_GET_SWITCH= 0, vergeben, 
sendest aber in der Anfrage (SlaveButtonState) 0x02

Bei SlaveSetLight sendest Du 0x01, das ist laut Typedef 0x02

LG
Markus

von ms (Gast)


Lesenswert?

Hallo Markus,

Master_State ist die StateMaschine vom Master. Da der MasterService von 
Main Zyklisch aufgerufen wird muss der Service wissen welche Aktion er 
ausführen muss. Das hat nichts mit der Kommunikation zu den Slaves zu 
tun.

Markus W. schrieb:
> sendest aber in der Anfrage (SlaveButtonState) 0x02

schau mal in die FloorLightService.h(Slave)
da steht
1
#define SET_LIGHT 0x01
2
#define GET_SWITCH 0x02

Hast Du eine Himbeere oder Odroid oder BB (linux) Oder RPI IOT Win10?
Da ist der Master besser aufgehoben.

ms

von M. W. (mw73)


Lesenswert?

Hallo ms!

Danke, das hab ich übersehen.
Ich werd mir das jetzt nochmal genau anschauen.

Das Christkind bringt mir vielleicht eine Himbeere.

LG
Markus

von ms (Gast)


Lesenswert?

Hallo Markus,

hast Du Erfahrung mit Linux und QT mit cross compile?
Oder ist dir VC++ mit dem .NET gedöns lieber.

ms

von M. W. (mw73)


Lesenswert?

Hallo ms!

Also mit Linux hab ich überhaupt keine Erfahrung (leider)
Grundsätzlich hab ich nur etwas C Erfahrung, ein kleinwenig C++
Darum weis ich nicht ob ich das mit dem Rasp auch gebacken bekomme.

Natürlich würde es mich sehr ineressieren.

LG
Markus

von ms (Gast)


Lesenswert?

Hallo Markus,

das bekommst du schon hin.

Linux: QT Setup ist nichts für schwache nerven. Auch die ganzen 
berechtigungen nerven manchmal. Großer vorteil du kannst über 
RemoteDesktop die pi vom deinem Rechner in der Aktuellen Sitzung aus 
bedienen ohne an der pi eine Tastatur oder Montitor angeschloßen zu 
haben.

Win10 IOT: ist echt einfach das Setup in VS. Nur das mit der Thread 
programmierung ist gewöhnungsbedürftig. Events habe ich noch nicht ganz 
raus.

Ich persönlich verwende RAD Studio da ich viel mit datenbanken zu tun 
habe war das die beste wahl. Leider noch keine möglichkeit für Linux 
soll sich aber mit Gozilla ändern.

Meine empfehlung: einen alten Rechner mit Linux Lubuntu und QT. 
RPI-Image für QT mit QMake stelle ich dir bereit. Aber nur sollte was 
unter dem Weihnachsbaum sein!!!

ms

von ms (Gast)


Lesenswert?

Hallo Markus,

welche Wetterstation willst du verwenden? Welche Rohrmotoren sind 
verbaut Somfy, elero, roma, nice, came usw

meine Ausbildung habe ich bei Came genossen.

ms

von M. W. (mw73)


Lesenswert?

Hallo ms!

wow, Du hast bei Came gearbeitet. Die machen doch auch Zugangskontrollen 
und Sicherheitssysteme oder?

... deshalb bist Du so gut drauf!!!

Also ich habe zu Hause Somfy verbaut. Es sind ganz neue mit 
Hinderniserkennung. Der Nachteil für mein Projekt ist allerdings, dass 
ich ja keine (zugänglichen) Endschalter habe die mir die Endlage 
bestätigen. Ich hätte mir für die Ansteuerung eine Kombination aus Zeit 
und Strommessung vorgestellt. Ich hab sie ja wie ich sie bekommen habe 
spaßhalber über einen Arduino Webserver gesteuert. Das hat aber ganz gut 
funktionert.

Hättest Du da eventuell eine bessere Idee?

Achja zur Wetterstation, die hätte ich auch selber gebaut. Also einen 
Controller im Außenbereich mit Dämmerungserkennung, Temperaturmessung, 
Windmessung, eine RTC, alles was Interessant wäre um die 
Rolladensteuerung zu beeinflussen.

...Wie würdest Du das machen?
Oder Du hast doch weiter oben mal geschrieben eine Station integriert zu 
haben. Könntest Du mir das auch empfehlen, oder ist die Eigenbau 
Variante ausreichend. Wie gesagt, mir gehts dabei nicht so sehr ums 
Wetter sondern nur um Einflüsse die für die Steuerung relevant sind.

Einen alten Rechner mit Linux wäre auch kein Problem. Es müsste also 
genau Lubuntu und QT sein.

Ich hab zwischenzeitlich nomal beim Christkind nachgefragt. Ja, die 
Chancen stehen gut für einen Pi und ein 5" lcd.

Nur wie gesagt ich bin jetzt noch nicht mit dem Code durch und würde wir 
so ungefähr bis Weihnachten zum Ziel setzten, den Code soweit verstanden 
zu haben.

Ich mach mich gleich wieder ans Werk

LG
Markus

von ms (Gast)


Lesenswert?

Hallo Markus,

meine WXT ist zu oversize die werden beim DWD oder sogar bei der NASA 
eingesetzt. Ich würde Dir Vorschlagen eine Fertige Lösung zu nehmen ELV 
usw.
Aber die sollte min eine RS232 Schnittstelle haben. Meine WXT kann Tag 
und Nacht nicht unterscheiden.

Endlagen Erkennung wird nicht einfach aber möglich. Hast du eine 
Bedieneinheit von Sonfy verbaut(ich habe jede woche von meinem Kumpel 
eine zu rep.)?

ms

von M. W. (mw73)


Lesenswert?

Hallo ms!

Danke, dann werde ich mich dementsprechend umsehen.

Eine Bedieneinheit hab ich keine drauf von Somfy. Die wurden einfach 
montiert und das Kabel haben sie mir dann durch den Schlauch 
reingeschoben.

LG
Markus

von M. W. (mw73)


Lesenswert?

Hallo ms!

Ich habe mich gestern noch mit dem Master Code beschäftige. Das ist 
soweit auch klar. Ich bin jetzt bei dem Punkt, an dem der Master seine 
Anfrage sendet, zB. STATE_GET_SWITCH. An diesem Punkt würde ich wieder 
Deine Hilfe benötigen und zwar was den eigentlichen Sendevorgang 
betrifft.

Also, diese Daten werden ja in der Funktion SlaveButtonState generiert 
und an die Funktion Net_SendChar weiter gegeben, wo sie in die 
Strukturvariable stTxData eingelesen werden.

Jetzt wird die Funktion Net_SendFrame aufgerufen und auf das Infobyte 
überprüft. Dannach kommt die CRC-Kalkulation.
Dann wird die Variable Net_TxCount mit 4 + der Datenlänge befüllt und 
der Inhalt der Variable Net_TxCount_Temp zugewiesen.

Frage: An dieser Stelle enden jetzt alle Funktionsaufrufe. Wenn der 
Sendepuffer leer ist, wird ja die ISR aufgerufen. Dort wird unter 
anderem ein Zeiger NET_UDR = *NetTxPtr erstellt. Dieser zeigt aber auf 
keine Variable
Kannst Du mir diesen Ablauf genauer erklären.

Ich hätte Dich auch noch ersucht, den Vorgang für das Auslesen der Daten 
für den Slave noch etwas zu erklären, also wie jetzt die Anfrage zB. 
STATE_GET_SWITCH vom Slave verarbeitet wird. Da hab ich noch Probleme 
damit.

LG
Markus

von ms (Gast)


Lesenswert?

Hallo Markus,

Markus W. schrieb:
> Zeiger NET_UDR = *NetTxPtr erstellt. Dieser zeigt aber auf
> keine Variable

falsch!!!
1
st_protokoll_Data stRxData;
2
st_protokoll_Data stTxData;
3
4
unsigned char *NetTxPtr; // <--- hier wird der Zeiger erstellt
5
unsigned char NetTxCount;
6
unsigned char NetTxCount_temp;
7
net_timeout_t net_timeout;

hier wird dem Zeiger die Adresse(im Speicher)von dem ersten Element der 
struct stTxData zugewiesen das ist .RxAddress
1
NetTxCount = 4 + stTxData.DataLength;
2
NetTxCount_temp = NetTxCount;
3
NetTxPtr = &stTxData.RxAddress; // Adresse wir zugewiesen

hier wird der Inhalt der Adresse auf die NetTxPtr zeigt in das NET_UDR 
geschrieben
1
NET_UDR = *NetTxPtr;

buttonStateFloorLightService ist die Zustandsvariable die nur durch den 
Master zurückgesetzt werden kann.
1
case GET_SWITCH:
2
     Net_RunOnAck(clearButtonStateNetFloorLight);// <--- Die funktion wird ausgeführt sobald der Master ein ACK Sendet
3
     Net_SendChar(RxFrame->TxAddress,&buttonStateFloorLightService,1,CRC_BIT|NEED_ACK); // NEED_ACK zeigt dem MAster an das er nach erhalt ein ACK senden muss
4
     break;


ms

von M. W. (mw73)


Lesenswert?

Halo ms!

Danke für die Ansätze!
Ich werd mir das heute noch ansehen.

LG
Markus

von M. W. (mw73)


Lesenswert?

Halo ms!

Ich hätte da fürs Verständnis noch einmal Deine Hilfe benötigt.
Und zwar ist mir nicht klar, wo genau die zu sendenden Daten in die 
USART transferiert werden.

Hier werden ja die Daten in die Struktur eingelesen:
1
void Net_SendChar(unsigned char ptr_RXAddress,unsigned char *val,unsigned int len, unsigned char infoByte) // hier werden die Daten in die Strukturvariable eingelesen
2
{
3
  int loop;
4
  stTxData.RxAddress = ptr_RXAddress;
5
  stTxData.TxAddress = Dev_Config->MyAdr;
6
  stTxData.InfoByte = infoByte;
7
  stTxData.DataLength = len;
8
  for(loop = 0; loop < len; loop++){
9
    stTxData.Data[loop] = *val++;
10
  }
11
  Net_SendFrame();
12
}


... und jetzt wird Net_SendFrame() aufgerufen:
1
void Net_SendFrame(void)
2
{
3
  uCRC16_t CRC; // uCRC16_t = typdef union aus crc16.h
4
  if(INCLUDE_CRC(stTxData.InfoByte))
5
  {
6
    stTxData.DataLength += (INCLUDE_CRC(stTxData.InfoByte));      // + 2 Byte CRC
7
    CRC = CalcCRCBuffer(&stTxData.RxAddress,stTxData.DataLength +2);  // + 2 Byte Header (normal 4 aber da CRC schon +2 ist aber nicht berechnet wird reichen 2 aus)
8
    stTxData.Data[stTxData.DataLength-(CRC_HI+1)] = CRC.cCRC16[CRC_HI]; // CRC Hi einfügen
9
    stTxData.Data[stTxData.DataLength-(CRC_LO+1)] = CRC.cCRC16[CRC_LO]; // CRC lo einfügen
10
  }
11
  NetTxCount = 4 + stTxData.DataLength; // ? destination, info, source, len
12
  NetTxCount_temp = NetTxCount;
13
  NetTxPtr = &stTxData.RxAddress; // hier wird dem Zeiger die Adresse(im Speicher)von dem ersten Element der struct stTxData zugewiesen das ist .RxAddress
14
  NetSetTxEnable(true);
15
  /*if(Dev_Config->MasterMode)*/NET_UCSRB |= (1<< TXB80); // nur beim Master
16
  //
17
  //else NET_UCSRB &= ~(1<< TXB80);
18
  NET_UCSRB |= (1<<UDRIE0); // Tx Empty einschalten
19
  
20
}
21
22
23
...Da ab hier kein anderer Aufruf mehr statt findet, ist mir nicht klar, an welcher Stelle die Daten in die USART gelangen bzw. gesendet werden.
24
25
LG
26
Markus

von M. W. (mw73)


Lesenswert?

Hallo ms!

Ich glaube ich weis jetzt wie das funktioniert. Ich hoffe ich geb jetzt 
keinen Quatsch von mir.

Also, Im Modul Net_sendFrame() wird ja dem Zeiger die Adresse des ersten 
Elemnents von stTxData zugewiesen (RxAddress).
1
NetTxPtr = &stTxData.RxAddress;
Dannach wird ja TX empty aktiviert.

Dadurch die ISR(USART_UDRE_vect)

Hier wird (bei gesetztem 9. Bit) die RX Adresse gesendet
1
NET_UDR = *NetTxPtr;
Jetzt kommt meine Vermutung, jetzt werden dem Zeiger die Adressen der 
weiteren Elemente der Struktur stTxData übergeben (Eine Adresse ´pro 
Durchlauf).
1
NetTxPtr++;
und zwar so lange, bis die Anzahl an zu sendenden Elementen, die über 
Net_TxCount festgelegt und bei jedem Durchlauf runtergezählt werden auf 
null ist.
1
NetTxCount--;

Könnstest Du mir das bitte bestätigen oder ggf. korrigieren.

Danke und LG
Markus

von M. W. (mw73)


Lesenswert?

Hallo ms!

Ich möchte mich an dieser Stelle mal
recht herzlich bei Dir bedanken

und wünsche Dir und Deiner Familie ein recht frohes Weihnachtsfest.

LG
Markus

von M. W. (mw73)


Lesenswert?

Hallo ms!

Da es doch schon eine Weile her ist, seit Deinem letzten Posting, wollte 
ich mal nachfragen ob Du noch weiter mit mir arbeiten möchtest. 
Vielleicht kannst Du Dich kurz diesbezüglich melden.

LG
Markus

von M. W. (mw73)


Lesenswert?

Hallo ms!

Könntest Du mir bitte zumindest Bescheid geben wenn Du nicht mehr weiter 
machen willst

LG
Markus

von M. W. (mw73)


Lesenswert?

... naja, kann man nichts machen, schade.
Trotzdem Danke für Alles.
Vielleicht hast Du ja wieder mal Lust.

LG
Markus

von M. W. (mw73)


Lesenswert?

Hallo ms,

könntest Du Dich nicht doch noch einmal melden?

Würde noch einmal Deine Hilfe benötigen.

Grüße
Markus

von Sabberlotte (Gast)


Lesenswert?

Markus W. schrieb:
> Würde noch einmal Deine Hilfe benötigen.

Andere hier könnten sicher auch helfen ;-)

von M. W. (mw73)


Lesenswert?

Hallo Sabberlotte,

Danke für die Info!
Das aber fast nicht zumutbar denn der Code ist ist sehr umfangreich.

...aber ich werde mir gezielte Fragen überlegen bei denen mir vielleicht 
jemand helfen kann.

Danke erstmal ;-)

lg
Markus

von M. W. (mw73)


Angehängte Dateien:

Lesenswert?

Guten Abend Zusammen!

Könnte mir jemand von euch bei einem Problem helfen?

Ich hab meinen RS-485 Bus soweit einmal am laufen (Schaltplan und 
Oszi-Bilder im Anhang).

Ich hab den Bus auf einem Steckbrett aufgebaut. Es sind ein Master und 
zwei Slaves vorhanden.

Wenn er läuft tut er das ganz gut und ohne Probleme. Jedoch kann es 
sein, dass sich nach dem Einschalten nichts tut.

Der Master beginnt die Kommunikation und fragt den ersten Slave zyklisch 
ab.
Ich habe bereits sehr viel wegen diverser Probleme gelesen und sämtliche 
bias- bzw. Terminierungsvarianten durchprobiert. Es ändert sich nichts.

Wenn der Bus nach dem Einschalten nicht läuft, und man führt beim Master 
einen Reset aus, dann wird eine Übertragung durchgeführt. Beim nächsten 
Reset wieder eine Übertragung aber immer nur eine einzige.

Wenn ich an irgendeinen Busteilnehmer meinen USB-Konverter am RX-Pin 
anstecke, funktioniert der Bus immer nach jedem Einschalten.

Bin momentan etwas ratlos. Vielleicht hat von euch jemand eine Idee.

Aktuelle Widerstandsconfig: 2x 120R Terminierung am Anfang und Ende. 
Einmal bias 680R von Leitung A auf VCC und einmal bias 680R von Leitung 
B auf VSS. Leitungslänge ca. 6 Meter Cat5. Bustreiber sind Max485, alles 
auf dem Steckbrett und mit 5V versorgt über ein Labornetzteil.

Für Ideenansätze wäre ich sehr dankbar.

Grüße
Markus

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Markus W. schrieb:
> Wenn er läuft tut er das ganz gut und ohne Probleme. Jedoch kann es
> sein, dass sich nach dem Einschalten nichts tut.
>
> Der Master beginnt die Kommunikation und fragt den ersten Slave zyklisch
> ab.

 Was denn nun ?
 Wenn der Master den ersten Slaven zyklisch abfragt, dann tut sich was
 auf dem Bus.
 Antwortet der Slave nicht oder was ?

 Was macht der Master überhaupt ?
 Den ersten Slaven zyklisch abfragen oder alle Slaven nacheinander
 zyklisch abfragen ?


> Wenn der Bus nach dem Einschalten nicht läuft, und man führt beim Master
> einen Reset aus, dann wird eine Übertragung durchgeführt. Beim nächsten
> Reset wieder eine Übertragung aber immer nur eine einzige.

 Was heisst Übertragung ?
 Master sendet und kriegt keine Antwort vom Slaven oder Master sendet
 und kriegt Antwort vom ersten Slaven aber es geht danach nicht weiter ?


> Wenn ich an irgendeinen Busteilnehmer meinen USB-Konverter am RX-Pin
> anstecke, funktioniert der Bus immer nach jedem Einschalten.

 Soll heissen ?
 Der Slave ist getrennt oder USB-Konverter parallel am RX-Pin ?
 Die anderen Slaven antworten jetzt ohne Probleme ?

Markus W. schrieb:
> Das aber fast nicht zumutbar denn der Code ist ist sehr umfangreich.

 Der Code ist wahrscheinlich die Ursache aber trotzdem könntest du
 etwas präziser sein bei der Fehlerbeschreibung.

 Und die ganze Geschichte mit 9-bit ist bei RS485 sowas von unnötig,
 weil fehleranfällig...
 z.B. sagt ATMEL folgendes:
1
 Do not use Read-Modify-Write instructions (SBI and CBI) to set or clear the MPCMn bit. The MPCMn bit
2
 shares the same I/O location as the TXCn Flag and this might accidentally be cleared when using
3
 SBI or CBI instructions.

 Auch wenn das normalerweise nicht geht, hat mir der gcc dies einmal
 so übersetzt (MEGA644):
1
      UCSR0A &= ~(1 << MPCM0);
2
/*****************
3
       cbi  0x0b, 0    //*** lss

: Bearbeitet durch User
von M. W. (mw73)


Lesenswert?

Ok, ich versuchs besser zu erklären.

Die Kommunkation sieht so aus, der Master fragt den ersten Slave ab, ob 
an dessen Taster eine Änderung statt gefunden hat. Der Slave gibt dem 
Master den Status des Tasters bekannt. Wurde der Taster am ersten Slave 
gedrückt (long oder short-click) dann gibt der Master den Befehl an den 
zweiten Slave, die dort angeschlossene led rauf oder runter zu dimmen.

Das funtioniert auch so weit ganz gut. Wenn mit dem Einshalten alles 
klappt arbeiten alle Teilnehmer wie gewünscht.

Manchmal aber passiert nach dem Einschalten gar nichts und es gibt keine 
Aktivität am Bus. Wenn der Taster an Slave 1 gedrückt wird, sollte ja 
die led rauf gedimmt werden. Tut sie dann aber nicht. Wenn man dann beim 
Master einen Reset ausführt wird auf einmal die led gedimmt. Jetzt 
betätigt man den Taster wieder, und es passiert nichts. Gibt man dem 
Master wieder einen Reset, wird die led auf einmal runter gedimmt. Also 
jeder einzelne Vorgang geht dann nur noch über einen Reset vom Master.

Jetzt schalte ich den Netzteil ab und dannach wieder ein. Auf einmal 
geht wieder alles ganz normal ????

Wenn ich den USB-Konverter an den rx-pin eines Teilnehmers hänge und 
schalte dann ein, funktioniert die Kommunikation immer. Der Konverter 
wird dabei parallel an einen rx-pin angeschlossen.

Ich bin mir nicht sicher, was die Ursache sein könnte obwohl ich eher 
von der Hardware ausgegangen wäre denn mit dem parallel geschalteten 
Konverter geht es ja auch immer und sonst eigentlich meistens womit ich 
aber nicht sagen möchte das ein Softwarefehler generell ausgeschlossen 
werden kann.

Was den 9-bit-Modus betrifft, bin ich leider noch zu unerfahren aber im 
Zuge meiner Recherchen bezüglich avr und rs485 hab ich fast 
ausschliesslich vom 9-bit-Betrieb gelesen.

Ich hoffe ich habe das Problem etwas besser beschrieben.

Grüße
Markus

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Markus W. schrieb:
> Aktivität am Bus. Wenn der Taster an Slave 1 gedrückt wird, sollte ja
> die led rauf gedimmt werden. Tut sie dann aber nicht. Wenn man dann beim
> Master einen Reset ausführt wird auf einmal die led gedimmt. Jetzt
> betätigt man den Taster wieder, und es passiert nichts. Gibt man dem
> Master wieder einen Reset, wird die led auf einmal runter gedimmt. Also
> jeder einzelne Vorgang geht dann nur noch über einen Reset vom Master.

 Das könnte bedeuten, dass deine Variablen und Flags nicht auf Null bzw.
 bestimmte Werte gesetzt werden, es wird angenommen, dass die Werte
 stimmen, bzw. Null sind.
 Oder die Slaven warten auf ein zusätzliches Byte.
 Oder...


Markus W. schrieb:
> Wenn ich den USB-Konverter an den rx-pin eines Teilnehmers hänge und
> schalte dann ein, funktioniert die Kommunikation immer. Der Konverter
> wird dabei parallel an einen rx-pin angeschlossen.

 ???
 Ein Teilnehmer ist ein Teilnehmer und nicht dein gesammtes Netz.
 Rx ist Eingang und noch dazu vom Bus getrennt, so etwas kann nur bei
 undefiniertem Pegel passieren. Und undefiniertes Pegel am Rx kann es
 nur in 2 Situationen geben:
  1) Dein RS-Bus befindet sich in einem undefiniertem Zustand.
  2) RE-Pin ist auf High.

 Das wiederum sollte nicht passieren wenn beim Rx-Pin (MEGA) Pullup
 eingeschaltet ist. USB-Konverter hat wahrscheinlich diesen Pullup
 und dadurch wird der Rx-Pin bei MEGA auch auf einen definierten
 Zustand gezogen.
 Ohne USB-Konverter wird der Slave den RS-Bus wahrscheinlich blockieren.

 Aber irgendwie ist das alles unlogisch - wieso geht das dann auf
 einmal, was ist mit Slave Nr.2 ?

 Ohne LA am Bus und Rx-Pins wird das nur tagelanges rumrätseln geben.

: Bearbeitet durch User
von M. W. (mw73)


Lesenswert?

Also ich habe ja bias-Widerstände am Bus und jeder Atmega hat am rx-pin 
einen pull-up - hast Du mal einen Blick auf den Schaltplan geworfen, da 
ist die aktuelle Beschaltung genau dargestellt.

Variablen und Flags sind ja beim Einschalten immer auf Null, oder nicht 
wenn ein Wert zugewiesen wurde, auf jeden Fall immer gleich beim 
Einschalten.

Achja und alle RE haben einen pull-down.

Mir fällt ja auch nichts mehr ein hierzu.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Markus W. schrieb:
> Variablen und Flags sind ja beim Einschalten immer auf Null, oder nicht

 Nein, nur I/O Register haben definierte Werte, alles andere hängt vom
 Compiler ab.

> Also ich habe ja bias-Widerstände am Bus und jeder Atmega hat am rx-pin
> einen pull-up - hast Du mal einen Blick auf den Schaltplan geworfen, da

 Dann würde der USB-Konverter nicht helfen aber der tut es...

: Bearbeitet durch User
von M. W. (mw73)


Lesenswert?

so ich hab jetzt noch etwas nachgemessen.
Jedes Mal, wenn am Bus nach dem Einschalten keine Aktivität vorhanden 
ist, wird auch vom  Master am tx-pin nichts gesendet. Am Master tx ist 
high-pegel.
Ich hab jetzt einmal den pull-down Widerstand am RE von 10k auf 47k 
erhöht.

Teste weiter

Markus

von Route_66 H. (route_66)


Lesenswert?

Markus W. schrieb:
> Also ich habe ja bias-Widerstände am Bus

Das sieht in deinen Oszi-Bildern aber ganz anders aus!

Mit Bias-Widerständen dürfte es den "verbotenen" Pegel in NewFile0.bmp 
und NewFile1.bmp nicht geben.

von M. W. (mw73)


Lesenswert?

Ja, aber wie gibts denn das?
Kannst Du Dir mal den Schaltplan ansehen,
genau so ist die Schaltung am Steckbrett aufgebaut.

Markus

von Route_66 H. (route_66)


Lesenswert?

Markus W. schrieb:
> Ja, aber wie gibts denn das?

Verbotenen Pegel bei korrektem Busabschluss und Biasing gibt es, wenn 
zwei oder mehr Teilnehmer gleichzeitig die Treiber auf Senden schalten, 
und unterschiedliche Pegel auf den Bus legen.

von M. W. (mw73)


Lesenswert?

Ok, also sollte demnach der Fehler in der Software liegen.

Ich hab mittlerweile auch rausgefunden das der Fehler auch mit parallel 
geschaltetem USB-Konverter auftritt.

von M. W. (mw73)


Angehängte Dateien:

Lesenswert?

Guten Abend,

@Route66: Ich hab jetzt einmal gemessen ob, wie Du vermutet hast 
gleichzeitig auf verschiedenen Stationen gesendet wird. Das kann ich 
nicht bestätigen. Bitte Sie Dir die Bilder mal an.

NewFile6 zeigt Master RE/DE und Slave1 RE/DE

NewFile7 zeigt Mster RE/DE und Slave2 RE/DE

NewFile10 zeigt beide Slaves


Grüße
Markus

von M. W. (mw73)


Angehängte Dateien:

Lesenswert?

könnte sich vielleicht nochmal jemand den Schaltplan ansehen, dass ich
zumindest einen Hardwarefehler ausschließen kannn.

Markus

von Sabberlotte (Gast)


Lesenswert?

Mach mal die Widerstände R12 und R13 (Bias) kleiner (470 Ohm).
Das liegt mit 680 Ohm hart an der Grenze.

von Sven K. (svenk)


Lesenswert?

Hallo Markus,

im Schaltplan sind led2 und c11 und c14 falsch angeschlossen.
Analog bei den Slaves ebenso.

Um das etwas besser nachvollziehen zu können solltest Du mal den 
aktuellen! Code vollständig von dem Master und Slaves zeigen. Bild vom 
Aufbau auch!

Gruß Sven

von M. W. (mw73)


Angehängte Dateien:

Lesenswert?

Guten Morgen,

zuerst einmal Danke für eure Beiträge!

@Sabberlotte
Werde ich gleich machen. Kannst Du mir noch erklären, wie Du diese Werte 
ermittelt hast, da ich ja schon die unterschiedlichsten Vorschläge 
bekommen habe.


@Sven
Danke für Deine geneue Beobachtung. Ist mir leider in der Eile passiert.
Ansonsten entspricht der Schaltplan genau dem Aktuellen Aufbau.
Anbei noch der Code, welcher aber sehr umfangreich ist.
Es handelt sich hierbei um den Testcode von ms.

Grüße
Markus

von Sabberlotte (Gast)


Lesenswert?

Guten Morgen Markus,

Der Gesamtwiderstand ist: 680+680+60(120/2) = 1420 Ohm
An 5V ergibt das einen Strom von (5/1420) ~ 3,52 mA,
3,52 mA an 60 Ohm ergigt eine Spannung von 211 mV.
Durch Bauteiltoleranzen kann das am MAX485 knapp werden
mit RO=1 (+200mV an A/B).

von M. W. (mw73)


Lesenswert?

Ah, Danke für die tolle Erklärung!

LG
Markus

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Markus W. schrieb:
> Ah, Danke für die tolle Erklärung!

 Die dir bestimmt nicht weiter hilft.
 680 Ohm sind fein, lass es ruhig.
 Wenn die Buslänge unter 50 Meter ist, brauchst du für das Ganze nicht
 einmal die Abschlusswiderstände.

von M. W. (mw73)


Lesenswert?

Mahlzeit,

so, ich hab die Widerstände auf 470 ohm getauscht. Wenn der Bus angeht 
(also das Einschalten funktioniert) dann sieht man die Änderung auch am 
Oszilloskop.

Nur leider war das nicht die Lösung für mein Problem jedoch bin ich über 
die Erklärung dankbar.

Ich gehe schon sehr stark von einem Timingproblem aus und werde mal 
sehen, was ich da im Code ändern könnte. Vielleicht die delay in der 
While-Schleife des Masters erhöhen. Vielleicht sollte ich auch 
Baudratenquarze einsetzen. Was denkt ihr darüber.

Grüße
Markus

von Sven K. (svenk)


Lesenswert?

Hallo Markus,

hast Du mal vor der while Schleife im Master vor sei()
die Wartezeit einfach mal erhöht? 2s oder 5s?

Ist das alles auf dem Steckbrett? Foto?
Ich hatte schon den Fall das die Kontakte nicht immer perfekt waren, da 
sucht man sehr lange an einem Grundproblem.

Gruß Sven

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Markus W. schrieb:
> sehen, was ich da im Code ändern könnte. Vielleicht die delay in der

 Vielleicht scheduler + 9-bit rausschmeissen und mit normaler
 Statemachine versuchen ?

 Warum überhaupt scheduler für einfaches LED an und aus ?

 Ein einfaches Rx_ISR in welchem auf SOF und Slave-Adresse geprüft
 wird, reicht vollkommen und kann später immer noch erweitert werden.

 Und zum Testen lässt man den Master alle 5s abwechselnd stumpf
 LED_An und LED_Aus senden, ohne scheduler und 9-bit.

: Bearbeitet durch User
von M. W. (mw73)


Lesenswert?

Hallo Zusammen

Danke Sven für Deinen Vorschlag!
Ich habe nach mittag im Mastercode die Wartezeit in der Schleife von 5ms 
auf 25ms erhöht und seitdem läuft es.

Weiters muss ich Dir recht geben bezüglich des Steckbrettes. Auch wenn 
nicht viel gesteckt ist, ist es jetzt schon voll mit einer Unmenge an 
Kabeln.

Danke auch Dir Marc für Deinen Beitrag. Ich hatte zu Beginn einen 
stumpfen Code wo der Master alle 3s eine einfache Meldung an den Slave 
gesendet hat. Das hat ohne Probleme funktioniert.

Mit dem Scheduler ist das komplizierter geworden. Der Scheduler wird 
sich natürlich nicht auf das Schalten einer Led beschränken sondern da 
kommen eine Menge Funktionen dazu.

Ich muss noch dazu sagen, dass ich den Code einst weilen nur als Debug 
compiliert habe.

Was haltet ihr von der Optimierung mit den Baudraten Quarzen?

Grüße
Markus

von M. K. (sylaina)


Lesenswert?

Markus W. schrieb:
> Was haltet ihr von der Optimierung mit den Baudraten Quarzen?

Ist bei längeren Leitungen und höheren Datenraten unbedingt zu 
empfehlen. Ich nutze eigentlich nur noch Baudratenquarze mit 14.7456 MHz 
an den Atmegas, früher hatte ich oft 16 MHz Quarze am Start. Die AVRs 
sind mir mit 14,7456 MHz aber auch schnell genug und damit sind auch 115 
kBd auch auf längeren Strecken kein Problem.

von Markus (Gast)


Lesenswert?

Hallo M. Köhler

Ich hätte die 7,3728 zu Hause. Sollten ja auch gehen oder?
Wenn das mal soweit läuft, hätte ich eine Leitungslänge von ca. 30-40m 
und insgesamt 6 Teilnehmern vorgesehen.

Grüße Markus

von M. K. (sylaina)


Lesenswert?

Ja klar, die gehen auch. Nicht selten nutze ich bei den 14.7456 MHz 
Quarzen den Prescaler von 8 (lasse auch die entsprechende Fuse an). Es 
geht ja bei dem Spass nur darum, dass man beim UBBR-Value einen glatten 
Wert erhält, das geht bei allen ganzzahligen Vielfachen von 0.9216 MHz.

von M. W. (mw73)


Lesenswert?

So, jetzt hab ich mal alles als Release kompiliert - wieder die 
Einschaltprobleme. Ich versteh das nicht. Wenn es mit dem Einschalten 
klappt dann läuft der Bus absolut verlässlich. Aber wie gesagt alle 2-3 
Mal Einschalten geht es erst. Dabei hab ich schon großzügige Timings 
verabreicht und wenn ich mit dem Oszilloskop schaue (wenn der Bus läuft) 
ist kein gleichzeitiges Senden zu sehen. Sehr ernüchternd.

Grüße
Markus

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Markus W. schrieb:
> Wenn es mit dem Einschalten
> klappt dann läuft der Bus absolut verlässlich.

Dann liegt es wahrscheinlich am Einschaltvorgang. Mach dazu am besten 
mal ein Flowchart mit Timings und schau dir dabei mal an was passieren 
würde, wenn das ein und andere Timing innerhalb seiner Toleranz driftet. 
Da könnte es eine blöde Überschneidung geben.

von M. W. (mw73)


Lesenswert?

Ok, ich werd das mal versuchen, soweit ich die Timings bestimmen kann.

Grüße
Markus

von M. W. (mw73)


Lesenswert?

eines find ich allerdings echt merkwürdig. Wenn der Programmer 
angeschlossen ist läuft der Bus jedes Mal an. Probleme treten nur auf, 
wenn der Programmer nicht an einem Controller hängt.

Da muss doch irgend ein Zusammenhang sein.

Resetbeschaltung: 10k an VCC, 100n gegen Masse.
Ich habe es auch ohne den Kondensator probiert, keine Änderung

Grüße
Markus

von Sven K. (svenk)


Lesenswert?

Hallo Markus,

zeige doch mal ein Bild von dem Aufbau.

Zum Kondensator: bist Du sicher das das die erwartete Größe ist? 
Vielleicht hat er eine viel zu kleine Kapazität.

Der Programmer macht nichts anderes als den Reset auch mit einem Pullup 
zu versorgen.

Vielleicht ist auch dein pullup Widerstand defekt ?
Oder Steckbrett Probleme?


Gruß Sven

: Bearbeitet durch User
von M. W. (mw73)


Angehängte Dateien:

Lesenswert?

Hallo Sven,

Wegen der Größe des Kondensators, die sollte soweit passen (hab auch 
schon hier im Forum deswegen gelesen).

Ich habe noch Bilder von meinem Aufbau angehängt.

Grüße
Markus

von Sven K. (svenk)


Lesenswert?

Hallo Markus,

ehrlich gesagt würde ich Dir ganz stark empfehlen jetzt den Schritt zu 
gehen und ein paar fertige Boards zu kaufen oder Du entwirfst dein 
eigenes. Nach dieser langen Testphase würde ich Dir aber mehr empfehlen 
auf fertige Boards mit Rs485 zu setzen. Ja das kostet Geld bietet Dir 
aber sofort lauffähige Verbindungen und Erfolgserlebnis.


Was hast Du denn vor wenn es mit den Platinen läuft?

Beispiele:

http://www.chip45.com/products/crumb644-1.1_avr_atmega_modul_board_atmega644p_usb_rs485.php

mit wählbarer Frequenz und Bus direkt drauf.

Es gibt sicher noch weitere Beispiele, war jetzt der erste Treffer.

Gruß Sven

von M. W. (mw73)


Lesenswert?

Hallo Sven,

Danke für den Link, ist eine interessante Seite.

Ich weis, das die Beschaltung am Steckbrett sehr ungünstig und 
fehleranfällig ist. Da ich eine vollständige Ausrüstung zum Ätzen habe 
werde ich mir die Platinen selber entwickeln (oder ggf. auf eine fertige 
Lösung zurück greifen). Später möchte ich einmal meine Rolläden damit 
steuern.

Eigentlich stehe ich ja noch am Anfang, da das ja nur der Testcode ist. 
Ich bin auch immer wieder am Überlegen ob ich den Code verwerfe und was 
einfacheres mache, wie es Marc bereits vorgeschlagen hat.

Zur Zeit läuft es aber gar nicht schlecht. Ich habe in der 
Initialisierungsphase ein paar kurze delays eingefügt und jetzt 
funktioniert das Einschalten jedel Mal. Ich werde mir aber die Zeit 
nehmen und ein Flowchart entwickeln.

Eines ist mir jedoch unklar und vielleicht kannst Du oder jemand anders 
mir das beantworten. Durch die eingefügten delays in der 
Initialisierungsphase hat sich der gesamte Bustransfer verlangsamt (lt. 
Oszilloskop).
Klar wäre mir das, wenn ich in der While Schleife delays einfüge aber in 
wie fern kann eine verzögerte Initialisierung den Bus beeinflussen?????

Grüße
Markus

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.