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.
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?
Karl K. schrieb:> Lediglich> die i2c-rtc und die Lcd-Anzeige sind manchmal - wohl aufgrund von> Störimpulsen - weg.
Fehlerquelle suchen, Watchdog Timer, Abblockkondensatoren....
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.
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.
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.
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.
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?
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.
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.
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.
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.
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.
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?
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.
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?
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.
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>
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.
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).
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.
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.
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.
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.
Das funktioniert relativ problemlos. Jeder Teilnehmer im Netz bekommt
ein bestimmtes Zeitfenster zum Senden zugewiesen. Das verhindert
Kollisionen.
Nächstes Problem ist das handshake.
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?
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
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.
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.
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.
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.
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.
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..."
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.
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.
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
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.
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.
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?
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 ...
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.
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.
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?
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.
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.
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.
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.
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.
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:
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.
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. :-(
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.
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!
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:
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.
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.
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.
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.
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.
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-ModellKarl 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.
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)
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.
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?
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.
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
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.
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):
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.
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!
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?
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.
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.
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.
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.
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.
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?
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.
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 fehlerfreiKarl K. schrieb:> funktioniert jetzt zufriedenstellend
Netter Ansatz. Leider ist das das Motto vieler Programmierer: "Ziemlich
gut ist gut genug!"
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.
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.
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.
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.
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.
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.
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 :-(
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.
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 ...
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.
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 ...
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.