Forum: Mikrocontroller und Digitale Elektronik Protokoll für einfache Kommunikation rs485


von Karl K. (leluno)


Lesenswert?

hallo,

ich will meinen Deye-Solar-Wechselrichter steuern. Dazu habe ich einen 
nano-AVR, der Lichteinfall, Batteriespannung, und Stellung des 
Lasttrennschalters misst und über zwei Relais den Lasttrennschalter und 
den Akku steuert. Funktioniert alles ohne größere Probleme. Lediglich 
die i2c-rtc und die Lcd-Anzeige sind manchmal - wohl aufgrund von 
Störimpulsen - weg. Deswegen will ich lcd und rtc auf einen zweiten Nano 
auslagern. uart-RS485-Kommunikation funktioniert auch - fast - 
fehlerfrei.
1
#if sender0_empfaenger1==0//Sender
2
if(sec%7==3)
3
  {
4
//0110006C0001020078 AF1E //crc-teststring
5
    u8 len=9;
6
    u16 crc=0;
7
    txBuffer[0]=0x01;
8
    txBuffer[1]=0x10;
9
    txBuffer[2]=0x00;
10
    txBuffer[3]=0x6c;
11
    txBuffer[4]=0x00;
12
    txBuffer[5]=0x01;
13
    txBuffer[6]=0x02;
14
    txBuffer[7]=0x00;
15
    txBuffer[8]=0x78;
16
17
  crc= function_crc( txBuffer,  len);
18
  txBuffer[len]  = crc & 255 ;
19
  txBuffer[len+1]= crc>>8  ;
20
21
  serial_tx(txBuffer,len+2);
22
  }
23
  
24
#else//empfänger  
25
  if(sec%7==3  
26
  && uart_str_rx[9]>0
27
  )
28
  {
29
    for (u8 i=0;i<15;i++)
30
    {
31
      lcd_goto(5+i,1);
32
      lcd_int4(uart_str_rx[i]);
33
    }
34
    
35
    u16  crc= function_crc( uart_str_rx,  9);
36
    uart_str_rx_ct=0;
37
    
38
    if(((crc>>8)==uart_str_rx[10]) && ((crc&255)==uart_str_rx[9]))
39
    {    
40
      lcd_goto(5+9,5);
41
      lcd_int4(crc&255);
42
      lcd_int4(crc>>8);
43
    }    
44
    memset(uart_str_rx, 0, 13);
45
  }
46
#endif

Jetzt geht es um das Protokoll. Wie macht man das am besten - wiederholt 
Senden bis vom Empfänger eine Bestätigung kommt oder z.B. 5mal Senden 
und der Empfänger steigt aus, wenn er korrekt empfangen hat?

Das ist sicher ein Problem, über das sich schon viele kluge Köpfe 
Gedanken gemacht haben. Gibt es vielleicht eine einfache 
Standard-Musterlösung?

: Bearbeitet durch User
von Rüdiger B. (rbruns)


Lesenswert?

Karl K. schrieb:
> Lediglich
> die i2c-rtc und die Lcd-Anzeige sind manchmal - wohl aufgrund von
> Störimpulsen - weg.

Fehlerquelle suchen, Watchdog Timer, Abblockkondensatoren....

von Nick (b620ys)


Lesenswert?

Karl K. schrieb:
> Gibt es vielleicht eine einfache Standard-Musterlösung?

Schau dir mal das ModBus-Protokoll an.

von Harald K. (kirnbichler)


Lesenswert?

Nimm Modbus-RTU. Das ist erprobt, dafür gibt es zig Testwerkzeuge und 
fertige Libraries auf so gut wie allen Plattformen.

Modbus-RTU bietet Fehlererkennung. Einerseits durch die Hardwareschicht 
der UART mit Parity- und Framingauswertung und andererseits durch 
16-Bit-CRC in jedem Telegramm. Ein Gerät ("Slave") kann ein fehlerhaftes 
Paket monieren (mit Modbus-Exceptions, der Gegenpart ("Master") kann 
wiederum bei fehlerhaften Paketen den zuletzt gesendeten Kram 
wiederholen.

Sofern nicht die Hardware besonders schrottig ist oder aber die 
Leitungen besonders ungünstig verlegt sind (z.B. um einen Wechselrichter 
gewickelt oder komplett auf Twisted-Pair verzichtet), treten im 
Normalbetrieb aber keine Fehler auf; Modbus-Verbindungen können jahre- 
und jahrzehntelang stabil arbeiten.

Ja, das Protokoll ist primitiv, da es genau zwei Datentypen kennt: Bit 
und 16-Bit-Wort. Aber es ist möglich und wird zigtausendfach 
praktiziert, auch größere Datentypen durch Zusammenfassen mehrerer 
16-Bit-Worte zu erhalten.

Das ist dann ein zusätzlicher Protokollayer, den man nur gut 
dokumentieren sollte. Die üblichen Modbus-Testprogramme (wie z.B. 
Modbus-Poll) kommen auch damit zurecht.

von Udo S. (urschmitt)


Lesenswert?

Karl K. schrieb:
> Funktioniert alles ohne größere Probleme. Lediglich
> die i2c-rtc und die Lcd-Anzeige sind manchmal - wohl aufgrund von
> Störimpulsen - weg.

Hier die Ursache suchen statt das System zusätzlich zu komplizieren wäre 
der bessere Weg.
Wie ist die Masseverbindung der unterschiedlichen Komponenten. Das ist 
eine häufige Störquelle.

Protokoll Modbus wie schon gesagt wurde.

von Michael B. (laberkopp)


Lesenswert?

Karl K. schrieb:
> wohl aufgrund von Störimpulsen - weg. Deswegen will ich lcd und rtc auf
> einen zweiten Nano auslagern

Falscher Ansatz.

Suche das Problem.
Schaffe nicht neue Probleme.

von Rainer W. (rawi)


Lesenswert?

Karl K. schrieb:
> "wohl aufgrund von Störimpulsen" hört sich nach blindem Raten an.
Guck, was wirklich das Problem ist und beseitige es.

Meinst du, dass es einfacher wird, wenn zusätzlich noch die beiden 
Controller miteinander kommunizieren sollen?

> Wie macht man das am besten - wiederholt Senden bis vom Empfänger eine
> Bestätigung kommt oder z.B. 5mal Senden und der Empfänger steigt aus,
> wenn er korrekt empfangen hat?

Fällt die Übertragung teilweise aus oder werden Daten fehlerhaft 
empfangen?
Wie lang sind deine Leitungen? Was gibt es für Störer in der Nähe?

Ohne die Art der Fehler zu kennen, kann man vieles probieren. Man kann 
die Zeichenkodierung ändern, also z.B. den Hammingabstand zwischen den 
Symbolen vergrößern, so dass Bitfehler erkannt und z.T. auch korrigiert 
werden können oder man kann eine Prüfsumme hinzufügen und bei 
Prüfsummenfehler die Daten neu anfordern - aber es kommt eben auf die 
Art der Fehler an.

Gegen Programmierfehler hilft das nichts.

: Bearbeitet durch User
von Nick (b620ys)


Lesenswert?

Karl K. schrieb:
> Lediglich die i2c-rtc und die Lcd-Anzeige sind manchmal

Bilder! :-)
Schon mal auf dem Oszi angesehen? Abschlusswiderstand richtig 
dimensioniert und verifiziert?

von Karl K. (leluno)



Lesenswert?

Nick schrieb:
> Abschlusswiderstand richtig

das ist eigentlich seit Jahren bewährte Technik. Der Zusammenhang 
"Umschalten der Stromquelle" ist auch relativ klar. Da entsteht manchmal 
ein Störimpuls, da das Hausnetz während des Umschaltens unterbrochen 
wird. Die Versorgung zum Nano wird natürlich nicht unterbrochen.

Nick schrieb:
> Bilder! :-)
ich bitte um Nachsicht für die noch provisorische Verkabelung der 
Steuerung - erstmal muss es richtig funktionieren.

Udo S. schrieb:
> Hier die Ursache suchen statt das System zusätzlich zu komplizieren wäre
> der bessere Weg.

Ich finde die Idee von zwei Nanos eigentlich nicht schlecht. Die können 
sich dann gegenseitig überwachen.

von Nemopuk (nemopuk)


Lesenswert?

Karl K. schrieb:
> Ich finde die Idee von zwei Nanos eigentlich nicht schlecht. Die können
> sich dann gegenseitig überwachen.

Normalerweise laufen Mikrocontroller jahrelang fehlerfrei durch. Ich 
würde lieber den Fehler beheben.

von Nick (b620ys)


Lesenswert?

Karl K. schrieb:
>> Bilder! :-)
> ich bitte um Nachsicht für die noch provisorische Verkabelung der
> Steuerung - erstmal muss es richtig funktionieren.

Schon OK. Ich hab nach scope-Bildern auf dem I2C gefragt ... oh ... 
gedacht gefragt zu haben. :-)

Wie lange ist denn die I2C-Leitung? Denn eigentlich ist das nur für 
kurze Strecken geplant gewesen. Es gibt zwar Isolatoren dafür, aber 
damit hab ich Null Erfahrungen.

von Rainer W. (rawi)


Lesenswert?

Karl K. schrieb:
> Ich finde die Idee von zwei Nanos eigentlich nicht schlecht. Die können
> sich dann gegenseitig überwachen.

Dafür wurde der WDT erfunden.

von Karl K. (leluno)


Lesenswert?

Nick schrieb:
> Wie lange ist denn die I2C-Leitung?

maximal 5cm auf der Streifenrasterplatine zum DS3231-Modul. Der 
gespeicherte Wert ist nach der Störung komplett weg - die rtc startet 
mit 1.1.2000 neu. Blöd weil ich eine Sonnenaufgangsfunktion hatte - geht 
aber mit der Messung des Lichteinfalls ohnehin besser.

von Hardy F. (hflor)


Lesenswert?

Was sagt Dein EVU zu dem fehlenden Abstandsflächen vor dem Zählerschrank 
und HAK?

von Harald K. (kirnbichler)


Lesenswert?

Hardy F. schrieb:
> Was sagt Dein EVU zu dem fehlenden Abstandsflächen vor dem Zählerschrank
> und HAK?

Zahlt der eigentlich Miete für die mehreren Quadratmeter, die der sich 
da so mittlerweile meint, fordern zu müssen?

von Michael B. (laberkopp)


Lesenswert?

