Forum: Mikrocontroller und Digitale Elektronik Array wird nicht kleiner, obwohl in Funktion definiert


von Johannes A. (jan007)


Lesenswert?

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.

von Joe F. (easylife)


Lesenswert?

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.

von Johannes A. (jan007)


Lesenswert?

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. ;)

von Joe F. (easylife)


Lesenswert?

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

von Peter II (Gast)


Lesenswert?

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.

von Johannes A. (jan007)


Lesenswert?

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.

von Johannes A. (jan007)


Lesenswert?

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.

von Peter II (Gast)


Lesenswert?

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)

von Johannes A. (jan007)


Lesenswert?

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.

von Johannes A. (jan007)


Lesenswert?

Ja klar, genau das ist das Problem.
Wird der Stack nicht aufgeräumt?

von Peter II (Gast)


Lesenswert?

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.

von Joe F. (easylife)


Lesenswert?

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... ;-)

von Johannes A. (jan007)


Lesenswert?

@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.

von Peter II (Gast)


Lesenswert?

Johannes A. schrieb:
> memset(addresses, 0, sizeof( addresses) );

mache mal

memset( &addresses, 0, sizeof( addresses) );

von Peter II (Gast)


Lesenswert?

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.

von Joe F. (easylife)


Lesenswert?

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).

von Johannes A. (jan007)


Lesenswert?

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.

von Peter II (Gast)


Lesenswert?

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.

von Joe F. (easylife)


Lesenswert?

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... ;-)

von Peter II (Gast)


Lesenswert?

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.

von Johannes A. (jan007)


Lesenswert?

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?

von Peter II (Gast)


Lesenswert?

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.

von Johannes A. (jan007)


Lesenswert?

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.

von Dirk B. (dirkb2)


Lesenswert?

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
Noch kein Account? Hier anmelden.