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?
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.
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.
"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.
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.
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.
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.
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.
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!).
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.
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).
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.
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.
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.
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?
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.
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.
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.
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.
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..."
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.
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.
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.
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 ...
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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).
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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?
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.
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.
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):
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!
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?
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.
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.
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?
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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 ...
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.
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 ...
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.