Beiträge von Knisterbein

    Vielen Dank Kai


    Das von Dir gelieferte Beispiel mit den Erläuterungen ist sehr hilfreich und hat auch mir, der auf einem Wissensstand von C++ seit 2010 sich kaum mehr weiter gebildet hat und im Mikrocontroller Umfeld immer eher auf C setzte, als auf C++. Zu dieser Zeit war constexpr noch nicht geboren.


    Auch das Statement:

    for (auto &nocke : nocken) {}


    scheint auch mit C++ 11 eingeführt worden zu sein und ist mir demnach (noch) nicht geläufig, nehme aber an, dass das «auto» an dieser Stelle eine Vereinfachung eines for() Schleife mitteilt und zum einen die Allokation eines Schleifenzählers, das Abbruchkriterium und auch die Anzahl der Durchläufe aus der Grösse der Tabelle nocke ermittelt wird.

    &nocke:nocken der Zeiger auf die Tabelle und dem anschliessenden Typen der Struktur

    nocke ist der Bezeichner des Schlaufenzählers, nocken der Inhalt des angegebenen Arrays, in diesem Beispiel zwei Strukturen nocken.

    Natürlich, ich muss dies selber nachlesen *g* Aber liege ich so in etwa richtig?

    Wenn dem so ist, dann erspart es einem die Schreibarbeit und beim Anlegen der Tabelle muss man sich jeweils nicht Gedanken darüber machen, den Compiler damit zu beauftragen, die Anzahl Einträge in der Tabelle bestimmen zu müssen. Damit werden einige Punkte, die gerne zu Fehlern führen, in einem Zug verhindert.


    Zu Deinem Kommentar in Post 23

    «Es ist mir ein Rätsel, warum auch in den Beispielen sehr häufig int verwendet wird. Ich habe noch keinen Controller mit mehr als 256 Pins gesehen. Schon gar keinen mit negativen Pin-Werten. Das soll aber erst mal nebensächlich sein, (int) stört die Funktion des Programmes nicht.»


    Per Definition ist ein int in der Grösse undefiniert und wird vom Compiler, abhängig von der Registergrösse der Ziel CPU, bestimmt.
    Nun passt dies aber bei einem Arduino mit einer 8-Bit CPU schon mal nicht zusammen, weil da nimmt der Compiler für int (wie Du korrekt geschrieben hast), 16 Bits. Ich weiss es nicht, vermute aber, dass man damit neuen Problemen ausweichen wollte, die man sich damit geschaffen hätte und definierte die 16Bit’s. Ich arbeitete mit C erst ab den 16 bit CPU’s (int war 16bit), dann mit den 32bit (int = 32bit) und heute sind es eben meist 64bit’s.


    Ich habe mir den Vortrag von Herb Sutter noch nicht ganz angehört, werde dies aber noch tun und vermutlich reicht einmal Anhören auch nicht.


    ich hoffe Du bleibst dem Forum noch lange treu, VIELEN DANK

    Pius

    Sorry, aber den Code durchschaue ich nicht.


    ein paar Hinweise:

    lösche Zeilen 25, 29, 33, 37 die sind alle doppelt gemoppelt


    Zeile 61 ist sicher falsch

    if (digitalRead(Nocke1) == HIGH, value <= 239 && value >= 284)

    ich vermute Du meinst

    if (digitalRead(Nocke1) == HIGH && value <= 239 && value >= 284)

    damit kommst Du aber kaum in den Block Zeile 66 weil value < 239 ist ja auch in der Zeile 61 bereits abgehandelt ausser Nocke1 ist FALSE


    Wenn Nocke1 FALSE ist passiert gar nichts. Dies kann zwar richtig sein, aber wenn zuvor Nocke1 HIGH war, dann wird nichst ausgeschaltet oder eingeschaltet.


    Ein Rat, folge der Logik im Kopf und schreibe diese in C so auf.

    Beispiel:


    // Wenn der Poti Wert 20% erreicht +-2% und der Schalter 2 EIN ist

    if (value <= 239 && value >= 284 && digitalRead(Nocke1) == HIGH ) {


    }

    Wenn nur Nocke1 FALSE ist wird kein Code mehr ausgeführt

    Vieleicht geht es leichter wenn Du die Logik am Anfang nicht verschachtelst:


    if(digitalRead(Nocke1) {


    if(value <= 239 && value >= 284 ) {

    ...

    }

    else {

    ...

    }


    }

    else {

    if(value <= 239 && value >= 284 ) {

    ...


    }

    else {

    ...


    }

    }


    Gruss

    Pius

    Ich habe zwar keine Ahnung vom Arduino, aber ein Rechteck Signal mit einer definierten On/Off Zeit lässt sich, sieht man von einem leichten Jitter mal ab, leicht realisieren.

    Ein Timer, der sagen wir mal mit einer Clock-Rate von 0.5mS zählt, löst immer dann einen Interrupt aus, wenn der Zähler den Wert (oder wenn man runter zählt 0) erreicht. In der Interrupt Routine wird dann die neue Zeit gesetzt und man wartet erneut, bis der Zähler das Ende erreicht hat.

    Bei jedem erreichen der Ziel - Zeit wird gleichzeitig das Ausgangspin aktiviert oder deaktiviert.

    Gruss

    Pius

    Hallo Mira

    tut mir Leid, aber mein Vorschlag durch Messen an den Stromverbrauch zu kommen ist damit auch vom Tisch, nachdem ich mir die Uhr angeschaut habe. Das wäre echt schwierig, im Gerät die Leitungen zum Akku aufzutrennen und dann mit einer Messung zu eruieren. Dazu kommt, dass der Chip unterschiedliche Regler enthält (alleine 5 LDO's, einen Schaltregler vom internen Akku und verm. mindestesn ein Schaltregler zum Laden des Akku's).

    Übrigens, das Datenblatt als PDF in Englisch findet man unter diesem Link.


    Auf Seite 8 findest Du eine Kurve mit dem Wirkungsgrad (beeindruckende 90%>) und auf Seite 10 die Stromkonsumation im ausgeschalteten Zustand, was aber Deine Frage nach wie vor nicht beantworten kann, dir aber zumindest einen Eindruck der optimierungen im Chip vermitteln kann.

    sorry, für meinen hilflosen Tipp.


    schönen Abend

    Pius

    Hallo Mira


    wenn ich das richtige Datenblatt gefunden habe, dann kann da drin der Stromverbrauch des AXP202 gar nicht als Wert angegeben werden, da dieser vom Aufbau der Schaltung abhängig ist.

    Aber mein Vorschlag, um den Stromverbrauch der Schaltung zu bestimmen ist:

    Strom Input - Strom Output (das was in die Batterie fliesst) ausrechnen und Du hast die Differenz.

    Aber viel besser ist es, die Leistung zu bestimmen, da die zugeführte Leistung - abgegebene Leistung der bessere Hinweis ist.

    Gruss

    Pius


    kannst Du einen Link des Datenblattes einfügen?

    Felix vielen Dank

    0.2V bei einer 0 ist perfekt, die 5.7V bei einem Nano, der von einen Regler auf dem Board versogt wird, dünkt mich etwas hoch. Der 328P ist für höchstens 5.5V Versorgung spezifiziert und wenn Du am Ausang's Pin bereits 5.7V messen kannst, dann ist entweder Dein Voltmeter sehr ungenau oder der Serie Regler auf dem Nano macht ein Problem (defekt).

    Das Voltmeter kannst Du grob mit einer 1.5V Trockenbatterie prüfen. Falls das Voltmeter korrekt misst, dasnn müsstest Du am Ausgang des Spannungsreglers auf dem Nano auch die 5V bestimmen können (siehe Schema).


    schönen Sonntag

    Pius


    Nano_sch.png

    Alles normal, so. Es freut natürlich immer, wenn es wo anders wieder weiter geht.

    Mich hätte dann doch noch interessiert, ob die 1.1V daher stammen, dass das Port Pin auf In geschaltet war oder nicht, oder ob der PullUp dann tatsächlich auch bei der OUT Beschaltung aktiv sein kann.

    Im Grunde denkt man bei einem solchen SSR jeweils viel zu weit. Wenn ich einen Optokoppler an einem Arduino Pin beschalten müsste, würde auch ich gegen 0 schalten, weil es mir aus älteren Logikfamilien her im Kopf herum schwirrt, dass der Low Strom an einem Ausgang jeweils etwa höher sein durfte.


    Folglich war und ist die Ausage richtig, dass dieses SSR direkt von einem Arduino Pin angesteuert werden kann, wie kukuk zitierte.

    Hallo KaiR


    Deine Überlegung ist im ersten Denkschritt richtig, nur glaube ich, dass dies in diesem Fall nicht funktioniert. Das Datenblatt des SSR zeigt am Eingang einen Block «Control Circuit» ohne elektrische Verbindung zu einer Stromversorgung. Wenn wir im einfachsten Fall davon ausgehen, dass die LED des Optokopplers mit einem Vorwiderstand* betrieben wird, dann hat wird die LED beim Pegel von 0V aus dem Arduino nie mit Strom versorgt. Aus diesem Grund gehe ich davon aus, dass bei diesem SSR der – Anschluss geschaltet werden muss. Dies würde bedeuten, dass man den Anschluss 3 vom SSR auf die 5V Versorgung legen muss und den Anschluss 4 mit einem Low vom Arduino versorgen muss. Bevor ich dies aber tun würde, müsste ich mir Sicherheit über den maximal fliessenden Strom ins SSR schaffen -> ausmessen. Im Datenblatt des SSR steht lediglich, dass der Strom kleiner als 2mA ist, wenn im OFF Zustand. Ich gehe davon aus, dass der Strom im ON Zustand etwas höher sein wird.


    Übrigens, die 1.1V aus dem Arduino deuten darauf hin, dass der Pin auf Input geschaltet sein könnte. Das Datenblatt des 328P sagt:

    SpannungenPin_328P.png


    Wenn ich mir die Pin Beschaltung anschaue, dann ist, dann kann der interne Pullup Widerstand auch bei der Output Beschaltung eines Ports akiv sein. Vielleicht liegt auch da der Grund der 1.1V, sofern der Pin tatsächlich immer als Out beschaltet ist.


    PinBeschaltung.png


    Nun, ich fragte nach einem Schema, auch wenn dies auf den ersten Blick sehr banal erscheint, stochern wir im Augenblick im Nebel herum und wenn man die Settings der Portbeschaltung nicht kennt, kommen neue Unbekannte dazu.


    Gruss

    Pius



    *Ich nehme aber an, dass die LED des Optokopplers im SSR nicht mit einem Vorwiderstand beschaltet ist, sondern dass die Entwickler eine Konstantstromquelle benutzen, damit der ON Strom in der LED nicht zu gross ansteigen kann. Schliesslich ist der Eingangsspannungsbereich des SSR mit bis zu 32V doch sehr gross.

    Ohne Schema kann ich dazu leider nichts aussagen. Auffällig, wenn die LED mal stark und mal schwach leuchtet weist auf einen Fehler in der Ansteuerung hin.

    Du schreibst, Ansteuerung 1.1V / 5V, muss ich dies so interpretieren, dass ein OFF einer Steuerspannung von 1.1V entspricht?

    Beim Datenblatt des SSR steht <1V für ON und da wäre dann 1.1V bereits zu hoch.

    Dateien

    • SSR-40DD-EKT.pdf

      (229,18 kB, 10 Mal heruntergeladen, zuletzt: )

    Hallo Zarroc

    dein Problem ist ohne ein Schema des Gerätes schwer zu lösen und ich kann mich nur auf Vermutungen abstützen.


    Zitat

    Nur: Der Lenovo ist von 2021 und verfügt über keine CMOS – Batterie mehr. Die Versorgung des CMOS -Chip erfolgt von der 11,5 Volt Batterie bzw. wird durch Spannungsteiler konform auf 3,4 Volt gehalten.


    Ich vermute, dass Du mit dem Spannungsteiler von 11.5V auf die benötigten 3,4V falsch liegen könntest. Ein Spannungsteiler funktioniert lediglich korrekt, wenn die Last (der Lastwiderstand) immer gleich und konstant bleibt. Möchte man dies tatsächlich via Spannungsteiler lösen, so galt früher mal die Regel, dass der Strom durch den Teiler etwa dem 5 Fachen des Laststromes entsprechen musste, um einigermassen eine stabile Versorgung zu erreichen.

    Daher vermute ich, dass man da viel eher einen Spannungsregler eingebaut hat und da könnte die Ursache für Dein Problem liegen.

    Du schreibst, dass die Spannung an der CR2032 lediglich 2.51V betrug. Dies könnte daher stammen, dass die CR2032 den Strom, der durch die geamte Schaltung fliesst, nicht liefern kann. Schlimmer noch, so vermute ich, hast Du nichts davon erwähnt, dass die ursprüngliche Versorgung des CMOS Chip (was für ein Chip ist da) durch Dich unterbrochen wurde. Daher mus sich annehmen, dass ein grösserer Strom aus der Batterie rückwärts in die Spannungsregelschaltung fliesst, was natürlich nicht sein dürfte.

    Eine andere Fehlerquelle könnten zusätzliche Schaltungsteile sein, die auch aus dem Akku dauer versorgt werden müssen. Dies auszuschliessen ist ohne Schema (und dies wird man wohl kaum finden) nicht möglich sein. Das Verfolgen der Leiterzüge auf der Platine wird auch eine eher unsichere Aufgabe werden.


    Gruss

    Pius

    Hallo Kai

    schön, Dein Beispiel. Für mich ist das C++ lange her und daher müsste ich ich es mir genauer ansehen um die Detail zu verstehen.

    Ein kleiner Hinweis:

    in der Zeile:


    constexpr byte LED_COUNT {sizeof(ledArray)/sizeof(ledArray[0])}; // Größe des Arrays speichern


    berechnest Du die Anzahl der Array members. Dies sieht man in dieser Art eher selten, ist aber genau der richtige Weg.

    Das zweite sizeof() in der Division entspricht der Grösse des Typs, daher würde ich sizeof( Led*) schreiben, was etwas deutlicher wirkt. Natürlich ist in diesem Fall beides identisch und daher richtig.


    Led *ledArray[] {&led3, &led4, &led5, &led6}; // LEDs für Lauflich in Array zusammenfassen
    constexpr byte LED_COUNT {sizeof(ledArray)/sizeof( Led* )}; // Anzahl Led im Array bestimmen


    herzliche Grüsse

    Pius

    Hallo CANDO


    Kai hat es richtig erklärt und ich kann ihm nur zustimmen. Das HTTP Protokoll ist eher schlecht für Dein Anliegen geeignet, da es sitzungsorientiert arbeitet.

    Ich würde empfehlen, bevor Du Dich mit der Übertragung der Befehle befasst, die Rollladen- Steuerung vorab zu realisieren. Zum Starten, Ausprobieren und der Funktionskontrolle sollten doch 2-3 Tasten reichen. Das Ausführen von Aktionen, das Verhindern von Kollisionen oder Fehlfunktionen des Rollladen ist Dein Hauptziel und wenn dieser Teil in allen Fällen richtig funktioniert, hast Du vermutlich den grössten Teil des Projektes erledigt. Den physischen Aufbau und die sich drumherum ergebenden Anforderungen sind uns nicht bekannt und da werden wir ausser bei Teilprobleme kaum sinnvolle Lösungsvorschläge aufzeigen können.

    Danach überlegt man ich, wie man die Steuerung via FB erledigen könnte (z.B: via IR oder mit einer HF FB, oder via IP/ TCP/HTTP).


    Da Dich aber natürlich Antworten auf die Benutzung des HTTP Protokoll interessiert hier ein möglicher Ansatz. Man kann sehr wohl, wenn Befehle nicht allzu zeitkritisch sind, vom Client zum Server mittels http Request eine logische Session mit dem Server aufbauen, indem man den jeden http Transfer als eine in sich abgeschlossene Einheit betrachtet. Dabei erstellt der Server einen handel (Zahl), der die Verbindung identifiziert. Dieser handel wird anschliessend vom Client bei jeder Aktion benutzt (mit geliefert), um die Session (eine logische Verbindung) zu identifizieren und aufrecht zu halten.


    Der Server setzt mit dem Aufbau der Sitzung ein Timeout auf, das ihm erlaubt zu erkennen, wenn ein vermutlicher Verbindungsabbruch erfolgte. Bei jedem Request des Clients mit dem korrekten Handle, wird das Timeout beim Server wieder zurück gesetzt (-> Verbindung ist noch da).


    Da der Server dem Client keine Anfrage oder Information zukommen lassen kann ohne dass der Client etwas geschickt hat, kann man lösen indem der Client in regelmässigen zeitlichen Abständen einen Request mit „KeepAlive“ an der Server schickt. Der Server muss darauf nicht unmittelbar Antworten, sondern kann seine Antwort etwas verzögern um vielleicht dem Client eine Information mitzuteilen.


    Diese Vorgehensweise benutzte ich, um ein Programm auf einem Client aus der Ferne kontrollieren zu können (Fern Wartung). Bekanntlich sitzen Arbeitsstationen in den Firmen hinter der FW und wollte man den Zugang von Aussen auf einen dieser Geräte erlauben, müsste man bei der FW ein Port öffnen und spezifizieren was da erlaubt sein soll und was nicht. Da aber die allermeisten Arbeitsstationen den Zugriff auf WebServer zulassen (von Innen nach Aussen) muss lediglich die Logik mit einem WebServer so umgestaltet werden, dass der Client und damit die SW auf dem Client immer einen HTTP Request zum Server offen hält, um darüber die Instruktionen von Aussen zu erhalten.


    Gruss
    Pus


    TCP Sitzungsaufbau

    Hallo Kai


    sehr schön gelöst, Dein Ansatz mit der eigenen %x Auswertung. Wenn ich mir dann ansehe, wie einfach das Auftreten von zwei % (Ausgabe eines % Zeichens) gelöst ist, dann freue ich mich um so mehr. Dein Lösungsansatz, ich brauche eine Schleife über alle Zeichen des fString ist, so meine ich, der beste Startpunkt und ich vermute, Du hast dann im else Fall (Zeile 110) den mit der äusseren Schlaufe erkannt, dass es im Grunde genommen genau gleich weiter laufen müsste, mit dem kleinen Unterschied des Post Increment des Zeigers. Ich musste genau an den selben Stellen meinen Kopf "schief halten" und kam dann, zumal ich mehr %x Steuerungen benötigte zum Schluss, dass die % Auswertung in meinem Fall besser mit einer State Machine gelöst wird. Damit erreichte ich, dass das Lesen immer an einer einzigen Stelle verblieb. Im nächsten Schritt wurde es dann zu einer singel Char Funktion (durch die State Machine), die in der Lage war, streams von char's nach %x zu behandeln und damit war die Lösung bereits soweit gediehn, dass ich sie im stdout (Standard C) benutzen konnte. Anstelle eines Switch Case Konstruktes für die unterschiedlichen %x benutzte ich jeweils eine Funktions-Zeiger-Tabelle, was natürlich den Code Aufwand anfänglich beträchtlich erhöhte, aber notwendig war, wenn ich unterschiedliche %x Steuerungen auf unterschiedliche Ausgangskanäle (LCD, UART, 7-SegDisp, Speicher) anwenden wollte.

    Das Meiste ist in der Datei Frm_putc.c Datei codiert (falls Du nachsehen willst). Eine Besonderheit ist darin in der Funktion void _frm_puts(const char* p, uint8_t Flash) ausprobiert. Darin wird innerhalb einer Funktion erneut eine Funktion deklariert (__getFrmNext(void)()) , die auf die lokalen Variablen der _frm_puts() Funktion Zugriff hat, sich aber nicht ausserhalb der Funktion _frm_puts() benutzen lässt. Mit diesem Klimmzug (sollte man nicht so implementieren und ist vermutlich weit entfernt vom C Standard) konnte Code eingespart werden. Im folgenden das Fragment des Codes:



    Nach wie vor ist und bleibt es eine Speziallösung, die noch viel Erweiterungen bekommen könnte. Aber, das lohnt sich echt nur, wenn man es tatsächlich benötigt.

    Eine ganz kleine Erweiterung würde Deine serialPrint() Funktion drastisch aufwerten:

    Benutze %s so wie es ursprünglich gedacht ist (ein Zeiger auf ein Textstring im RAM) und benütze beispielsweise ein %S

    um ein String aus dem Flash auszugeben.


    Die Fehlermeldung mit dem CAST ist doch korrekt. Es gibt unterschiedliche Makros für die Deklaration eines Zeigers im Flash. Meine Faulheit benützt dann meist nur einen char * oder einen uint8 * anstelle von Zeigern ins Flash so falsch nach dem Motto, ich weiss was ich tue.

    Ich denke hier kommt die Problematik der CPU-Architektur dem C-Standard in die Quere. Würde man Konsequent C++ benutzen, würde man vermutlich dazu eine Klasse implementieren (als Member ein Flag ob es sich um einen RAM oder FLASH Zeiger handelt), was sich bei der Arduino Umgebung sicher nicht lohnt, da die CPU Architekturen mittlerweile ja ganz unterschiedlich sein dürfen.
    Ein genaueres Betrachten der Datei pgmspace.h hilft einem da weiter.

    herzlichen Gruss

    Pius


    den angesprochenen Code schickte ich in diesem Thread in der FrmDemo.ZIP Datei.

    ja, Kai, wenn man sich die Summe der Strings berechnet ist der Unterschied 100% (lediglich die txtXX).

    Was ich noch immer nicht verstanden habe ist, wie der Compiler vor dem Programm Start die Strings in's RAM verschiebt. Wenn ich das Programm im Studio starte und vor dem main() anhalte, kann ich im RAM die Texte sehen, verbleiben die Texte im Flash findet man keinen Text mehr im RAM.


    Du erinnerst Dich sicher an meine Code Beispiele mit dem @Txx. Da wird in der Ausgabe, die auch char weise erfolgt, das @ und der folgende Code interpretiert und bei Txx ein Flash Text mit dem Index xx ausgegeben. Auf diese Wiese wird das Zusammensetzen von Ausgaben aus konstanten Texten und Daten dann nochmals optimiert. Wobei sich eine solche Methode aber nur bei umfangreicheren Projekten lohnt, da der Interpreter selbst auch wieder Code belegt und dies nur produktiv wird, wenn man es häufig benutzt und alle Details (Möglichkeiten) kennt. Die Funktion serialPrint könnte man ja soweit erweitern, das die Ausgabe nicht nur auf die UART erfolgt, sondern beispielsweise auch auf eine Anzeige angewendet werden kann. Dazu ist es am Einfachsten nur eine put(char C) Funktion zu benutzen und der allgemeinenPrint() Funktion jeweils die put(char c) Funktion als Zeiger mit übergibt, oder sie in einer statischen Variablen zu halten.

    Auf jeden Fall lohnt es sich, sich darüber Gedanken zu machen, bevor man in einen Speicherengpass rennt.

    schönen AbendPius

    Hallo KaiR


    super, das ist doch ein Anfang. Der Lösungsansatz via Null Terminierte Zeichenketten definieren und anschliessend eine Zeiger Tabelle (pTxt[]), die auf die entsprechenden Zeichenketten zeigen ist meines Wissens der einzig gangbare Weg. Damit man dann die entsprechenden Strings einfacher im Code erkennen kann, hast Du ein enum benutzt und dabei den einzelnen Indices einen sprechenden Namen (analog zum Inhalt) gegeben.


    Nun habe ich im beiliegenden Code versucht, lediglich die Textkonstanten (txt00 .. txt18) im Flash zu belassen, indem ich mit dem Makro

    TXTFLASH dem Compiler signalisiere, dass die Texte aus dem Flash zu holen sind. Ist das Makro gesetzt, dann wird das Flash benutzt, wenn nicht, das RAM.

    Für die Ausgabe in der var par Funktion void serialPrint(bool lineFeed, ...) musste ich dann im Falle dass der Zeiger aus dem Flash stammt, die Zeichenketten zeichenweise ausgeben (pgm_read_byte_near()).


    Da in diesem Fall die Funktion serialPrint() ja logischerweise immer nur aus dem Flash liest, musste ich bei den Aufrufen auch die mit "" eingefügten Texte im Flash belassen (F("s zu viel ")).


    In meinem Beispiel verbleibt die Zeiger-Tabelle (pTxt[]) im RAM, beinhaltet aber FLASH Zeiger. Im nächsten Schritt könnte man auch die Tabelle im Flash belassen (eine Tabelle im Flash die Zeiger auf Flash-Strings enthält), was dann aber serialPrint() in dieser Art nicht mehr akzeptieren würde.

    Müsste ich hier weiter machen, dann würde ich vermutlich der serialPrint() Funktion Flash Doppelzeiger übergeben (ja das ist echt etwas anstrengender). Da ich selber ungerne mit Funktionen mit einer Variablen Anzahl Parameter arbeite (belastet sicher den Stack stärker) würde ich mir eher eine Funktion schreiben, die für die Ausgabe einen Zeiger auf ein Zeiger-Array im Flash geliefert bekommt und in der Tabelle den letzten Eintrag auf NULL setzen, um das Ende der Tabelle erkennen zu können.

    Aber es ist genau dies am Programmieren das mir jeweils Spass gemacht hat. Man kann, aber man muss nicht

    Nun Hans, auch ich bin nun in Rente und kenne das wenn man meint man könnte Hürden nicht mehr meistern. Oft, sehr oft denke ich, dass ich dies oder das nicht mehr angehen will. Und dann raffe ich mich mal auf und wage einen neuen Schritt, dann bin ich erstaunt ob mir selbst, wenn ich gewonnen habe und wenn nicht, dann sage ich zu mir, ich muss nicht mehr. So hoffe ich zufrieden zu bleiben.


    Leider sind die Lib’s beim Arduino meist in C++ erstellt, weil C++ macht die Benutzung der Lib’s einfacher und oft auch intuitiver. Will man es etwas verstehen, dann kommt man um ein paar Grundlagen nicht herum. Ich mache die Erfahrung, dass bei sehr jungen Anwendern das Ziel ist, ein Problem zu lösen, wir Älteren wollen ein Problem lösen und die Lösung etwas verstehen. Zu früheren Zeiten wurden Lib’s ausführlich dokumentiert, was in den letzten Jahren immer weniger wurde (mein Eindruck). Solche Doku’s erleichterten mir die Orientierung innerhalb der Lösungen.


    Also, Du hast die C++ Bücher nun mal, dann stöbere immer mal wieder darin. Lass weg was Dich nicht interessiert (wir dürfen das) und lies das was Dir hilft. In den Büchern ist es jeweils sehr schwer zu bestimmen, was denn nun C oder C++ ist, also wirst Du sicher auch von diesen Büchern profitieren.


    Frage hier weiter und warte nicht zu lange damit, weil in solchen Fällen meist der Umfang eines Projektes schon soweit gewachsen ist , dass es für die Isolation des fraglichen Punktes mehr Aufwand bedeutet.


    herzlichen Gruss

    Pius

    Hallo Hans


    ja, vielleicht waren meine Äusserungen zuwenig klar, deshalb ein kleines Beispiel und dabei sollte der RAM Bedarf viel niedriger sein.
    Probiere es mal aus. Will man Array's von Strings aus dem Flash anlegen, danngeht es leider nicht ohne den Umweg einer Zeiger Tabelle, ansonsten man lediglich nur gleich lange Strings behandeln könnte, was kaum je gefragt ist.
    Übrigens, die Strings sollten nicht innerhalb einer Funktion definiert werden. Alle Deklarationen innerhalb eines Funktionsrumpfes

    werden auf dem Stack abgelegt, was zur Laufzeit auch wieder RAM belegt.


    Gruss

    Pius

    Danke Kai

    Du nimmst es mir vorweg. Hans benutzt anstelle von C Array’s die String Klasse aus C++.

    Dies darf man natürlich tun. Der Sinn und Zweck der Klasse ist in erster Linie (meine Meinung) die vereinfachte Anwendungen von sich verändernden Texten in Bezug auf die Gösse, eher nicht zum Anlegen von konstanten Texten. Da ich der Überzeugung bin dass man, wenn man C++ effizient benutzen will zuerst das Verhalten von C gut kennen muss.

    Aber dies soll hier nicht interessieren. Picken wir doch einige Grundsätze aus dem Code heraus:

    Zitat

    Mit dem "ß" im "char TextA[7] hatte die IDE auch Probleme

    klar, weil es in der Standard ASCII Tabelle (7-Bit) das Zeichen 'ß' nicht gibt.


    Aufgepasst, eine Deklaration mit "Text" "baut" der Compiler ein char Array mit der Länge 5 und füllt in die letzte Position des Array's eine 0 ab, was identisch ist mit der folgenden Zeile:


    char A[] = 'T', 'e', 'x','t', 0;


    char A[] = 84,101,120,116, 0; // hier sind nun die Zeichen durch die dezimalen ASCII Werte ersetzt.


    Der Unterschied von ‘ ‘ und " " ist der, dass ‘ ‘ einen einzelnen Wert meint und " " ein Array vom Typ char meint, das auf dem letzten Zeicheninhalt den Wert 0 enthält.


    Da C keinen Datentyp Array kennt, werden Array's, wenn sie als Parameter übergeben werden, immer als Zeiger auf den Anfang eines Array's übergeben. Daraus folgt, dass die Funktion, der der Zeiger übergeben wird, nie wissen kann, wie gross das Array ist.


    Damit nun aber eine Ausgabe z.B: mit print() funktioniert und die Funktion print weiss, wann bei der Ausgabe das Ende des Arrays erreicht ist, wird am Ende eine 0 angefügt (Dieser Zahl ist in der ASCII Tabelle kein Zeichen zugeordnet).


    Zitat: mit passender Länge wollte der Compiler den Code nicht fressen.


    Weiter muss man wissen, dass C (C++ auch) den Index in Array's immer mit 0 beginnt. Demnach entspricht das erste Zeichen im Array A[0].


    String TextD = " funktioniert!";


    Obige Zeile instanziiert ein Objekt String (legt ein Objekt von der Klasse String an), das erstmal keinen Speicher für die Grösse einer Zeichenkette reserviert (ist leer). Erst mit dem Operator = wird der Klasse mitgeteilt, dass man ihr einen Inhalt eines char Array’s zuordnen will. (Der = Operator ist eine implementierte Member-Funktion in der Klasse String). Diese füllt das Objekt mit der Zeichenkette ab, die als char[15] im const Segment vorliegt.


    Das Literal

    " funktioniert!" entstammt dem const segment des Compilates. Obwohl ich kein Arduino Fachmann bin, würde ich behaupten, dass


    String TextD(" funktioniert!");


    Hier zum identischen Ergebnis führen wird, weil hier der Konstruktor mit dem Parameter eines char Arrays aufgerufen wird.


    TextD = (" funktioniert auch");


    würde dann den Inhalt von TextD mit dem neuen Inhalt überschreiben.


    Wenn nun Kai schreibt:

    Zitat

    Mit C-Strings braucht man sich diese Gedanken nicht machen.

    Meint er mit C-String folgende Deklaration (hier als Beispiele)


    char TextB[] = "Test";

    const char TextB[] = "Test"; // weil der Inhalt nie veraendert werden soll das Schluesselwort "const"


    Ich würde davon abraten, für mehrere Zeichenketten mit unterschiedlichen Längen ein zwei dimensionales Array zu benutzen. Probiert es aus!


    char TextE[][] = {"Hallo", " Katze"," Nachbar", " Kinder","Zahn"} ; // geht leider nicht


    In diesem Fall würde ich mehrere einzelne const Variablen definieren, was dann das Schreiben der Ausgabe etwas leserlicher gestalten lässt:


    const char strHello[]   = "Hallo";

    const char strKatze[]   = "Katze";
    const char strNachbar[] = "Nachbar";


    Ich empfehle Programmieren in C von Rudolf Berrendorf, der beschreibt die Grundlagen viel besser als ich, oder das Buch von Heimo Gaicher "Programmierung in C" das Kai auch schon empfohlen hat.


    schönen Abend

    Pius

    Vorsicht mit der Zeile:

    char TextA[8] = {'h', 'e', 'i', 's', 's', 'e', 'n'};


    das Array TextA ist 8 char gross dimensioniert und danach mit 7 chars aufgefüllt worden.

    Bei TextA[7] (der 8. Eintrag) ist der Inhalt undefiniert.