mit bitWrite kann ich doch in einer Variablen gezielt ein Bit auf 1 oder 0 setzen? Oder?
Irgendwie ändert sich etwas falsch immer im Wechsel bei mir.
Ich taste mich heran in einer DS3231 RTC gezielt die Alarmregister zu setzen.
Bei Register/Adresse 0A und 0D läuft immer was schief.
Ich ändere von 07h bis 0Dh immer Bit 7 und in 0A und 0D zusätzlich Bit 6.
Mit aktuellen Code ändert sich nach jedem Reset der Inhalt von Register 0Ah und 0Dh.
Sitze schon 2 Tage vor dem Problem. Arbeite mit seriellen Ausgaben, finde aber nichts was schief läuft.
Ob ich in der set Funktion die Variablen
int addr_07, addr_08, addr_09, addr_0A, addr_0B, addr_0C, addr_0D = 0;
als byte oder int definiere macht keinen Unterschied.
ich glaube ich kann es auf die Befehlszeile mit Bit 6 eingrenzen.
bitWrite(addr_0A, 6, set_DYDT_1); // setzt das Alarm Day/Date Bit ensprechend
bitWrite(addr_0D, 6, set_DYDT_2); // setzt das Alarm Day/Date Bit ensprechend
Definiere ich die bytes (SET_ALARM_1_DYDT und SET_ALARM_2_DYDT) mit 0 statt 1, funktioniert alles mit den 7. Bits wie es soll. Ist irgendwo ein Fehler in der Variablenübergabe an die Funktion oder in der Funktion? Was mich eben auch wundert ist, warum dann Bit 7 fälschlicherweise mit geändert wird. Hat bitWrite einen Bug?
ja ich meine das die lokal definierten byte Variablen mit Wert 0 initialisiert werden. Soll man doch lokal so machen.
Auch wenn die dann wieder mit Werten der RTC gefüllt werden.
Gibt es ein Problem mit dem lokal definieren?
Wobei alle anderen Registerinhalte, außer 0Ah und 0Dh, genau das machen was sie sollen.
Doc_Arduino:
ja ich meine das die lokal definierten byte Variablen mit Wert 0 initialisiert werden.
Standardmäßig werden lokale Variablen nicht initialisiert. Weil der Initalisierungs-Code den Funktionsaufruf noch langsamer machen würde. Und so wie du das programmierst wird nur die letzte Variable auf 0 gesetzt!! Die anderen bleiben un-initialisiert. Siehe Trap #15:
Sollte aber wie gesagt hier keine Rolle spielen, da du die Werte gleich von der RTC liest.
Wo noch ein kleiner Fehler ist, beim Rückschreiben der Werte. Du machst da zweimal endTransmission(). Beim zweiten mal fragst du den Rückgabe-Wert ab. Das solltest du nur einmal machen und gleich abfragen. Das muss aber auch nichts mit dem Problem zu tun haben.
Ich habe doch nur 2 komplette I2C Zugriffe in eine Funktion hintereinander gepackt und modifiziere zwischendurch paar Variablen. Die beiden Zugriffe am Anfang und Ende sind doch für sich immer komplett abgeschlossen. Muß ich laut meiner Meinung nach auch machen, sonst kann ich nicht wieder auf die gewünschte Anfangsadresse des Registers setzen.
Am Anfang beim auslesen, soll die Funktion vorzeitig abgebrochen werden, wenn der Zugriff generell schon scheitern sollte.
Ich kann das aber zum testen umbauen, in dem ich die addr_x Variablen global mache und lesen und zurückschreiben als getrennte Funktion schreibe bzw. die vorhandene read Funktion dafür mit nutze.
Wire.write(decToBcd(addr_0D));
Wire.endTransmission(); // Byte in Register schreiben
if (Wire.endTransmission() > 0 ) {
error = true; // I2C Busfehler
}
endTransmission() ist die Methode die die Daten überhaupt erst auf den Bus schreibt. Vorher wird nur in den Puffer geschrieben. Beim zweiten mal sollte er theoretisch zwar nichts machen, da dann der Ausgangspuffer leer ist, aber es ist trotzdem falsch.
Entferne da einfach das erste endTransmission(). Dann passt es.
Beim Schreiben der Adresse für den Lese-Zugriff machst du es doch auch korrekt:
Wire.beginTransmission(i2c_adresse);
Wire.write(0x07); // setzen auf Registernummer bzw. dort wo es losgehen soll
if (Wire.endTransmission() > 0 ) { // war Connect fehlerfrei?
error = true; // I2C Busfehler
return error; // Abruch
}
dann schleppe ich den Fehler schon ewig mit mir rum. Hab's geändert. Leider funktioniert das Ganze immer noch nicht richtig.
Nach jeden Reset wechselt der Inhalt und das auch noch falsch. Bit 7 wird überhaupt nicht auf 1 gesetzt dafür. Dafür wird Bit 5 und 6 immer im Wechsel auf 1 gesetzt nach jeden Reset. Wie seit Anfang an.
Habe zusätzlich wie gesagt die addr_x global gemacht und damit die read und set Funktion sinnvoller.
Registerinhalte wechselt sich immer ab nach jeden Reset.
Also egal wie ich es derzeit mache, lasse ich nur ein Bit (6 oder 7) auf 1 ändern, egal welches, funktioniert alles. Lasse ich beide ändern haut nichts mehr hin.
Demnach werden globale und lokale statische Variablen immer automatisch mit 0 initialisiert.
Und lokale nicht statische Variablen müssen mit 0 initialisiert werden, sonst haben sie einen Wert von dem was gerade in dem Speicherbereich steht in dem sie angelegt wurden. Also muß man lokale Variablen mit 0 definieren. So habe ich das seinerzeit verstanden.
Generell ja, aber müssen nicht unbedingt. Es kommt darauf an wie man sie verwendet. Es gibt jede Menge Anwendungen wo man lokale Variablen anlegt und sie danach gleich mit anderem Code beschreibt. Dann kann man sich die Initialisierung theoretisch sparen. Wenn aber die Möglichkeit besteht dass dieser Code nicht ausgeführt wird, aber die Variablen danach trotzdem verwendet werden, muss man sie initialisieren.
Das compiliert zwar, aber liefert korrekterweise eine Warnung wenn man mit /W4 oder /Wall compiliert:
warning C4701: potentially uninitialized local variable 'var1' used
warning C4701: potentially uninitialized local variable 'var2' used
In der Version ohne die if-Abfrage kommt das nicht, da der Compiler merkt, dass nach der Deklaration auf jeden Fall eine Zuweisung kommt
Abseits von C/C++ ist da auch C# ein schönes Beispiel mit out Parametern:
Wenn man in C# einen Funktions-Parameter mit "ref" definiert ist das wie eine Referenz in C. Also sowas:
void func(int &var)
{
var = 5;
}
Die Änderung ist dann außerhalb sichtbar.
In C# will der Compiler aber unbedingt dass man die übergebene Variable vor dem Funktionsaufruf extra initialisiert. Deshalb gibt es statt dessen out. Funktioniert wie ref aber der Compiler meckert nicht wenn die Variable nicht initialisiert ist.
das verstehe ich jetzt absolut nicht. Die Variablen var1 und var2 werden doch ganz klar in beiden Fällen vor deren Nutzung definiert. Warum soll man danach mit denen nicht vernünftig arbeiten können. Irgendwie bricht jetzt gerade das gesamte Kartenhaus meines Programmierwissens zusammen.
Moment, vielleicht liegt es auch daran, dass er im zweiten Fall, wenn run unwahr ist, keine eindeutige Wertzuweisung hat. Teste mal bitte mit
void func(bool run)
{
int var1 = 0;
int var2 = 0;
if(run)
......
Allerdings sind meine addr_x Variablen mittlerweile global mit 0 initialisiert. Daran kann es eigentlich nicht liegen.
Das geht natürlich. So ist es richtig. Das brauche ich nicht zu testen. Ich habe die Initialisierung auf 0 ja explizit weggelassen. Dann läuft es wenn run true ist, aber geht schief wenn es false ist.
Die Variablen var1 und var2 werden doch ganz klar in beiden Fällen vor deren Nutzung definiert.
Die Variablen werden deklariert. Aber bekommen im zweiten Fall nicht immer einen Wert zugewiesen. Lokale Variablen verwenden denen kein Wert zugewiesen wurde == Programmierfehler.
Aber das ist wie gesagt off topic.
Zu deinem eigentlichen Problem. Ich sehe so vom Ansehen nicht wirklich wo da der Fehler ist. Wenn du sagst, dass es ohne I2C Kommunikation geht und die Kommunikation korrekt funktioniert sollte es eigentlich gehen.
Nachdem sämtliche Test's ohne RTC ohne Fehler liefen, habe ich mich wieder mit der RTC damit beschäftigt.
Habe mir dann vor lauter Frust das "bitWrite" selbst programmiert damit ich wirklich weis was passiert. Funktioniert zwar, brachte aber keine Besserung. Also habe ich angefangen verschiedene Bits im Sketch zu ändern, dabei fiel auf, dass es merkwürdige Effekte gab. Das Problem Überlauf stand im Raum. Und wie ich da so sitze und mir nochmal alles anschaue, fiel der Groschen. Es sollte schon der Wert, also die Wunsch-Bitkombination, im Register ankommen, so wie man es sich ausgedacht hat. Das war leider nicht der Fall. Weil ich mir die RTC write Funktion von jurs zu Grunde gelegt hatte. Damit kann man jedoch nur Zeit und Datum stellen, weil das in den BCD Code und zurück gewandelt wird.
Ich habe also die ganze Zeit unbemerkt meine Bitkombinationen vorm schreiben in BCD gewandelt. Da muß ja in höheren Bit-Wertigkeiten Müll rauskommen. Geändert und funktioniert. Man war die Fehlersuche schwer.
Bei direkter Bitmanipulation muß man eben verdammt aufpassen.
Dazu gelernt hab wie man selbst Bits zwangsweise ändert.
Der Sonntagabend ist gerettet.
Jetzt muß ich den Rest nur wieder in den richtigen Zustand bringen.
gesehen hat man es immer. Ich ja auch. Nur richtig wahr genommen hat man es nicht.
Fremden Code zu lesen, zu verstehen und wissen was richtig und was falsch läuft ist immer schwer. Da ziehe ich vor allen die das können, Dich eingeschlossen, meinen Hut. Von solchen Experten gibts ja mehrere im Forum.
Es war ja schon eine Hilfe zu wissen das der gesamte RTC Zugriff an sich sozusagen fehlerfrei war. Bis auf die Kleinigkeiten, die zum Glück keine negative Wirkung hatten.
Am Ende war mir klar gewurden, es muß mit dem lesen oder schreiben mit der RTC zu tun haben. Nur was und wie war die Frage gewesen.