Karl K. schrieb:
> Lediglich
> die i2c-rtc und die Lcd-Anzeige sind manchmal - wohl aufgrund von
> Störimpulsen - weg.

Karl K. schrieb:
> ich bitte um Nachsicht für die noch provisorische Verkabelung der
> Steuerung - erstmal muss es richtig funktionieren.

Wie soll es mit provisorischer Verkabelung störungsfrei funktionieren ?

Ich sehe Antennen, zum Aussenden von Störungen und Empfangen von 
Störungen und Masse wird kreuz und quer geführt.

Das ist keine elektronische Schaltung sondern ein Breakout Aufbau mit 
der Hoffnung daß es irgendwie glatt geht. Bloss muss die Hoffnung ja 
nicht immer erfüllt werden.

von Rainer W. (rawi)


Lesenswert?

Karl K. schrieb:
> ... zum DS3231-Modul. Der gespeicherte Wert ist nach der Störung komplett
> weg - die rtc startet mit 1.1.2000 neu.

Also liegt es gar nicht am Mikrocontroller?
Hast du eine Backup+Batterie an der DS3231 angeschlossen?

Wie sieht dein Schaltplan aus?

von Karl K. (leluno)


Angehängte Dateien:

Lesenswert?

Rainer W. schrieb:
> Also liegt es gar nicht am Mikrocontroller?

ja - genau das vermute ich. Ich hatte das ganze per Blechgehäuse 
abgeschirmt - hat aber nichts geholfen.

Rainer W. schrieb:
> Backup+Batterie

ist angeschlossen - Sinn ist ja, dass der uc nach Neustart das korrekte 
Datum findet.

Rainer W. schrieb:
> Wie sieht dein Schaltplan aus?

Ich verwende fertige module, die über Steckleisten mit dem nano 
verbunden werden. Einen Schaltplan gibt es nicht.

Michael B. schrieb:
>  Breakout Aufbau

Ja, genau. Ich bin ja am Entwickeln - also brauche ich einen 
Breakout-Aufbau.

Rainer W. schrieb:
> Meinst du, dass es einfacher wird, wenn zusätzlich noch die beiden
> Controller miteinander kommunizieren sollen?

Es eröffnet Möglichkeiten. Ich habe dann ein Netzwerk und kann den uc 
auch vom PC aus steuern. Z.B. Grenzwerte für das Schalten des ucs vom PC 
aus ändern ohne den uc neu zu programmieren.

von Bruno V. (bruno_v)


Lesenswert?

Ein Protokoll könnte Deine Fähigkeiten arg fordern. Der wesentlichen 
Punkte:

> Wenn Nutzdatenbytes den Wertebereich 0..255 haben,
> dann sind Start- und Endekennung schwierig.

Du brauchst zumindest ein exklusives StartByte, wenn Du nicht mit 
komplizierten Timeouts den Anfang eines Telegrams erkennst. (Zählen der 
Bytes ist noch komplizierter)

Exklusiv heißt: kein Nutzdatenbyte (incl. möglicher Checksumme) hat 
diesen Wert (diese Werte). Dazu gibt es mehrere Möglichkeiten:
 * Du teilst jedes Nutzdatenbyte in 2 Bytes (z.B. 2 Hex-Ascii-Werte)
 * Du teilst 7 Nutzdatenbytes auf die unteren 7 Bits von 8 Bytes
 * "Bytestuffing" (nutze ich sehr häufig, mehr bei Bedarf)
 * Strings statt Binärwerte (ist die Standardlösung, da unabhängig von 
Alignment, Endianess, etc.)

Für den Anfang würde ich "Hex" nehmen. 0x1a wird z.B. als '1' und 'a' 
übertragen , also deren ASCII-Werte.

Dann kannst Du einen beliebigen Wert als Startwert nehmen, z.B. 'S'. Mit 
13 oder so als Endekennung kannst Du Telegramme im Terminalprogramm 
direkt mitlesen (ein wertvoller Vorteil!).

Dein Telegramm im OP sähe dann so aus:

> S0110006c0001020078
>

: Bearbeitet durch User
von N. M. (mani)


Lesenswert?

Ich persönlich würde es über Timeouts machen. Ist auch kein Hexenwerk. 
Es gibt aber auch andere einfache Wege.

Bruno V. schrieb:
> Du brauchst zumindest ein exklusives StartByte

Nicht zwingend. Zumindest nicht in der Art dass man einen 
eingeschränkten Zeichenbereich hätte.
Eine einfache Möglichkeit wäre den 9Bit Modus zu verwenden. Ist das 
oberste Bit gesetzt, ist es das erste Byte im Frame. Die restlichen 8 
Bit innerhalb eines Zeichens sind dann normale Nutzdaten.
Im ersten Zeichen könnte man z.B. neben der Start Kennennung noch die 
Anzahl der nachfolgenden Bytes unterbringen. Ein Frame könnte also 
maximal 256 Bytes lang sein. Danach das CMD, Nutzdaten, CRC wobei dabei 
das 9. Bit nie gesetzt ist.

Man kann also sehr leicht auf den Anfang eines Frames synchronisieren 
(9.Bit) und den Frame anhand Längenangabe,CMD und CRC validieren.

von Harald K. (kirnbichler)


Lesenswert?

Bruno V. schrieb:
> Ein Protokoll könnte Deine Fähigkeiten arg fordern.

Aus gutem Grund habe ich Modbus/RTU vorgeschlagen. Das hat zwar einen 
gewissen Overhead, ist aber etabliert, in Form von zig Libraries 
verfügbar und es gibt jede Menge Testprogramme dafür, so daß beide 
Seiten der Kommunikation problemlos alleinstehend getestet werden 
können.

Sowas hilft Fehlerquellen zu reduzieren und ist alleine deswegen schon 
jeder Selbstbaulösung überlegen.

Und ... man lernt dazu und hat was in der Tasche, das man später auch 
woanders verwenden kann; Modbus ist so selten nicht.

Wenn nur genau zwei Geräte miteinander kommunizieren sollen, kann man 
Modbus auch ohne RS485 betreiben, einfach durch Verbindung zweier 
serieller Schnittstellen. Bei kurzen Verbindungen und gemeinsamer Masse 
kann man auch auch Pegelwandler verzichten (sofern beide Seiten die 
gleichen Pegel nutzen).

von Nick (b620ys)


Lesenswert?

N. M. schrieb:
> Ich persönlich würde es über Timeouts machen. Ist auch kein Hexenwerk.
> Es gibt aber auch andere einfache Wege.

Das über timing zu machen geht im Mikrocontroller-Umfeld gut. Sobald 
aber ein Betriebssystem an der Kommunikation beteiligt ist, geht das 
leicht ins Gehöse. Die können kein genaues Timing.

Da hab ich schlechte Erfahrungen mit RT-Linux gemacht. Ich hatte eine 
ModBus-Kommunikation über RS485 und Zweidraht. Die Umschaltung von 
Senden zu Empfangen am PC war einfach zu lahm. Konsequenz: Lieber 
4-Draht, dann muss man nicht umschalten.

Zweiter Reinfall:
Mein Kasterl zur Verkehrserfassung hat über 2-Draht-RS485 mit einem 
Master kommuniziert (war ähnlich ModBus). Vom Kunden gab es immer wieder 
mal Klagen, dass Pakete verloren gehen. Das war aber nie 
nachvollziehbar. Bis ich dann ein Protokoll der Kommunikation bekommen 
hab und -nach langen Grübeln und Anschauen- mir aufgefallen ist, dass es 
nur bei besonders langen Paketen war. Die hatten einfach stur nach x ms 
den Bus umgeschaltet statt den Datenverkehr zu beobachten und sich an 
das 3.5 Zeichen timeout zu halten. Deren Betriebssystem war BusyBox. 
Ihre "Lösung" war dann, einfach genauso stur umzuschalten, aber halt 
später.

Also Vorsicht mit timing-Geschichten wenn "echte Betriebssysteme" 
beteiligt sind. Ansonsten bekommt man das hin, 1 ms Auflösung geht 
problemlos.

von Nick (b620ys)


Lesenswert?

Bruno V. schrieb:
>> Wenn Nutzdatenbytes den Wertebereich 0..255 haben,
>> dann sind Start- und Endekennung schwierig.
>
> Du brauchst zumindest ein exklusives StartByte, wenn Du nicht mit
> komplizierten Timeouts den Anfang eines Telegrams erkennst. (Zählen der
> Bytes ist noch komplizierter)

Das stimmt so nicht. Dazu mal TCP anschauen, oder ModBus.
Das Synchronisieren ist halt bissl aufwendig.

Startbyte z.B. 0xAA
Dann Längenangabe des Paketes
Daten ...
CRC

Wenn man irgendwo im Datenstrom aufsetzt wartet man das Startbyte ab, 
liest die vermeintliche Länge, wartet den vermeintlichen CRC ab (Timeout 
beachten) und dann muss der CRC passen. Falls nicht, ein Zeichen nach 
dem -jetzt bekannterweise falschen- Startbyte wieder neu probieren.

von Rainer W. (rawi)


Lesenswert?

Karl K. schrieb:
> Einen Schaltplan gibt es nicht.

Schlechter Plan. Die Module nehmen dir das Nachdenken über 
Stromversorgung, Aufbau I2C-Bus und die Verbindung der Module 
untereinander nicht ab. Für die Dokumentation deines Aufbaus brauchst du 
den Schaltplan sowieso.

> Es eröffnet Möglichkeiten. Ich habe dann ein Netzwerk und kann den uc
> auch vom PC aus steuern. Z.B. Grenzwerte für das Schalten des ucs vom PC
> aus ändern ohne den uc neu zu programmieren.

Und warum brauchst du dafür ein Netzwerk?
Bisher hört es sich nicht so an, als ob deine GPIOs knapp sind.

: Bearbeitet durch User
von Helmut -. (dc3yc)


Lesenswert?

Schaltplan ist ein Muss! Da sieht man auch, ob du die richtigen Pullups 
für den I2C-Bus verwendet hast. Die auf den Modulen üblicherweise 
aufgelöteten passen nämlich nicht und sind normalerweise zu gross.

von Karl K. (leluno)


Angehängte Dateien:

Lesenswert?

Bruno V. schrieb:
> Ein Protokoll könnte Deine Fähigkeiten arg fordern

