Beiträge von KaiR

    Hans64: In der Tat dienen dient C2 zum Glätten. Ich hatte ohne diesen Kondensator eine Spannungslinie von der Solarzelle die in etwa so aussah, als ob man einen Wechselstrom mit einem Einweggleichrichter gleichgerichtet hätte. Der Kondensator C3 ergibt sich aus den Hinweisen des Datenblattes zum INA138 und wirkt als Tiefpassfilter.

    nische: ich weiß nicht so recht, was Du mit „aufstartendem Solarpanel“ meinst.

    Hans64: Was konntest Du nicht nachvollziehen…? Vielleicht kann ich es ja noch erklären.

    Ich habe mal etwas herumprobiert wie man eine (Sonnenfolger-) Schaltung realisieren könnte, die stromabhängig gesteuert wird. So, dass z.B. eine Ausrichtung der Solarzelle(n) nur dann erfolgt, wenn diese einen Mindeststrombetrag liefert der größer ist, als die Menge Strom, welche Schaltung verbraucht um den Steuervorgang durchzuführen.


    Wenn genug Strom von der Solarzelle geliefert wird, kann man auch davon ausgehen, dass es hell genug ist und sich eine Steuerung überhaupt lohnt. Dadurch würde eine automatische Anpassung an die sich verändernden Tageslängen erfolgen. Zwar drängt sich der Gedanke auf, dass man einfach nach der Spannung der Solarzelle geht, aber das funktioniert nicht, weil Solarzellen auch bei geringem Lichteinfall recht schnell ihre Betriebsspannung erreichen ohne viel Strom zu produzieren.


    Zum Probieren habe ich folgende Schaltung aufgebaut:


    Screenshot_Strommess-Steuerung.png


    Diese Schaltung besteht im Wesentlichen aus dem Strommessverstärker INA138 und einem 2fach-Operationsverstärker LM358. Der von der Solarzelle erzeugte Strom wird über einen 1Ω Widerstand (Shunt) geleitet. Der an diesem Widerstand entstehende Spannungsunterschied wird von dem Strommessverstärker, wie der Name schon sagt, verstärkt. Bei 50kΩ an seinem Ausgang ergibt sich der Verstärkungsfaktor 10. Das bedeutet, wenn der Shunt von 1mA Strom durchflossen wird, liegt am Ausgang des INA138 eine Spannung von 10mV an (Spannungsabfall am Widerstand = 1V/A * 10-3 A = 0.001V * Verstärkung 10 = 10mV).


    Diese Spannung liegt am Operationsverstärker an, der als Spannungsfolger arbeitet. Der Ausgang vom Spannungsfolger wird wiederum an den nicht invertierenden Eingang des zweiten OpAmps geleitet, der als nicht invertierender Schmitt-Trigger konfiguriert ist.


    Die Vergleichsspannung am invertierenden Eingang wird mit Hilfe einer Spannungsreferenz, dem TL431 zur Verfügung gestellt. Der TL431 ist quasi eine einstellbare Zenerdiode. Seine Minimalspannung beträgt 2,5V. Auf diesen Wert wurde der TL431 auch eingestellt. Seine Ausgangsspannung wurde durch einen Spannungsteiler auf 100mV herunter geteilt, welche als Referenzspannung am Operationsverstärker anliegt.

    Dadurch wird der Schmitt-Trigger ausgelöst, wenn die Solarzelle mindestens 10mA Strom liefert. Das High-Signal des Schmitt-Triggers kann zum Einschalten des Sonnenfolgers verwendet werden.


    Die Schaltung wird durch den Strom der Solarzelle gespeist. Solange die Betriebsspannung der Solarzelle unter 3V liegt und weniger als 1mA Strom erzeugt wird passiert nichts, weil der Strommessverstärker eine Mindestspannung von 2,7V benötigt. Der LM358 benötigt min. 3V. Die Spannungsreferenz arbeitet ab 2,5V. Die Spannungsreferenz habe ich eingesetzt damit ab diesem Punkt, ab dem die Schaltung zu arbeiten beginnt, eine gleichbleibenden Referenzspannung am Operationsverstärker anliegt. Unabhängig davon, ob die Solarzelle nun eine momentane Spannung von 3V, 4V oder 5V usw. hat.


    Ausprobiert habe ich das mit einer 5V / 2,5W Solarzelle.


    Das Ganze sah so aus:


    Strommess-Steuerung.jpg


    Auf dem Bild sieht man oben den Strommessverstärker (blaue Platine) und darunter den LM358. Der Ausgang des Schmitt-Triggers treibt den MOS-Fet. Geht der Schmitt-Trigger auf High, leuchtet die gelbe Diode, ansonsten ist sie aus. Das habe ich als Indikator eingebaut.

    Als Last habe ich einen LiPo Akku mit einem Laderegler angeschlossen. Der Stromfluss erfolgt also im Wesentlichen von der Solarzelle über den Messwiderstand in den Akku.


    Die Solarzelle wurde unterschiedlichen Helligkeiten ausgesetzt. Dazu musste ich eine LED Lampe verwenden, weil sich die Sonne in letzter Zeit doch recht rar macht. Zum Ausprobieren hat es aber gereicht. Wenn die gelbe LED anfing zu leuchten, lieferte die Solarzelle etwa 10mA. Der Ausgang vom Schmitt-Trigger ist auf High gegangen. Ab etwa 7,5 mA schaltet der OpAmp wieder auf Low.


    Also im Prinzip funktioniert das ;). Allerdings nur mit Solarzellen, die eine Betriebsspannung >= 3V haben.


    Die Schaltung ist nicht super genau. Zum Einen, weil ich einen "normalen" Widerstand als Shunt benutzt habe und dieser natürlich mehr temperaturabhängig ist als spezielle Stromshunts. Außerdem ist die Schaltung auf einem Breadboard aufgebaut. Da entstehen schnell mal Ungenauigkeiten durch die Übergangswiderstände an den Kontaktfedern. Zum Dritten habe ich die Verstärkung der Einfachheit halber mit ca. 53kΩ (E12 Reihe 47kΩ + 3.3kΩ) statt mit 50kΩ konfiguriert. Die Schaltung ist aber immer noch genau genug um den Schaltvorgang durchzuführen. Da kommt es auf 800µA mehr oder weniger nun auch nicht an.

    Das OLED kann wahrscheinlich nicht direkt angeschlossen werden. Einmal weil, wie Hans64 schon erwähnte, die OLEDs i.d.R. per I2C angesteuert werden, zum Anderen weil RS232 normalerweise mit 12V betrieben wird, während die OLEDs mit 5V oder gar 3.3V betrieben werden.


    Normalerweise gibt es FTDI Adapter die die Umsetzung Von RS232 auf USB erledigen. Also im Prinzip das was von dem Hersteller angeboten wird. So etwas gibt es auch im Elektrohandel z.B. hier. Eine noch günstigere Variante wäre solch ein Teil. So eines verwende ich um Switche zu konfigurieren.


    Das ist etwas günstiger. Eigenbau wird wahrscheinlich auch nicht billiger. Allerdings kann ich nicht sagen, ob die vom Hersteller angebotenen Kabel noch irgend eine Spezialität haben, dass unbedingt diese zusammen mit dem Gerät genutzt werden müssen. Vom RS232 Kabel muss aber die PIN-Belegung passen. Wenn man die kennt kann man das evtl. am Kabel „umpolen“.

    nische: Es wird ja langsam. Ich hatte bei meinem Aufbau seinerzeit ja auch mal ein Relais eingesetzt. Allerdings habe ich das wieder verworfen, weil die kleinen Dinger doch recht viel Strom benötigen. Siehe Beitrag #143.

    Darum bin ich seinerzeit auf die Schaltung per Mosfet umgestiegen.

    Solar-LED-Treiber


    Mir sind gestern beim Aufräumen ein paar ICs des Typs YX8018 in die Hände gefallen. Diese Teile werden in LED-Leuchten verbaut, bei denen am Tag der Akku aufgeladen wird und sobald es dunkel wird, werden ein oder mehrere LEDs angeschaltet. Z.b. gibt es da diese Gartentiere mit den leuchtenden Augen :).


    Außer dem IC und einer Induktivität wird nichts gebraucht um die Schaltung aufzubauen. Der Clou ist, dass nur ein 1,2V Akku benötigt wird um die LED ans Leuchten zu bringen. Das klappt auch mit weißen LEDs die fast 3V Spannung benötigen. Das ganze funktioniert nach dem "Joule Thief" Prinzip, bei dem die Induktivität eine entscheidende Rolle spielt:



    Ich habe folgende Schaltung mal auf einer 2x2cm Streifenrasterplatine aufgebaut:


    Sloar-LED-Treiber-Schaltplan.png



    Solar-LED-Treiber-2.jpg                          Solar-LED-Treiber-1.jpg


    Wie man sehen kann, gibt es außer den Steckleisten für die Anschlüsse von Akku (blau), Solarzelle (gelb) und der LED (schwarz) nur das TO-94 IC und die Induktivität.


    Das komplette Machwerk sieht wie folgt aus:


    Solar-LED-Treiber-3.jpg


    Das funktioniert sogar :). Sobald für die Solarzelle nicht mehr genug Licht vorhanden ist, fängt die LED an zu leuchten. Der IC verfügt auch über einen Tiefenentladungsschutz für den Akku.


    Während ich so gebastelt habe, stellte sich mir die Frage, ob man den IC nicht auch für den Sonnenfolger verwenden kann. So, dass die Solarzelle mit Hilfe des ICs auch zum Ein- bzw. Ausschalten des Sonnenfolgers verwendet werden kann.


    Dieses IC ist in den üblichen China-Shops, aber auch bei Amazon oder eBay für wenig Geld zu beziehen. Weitere Typen die gleich oder ähnlich funktionieren, haben die Bezeichnung QX5252F, ANA618 und CL0116.

    So wie es aussieht hast Du ein Cockpit von einem "echten" Golf? Ich fürchte das ist etwas zu komplex. Du willst die Daten von einem Spiel abgreifen und die auf dem Cockpit anzeigen.


    Hast Du eine Ahnung wie Du die relevanten (Spieldaten) Daten in den Arduino bekommst? Hast Du eine Ahnung wie Du die Spieldaten in ein Signal umsetzt, damit Tacho/ Drehzahlmesser überhaupt etwas anzeigt? Wie das Signal aufgebaut sein muss (PWM oder anderes)? Möglicherweise funktioniert das über Rechtecksignale unterschiedlicher Frequenz. Weißt Du wie man die erzeugt? Kannst Du programmieren? Die Software muss in 32KB Flashspeicher und 2KB RAM passen.


    Ich bin kein KFZ-Elektriker. Da habe ich keine Ahnung von. Aber wenn die Anzeigen/Kontrolleuchten auch 12V benötigen (was ich vermute), musst Du alle Signale von 5V auf 12V bringen (Senden) und umgekehrt von 12V auf 5V (Empfangen). Du wirst für jede Information (Geschwindigkeit, Drehzahl, Kontrollleuchten usw.) einen eigenen PIN brauchen. Und natürlich Software um das Ganze zu steuern. Einfach nur ein Kabel dranhängen und eine passende Masse suchen ist nicht. Da reicht auch nicht ein Widerstand.

    Es ist nicht bekannt, wie der Tacho gesteuert werden kann. Über Spannungen und Ströme nichts bekannt ist außer, dass Du alles über eine 12V Batterie laufen lassen willst. Du willst laut deiner Beschreibung nicht nur das Tachosignal, sondern auch den Status der Handbremse, Licht, Drehzahl alles über ein Kabel mit einem einzigen Pin regeln. Ich würde ich mal sagen... das kannst Du knicken.


    Du erwähnst eine Schaltplatine. Über die ist aber auch nichts bekannt.


    Ohne konkrete Informationen was das für ein Tacho ist, wie er gesteuert werden kann (Datenblatt) , wie Du die Informationen vom Spiel zum Arduino bringen willst damit er sie auf die Tachoanzeige übertragen kann usw. usw. usw. kann Dir keiner helfen.


    Da wirst Du Dir mit Deiner Fragestellung schon wesentlich mehr Mühe geben müssen.

    Also wenn der „Arduino“ mehr als 5V an Betriebsspannung und/oder am Pin7 abbekommt, raucht er ab.

    Von daher brauchst Du schon zwei Stromkreise. Welche Spannung liegt am roten Kabel vom Tacho an?


    Was ist das für ein ominöser Widerstand? Welchen Wert hat er? Er bildet einen Spannungsteiler mit dem Innenwiderstand von Pin 7. Wenn an dem roten Kabel auch 12V anliegen müssen über dem Widerstand mindestens 7V abfallen. Sonst ist der „Arduino“ hinüber.


    Welchen Zweck soll der „Arduino“ überhaupt in diesem Konstrukt erfüllen?

    Der Adressbereich von I2C Geräten ist begrenzt. Immer wieder kommt es vor, dass z.B an Sensoren oder anderen Geräten die I2C-Adresse nicht änderbar ist. Wie kann man zwei davon "gleichzeitig" an einem I2C-Bus betreiben?


    Die Lösung dafür ist ein I2C-Switch. Man kann solche Teile kaufen. Wenn man z.B. nach dem Begriff TCA9548 sucht, wird man schnell fündig. Die angebotenen Breakouts basieren auf dem PCA9548 IC. Der PCA9546, PCA9540 sind Alternativen mit weniger Ports (4 bzw. 2 Ports statt 8).


    Man kann sich einen I2C-Switch aber auch selber mit ein paar N-Kanal MOSFets, wie dem z.B. BS170, selber zusammenstecken. Das sieht dann so aus:

    I2C-Switch.png

    U1 und U2 im Schaltplan entsprechen einem Pin am Mikrocontroller. SCL und SDA (links) entsprechen dem Signal welches vom I2C Master kommt. I.d.R. ist das der gleiche Mikrocontroller, der auch zum Ansteuern der Mosfets verwendet wird. An den IO_SCLX und IO_SDAX Ausgängen wird jeweils ein I2C Slave angeschlossen. Die 4k7 Widerstände sind Pullups für die I2C Leitungen.


    Auf dem Breadboard zusammengesteckt sieht es wie folgt aus:


    Bild-I2C-Switch.jpg


    Ich habe zum ausprobieren zwei OLED-Displays mit dem selbst zusammengesteckten Switch betrieben. Es werden immer zwei MOSFETs paarweise durch einen Pin vom Mikrocontroller geschaltet. Ein Paar entspricht immer einer SCL und einer SDA Leitung. Wird der PIN auf HIGH gesetzt, ist das entsprechende SCL und SDA Leitungspaar aktiv. Ist der Pin auf LOW gesetzt, ist auch das entsprechende Leitungspaar deaktiviert. Durch die Schaltung können beide Displays an einem Controller getrennt betrieben werden, obwohl sie eine identische Adresse haben.

    Werden beide Kanalpaare gleichzeitig aktiviert, erfolgt auf beiden Displays eine identische Ausgabe. Die eingestellte Taktfrequenz betrug 400kHz.



    Solch einen Switch kann man natürlich auch für Sensoren verwenden. Bei den verwendeten MOSFETS muss unbedingt darauf geachtet werden, was sie für eine Input-Kapazität haben. Diese muss so gering wie möglich sein. Auf einem I2C-Strang darf die Gesamtkapazität 400pF nicht überschreiten. Die BS170 sind mit einer Kapazität von typisch 24 pF und max. 40pF bei 10V angegeben.

    Du hattest die Teile ja schon mal im Beitrag #57 erwähnt. Offenbar sind sie inzwischen angekommen. Dann hast Du ja etwas für Zeitschaltung deines Sonnenfolgers.:thumbup:

    Normalerweise enthält die Klammer der While-Schleife einen Vergleich/eine Bedingung. Ist die Bedingung erfüllt ist sie „wahr“ was dem Wert 1 entspricht. Die While-Schleife wird immer so lange ausgeführt, solange die Bedingung „wahr“ ist.

    Schreibt man eine 1 in die Klammer, so ist die Bedingung für immer und ewig „wahr“. Der Ausdruck „While(true)“ wird auch gerne verwendet.


    Ich habe das Char-Array mit dem Zeichen '\x2D' gefüllt, um das Debuggen zu vereinfachen, falls man (formatierte) Zwischenausgaben mit Serial.print machen möchte. Das entspricht schlichtweg dem hexadezimalen ASCII Code für das "-" Zeichen. Wäre das Array mit Nullen gefüllt, würde von Serial.print nichts angezeigt, weil das Array ja von rechts nach links beschrieben wird, die Ausgabe aber von links nach rechts erfolgt. Und die Null ist ja bekanntlich das String-Ende Zeichen. Man würde erst etwas sehen, wenn alle 30 Zeichen geschrieben wurden.

    Ich wollte, dass in der Funktion selbst kein Zeiger verändert werden kann. Auch wenn es sich dabei „nur“ um Kopien handelt. Mehr nicht. Ich wollte NICHT den Inhalt schützen. Siehe #43.


    Dann will ich auch mal eine abgewandelte Version der reverseCode() Funktion beisteuern. Natürlich funktioniert sie im Prinzip genau so, wie die von Pius vorgestellte Variante aus dem Beitrag #42. Allerdings wird hier nicht mit Zeigern gerechnet und der Zugriff auf den Inhalt des Arrays erfolgt auf die für Einsteiger eher verständliche und auch in Lehrbüchern häufig vermittelte Weise.


    Code
    1. void reverseCode(char* const lsbString) {
    2. byte len = strlen(lsbString)-1, y;
    3. char tmp;
    4. while(len > y) {
    5. tmp = lsbString[len];
    6. lsbString[len--] = lsbString[y];
    7. lsbString[y++]=tmp;
    8. }
    9. }


    Welche Variante nun wirklich als allgemein verständlicher einzustufen ist, bleibt dem geneigten Leser überlassen. Auch in der, meiner Meinung nach verständlicheren Variante, ist es wichtig zu erkennen, dass in der Zeile lsbString[len--] = lsbString[y]; ERST der Wert an die Position "len" geschrieben wird und DANN "len "um Eins dekrementiert wird. Das gleiche gilt für die darauf folgende Zeile. Ein Umdrehen in "--len" und/oder "++y" wird für eine Überraschung sorgen.


    Außerdem habe ich die Laufzeit von drei Varianten verglichen. Die oben vorgestellte, die von Pius aus Beitrag #42 und die ebenfalls von Pius gezeigte, pfiffige XOR Variante aus Beitrag #40 (letztes Beispiel):


    Zeitverhalten-Vergleich.png


    Es wurde jeweils vor und nach dem Aufruf einer Funktion die Zeit mit micros() genommen. Die Differenz aus beiden Zeiten ergibt die Laufzeit. Alle drei Funktionen wurden 10 mal ausgeführt. Die Angaben sind natürlich nicht besonders genau, weil die Rechenzeit für das Speichern der Zeit und die Berechnung der Zeitdifferenz auch in den Wert mit einfließt. Außerdem beträgt die Auflösung des micros() Befehls bei 16Mhz nur 4μs. Es wird also immer nur ein Vielfaches von vier zurückgeliefert. Dennoch sind die Werte genau genug, um eine Tendenz aufzuzeigen.


    Es zeigt sich, dass Pius' hochoptimierte Funktion im Durchschnitt die schnellste ist. Erwartungsgemäß ist die XOR Variante die, die am meisten Zeit verbraucht. Es zeigt sich aber auch, dass die reverseCode() Variante nur wenig langsamer als die hochoptimierte strMirror() Funktion ist.


    Wenn es darum geht, in einem Programm einen String zu drehen wenn ein RFID Code empfangen wird, ist eine 4µs langsamere Verarbeitung sicher zu verkraften. Anders wäre es, wenn es um einen Prozess ginge, der tausende Male durchgeführt werden muss. Hier würde sich die Differenz zu einer beachtenswerte Größe aufaddieren.


    Es zeigt sich mal wieder, dass es für die Programmierung kein festes Rezept gibt. Es ist immer ein Abwägen zwischen Les- und Wartbarkeit des Codes und dem herausholen des Optimums. Ziel ist immer ein möglichst fehlerfreies Programm. Dabei helfen möglichst einfache Konstrukte und eine gute Lesbarkeit des Codes.


    Wer die Zeigerarithmetik beherrscht und Code schreibt, den kein anderer verstehen muss außer er selbst, der kann natürlich optimieren und kürzen bis der Arzt kommt. Manchmal ist es ja auch notwendig, wenn beispielsweise ein bestimmtes Laufzeitverhalten/ ein bestimmter Speicherverbrauch erforderlich ist.


    Wer aber nicht so hochbewandert ist und seinen Code auch noch verstehen will, wenn er sich nach längerer Zeit mal wieder damit beschäftigen muss, sollte sich lieber auf einfachere Elemente beschränken. Macht man keine groben Fehler, nimmt einem der Compiler schon einiges an Optimierung ab. Dazu ist er ja eigentlich auch da. In der Regel konzentriert man sich auf das zu lösende Problem und nicht auf die Rechnerarchitektur.


    Wie Pius' Beschreibungen zeigen, ist die Kenntnis dieser Dinge natürlich sehr hilfreich nahe an ein Optimum zu kommen, ohne sich auf die Compilertechnik verlassen zu müssen und sie hilft, von vornherein schnellen und sparsamen Code zu schreiben. Aber... dazu braucht es Zeit zum Lernen und viel Programmierpraxis. Gerade Fehler beim Umgang mit Zeigern sind berüchtigt, weil sie oft nicht so leicht zu erkennen sind.


    Es wird im Forum ja immer wieder betont, dass hier vorwiegend Einsteiger um Rat fragen. Da ist es natürlich nicht immer so einfach einzuschätzen, wieviel Komplexität bei den Antworten zuzumuten ist, ohne gleich abzuschrecken.


    Abgeschweift sind wir eh schon:). Was alles aus einer einfachen Frage werden kann...;)

    Die Zeiger(kopien) wurden mit const deklariert, damit eben diese in der reversCode() Funktion nicht verändert werden können (auch nicht aus versehen). Schließlich sind sie ja die Basis für den indizierten Zugriff auf den Inhalt der Arrays gewesen. Eine Zeigerarithmetik wie bei den Dir vorgestellten Funktionen war ja gar nicht vorgesehen.


    Der „Inhalt“ wiederum sollte ja verändert werden.

    @Pius: Danke für die Beispiele. Die sind wirklich Anfängergerecht ;). Die Beispiele sind für die Bonusrunde....


    Die XOR Variante ist eine, an der auch ich zu knabbern habe. Auf sowas wäre ich nicht gekommen. Da hast Du mir mit dieser Art von Dreieckstausch wirklich was für mich Neues gezeigt.

    Mi Ke :


    Nach der Beschreibung von dem dir genutzten RFID Reader muss ja am Ende alles herumgedreht werden, damit man auf die richtigen Werte für den Länder- und Kartencode kommt. Dazu haben wir uns Gedanken zu einer Routine gemacht, die einen String invertiert.

    In Deinem Fall, ausgehend davon, dass der Code immer 30 Byte lang ist und immer den gleichen Aufbau hat, wäre es doch sinnvoll die Daten direkt "verkehrt herum" einzulesen.


    Dann kann er nämlich sofort weiter verarbeitet werden. Das könnte so aussehen:



    Da ist jetzt einiges an Code mit den Funktionen. Wo ich aber drauf hinaus will ist die Endlosschleife in setup(); Dort ist ein Beispiel zu sehen, wie die Werte statt von der Position 0->30 des Char-Arrays "msbRFIDCode" von der Position 30->0 eingelesen werden. Dann spart man sich das spätere herumdrehen und damit Rechenzeit und Speicherplatz. Die Funktion reverseCode() wird überflüssig.


    Ich habe die Endlosschleife in setup() gepackt, damit man weniger globale Variablen definieren muss.


    Vielleicht kannst Du es ja so gebrauchen. Wenn nicht ... vielleicht ist der ein oder andere Denkanstoß dabei.


    Wenn keine neuen Fragen auftauchen, wars das aber erst mal dazu.

    Um das mit dem Speicherverbrauch (Nur Flash) mal zu demonstrieren habe ich in meinem Gesamtprogramm nur folgende Funktion betrachtet:



    Nach dem Compilieren hat das (gesamte) Programm 2302 Bytes verbraucht. Die Funktion allein verbraucht natürlich weniger. Im folgenden wurde die Variable "digit" wegrationalisiert indem die Funktion hex2int() und die "Bitschieberei" zu einem Ausdruck zusammen gefasst wurde.


    Erwartungsgemäß ist der Speicherverbrauch geringer (2296 Bytes). Nun wollen wir noch richtig viel Speicher sparen und die "tmp" Variable wegrationalisieren:


    Code
    1. uint64_t hex2dec(const char* hexString) {
    2. static uint64_t res;
    3. int len = strlen(hexString);
    4. res=0;
    5. for(int i=0,y=len-1; i < len ; i++,y--) {
    6. res += ((uint64_t) 1 << (y*4))*hex2int(hexString[i]);
    7. }
    8. return res;
    9. }

    Entgegen meiner Erwartung beträgt der Speicherverbrauch immer noch 2296 Bytes. Es hat sich nichts verändert.

    Auch beim Speicherverbrauch im RAM gab es keinen Unterschied. Es ist davon auszugehen, dass der Compiler implizit einen Speicherbereich für Zwischenergebnisse schafft.


    Weiterhin denkt man "int" ist ein 16 Bit Datentyp, verbraucht also 2 Byte. Da der zu erwartende Wertebereich von "len" auch in 8 Bit passt, nimmt man doch besser den Datentyp "uint8_t" oder "byte" statt "int".


    Das habe ich gemacht, compiliert und was ist das Ergebnis? 2298 Byte. Weiß der Geier warum (habe ich bis gerade gedacht).


    Code
    1. uint64_t hex2dec(const char* hexString) {
    2. static uint64_t res;
    3. uint8_t len = strlen(hexString);
    4. res=0;
    5. for(int i=0,y=len-1; i < len ; i++,y--) {
    6. res += ((uint64_t) 1 << (y*4))*hex2int(hexString[i]);
    7. }
    8. return res;
    9. }

    Wenn man sich den Code genauer anschaut, wird auffallen, dass in der For-Schleife die "int" Variable "i" mit "uint8_t" "len" verglichen wird. Außerdem wird der "int" Variable y der "len" Wert zugewiesen. Hier macht der Compiler wahrscheinlich intern einen Typencast weil zwei unterschiedliche Datentypen miteinander verglichen bzw. einander zugewiesen werden.

    Code
    1. uint64_t hex2dec(const char* hexString) {
    2. static uint64_t res;
    3. uint8_t len = strlen(hexString);
    4. res=0;
    5. for(uint8_t i=0,y=len-1; i < len ; i++,y--) {
    6. res += ((uint64_t) 1 << (y*4))*hex2int(hexString[i]);
    7. }
    8. return res;
    9. }

    Deklariert man die "i" Variable (und in diesem Fall auch y) ebenfalls als 8-Bit Datentyp (uint8_t oder byte), sinkt der Speicherverbrauch auf 2272 Byte. Die effektivste "Sparmaßnahme" von allen. Man muss also gut aufpassen was man so an Datentypen miteinander "mischt" bei Vergleichen oder Zuweisungen.


    Alles ausprobiert mit Visual Studio Code (PlatformIO) und dem Atmel AVR Framework 3.3.0.