Ich experimantiere gerade mit den 1Wire Sensoren DS18x20 rum.
Hier ein Auszug aus dem Programm (vieles aus dem Forum zusammengeklaut
;) ):
/**
* Liest die Adressen alle Sensoren aus und gibt sie zurück
*/
void scan_bus(uint8_t addresses[MAX_SENSORS][8]) {
uint8_t id[8], diff;
uint8_t i = 0, z = 0;
char s[10];
for (diff = SEARCH_FIRST; diff != LAST_DEVICE;) {
diff = w1_rom_search(diff, id);
for (z = 0; z < 8; z++) {
addresses[i][z] = id[z];
}
}
void read_temp() {
uint8_t addresses[MAX_SENSORS][8];
scan_bus(addresses);
for (z = 0; z < MAX_SENSORS; z++) {
if (!addresses[z][0]) {
break;
}
// fürs debugging mal ausgeben:
sprintf(s, "Sensor %d\t", z);
uart_puts(s);
for (uint8_t x = 0; x < 8; x++) {
sprintf(s, "%02X:", addresses[z][x]);
uart_puts(s);
}
uart_puts("\n\r");
}
}
int main {
while(1) {
read_temp();
_delay_ms(5000);
}
}
Das tut auch erst mal ABER
wenn ich am Bus einen von zwei Sensoren ziehe, steht in addresses[1]
plötzlich der Wert des ersten, erwarten würde ich aber
00:00:00:00:00:00:00:00.
Stecke ich den wieder rein, dann steht in addresses[1] wieder der
richtige Wert. Ziehe ich ihn wieder raus, na Ihr wisst schon ....
Zweite Frage:
Aus der Funktion w1_rom_search bekommme ich über uint8_t id[8] die
HardwareAdresse. Die ich dann über so eine komische for-Schleife an
addresses zuweise. Geht das nicht auch eleganter?
Ich denke an Pointer, habe ich aber nicht hin bekommen.
Ich kann mir kaum vorstellen, dass in adresses[1][] überhaupt irgendetwas anderes als zufällige Werte drin stehen. In scan_bus() wird i nicht erhöht, ist also immer 0, daher ändert sich immer nur adresses[0][]. Wozu char s[10] in scan_bus() deklariert wird bleibt auch ein Rätsel. Generell ist es ja eher so, dass so ein Scan einmalig beim Start der Hardware gemacht wird. Ob das "plug-and-play" fähig ist müsste man erstmal prüfen.
OK, Danke für den Hinweis. Die ganze Funktion ist deutlich länger
(Bus-Errors abfange usw.) Bitte am Schluss ein
i++;
einfügen. Das steht auch wirklich da. ;)
Johannes A. schrieb: > Die ganze Funktion ist deutlich länger > (Bus-Errors abfange usw.) Tja. Vermutlich muss du vor jedem Scan einen Bus-Reset durchführen. https://www.maximintegrated.com/en/app-notes/index.mvp/id/162
Johannes A. schrieb: > wenn ich am Bus einen von zwei Sensoren ziehe, steht in addresses[1] > plötzlich der Wert des ersten, erwarten würde ich aber > 00:00:00:00:00:00:00:00. warum erwartest du das? Wer soll dort die 00:00 ... reinschreiben? Du musst dir vermutlich selber merken, wie viele Device im Array gueltig sind.
Konnte ich mir nicht vorstellen, habs trotzdem getestet. Nein ein Reset ist nicht nötig. Ein Bus-Reset setzt keine Variablen zurück und wo nix ist, kannn nix antworten. Das ist ein Softwareproblem! Ich habe ein Array das nicht wieder auf Null oder leer gesetzt wird, obwohl die Funktion ja verlassen wird.
Habe gerade die Sensoren vertauscht, im Sinne von welcher gezogen wird und welcher drinn bleibt. Da die Dinge in Reihenfolge der Adressen abgefragt werden und antworten, ist es je nach Adresse so, das entweder zwei mal die gleiche ausgegeben wird, (wenn vorher der Einzelne auf [1] stand) oder sich gar nichts ändert. Debugausgaben zeigen an, das wirklich vernüftige Daten ausgelesen werden. Also nix mit fehlendem Bus-Reset oder so.
Johannes A. schrieb: > Da die Dinge in Reihenfolge der Adressen abgefragt werden und antworten, > ist es je nach Adresse so, das entweder zwei mal die gleiche ausgegeben > wird, (wenn vorher der Einzelne auf [1] stand) oder sich gar nichts > ändert. die 2. wir nicht ausgegeben, die schleife wird woher beeendet. Sie steht nur noch drin. mache doch vorher man alles leer (memset)
Das würde bedeuten, das das
uint8_t addresses[MAX_SENSORS][8];
in read_temp() nur einmal im Leben des gesamten Programms ausgeführt und
der Stack nicht aufgeräumt wird. Ist aber nicht mein Verständnis.
Sollte nicht bei jedem read_temp() die Variable neu erzeugt werden. Ich
habe sich ja nicht static oder global gemacht.
Ja klar, genau das ist das Problem. Wird der Stack nicht aufgeräumt?
mache doch einfach mal
1 | void scan_bus(uint8_t addresses[MAX_SENSORS][8]) { |
2 | |
3 | uint8_t id[8], diff; |
4 | uint8_t i = 0, z = 0; |
5 | char s[10]; |
6 | |
7 | memset(addresses, 0, sizeof( addresses) ); |
8 | for (diff = SEARCH_FIRST; diff != LAST_DEVICE;) { |
9 | diff = w1_rom_search(diff, id); |
10 | |
11 | for (z = 0; z < 8; z++) { |
12 | addresses[i][z] = id[z]; |
13 | }
|
14 | }
|
oder lass scan_bus als return die anzahl der device ausgeben.
Machs halt gleich richtig, und lasse dir von scan_bus() die Anzahl der gefundenen Devices zurückgeben
1 | int scan_bus(uint8_t addresses[MAX_SENSORS][8]) |
2 | {
|
3 | (...)
|
4 | i++; |
5 | (...)
|
6 | |
7 | return i; |
8 | }
|
9 | |
10 | |
11 | void read_temp() { |
12 | uint8_t addresses[MAX_SENSORS][8]; |
13 | int devices; |
14 | |
15 | devices = scan_bus(addresses); |
16 | |
17 | for (z = 0; z < devices; z++) { |
18 | (...)
|
19 | }
|
Dann kannst du auch
1 | if (!addresses[z][0]) { |
rausschmeissen, ist ja eh nicht zuverlässig, wenn das oberste byte der Adresse mal zufällig 0 sein sollte... Update: Peter II schrieb: > oder lass scan_bus als return die anzahl der device ausgeben. Wenn sich 2 schon so einig sind... ;-)
@Peter II Dein Vorschlag tut nicht. Nix wird genullt. Bekomme aber eine Warnmeldung vom Compiler: warning: argument to ‘sizeof’ in ‘memset’ call is the same expression as the destination; did you mean to dereference it? [-Wsizeof-pointer-memaccess] memset(addresses, 0, sizeof( addresses) ); @Peter II & @(easylife) Natürlich kann ich das so lösen, wie Ihr beide vorgeschlagen, das löst aber nicht mein Verstädnisproblem.
Johannes A. schrieb: > memset(addresses, 0, sizeof( addresses) ); mache mal memset( &addresses, 0, sizeof( addresses) );
Johannes A. schrieb: > Natürlich kann ich das so lösen, wie Ihr beide vorgeschlagen, das löst > aber nicht mein Verstädnisproblem was ist denn dein Verstädnisproblem? Wenn niemand ein Array überschreibt, bleibt der alte Inhalt erhalten.
Dein Verständnisproblem kann man natürlich auch nur ahnen. Ich denke, du gehst davon aus, dass addresses[][] irgendwo genullt werden würde. Das passiert aber im günstigsten Fall nur bei Programmstart (wovon man übrigens nicht ausgehen sollte). scan_bus() überschreibt einfach nur Werte im Array, das in read_temp() deklariert wurde. Beim erneuten Aufruf von scan_bus() bleiben die alten Werte natürlich erhalten, weil scan_bus ja weniger Adressen ins Array schreibt (bei dir momentan 1, d.h. die 2. Adresse bleibt erhalten).
habe gerade folgendes gemacht:
in read_temp()
uart_puts("Init addresses[MAX_SENSORS][8] ...\t");
uint8_t addresses[MAX_SENSORS][8];
uart_puts("Init addresses[MAX_SENSORS][8] fertig\n\r");
Es wird wirklich uint8_t addresses[MAX_SENSORS][8]; jede mal neu
ausgeführt. Offensichtlich werden aber Arrays im Ggs. zu anderen
Variablen NICHT aufgeräumt bzw. ausgenullt. Bei int usw. soll das ja
angeblich gemacht werden. C ist ne komische Sprache, oder ich hab was
nicht verstanden.
Johannes A. schrieb: > Es wird wirklich uint8_t addresses[MAX_SENSORS][8]; jede mal neu > ausgeführt. das ist überhaupt kein Befehl der ausgeführt werden kann. Es ist eine Anweisung auf dem Stack platz für ein paar Byte einzurichten. Dabei wird überhaupt nicht genullt. Dann müsste man schon
1 | uint8_t addresses[MAX_SENSORS][8] = {0}; |
schreiben.
Johannes A. schrieb: > C ist ne komische Sprache, oder ich hab was > nicht verstanden. letzteres.
1 | uint8_t addresses[MAX_SENSORS][8]; |
wird nicht ausgeführt, sondern reserviert Speicher. Der Aufruf scan_bus(addresses) übergibt dann einen Pointer auf diesen Speicherbereich an scan_bus(); In C wird speicher nie automatisch initialisiert. Auch andere Variablen nicht. Manche Compiler machen das zwar, davon darf man aber nicht ausgehen. Update: ich halte mich jetzt hier raus, das ist ja beängstigend, wie Peter und ich im Mintentakt das gleiche sagen... ;-)
Joe F. schrieb: > In C wird speicher nie automatisch initialisiert. Auch andere Variablen > nicht. doch, nur nicht bei lokalen Variablen. Globale werden immer initialisiert. > Manche Compiler machen das zwar, davon darf man aber nicht ausgehen. es ist genau definiert, was initialisiert werden muss und was nicht.
uint8_t addresses[MAX_SENSORS][8] = {{0}};
hat das Problem gelöst.
Scheinbar habe ich das falsch verstanden.
Allerdings:
void test_var() {
uint8_t z;
char s[10];
z++;
sprintf(s, "%d\n\r", z);
uart_puts(s);
}
von main periodisch aufgerufen, bringt immer 1
schreibe ich static uint8_t z dann wird der Wert hochgezählt.
Offenischtlich handhabt das der avr-gcc unterschiedlich.
Bekommen aber bei compilieren den Hinweis
In function ‘test_var’:
warning: ‘z’ is used uninitialized in this function
Damit gestehe icvh meinen Denkfehler ein ;)
Vielen Dank für Eure Mühe und Geduld mit mir!!!
Hat jemand vielleicht noch ein Lösung für meine zweite Frage oben?
Johannes A. schrieb: > von main periodisch aufgerufen, bringt immer 1 > schreibe ich static uint8_t z dann wird der Wert hochgezählt. > Offenischtlich handhabt das der avr-gcc unterschiedlich. nein macht er nicht. Es steht nur zufällig eine 0 drin. Das ganze ist abhängig vom Stack-Inhalt. (um genau zu sein, wird z vermutlich nur ein Register sein, wo zufällig eine 0 drin steht). Darauf verlassen kann man sich auf keine Fall.
Ja Peter, das habe ich schon so verstanden, das das Zufall / Compiler abhängig ist. Entweder ist das beobachtete so wie Du sagst oder der avr-gcc hilft hier nach. Unsauber ist es allemal, deswegem auch das waring der Compilers.
Johannes A. schrieb: > Entweder ist das beobachtete so wie Du sagst oder der > avr-gcc hilft hier nach. Du kannst durch Beobachten nicht auf das Verhalten von C schließen. Der Standard lässt einige Dinge offen, bzw überlässt das den Compilerherstellern. Die können sich aber schon bei einer anderern Optimierungsstufe anders ausgelegt weerden.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.