Deswegen frage ich ja hier. Fleury-bib leicht modifiziert:
1
ISR (UART0_RECEIVE_INTERRUPT)  
2
{
3
if(uart_str_rx_ct>uart_string_len+1)uart_str_rx_ct=0;
4
uart_str_rx[uart_str_rx_ct++] = UDR0;
5
return;
6
...
7
  if(sec%10==3)
8
  {
9
    u16 crc=0;
10
11
    uart_string_len=14;
12
    txBuffer[0]=0x01;//adr-sender
13
    txBuffer[1]=0x02;//adr-empfänger
14
    txBuffer[2]=uart_string_len;//len-payload
15
    txBuffer[3]=0;//cmd
16
17
    txBuffer[4]=hou;
18
    txBuffer[5]=min;
19
    txBuffer[6]=sec;
20
    txBuffer[7]=tag1_nacht0;
21
    txBuffer[8]=status_wr;
22
    
23
    txBuffer[9]=akku_volt>>8;
24
    txBuffer[10]=akku_volt;
25
26
    txBuffer[11]=pv_in>>8;
27
    txBuffer[12]=pv_in;
28
29
    txBuffer[13]=LTswitch;
30
31
  crc= function_crc( txBuffer,  uart_string_len);
32
  txBuffer[uart_string_len]  = crc & 255 ;
33
  txBuffer[uart_string_len+1]= crc>>8  ;
34
35
  serial_tx(txBuffer,uart_string_len+2);
36
  }
37
  
38
#else//empfänger  
39
  if(sec%7==3  
40
//  && uart_str_rx[9]>0
41
  )
42
  {
43
    for (u8 i=0;i<20;i++)
44
    {
45
      lcd_goto(5+i,1);
46
      lcd_int4(uart_str_rx[i]);
47
    }
48
49
    u8  uart_string_lenx = uart_str_rx[2];
50
      lcd_int4(uart_string_lenx);
51
    
52
    u16  crc= function_crc( uart_str_rx,  uart_string_lenx);
53
    uart_str_rx_ct=0;
54
    
55
    if(((crc>>8)==uart_str_rx[uart_string_lenx+1]) && ((crc&255)==uart_str_rx[uart_string_lenx]))
56
    {    
57
      akku_volt=(uart_str_rx[9]<<8)+uart_str_rx[10];
58
      
59
      pv_in=(uart_str_rx[11]<<8)+uart_str_rx[12];
60
        
61
      u8 LTswitchx=uart_str_rx[13];
62
      
63
      status_wr=uart_str_rx[8];
64
      
65
      tag1_nacht0=uart_str_rx[7];
66
    }    
67
    memset(uart_str_rx, 0, 20);
68
  }
69
#endif
Das funktioniert relativ problemlos. Jeder Teilnehmer im Netz bekommt 
ein bestimmtes Zeitfenster zum Senden zugewiesen. Das verhindert 
Kollisionen.

Nächstes Problem ist das handshake.

von Veit D. (devil-elec)


Lesenswert?

Karl K. schrieb:
> Nick schrieb:
>> Wie lange ist denn die I2C-Leitung?
>
> maximal 5cm auf der Streifenrasterplatine zum DS3231-Modul. Der
> gespeicherte Wert ist nach der Störung komplett weg - die rtc startet
> mit 1.1.2000 neu. Blöd weil ich eine Sonnenaufgangsfunktion hatte - geht
> aber mit der Messung des Lichteinfalls ohnehin besser.

Hättest du gleich schreiben können. Vergiss jetzt dein Protokoll. Das 
ist nicht dein Problem. Du hast mit der RTC generell ein Problem. Das 
gilt es zu lösen. Ich setzte voraus das die Knopfzelle der RTC i.O. ist. 
Hast du es nachgemessen? Ich habe das Gefühl, du schreibst keine 
Daten/Änderungen in die RTC, ansonsten wären die nämlich nicht weg. Ich 
vermute du hälst die aktuellen Daten nur im RAM vom µC und denkst die 
wären in der RTC. Schreibe ein einfaches Programm was das Datum + Zeit 
stellt und lies die Daten zurück. Bereite das Programm vor damit es nur 
ausliest. Wenn das klappt, mach das RTC Modul Spannungslos, die 
Knopfzelle bleibt drauf. Kurz warten, anstecken und nur auslesen. Was 
passiert?

von Nick (b620ys)


Lesenswert?

Karl K. schrieb:
> Deswegen frage ich ja hier. Fleury-bib leicht modifiziert:

Dann lies dir doch bitte auch die Vorschläge hier durch. Und 
berücksichtige die dann auch.

Das was Du gezeigt hast ist "realativ" problematisch. Wenn alles klappt, 
dann geht es. Wenn ein Fehler auftritt, dann nicht mehr.

Karl K. schrieb:
> Nächstes Problem ist das handshake.

ModBus!
Polling der Gegenseite durch den Master. Antwort innerhalb einer 
vorgegebenen Zeit oder Anfrage wiederholen.

Karl K. schrieb:
> Fleury-bib

Zu "Bib" fällt mir nur das Michelin-Männchen ein. 
https://de.wikipedia.org/wiki/Bibendum

von Wastl (hartundweichware)


Lesenswert?

CRC Funktionen und LCD Ausgaben in der ISR.

Hol mir Kraut (oh mir graut) ....

Die aussagekräftigen und scharfen Fotos tun ihr Übriges ...
... über die Qualifikation zu berichten.

: Bearbeitet durch User
von Karl K. (leluno)


Lesenswert?

Wastl schrieb:
> CRC Funktionen und LCD Ausgaben in der ISR.
1
return;
2
...

return heißt, dass die irc an dieser Stelle beendet ist.Kürzer geht 
wirklich nicht.

... heißt, dass dies ein anderer Programmteil ist.

Veit D. schrieb:
> Ich habe das Gefühl, du schreibst keine
> Daten/Änderungen in die RTC, ansonsten wären die nämlich nicht weg.

No.
1
if(gbi(PIN(D),2)==1)
2
{
3
lcd_clear(BLACK);
4
}
5
else
6
{
7
lcd_clear(RED);
8
kk_ds1307_setTime(14,36,0);//Sommerzeit 
9
kk_ds1307_setDate(31,12,25);
10
}
11
kk_ds1307_getAll_to_global_struct_zt();

Die RTC wird nur beim Start und jeweils um 0Uhr ausgelesen und die 
Programmzeit aktualisiert. Ich habe bewährte Routinen zum Schreiben und 
Lesen der RTC. Ich werde das aber so umstellen, dass die RtC über RS485 
vom PC aus aktualisiert wird. Es ist lästig, das Programm ändern zu 
müssen um die RTC einstellen zu können.

: Bearbeitet durch User
von Harald K. (kirnbichler)


Lesenswert?

Nick schrieb:
> Ich hatte eine
> ModBus-Kommunikation über RS485 und Zweidraht. Die Umschaltung von
> Senden zu Empfangen am PC war einfach zu lahm. Konsequenz: Lieber
> 4-Draht, dann muss man nicht umschalten.

Das ist nur an einem Ende des Busses eine Lösung, alle anderen müssen 
trotzdem umschalten.

Das eigentliche Problem lässt sich aber durch Wahl der richtigen UARTs 
elegant lösen, die nämlich beherrschen die Sender-/Empfänger-Umschaltung 
in Hardware. Und dazu gehören auch viele USB-Seriell-Bridges, wie z.B. 
alles von FTDI.

Ansonsten hättest Du unter Deinem Linux nur den Devicetreiber anpassen 
müssen, dann hätte das auch Dein PC hinbekommen können. Die 
PC-Standard-UART löst zwar keinen Interrupt aus, wenn sie mit Senden des 
letzten Bits fertig ist, aber es gibt ein Flag in einem Statusregister, 
das man abfragen kann, notfalls in einem Timerinterrupt, der mit dem 
Übertragen des letzten zu sendenden Zeichens an die UART aufgezogen 
wird.
Damit schafft das auch ein wirklich alter PC, sofern man nicht mit 
unnötig hohen Baudraten arbeitet.

von Veit D. (devil-elec)


Lesenswert?

Karl K. schrieb:

> Veit D. schrieb:
>> Ich habe das Gefühl, du schreibst keine
>> Daten/Änderungen in die RTC, ansonsten wären die nämlich nicht weg.
>
> Die RTC wird nur beim Start und jeweils um 0Uhr ausgelesen und die
> Programmzeit aktualisiert. Ich habe bewährte Routinen zum Schreiben und
> Lesen der RTC. Ich werde das aber so umstellen, dass die RtC über RS485
> vom PC aus aktualisiert wird.

Das ist nicht die Antwort auf das Problem. Was passiert wenn du die RTC 
für paar Sekunden nur von der Knopfzelle versorgen lässt und danach 
wieder ausliest? Nur die RTC und der µC sollen dabei im Spiel sein. Ich 
glaube ja immer noch das die RTC sich die Zeit nicht merkt bzw. nicht 
merken kann. Durch was soll eine RTC ihre Einstellung verlieren. Nur 
wenn keine Puffer/Versorgungsspannung anliegt.

> Es ist lästig, das Programm ändern zu
> müssen um die RTC einstellen zu können.

Wer hindert dich das zu ändern? Ist doch dein Programm.
1
> kk_ds1307_setTime(14,36,0);//Sommerzeit 
2
> kk_ds1307_setDate(31,12,25);
Und haste danach ausgelesen zum Gegenprüfen?
RS485 hilft dir dabei jedenfalls nicht das Problem zu lösen.

Ich wundere mich das alle anderen hier immer nur vom Protokoll 
schreiben, aber das eigentliche Problem links liegen lassen. Verstehe 
ich nicht.

: Bearbeitet durch User
von Bruno V. (bruno_v)


Lesenswert?

N. M. schrieb:
> Nicht zwingend. Zumindest nicht in der Art dass man einen
> eingeschränkten Zeichenbereich hätte.

Naja, wenn ich 8 Bit Daten in 9 Bit übertrage, dann ist das Startbyte 
in genau der von mir beschriebenen Weise exklusiv.

Nick schrieb:
>> Du brauchst zumindest ein exklusives StartByte, wenn Du nicht mit
>> komplizierten Timeouts den Anfang eines Telegrams erkennst. (Zählen der
>> Bytes ist noch komplizierter)
>
> Das stimmt so nicht. Dazu mal TCP anschauen, oder ModBus.
> Das Synchronisieren ist halt bissl aufwendig.

Du beschreibst genau das, was ich beschrieben habe. Timeouts oder 
StartByte. Auf was bezog sich das "stimmt so nicht"? TCP hingegen ist 
eine Schicht höher und setzt komplette Telegramme voraus.

von Nick (b620ys)


Lesenswert?

Harald K. schrieb:
>> Senden zu Empfangen am PC war einfach zu lahm. Konsequenz: Lieber
>> 4-Draht, dann muss man nicht umschalten.
>
> Das ist nur an einem Ende des Busses eine Lösung, alle anderen müssen
> trotzdem umschalten.

Das ist die komplette Lösung. Denn das Umschalten am _PC_ war zu lahm. 
Daher mein Hinweis auf "Betriebssysteme". Wer das am µC nicht 
timing-gerecht hinbekommt, stellt hier eine Frage nach "Protokollen für 
einfach Komm..."

von Karl K. (leluno)


Lesenswert?

Veit D. schrieb:
> Und haste danach ausgelesen zum Gegenprüfen?

Selbstverständlich - der uc startet immer mit RTC-Zeit. So wie er soll. 
Die RTC läuft. Strom weg - uc startet mit richtiger RTC-Zeit neu. Da 
liegt nicht das Problem.

von Nick (b620ys)


Lesenswert?

Karl K. schrieb:
> CRC Funktionen und LCD Ausgaben in der ISR.
> return;
> ...
>
> return heißt, dass die irc an dieser Stelle beendet ist.Kürzer geht
> wirklich nicht.

Da steht aber noch ein "if" davor.

Und dann kommt in der ISR noch ein
"#else//empfänger"

Allerdings könnte es sein, dass der code durch den snip (...) unnötig 
verstümmelt wurde.

Lustig ist auch, dass dennoch weitergelesen wird wenn der string schon 
komplett empfangen wurde.
Also:
String komplett lesen, uart_str_rx_ct inkrementieren. Wenn der String 
komplett gelesen ist in der ISR dekodieren und dann vergessen 
uart_str_rx_ct wieder auf Null setzen.


Wo das "#if" zum "#else" hingekommen ist weiß ich nicht. Und in dem 
Zweig wird lustig das LCD behandelt. Gegen den CRC hab ich persönlich 
und ernsthaft nix, das ist von der Zeit her sehr überschaubar. Aber man 
sollte das eigentlich nicht in der ISR machen. Da sind wir uns einig.

Hier code zu kommentieren ist müssig.
Für sowas würde ich mich schämen:
"uart_string_len=14;"

"const uart_string_len=14;"
ist richtig. K&R-Fans machen ein "#define" draus. Der Compiler will 
möglichst viele Chancen haben zu optimieren. Und das geht leichter mit 
Konstanten statt mit Variablen, auch wenn sie nie geändert werden.

von Heinz R. (heijz)


Lesenswert?

Karl K. schrieb:
> Ich finde die Idee von zwei Nanos eigentlich nicht schlecht. Die können
> sich dann gegenseitig überwachen.

ich finde die Idee sowas mit Nanos usw zu machen generell schlecht

Irgendwann willst / musst kurz was ändern, dann geht die Sucherei, 
kompilieren usw wieder los

Hierzu gibt es heutzutage wesentlich einfachere Möglichkeiten

von Veit D. (devil-elec)


Lesenswert?

Karl K. schrieb:
> Veit D. schrieb:
>> Und haste danach ausgelesen zum Gegenprüfen?
>
> Selbstverständlich - der uc startet immer mit RTC-Zeit. So wie er soll.
> Die RTC läuft. Strom weg - uc startet mit richtiger RTC-Zeit neu. Da
> liegt nicht das Problem.

Okay, hättest du gleich schreiben sollen wie du getestet hast. Welche 
"Störung" soll dann in der RTC die Daten löschen? Wenn die Knopfzelle 
die Versorgung übernimmt, kann da nichts passieren. Was erhoffst du dir 
demzufolge vom RS485 Bus? Der ist nachgelagert.

: Bearbeitet durch User
von Nick (b620ys)


Lesenswert?

Veit D. schrieb:
> Was erhoffst dir die demzufolge vom RS485 Bus? Der ist nachgelagert.

Eins nach dem Anderen angehen. Über die Reihenfolge kann man aber 
anderer Meinung sein.

von Veit D. (devil-elec)


Lesenswert?

Nick schrieb:
> Veit D. schrieb:
>> Was erhoffst dir die demzufolge vom RS485 Bus? Der ist nachgelagert.
>
> Eins nach dem Anderen angehen. Über die Reihenfolge kann man aber
> anderer Meinung sein.

Wenn irgendwas die RTC von außen "resetten" soll, kann das nicht über 
die Datenleitung kommen. Wie soll das gehen?

von Nick (b620ys)


Lesenswert?

Veit D. schrieb:
> kann das nicht über
> die Datenleitung kommen. Wie soll das gehen?

Hab ich nicht behauptet und auch nicht gesagt.

Es gibt Probleme mit dem Protokoll. Mir fällt z.B. das fehlende 
Null-setzen von uart_str_rx_ct auf und das fehlende Syncbyte. So wie das 
jetzt ist, ist es schwieriger zu synchronisieren. Auch wenn er das dann 
schon merkt, dass er danaben ist. Dann sind die Daten aber futsch, denn 
das Wiederaufsetzen fehlt. Zumindest in dem gezeigten code.
Wenn das Protokoll sicher läuft, kann er sich um die RTC kömmern. Er 
kann natürlich erst die RTC machen und dann das Protokoll.

Bis jetzt hat der TO keine scope-Bilder vom i2c-Bus gezeigt 
(Abschlusswiderstand), also ist es ihm wohl vorerst mal nicht so 
wichtig.

Oder er sitzt vorm PC und lässt den Kopf rauchen. Oder schaufelt Schnee.
Für mich ist es erst wieder sinnvoll mich hier zu beteiligen, wenn ein 
geänderter code vorliegt und Messungen.
Ohne Angaben und zielführende Rückmeldungen kann lange orakeln ...

von Veit D. (devil-elec)


Lesenswert?

Hallo,

wie soll denn ein fehlerhaftes Protokoll die RTC resetten? Geht doch gar 
nicht. Also warum bastelt man hier an einem zusätzlichen Protokoll, wenn 
man das Problem auch mit der vorhandenen 5cm I2C Verbindung auf den 
Grund gehen kann. Diese verbleibt ohnehin vorhanden.
Der TO fragt nach einem Protokoll, hat aber ein Problem mit einer sich 
resettenden RTC. Hat nichts miteinander zu tun. Man muss bei der RTC 
anfangen.

von Karl K. (leluno)


Lesenswert?

Veit D. schrieb:
> wie soll denn ein fehlerhaftes Protokoll die RTC resetten?

so:
1
    if(((crc>>8)==uart_str_rx[uart_string_lenx+1]) && ((crc&255)==uart_str_rx[uart_string_lenx]))
2
    {    
3
    u8 cmd =uart_str_rx[3];
4
    switch (cmd)
5
      {
6
        case (7)://command set rtc
7
        hou=uart_str_rx[4];
8
        min=uart_str_rx[5];
9
        sec=uart_str_rx[6];
10
        DAY=uart_str_rx[7];
11
        MON=uart_str_rx[8];
12
        YEA=uart_str_rx[9];
13
14
        kk_ds1307_setTime(hou,min,sec);//Sommerzeit 
15
        kk_ds1307_setDate(DAY,MON,YEA);
16
17
        break;
18
...

(noch nicht getestet)

von Karl K. (leluno)


Lesenswert?

Nick schrieb:
> Mir fällt z.B. das fehlende
> Null-setzen von uart_str_rx_ct auf und das fehlende Syncbyte.

uart_str_rx_ct wird nach jedem Auslesen von uart_str_rx auf 0 gesetzt - 
also in 10sec Zeitintervallen. Egal ob die crcv stimmt oder nicht.

das Syncbyte fehlt nicht sondern ist das 9.Byte. Das müsste im 
Fleury-code drin sein. Da bin ich mir aber nicht sicher. Ich hatte 
anfangs ein Problem mit dem Timing:
uart_init(18230);//baudrate 9600=>18226-18233 ok
Eigentlich müsste es ja 19200 wegen 
clock_prescale_set(clock_div_2);//8mhz sein.
Möglicherweise ist das Timing jetzt so genau, dass es auch ohne 9.bit 
zur Synchronisierung funktioniert.

Bei Hterm ist das Stopbit mit drin und es wird korrekt angezeigt???

Das wäre aber natürlich ein Fehler der beseitigt werden müsste.
Danke für den Hinweis.

von Schwierig (ruelps)


Lesenswert?

Karl K. schrieb:
> Bruno V. schrieb:
>> Ein Protokoll könnte Deine Fähigkeiten arg fordern
>
> Deswegen frage ich ja hier. Fleury-bib leicht modifiziert:
>
> [c]
> ISR (UART0_RECEIVE_INTERRUPT)
> {
> if(uart_str_rx_ct>uart_string_len+1)uart_str_rx_ct=0;

Was bitte soll das sein?

von Nick (b620ys)


Lesenswert?

Karl K. schrieb:
> uart_str_rx_ct wird nach jedem Auslesen von uart_str_rx auf 0 gesetzt -
> also in 10sec Zeitintervallen. Egal ob die crcv stimmt oder nicht.

Für mich ist das Gewurstel. Code muss klar strukturiert sein, und 
Abhängigkeiten vom Benutzer so gut wie möglich abgeschirmt werden.

Also:
Eine ISR ist eine ISR, sonst nichts.
Die ISR empfängt Zeichen, sonst nichts. Die schiebt sie dann in einen 
Ringpuffer. Der Ringpuffer sperrt die ISR wenn er head & tail des 
Ringpuffers verändert.

Der Task der die empfangenen Zeichen aufs Protokoll untersucht und das 
Timing kontrolliert frägt den Ringpuffer ab, und nur den Ringpuffer.
Die ISR hat also keine Ahnung was das Protokoll ist, was ein CRC ist. 
Die kannst Du dann beliebig oft in anderen Projekten hernehmen, ohne mit 
#defines irgendwelche Seltsamkeiten zu beeinflussen. Genauso der 
Ringpuffer. Der hat keine Ahnung was CRC ist. Kannst Du dann auch immer 
wieder verwenden.
Spezifisch wird es erst in dem Task der das Protokoll behandelt.

So musst Du nirgendwo nach X Sekunden irgend einen Zähler, der in deiner 
ISR essentiell ist, verändern. Vor Allem ist das Interupt-sicher. Denn 
der Interupt kann irgendwann auftreten und du hast keine Ahnung wann das 
genau ist und ob du nicht in dem Moment was machst was von der ISR 
verändert wird.

Module müssen strikt gekapselt sein. Alles Andere wird zwangsweise 
Gebastle und Gefrickle.
Ich vermute, dass das "uart_str_rx_ct" eine globale Variable ist. Das 
ist jenseitig unterirdisch.

Sorry für die harten Worte, aber das gehört zum Handwerkszeug.
Ah, und das 9. Bit würde ich persönlich nie verwenden. Das ist für mich 
auch wieder so was hingebasteltes. Auch wenn es die Krücke in Hardware 
gibt.

von Karl K. (leluno)


Lesenswert?

Schwierig schrieb:
>> if(uart_str_rx_ct>uart_string_len+1)uart_str_rx_ct=0;
>
> Was bitte soll das sein?

Verhindert den Speicherüberlauf falls - aus welchem Grund auch immer - 
der Zähler nicht durch den Auslesecode des Hauptprogramms zurückgesetzt 
wird.

von Karl K. (leluno)


Lesenswert?

Nick schrieb:
> Eine ISR ist eine ISR, sonst nichts.
> Die ISR empfängt Zeichen, sonst nichts. Die schiebt sie dann in einen
> Ringpuffer.

Ja - verstehe ich. Bei meinem Code ist Platz für genau einen Datensatz. 
ein Ringpuffer kann mehrere Datensätze aufnehmen - muss dann aber wegen 
der Trennung der Datensätze verwaltet werden.

> Der Ringpuffer sperrt die ISR wenn er head & tail des
> Ringpuffers verändert.

verstehe ich nicht.

> Die ISR hat also keine Ahnung was das Protokoll ist, was ein CRC ist.

ja - das ist in meinem Code auch so. Die byte-complete-ISR schiebt die 
bytes stur in das RX-array und fängt - wenn das array voll ist - wieder 
von vorne an. Nur wenn im rx-array ein vollständiger crc-korrekter 
Datensatz steht, wird er weiterverarbeitet.

Ich muss zugestehen, dass ich die Empfangsroutine im Fleury-code nicht 
verstanden habe und es deswegen selbst gemacht habe. Kann durchaus sein, 
dass es mit dem Ringpuffer deutlich besser geht. Die Kommunikation 
zwischen den beiden ucs läuft aber seit dem Wochende völlig problemlos, 
Wechselrichter und Batteriespeicher werden an- und abgeschaltet und auch 
die Steuerung des Lasttrennschalters funktioniert so dass andere 
Baustellen erst mal drängender sind.

von Nick (b620ys)


Lesenswert?

Karl K. schrieb:
> Ja - verstehe ich. Bei meinem Code ist Platz für genau einen Datensatz.
> ein Ringpuffer kann mehrere Datensätze aufnehmen - muss dann aber wegen
> der Trennung der Datensätze verwaltet werden.

Du musst jeden Puffer "verwalten". Ein Ringpuffer kann natürlich 
"beliebig" viel aufnehmen. Das machts nur einfacher. Einmal den 
Ringpuffer programmieren (incl. Schutz vor Überlauf) und ab dann 
glücklich sein.
Irgendwelche Interpretationen haben in der ISR nichts verloren. Die 
müssen immer so schnell wie möglich beendet werden.

Karl K. schrieb:
>> Der Ringpuffer sperrt die ISR wenn er head & tail des
>> Ringpuffers verändert.
>
> verstehe ich nicht.

Du weisst nicht, wann der nächste INT auftritt. Wenn er genau in dem 
Moment auftritt wo du aus dem Puffer liest -und damit head & tail 
veränderst- sind die Daten möglicherweise nicht mehr konsisten. Zwei 
Prozesse wollen "gleichzeitig" etwas ändern.

Karl K. schrieb:
> Nur wenn im rx-array ein vollständiger crc-korrekter
> Datensatz steht, wird er weiterverarbeitet.

Also kümmert sie sich um den CRC. Das soll nicht seine Aufgabe sein. Ein 
Zeichen empfangen hat nichts mit CRC zu tun. Ein Briefkasten empfängt 
Post und sortiert nicht nach Werbung, Steuerbescheide oder Liebesbriefe.

Karl K. schrieb:
> Ich muss zugestehen, dass ich die Empfangsroutine im Fleury-code nicht
> verstanden habe und es deswegen selbst gemacht habe.

Das ist nicht schlimm, dass du ihn nicht verstehst. Und ich kenn ihn 
nicht.

Karl K. schrieb:
> Die Kommunikation
> zwischen den beiden ucs läuft aber seit dem Wochende völlig problemlos,

Glaub ich nicht. :-)
Was passiert, wenn ein Zeichen eine falsche Parity hat? Wann schlägt 
dann das Timeout zu? Oder will die ISR dann das nächste Paket wo hin 
schreiben?
Trenn die Sachen in jeweils einfache, überschaubare Aufgaben und 
vermisch Funktionalitäten nicht.

von Veit D. (devil-elec)


Lesenswert?

Karl K. schrieb:
> Veit D. schrieb:
>> wie soll denn ein fehlerhaftes Protokoll die RTC resetten?
>
> so:
>
> (noch nicht getestet)

Hallo,

demnach schickst du falsche Daten. Ist alles nicht testbar. Die Fleury 
USART Lib muss man nicht bis ins Detail verstehen, man muss sie nur 
anwenden wissen. Dazu muss sie nicht verändert werden. Mach dir einen 
Plan und fang am Besten von vorn an. Du hast dich da irgendwie verrannt. 
Alles weitere dazu hat Nick schon geschrieben.

: Bearbeitet durch User
von Karl K. (leluno)


Lesenswert?

Nick schrieb:
> Also kümmert sie sich um den CRC. Das soll nicht seine Aufgabe sein. Ein
> Zeichen empfangen hat nichts mit CRC zu tun.

Das verstehst du falsch. Die ISR sieht genau so aus:
1
ISR (UART0_RECEIVE_INTERRUPT)  
2
{
3
if(uart_str_rx_ct>uart_string_len+1)uart_str_rx_ct=0;
4
uart_str_rx[uart_str_rx_ct++] = UDR0;
5
return;
6
}

Da passiert nichts außer dass UDRO in den rx-Speicher geschrieben wird.
Das Hauptprogramm prüft, ob ein korrekter Datensatz drinsteht und 
verarbeitet ihn dann weiter.

von Nick (b620ys)


Lesenswert?

Karl K. schrieb:
> Das verstehst du falsch. Die ISR sieht genau so aus:

Ja, da hast Du Recht!
Ich hab mich von der eigentümlichen Formatierung und der fehlenden "}" 
irritieren lassen.
Hätte ich genauer schauen sollen. :-(

von Harald K. (kirnbichler)


Lesenswert?

1
ISR (UART0_RECEIVE_INTERRUPT)  
2
{
3
if(uart_str_rx_ct>uart_string_len+1)uart_str_rx_ct=0;
4
uart_str_rx[uart_str_rx_ct++] = UDR0;
5
return;
6
}


C und anderer Code wird durch Einsatz von Leerzeihen und Zeilenumbrüchen 
deutlich lesbarer.

Funktionen, die keinen Rückgabewert haben, muss man nicht mit einem 
"return"-Statement beenden, sie hören auch auf, wenn sie aufhören.
1
ISR (UART0_RECEIVE_INTERRUPT)  
2
{
3
  if (uart_str_rx_ct > uart_string_len + 1)
4
    uart_str_rx_ct = 0;
5
6
  uart_str_rx[uart_str_rx_ct++] = UDR0;
7
}

von Nick (b620ys)


Lesenswert?

Aaaalso ...
Ich möchte beim TO um Entschuldigung bitten. Ich hab den code nicht 
aufmerksam gelesen, sondern hab mich im Wesentlichen an der Formatierung 
orientiert (Berufskrankheit).
Dadurch fallen ein paar meiner Vorwürfe weg.
Die ISR ist kurz, lediglich würde ich wirklich und eindringlich zum 
Ringpuffer raten. Indem man mehr Abstraktionsebenen einführt wird der 
code lesbarer. Z.B. beim Ringpuffer must du keinen code für die ISR 
lesen und kannst auch nicht darin rumfummeln.
Also von der Struktur her bleib ich bei meinen Aussagen.

Wie mein Vorposter schon schrieb, besser formatieren. So wie er es 
gemacht hat seh ich alles sofort auf einen Blick, auch wenn es nicht 
mein Stil ist.

Und wenns geht keine snipps, da fehlt sonst der Kontext. Ob hier der 
gesammte Quelltext besser gewesen wäre, ist zweifelhaft. Dann halt bitte 
die komplette Funktion.

Für eine strukturierte Fortsetzung!

von Karl K. (leluno)


Lesenswert?

Veit D. schrieb:
> Du hast dich da irgendwie verrannt.

Dieser Post hat mich einen halben Tag Arbeit gekostet. Viele kleinere 
Probleme. Hauptsächlich beim Timing. Ging dann nur mit Hilfe des 
Oszilloskops - aber jetzt läuft alles. RTC per PC-c#-Programm gestellt. 
uc startet mit von der rtc gelesener Zeiteinstellung (Foto).

Nick schrieb:
> Ich möchte beim TO um Entschuldigung bitten.

Ich bin dir dankbar, dass du dich intensiv mit dem von mir geschilderten 
Problem befasst hast. Fehler von mir war, dass ich den Code nicht 
ordentlich genug präsentiert habe. Ich werde mir damit in Zukunft noch 
mehr Mühe geben.

Der Unterschied zwischen deinen Anregungen und meinem Code ist wohl, 
dass bei dir - ebenso wie bei Fleury - die Fehlerbehandlung in der irc 
erfolgt, bei mir im Hauptprogramm:
1
#if defined( ATMEGA_USART1 )
2
(Original-Fleury)
3
ISR(UART1_RECEIVE_INTERRUPT)
4
/*************************************************************************
5
Function: UART1 Receive Complete interrupt
6
Purpose:  called when the UART1 has received a character
7
**************************************************************************/
8
{
9
    unsigned char tmphead;
10
    unsigned char data;
11
    unsigned char usr;
12
    unsigned char lastRxError;
13
 
14
 
15
    /* read UART status register and UART data register */ 
16
    usr  = UART1_STATUS;
17
    data = UART1_DATA;
18
    
19
    /* get FEn (Frame Error) DORn (Data OverRun) UPEn (USART Parity Error) bits */
20
    lastRxError = usr & (_BV(FE1)|_BV(DOR1)|_BV(UPE1) );
21
            
22
    /* calculate buffer index */ 
23
    tmphead = ( UART1_RxHead + 1) & UART_RX_BUFFER_MASK;
24
    
25
    if ( tmphead == UART1_RxTail ) {
26
        /* error: receive buffer overflow */
27
        lastRxError = UART_BUFFER_OVERFLOW >> 8;
28
    }else{
29
        /* store new index */
30
        UART1_RxHead = tmphead;
31
        /* store received data in buffer */
32
        UART1_RxBuf[tmphead] = data;
33
    }
34
    UART1_LastRxError |= lastRxError;   
35
}

Wegen der manchmal auftretenden Störungen werde ich den uc am 
Wechselrichter auf die absolut notwendigen Funktionen reduzieren: Messen 
von Licht und WR-Spannung, schalten der zwei Relais, Berechnen der 
notwendigen Schaltvorgänge. Anzeige und Zeitbestimmung, Änderung von 
Schaltgrenzen  sowie Feinsteuerung erfolgen mit dem zweiten uc bzw. vom 
PC aus.

von Karl K. (leluno)


Angehängte Dateien:

Lesenswert?

Foto vergessen

von Rainer W. (rawi)


Lesenswert?

Karl K. schrieb:
> Wegen der manchmal auftretenden Störungen werde ich den uc am
> Wechselrichter auf die absolut notwendigen Funktionen reduzieren:

Wer garantiert dir dann, dass dieser µC nicht gestört wird?
Du musst den Fehler, d.h. die Stör-URSACHE finden und beseitigen.

von Nick (b620ys)


Lesenswert?

Karl K. schrieb:
> Ich werde mir damit in Zukunft noch mehr Mühe geben.

Danke! Erfolgreich!

Karl K. schrieb:
> ebenso wie bei Fleury

Also der code zeigt mir, dass die mit tail und head arbeiten. Das 
bedeutet für mich, dass die einen Ringpuffer haben (ohne den header-file 
zu kennen).
Schau doch mal im header von Fleury, ob es da Funktionen gibt um 
einzelne Zeichen reinzuschubsen. Ich vermute, dass Du das nicht wie 
vorgesehen verwendest.

von Nick (b620ys)


Lesenswert?

Rainer W. schrieb:
> Du musst den Fehler, d.h. die Stör-URSACHE finden und beseitigen.

Er muss zwei Sachen machen. Die Software robuster machen, so dass sie 
Fehler erkennt und abfängt (nochmal eine Anfrage machen). Und natürlich 
auch die Elektronik störungsresistent machen.
RS485 ist eigentlich extrem störsicher, so man ordentliche Treiber 
(welche?) verwendet.

von Karl K. (leluno)


Lesenswert?

Nick schrieb:
> Das bedeutet für mich, dass die einen Ringpuffer haben

ja - hat er. 32Byte #define UART_RX_BUFFER_SIZE 32

Wenn man den Anfang des Datensatzes markiert (wie?) sind das nicht 
einmal zwei Datensätze (bei mir zur Zeit maximal 16bytes je Datensatz). 
Was bringt das außer Verwaltungsaufwand?

Einen Stapelspeicher, der mehrere Datensätze mit fester Anfangsadresse 
aufnimmt, könnte ich mir ja noch als vorteilhaft vorstellen. Bei meiner 
konkreten Anwendung mit nur ganz geringem Datenaustausch aber eher 
oversized.

Nick schrieb:
> ich vermute, dass Du das nicht wie vorgesehen verwendest.

ja - weil ich den Sinn der Fehlerabfrage in der irc nicht verstehe.

Rainer W. schrieb:
> Wer garantiert dir denn, dass dieser µC nicht gestört wird?

Niemand. Bislang ist nur die RTC und das TFT ausgefallen. Der uc hat 
weitergearbeitet - aber mit falscher Zeit. Bislang hat es also keinen 
Ausfall des uc gegeben.

> Du musst den Fehler, d.h. die Stör-URSACHE finden und beseitigen.
RTC weg, TFT weg, zeitabhängige Berechnung des Sonnenstands durch 
Messung des Lichteinfalls ersetzt. Damit ist zwar nicht die Stör-Ursache 
aber die Störung beseitigt. Das, was jetzt noch übrig ist, ist 
hoffentlich störsicher. Deswegen wird das jetzt getestet.

von Nick (b620ys)


Lesenswert?

Karl K. schrieb:
> ja - hat er. 32Byte #define UART_RX_BUFFER_SIZE 32

Kann man ja hochsetzen. Platz für 2 Datensätze wäre wohl genug. Ich gehe 
davon aus, dass Du nicht die Unmengen verschicks. Waren doch irgendwie 
alle 30 Sekunden.

Karl K. schrieb:
> Wenn man den Anfang des Datensatzes markiert (wie?) sind das nicht
> einmal zwei Datensätze (bei mir zur Zeit maximal 16bytes je Datensatz).

Läuft das nicht über das 9. Bit? Wie gesagt, ich halte eher nichts 
davon, aber ist halt so.


> Was bringt das außer Verwaltungsaufwand?

Die Trennung der Schickten.
Ich hätte darauf früher verweisen sollen:
https://de.wikipedia.org/wiki/OSI-Modell

Karl K. schrieb:
> Einen Stapelspeicher, der mehrere Datensätze mit fester Anfangsadresse
> aufnimmt, könnte ich mir ja noch als vorteilhaft vorstellen.

Hmm!? Stapelspeicher? Wenn Du tatsächlich einen Stack meinst: Den 
braucht man, wenn Datensätze nochmal übertragen werden müssen (wg. 
Fehler) und man nicht mehr so recht weiß welches. Dann braucht man aber 
auch eine ID für die Pakete. Runtergenommen werden die Pakete vom 
Stapel, wenn eine positive Quittung dafür vorliegt. Bei striktem 
PingPong muss man sich nur das zuletzt gesendete Paket merken um es 
nochmal senden zu können. Also ein Stapel mit der Tiefe 1.

Karl K. schrieb:
> ja - weil ich den Sinn der Fehlerabfrage in der irc nicht verstehe.

Die gehört da nicht rein. Schieb einfach Zeichen für Zeichen in das 
Fleury-Dingens. Und zeig mal den header davon. So kann ich nur orakeln. 
Bei "Fleury" liefert mir Google nur Bilder aus Frankreich.

von Harald K. (kirnbichler)


Lesenswert?

Karl K. schrieb:
> Wenn man den Anfang des Datensatzes markiert (wie?) sind das nicht
> einmal zwei Datensätze (bei mir zur Zeit maximal 16bytes je Datensatz).
> Was bringt das außer Verwaltungsaufwand?

Deine "Datensätze" interessieren den Ringpuffer nicht. Die Logik, um 
Deine "Datensätze" zusammenzustellen, gehört nicht in die ISR, sondern 
in Deine Hauptschleife. Die sieht zyklisch nach, ob Zeichen im 
Ringpuffer angekommen sind, holt die da raus und packt sie in einen nur 
für Deine Hauptschleife interessanten Puffer für einen Datensatz.

Sofern Deine Hauptschleife schnell genug ist, kann die Größe des 
Ringpuffers auch deutlich kleiner sein als ein Datensatz; die Aufgabe 
der ISR und des Ringpuffers ist es nur, auf der UART eintrudelnde 
Zeichen zu empfangen und zwischenzuspeichern, ohne daß welche verloren 
gehen, weil die nachgelagerte Funktionalität in der Hauptscheife zu 
langsam ist.

So wird in zig Millionen(!) Anwendungen mit UARTs, Ringpuffern und ISRs 
gearbeitet.

Siehe https://www.mikrocontroller.net/articles/FIFO für die Grundlagen 
des Ringpuffers, und natürlich 
http://www.peterfleury.[epizy].com/avr-software.html

(Die eckigen Klammern sind dem eindeutig kaputten Spam-Filter der 
Forensoftware geschuldet)

: Bearbeitet durch User
von Nick (b620ys)


Lesenswert?

Harald K. schrieb:
> ofern Deine Hauptschleife schnell genug ist, kann die Größe des
> Ringpuffers auch deutlich kleiner sein als ein Datensatz;

Das stimmt so nicht ganz. Man muss mindestens einen kompletten Datensatz 
- 1 Byte aufheben, damit man sich neu synchronisieren kann. Es ist 
hilfreich, wenn der Ringpuffer eine "peek"-Funktion hat. Damit kann man 
nachschauen welches Zeichen auf einer angegebenen Position ist, ohne es 
"tatsächlich" zu lesen und somit aus dem Ringpuffer zu nehmen.
Das geht auch ohne peek, dann verlagert man aber die Pufferung auf eine 
höhere Ebene. Gefällt mir nicht so gut, weils dann im Fehlerfall eine 
unnötige Kopiererei und Schieberei gibt.

Ansonsten bin ich Deiner Meinung.

Den Puffer zwei oder paar Datensätze lang zu machen ist nur eine 
defensive Maßnahme die nur etwas RAM kostet. Der Ringpuffer wird dadurch 
nicht langsamer. Das ist ja das Schöne daran.

von Karl K. (leluno)


Lesenswert?

Harald K. schrieb:
> Die Logik, um
> Deine "Datensätze" zusammenzustellen, gehört nicht in die ISR, sondern
> in Deine Hauptschleife.

Danke für die hilfreichen Erklärungen. Fifo-Link habe ich mir angeschaut 
- interessant, wobei auf die Schnelle sicher nicht umzusetzen.

Verständnisfrage:
Es stehen mehrere Datensätze unterschiedlicher Länge im Fifo. Wie 
erkennt das Hauptprogramm wo ein Datensatz anfängt und wie lang er ist. 
Man bräuchte für die Trennung ja ein byte, das nicht in den Datensätzen 
vorkommen darf?

von Rainer W. (rawi)


Lesenswert?

Karl K. schrieb:
> Danke für die hilfreichen Erklärungen. Fifo-Link habe ich mir angeschaut
> - interessant, wobei auf die Schnelle sicher nicht umzusetzen.

Wenn es einen Tag länger dauert, wäre doch auch nicht so schlimm.

> Man bräuchte für die Trennung ja ein byte, das nicht in den Datensätzen
> vorkommen darf?

Ja, das wäre eine Möglichkeit. Oder die Datensätze müssen eine 
Längeninformation enthalten.

: Bearbeitet durch User
von Nick (b620ys)


Lesenswert?

Karl K. schrieb:
> Es stehen mehrere Datensätze unterschiedlicher Länge im Fifo. Wie
> erkennt das Hauptprogramm wo ein Datensatz anfängt und wie lang er ist.

Mein posting vom 11.01.2026 10:41

von Rainer W. (rawi)


Lesenswert?

Nick schrieb:
> Mein posting vom 11.01.2026 10:41

Du meinst wohl dies hier:

Nick schrieb:

von Harald K. (kirnbichler)


Lesenswert?

Nick schrieb:
> Das stimmt so nicht ganz. Man muss mindestens einen kompletten Datensatz
> - 1 Byte aufheben, damit man sich neu synchronisieren kann.

Nö, die Hauptschleife muss nur das Empfangsfifo schneller leeren als es 
beschrieben wird. Und dann funktioniert auch die Datensatztrennung mit 
Timeout.

Die Synchronisation, wie auch immer sie erfolgt, ist ausschließlich 
Angelegenheit der Hauptschleife.

Wie ich schon schrieb, das ist seit Jahrzehnten etablierte 
Vorgehensweise in verdammt vielen Anwendungen.

Und bevor man anfängt, irgendwelche Spezialprotokolle zu verwenden, 
sollte man sich einfach mal ein etabliertes, weit verbreitetes und 
einfaches Protokoll ansehen. Wie ich auch schon schrieb, bietet sich 
da Modbus/RTU an. Sofern nur zwei Geräte miteinander kommunizieren, kann 
man den etwas kniffligeren Teil der Sender/Empfänger-Umschaltung unter 
den Tisch fallen lassen, die sonst durch die Ansteuerung von 
RS485-Treibern nötig wird.

Und ich wiederhole mich schon wieder: Für Modbus/RTU gibt es ausreichend 
viel Testsoftware, so daß man beide Seiten der Kommunikation mit einem 
definiert "sauber" arbeitenden Gegenstück testen kann.

von Nick (b620ys)


Lesenswert?

Harald K. schrieb:
> Nö, die Hauptschleife muss nur das Empfangsfifo schneller leeren als es
> beschrieben wird. Und dann funktioniert auch die Datensatztrennung mit
> Timeout.

Dann kannst Du ja gleich den Ringpuffer weglassen. So ganz hast Du das 
mit den Schichten nicht verstanden.

3. Schicht:
Wenn Du im Ringpuffer einen synchronisierten Datensatz hast, kannst Du 
das zweite Byte lesen (per peek) und dann den Ringpuffer fragen ob da 
auch so viele bytes sind. Wenn nicht, sag dem Taskmanager (oder wie 
immer du das nennen willst) Nöö, hab grad nix zu tun, kannst mich x ms 
schlafen legen.
Wenn ja, dann lies genau so viele Bytes wie sich aus der Länge ergibt. 
Datensatz komplett aus dem Ringpuffer raus, und erstes Byte sollte 
wieder das Startbyte sein.

Das setzt aber voraus, dass man seinen code in Tasks aufteil, also nix 
mit "im Hauptprogramm".

Das "Hauptprogramm" sieht unglaublich banal und so aus (ohne einen 
Taskmanager):
1
void main(void) {
2
  init();
3
  for (;;) {
4
    Task1();
5
    Task2();
6
    ...
7
  }
8
}

von Harald K. (kirnbichler)


Lesenswert?

Nick schrieb:
> Dann kannst Du ja gleich den Ringpuffer weglassen. So ganz hast Du das
> mit den Schichten nicht verstanden.

Den Kelch geb' ich an Dich zurück. Danke.

von Nick (b620ys)


Lesenswert?

Harald K. schrieb:
> Den Kelch geb' ich an Dich zurück. Danke.

Das ist aber ein rostiger Blumenkübel.

Du sagst, man muss nur schnell genug aus dem Ringpuffer lesen, dann kann 
er kleiner als ein Datensatz werden. Gut, Du musst dann letztendlich 
Byteweise vom Ringpuffer in einen Satzpuffer kopieren. Klingt wirklich 
elegant. Nennt sich das dann "Linearpuffer für genau einen Datensatz"?
Und wenn Du noch schneller liest, dann degeneriert der Ringpuffer zum 
Bytepuffer. Lass ihn gleich aus und lass dich direkt von der ISR 
bedienen, den "Linearpuffer" kannst Du ja noch weiterverwenden.
Und nicht vergessen: Immer feste pollen! Sonst läuft der zu kleine 
Ringpuffer über der per se, da ohne Polling, minimale Recourcen 
verbrauchen würde. Ist aber besser so!

Merkste?

So, ich werde hier keine Zeit mehr verschwenden.
Viel Erfolg noch!

von Harald K. (kirnbichler)


Lesenswert?

Nick schrieb:
> Du sagst, man muss nur schnell genug aus dem Ringpuffer lesen, dann kann
> er kleiner als ein Datensatz werden. Gut, Du musst dann letztendlich
> Byteweise vom Ringpuffer in einen Satzpuffer kopieren. Klingt wirklich
> elegant.

Ja, natürlich. Und so funktioniert das schon seit zig Jahrzehnten. So 
funktionieren unzählige UART-Treiber in unzählichen Anwendungen.

Könnte es sein, daß Du mit UARTs bislang eher nur theoretisch oder in 
einem sehr eng umschriebenen Anwendungsbereich zu tun hattest?

von Bruno V. (bruno_v)


Lesenswert?

Nick schrieb:
> Wenn Du im Ringpuffer einen synchronisierten Datensatz hast,

Deine Ringpuffer machen eine Protokollauswertung. Kann man machen. 
Sollte man nicht.

Überlicherweise dienen Ringpuffer dazu, z.B. asynchrone Uarts mit der 
auslenden Task zu synchronisieren:
 * RX: Reinschreiben im Interrupt, rauslesen in einer Task
 * TX: Reinschreiben im Hauptprogramm, rauslesen im (TX-) Interrupt

Die Interruptroutine ist damit sehr kurz: Byte auslesen und einfügen. 
Keine Benachrichtigung, keine Protokollauswertung. Nada, niente.

Warum hält man die Interruptroutine (und die Schnittstelle) kurz und 
simpel? Damit viele unabhängige Interrupts niemals(!!!) 1ms warten 
müssen: die typische Zeit für den ms-Ticker und den RX-Fifo bei 115k

Auf verarbeitet man dann byte für byte und tut in aller Ruhe, was zu tun 
ist.

Der Code wird damit auf allen 3 Ebenen (Task, Interrupt, Fifo) kleiner, 
portabel er, zuverlässiger, einfacher.

Wie bei den Drehgebern: Die meisten hier sind zu Beginn auch durch die 
naheliegenden Ansätze gegangen.

D.h. nicht, dass man das Protokoll niemals im Interrupt dekodieren soll. 
Es heißt nur, dass es gute Gründe geben muss für so ein Gefrickel.

: Bearbeitet durch User
von Karl K. (leluno)


Angehängte Dateien:

Lesenswert?

Die Kommunikation läuft jetzt weitgehend fehlerfrei - 16byte 
Datensatz/6byte handshake.

Schön wäre jetzt, wenn man den Sender-uc mittels bootloader über rs485 
programmieren könnte.

von Rainer W. (rawi)


Lesenswert?

Karl K. schrieb:
> Die Kommunikation läuft jetzt weitgehend fehlerfrei - 16byte
> Datensatz/6byte handshake.

Dann beseitige erstmal die restlichen Fehler. Vorher schon die nächste 
Baustelle aufzumachen, vermischt nur irgendwelche Fehlersymptome und 
macht die Fehlersuche komplexer.

: Bearbeitet durch User
von Karl K. (leluno)


Angehängte Dateien:

Lesenswert?

Falls es jemanden interessiert, hier ist der fertige Code. Die 
Kommunikation zwischen Sender-uc und Empfänger-uc funktioniert jetzt 
zufriedenstellend einschließlich handshake.

Als nächstes kommt jetzt ein c#-Programm um Einstellungen im Sender-uc 
vom PC aus zu ändern.

von Harald K. (kirnbichler)


Lesenswert?

Karl K. schrieb:
> Als nächstes kommt jetzt ein c#-Programm um Einstellungen im Sender-uc
> vom PC aus zu ändern.

Hättest Du Modbus gewählt, wäre das nicht nötig.

von Karl K. (leluno)


Lesenswert?

Harald K. schrieb:
> Hättest Du Modbus gewählt, wäre das nicht nötig.

Was ist Modbus? Meine Datensätze sind ja genau wie Modbus aufgebaut. Ist 
das dann nicht Modbus?

Was wäre mit Modbus nicht nötig? Ich will Einstellungen des ucs 
verändern ohne den uc neu zu programmieren. Wie soll Modbus das machen? 
Hat Modbus fertige Befehle um in das eprom des m328 zu schreiben? wenn 
ja, kann ich mir die Arbeit wirklich sparen - aber wo finde ich sie?

Beitrag #7996363 wurde vom Autor gelöscht.
von Harald K. (kirnbichler)


Lesenswert?

Deine Fragen lassen mich ratlos zurück.

von Rahul D. (rahul)


Lesenswert?

Karl K. schrieb:
> Hat Modbus fertige Befehle um in das eprom des m328 zu schreiben?

Nein. Modbus ist ein Protokoll, das Speicherplätze adressiert.
Also entweder abfragt oder setzt.
Wie dein Controller damit umgeht ist dir überlassen.
Manche lesen nur Messwerte darüber aus ("Input Registers"), andere 
senden auch Konfigurationsdaten, Grenzwerte o. dergl. ("Holding 
Registers").

Ohne jetzt deinen Quellcode betrachtet zu haben:
Man würde einen bestimmten Adressbereich dem EEPROM zuweisen, und wenn 
die Modbus-Registeradresse in diesem Adressbereich liegt, wird das 
EEPROM entweder beschrieben oder ausgelesen.
Wobei Modbus 16-Bit-Register adressiert.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Karl K. schrieb:
> Was ist Modbus?
https://www.google.com/search?q=Was+ist+Modbus

Dieses Stichwort ist erstmals 16 Minuten nach deinem Eröffnungspost und 
danach wiederholt nochmal gefallen. Hattest du in diesen 10 Tagen nicht 
ein wenig Zeit, um dich mal in das Thema einzulesen?

> Hat Modbus fertige Befehle um in das eprom des m328 zu schreiben?
Gegenfrage: Modbus wurde 1979 spezifiziert. Gab es damals schon einen 
Mega328?

> aber wo finde ich sie?
Du implementierst/programmierst diesen kleinen Zwischenschritt von der 
Kommunikation zum EEPROM selber.

BTW: der Mega328 hat kein EPROM.

Karl K. schrieb:
> Die Kommunikation läuft jetzt weitgehend fehlerfrei

Karl K. schrieb:
> funktioniert jetzt zufriedenstellend
Netter Ansatz. Leider ist das das Motto vieler Programmierer: "Ziemlich 
gut ist gut genug!"

: Bearbeitet durch Moderator
von Karl K. (leluno)


Lesenswert?

Lothar M. schrieb:
> Dieses Stichwort ist erstmals 16 Minuten nach deinem Eröffnungspost und
> danach wiederholt nochmal gefallen. Hattest du in diesen 10 Tagen nicht
> ein wenig Zeit, um dich mal in das Thema einzulesen?

Die Frage bezog sich auf den Vorpost. Der deye-Wechselrichter hat 
Modbus. Das nützt aber nicht viel, weil sich der Akku damit nicht 
ausschalten lässt und der Standbye-Verbrauch bei >70Watt liegt - den 
Akku also nachts sinnlos leersaugt. Ich weiß also was Modbus ist.

Lothar M. schrieb:
> BTW: der Mega328 hat kein EPROM.

Vielleicht doch? Datasheet:
High endurance non-volatile memory segments
● 32K bytes of in-system self-programmable flash program memory
● 1Kbytes EEPROM
● 2Kbytes internal SRAM
● Write/erase cycles: 10,000 flash/100,000 EEPROM


Wenn er keins hätte - auf dem Rtc-Modul ist auch eins, das könnte 
ebenfalls genutzt werden.

Lothar M. schrieb:
> Netter Ansatz. Leider ist das das Motto vieler Programmierer: "Ziemlich
> gut ist gut genug!"

Das System läuft. Alternative bessere Lösungen für das deye-WR-Problem 
gibt es meines Wissens nach nicht. Gut genug wäre also immer noch besser 
als ohne mein Programm.

von Harald K. (kirnbichler)


Lesenswert?

Karl K. schrieb:
> Der deye-Wechselrichter hat
> Modbus. Das nützt aber nicht viel, weil sich der Akku damit nicht
> ausschalten lässt und der Standbye-Verbrauch bei >70Watt liegt - den
> Akku also nachts sinnlos leersaugt. Ich weiß also was Modbus ist.

Du stellst einen Zusammenhang her, der nicht existiert. Was Modbus ist, 
weißt Du offensichtlich nicht.

Aber da Du Dir nicht helfen lassen willst - bitte, viel Erfolg mit 
Deiner Frickellösung.

von Karl K. (leluno)


Lesenswert?

Harald K. schrieb:
> Was Modbus ist,
> weißt Du offensichtlich nicht.

>Modbus ist ein Protokoll, das Speicherplätze adressiert.
Also entweder abfragt oder setzt.
Wie dein Controller damit umgeht ist dir überlassen.<

So sehe ich das auch. Ein Protokoll - mehr nicht.
>Modbus-Frame-Aufbau: [Slave-Adresse][Funktionscode][Daten][CRC-16]<
Genau so hab ich das. Also Modbus. Oder doch nicht Modbus?

Ich glaube dir, dass du mehr Ahnung vom Programmieren hast wie ich. Aber 
deine Aussagen sind unverständlich. Was meinst du damit, dass Modbus die 
Lösung der von mir geschilderten Aufgabenstellung sein soll? Es geht 
doch zuersteinmal um das hardwäremäßige Senden und Empfangen einzelner 
Bytes. Ob diese Bytes dann mittels Modbus oder mittels irgendeines 
anderen Protokolls zusammengesetzt sind ist doch völlig Banane.

von Harald K. (kirnbichler)


Lesenswert?

Ich geb's auf.

von Karl K. (leluno)


Angehängte Dateien:

Lesenswert?

Harald K. schrieb:
> Ich geb's auf.

ich nicht.

Ich habe das Terminal-Programm 
-Beitrag "Re: C# Daten über Serial Port empfangen und in Char speichern"
-
um crc-Berechnung und Programmtasten für feste Befehle ergänzt, so dass 
jetzt ein Netzwerk zwischen PC, ucs und Wechselrichter besteht. Das 
ganze funktioniert.

Es gibt ja schon jede Menge Terminal- und Modbus-Projekte. Ich werde 
meins sicher fortsetzen weil es halt meins ist. Es würde mich aber 
interessieren, ob es Vergleichbares fertig gegeben hätte.

von Nemopuk (nemopuk)


Lesenswert?

Karl K. schrieb:
> Hat Modbus fertige Befehle um in das eprom des m328 zu schreiben?

Lothar M. schrieb:
> der Mega328 hat kein EPROM.

Karl K. schrieb:
> Vielleicht doch?
> 32K bytes of in-system self-programmable flash program memory
> ● 1Kbytes EEPROM

EEPROM ist nicht EPROM, und Flash Speicher ist auch nicht EPROM. EPROM 
werden mit starkem UV Licht gelöscht. Erst danach kann man sie sinnvoll 
beschreiben.

Karl K. schrieb:
> Es geht doch zuersteinmal um das hardwäremäßige Senden und Empfangen
> einzelner Bytes. Ob diese Bytes dann mittels Modbus oder mittels
> irgendeines anderen Protokolls zusammengesetzt sind ist doch völlig
> Banane.

Ich dachte, es geht "zuersteinmal" darum die korrekte und zuverlässige 
Übertragung zu sichern. Du willst deine Geräte sicher nicht nach jeder 
kleinen Störung (z.B wenn der Nachbar seine Leuchtstoffröhre schaltet) 
manuell resetten müssen. Du brauchst ein Kommunikationsprotokoll, dass 
Störungen erkennt, die fehlerhaften Daten verwirft, die 
Kommunikationspartner wieder synchronisiert und dann ggf. die fehlenden 
Teile wiederholt.

: Bearbeitet durch User
von Karl K. (leluno)


Lesenswert?

Nemopuk schrieb:
> Du brauchst ein Kommunikationsprotokoll, dass
> Störungen erkennt, die fehlerhaften Daten verwirft, die
> Kommunikationspartner wieder synchronisiert und dann ggf. die fehlenden
> Teile wiederholt.

hab ich doch. Über einen timer wird erkannt wann keine Bytes mehr kommen 
und der Datensatz übertragen ist. Dann setzt der Empfänger den rx-Zeiger 
für neuen Empfang zurück und prüft, ob die crc stimmt. Stimmt die crc, 
gibt es ein handshake. Der Sender wartet auf das handshake. Kommt das 
handshake nicht, wird erneut gesendet.

Nemopuk schrieb:
> EEPROM ist nicht EPROM, und Flash Speicher

eine falsa demonstratio - ich gehe mal davon aus, dass der Mod genau 
gewusst hat, was gemeint ist. RO - read only - des EEPROMs  passt auf 
den Speicher des M328 eh nicht so richtig - auch wenn es im Datenblatt 
steht.

von Rainer W. (rawi)


Lesenswert?

Karl K. schrieb:
> eine falsa demonstratio - ich gehe mal davon aus, dass der Mod genau
> gewusst hat, was gemeint ist.

Dann schreib doch, was gemeint ist und nicht irgendetwas anderes :-(

von Nemopuk (nemopuk)


Lesenswert?

Karl K. schrieb:
>> Du brauchst ein Kommunikationsprotokoll, dass
>> Störungen erkennt ...

> hab ich doch.

Na dann ist ja gut

von Rahul D. (rahul)


Lesenswert?

Nemopuk schrieb:
> Na dann ist ja gut

Manche müssen halt unbedingt das Rad neu erfinden...

von Nemopuk (nemopuk)


Lesenswert?

Rahul D. schrieb:
> Manche müssen halt unbedingt das Rad neu erfinden...

Ich habe mal das Z-Modem Protokoll (zwar nicht erfunden aber) selbst 
implementiert. War lehrreich. Der Autor hat es gut dokumentiert.

von Harald K. (kirnbichler)


Lesenswert?

Nemopuk schrieb:
> War lehrreich.

Das ist auch was anderes, als etwas "eigenes" zu stricken. Denn Deine 
Implementierung konntest Du sicherlich mit entsprechenden Gegenstellen 
testen, d.h. mit Terminalprogrammen à la Teraterm oder, sofern Du das zu 
entsprechenden Zeiten gemacht hat, mit irgendwelchen Mailboxen am 
anderen Ende der Telephonleitung ...

von Nemopuk (nemopuk)


Lesenswert?

Harald K. schrieb:
> Denn Deine Implementierung konntest Du sicherlich mit entsprechenden
> Gegenstellen testen, d.h. mit Terminalprogrammen à la Teraterm ode

Ja, aber umgekehrt. Es war teil meines Terminalprogramm für Mailboxen 
(ein nicht weniger lehrreiches Hobbyprojekt).

Beruflich habe ich leider nicht die Zeit, mich so intensiv mit 
Grundlagen zu befassen. Da muss alles schnell (=billig) fertig werden. 
Ich hasse das. Aber man wird gut bezahlt.

: Bearbeitet durch User
von Harald K. (kirnbichler)


Lesenswert?

Nemopuk schrieb:
> Beruflich habe ich leider nicht die Zeit, mich so intensiv mit
> Grundlagen zu befassen.

Wer hat das schon? Wenn man das im Rahmen des Berufs hinbekommt, kann 
man sich wohl sehr glücklich schätzen, und wenn einem das auch noch Spaß 
macht ...

von Rahul D. (rahul)


Lesenswert?

Nemopuk schrieb:
> Ich habe mal das Z-Modem Protokoll (zwar nicht erfunden aber) selbst
> implementiert.

Wenn es für eine spezielle Plattform ist, ist das doch Standard.
Ich habe auch schon einen Modbus-Parser für den STM32 implementiert.
Ein Kommilitone hat - ohne den Ursprung zu kennen - den 
Bresenham-Algorithmus "erfunden". Dass es schon jemandem vor ihm gab, 
nach dem der Algorithmus benannt wurde, war für ihn OK.

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.