Forum: Mikrocontroller und Digitale Elektronik C Array - neuen Wert in Array aufnehmen und die Werte zuvor nach rechts schieben


von Nitram E. (slexx)


Lesenswert?

Guten morgen,

ich bin gerade dabei einen ersten Bargraph auf den TFT zu bringen.
So soll es werden.
Aller 15 Sekunden wird die Temperatur gemessen und in "int TempLesen" 
übergeben und gleichzeitig in das Array "byte Temp[10];" auf das erste 
Element "Temp[0]; übergeben. ABER, vorher sollen die Werte alle um eine 
Stelle nach Rechts verschoben werden.

Also z.b so:

vor dem schieben  Temp[] = 12,14,15,17,20
nach dem schieben Temp[] = 11,12,14,15,17 neu ist die 11 und die 20 soll 
wegfallen!

Das ganze hatte ich mir so überlegt:
1
byte Sekunde;
2
byte TempRead;
3
4
setup..
5
loop...
6
7
if(Sekunde==15 || Sekunde==30|| Sekunde==45 || Sekunde==0)
8
{
9
  .
10
  .
11
  .
12
  Temp[4]= Temp[3];
13
  Temp[3]= Temp[2];
14
  Temp[2]= Temp[1];
15
  Temp[1]= Temp[0];
16
  Temp[0]= TempRead;
17
}

Das Problem ist aber, dass das ganze Array mit der gleichen Zahl 
beschrieben wird!
Jetzt habe ich gegooglt und finde paar Sachen mit einer for-schleife 
aber so richtig schlau werde ich dabei nicht! Vlt hat ja jemand 
Denkanstöße

von Phil J. (exloermond)


Lesenswert?

Eine Schleife ist Kosmetik.
Kann man später drüber reden.

Schau dir mal an was dein Code macht.

Du schreibst die Zahl x von Arrayposition 4 nach 3. Von 3 nach 2... usw.
Das erklärt dein Ergebnis.
Allerdings sollte an Position 0 dann wirklich deine ausgelesene 
Temperatur stehen.

: Bearbeitet durch User
von Der Andere (Gast)


Lesenswert?

Martin T. schrieb:
> if(Sekunde==15 || Sekunde==30|| Sekunde==45 || Sekunde==0)

Du bist sicher, dass die Schleife pro Sekunde nur einmal durchlaufen 
wird?

Martin T. schrieb:
> Temp[4]= Temp[3];
>   Temp[3]= Temp[2];
>   Temp[2]= Temp[1];
>   Temp[1]= Temp[0];
>   Temp[0]= TempRead;

Der Fehler liegt in dem Teil des Codes den du nicht gepostet hast.

Die klassische Lösung für dein Problem wäre ein Ringpuffer.

von Dirk B. (dirkb2)


Lesenswert?

Dann zeig doch mal den fehlerhaften Code.

Zu Testzwecken kannst du ja mal Temp[0]= Sekunde; schreiben, denn die 
scheint sich ja zu ändern.

Schau dir mal einen Ringbuffer an.

von Nitram E. (slexx)


Lesenswert?

Phil J. schrieb:
> Eine Schleife ist Kosmetik.
> Kann man später drüber reden.
>
> Schau dir mal an was dein Code macht.
>
> Du schreibst die Zahl x von Arrayposition 4 nach 3. Von 3 nach 2... usw.
> Das erklärt dein Ergebnis.
> Allerdings sollte an Position 0 dann wirklich deine ausgelesene
> Temperatur stehen.

Hmmm...hab ich nen Denkfehler?
Wert[5] übernimmt Wert[4] -> Wert[4] den Wert[3]...usw!

Und das es ja eine if Funktion ist wird das ganze nur einmal gemacht 
also müsste das doch klappen.... verstehe ich gerade nicht! :(

von Rolf M. (rmagnus)


Lesenswert?

Der Andere schrieb:
> Die klassische Lösung für dein Problem wäre ein Ringpuffer.

Ob sich der lohnt, bei 10 Bytes, die alle 15 Sekunden mal verschoben 
werden sollen?

von TM F. (p_richner)


Lesenswert?


von Dominik B. (odysseus1710)


Lesenswert?

Wie mein Vorredner schon angedeutet hat, überschreibst du deine Werte. 
Wenn du das so machen willst, musst die die Daten temporät 
zwischenspeichern, bevor du diese neu zuordnest.

Einfach geht es, wenn du das von hinten aufrollst, da ein letzter Wert 
ja wegfallen soll:
1
for(int i=4; i>0; i--){
2
  Temp[i] = Temp[i-1];
3
}
4
Temp[0] = TempRead;

von Der Andere (Gast)


Lesenswert?

Martin T. schrieb:
> loop...
>
> if(Sekunde==15 || Sekunde==30|| Sekunde==45 || Sekunde==0)
> {

Wahrscheinlich wird die "loop" Schleife mehrere 100 (1000) mal 
durchlaufen während Sekunde== 15 oder ... ist. Wenn TempRead aber nur 
einmal gesetzt wurde steht im ganzen Array dann TempRead drin.
Siehe meine Frage oben:

Der Andere schrieb:
> Du bist sicher, dass die Schleife pro Sekunde nur einmal durchlaufen
> wird?



Martin T. schrieb:
> Temp[10]

Und dein Array ist auch 11 Elemente groß? Offset 0 bis Offset 10?

von Dirk B. (dirkb2)


Lesenswert?

Martin T. schrieb:
> Und das es ja eine if Funktion ist wird das ganze nur einmal gemacht

Der Andere schrieb:
> Du bist sicher, dass die Schleife pro Sekunde nur einmal durchlaufen
> wird?

Wirklich ganz sicher? Nur einmal in der Sekunde.
Oder ist die loop Schneller und mehrere Tausend mal in einer Sekunde 
durchlaufen?

von Dirk B. (dirkb2)


Lesenswert?

Phil J. schrieb:
> Du schreibst die Zahl x von Arrayposition 4 nach 3. Von 3 nach 2... usw.
> Das erklärt dein Ergebnis.

Das ist großer Quatsch. Das Ziel steht links und die Quelle rechts.
Also wird von Position 3 nach Position 4 kopiert.

von Dominik B. (odysseus1710)


Lesenswert?

Vergiss meinen obigen Post, sehe gerade, dass du das eigentlich so 
gemacht hast - Sorry

von Der Andere (Gast)


Lesenswert?

Dominik B. schrieb:
> Einfach geht es, wenn du das von hinten aufrollst, da ein letzter Wert
> ja wegfallen soll:
> for(int i=4; i>0; i--){
>   Temp[i] = Temp[i-1];
> }
> Temp[0] = TempRead;

Ist eleganter macht aber exakt das GLeiche wie der gepostete Code.

von H.Joachim S. (crazyhorse)


Lesenswert?

if (Sekunde==0...) kann ganz schon oft wahr sein, kommt eben auf den 
Restprogramm an.

Ansonsten ist es eigentlich Quatsch, alle Variablen ständig 
rumzuschubsen. Benutz doch einfach einen Zeiger.

Temp[index++]=TempRead;
if (index >=sizeof...) index=0;

von TM F. (p_richner)


Lesenswert?

https://www.mikrocontroller.net/articles/FIFO

Hier ist alles beschrieben.

Benutze vom Standard Ringbuffer das Codebeispiel dann mache einen 
Header(fifo.h) zu diesem File wie:
1
#ifndef FIFO_H_INCLUDED
2
#define FIFO_H_INCLUDED
3
4
int8_t bufferIn(int8_t byte);
5
int8_t bufferOut(int8_t *pByte);
6
void bufferClear(int8_t index);
7
#endif // FIFO_H_INCLUDED

Danach funktioniert es.
1
// In FIFO schreiben
2
bufferIn(deineDaten);
3
// Aus FIFO lesen
4
bufferOut(&wohinduSpeichernwillst);

von Justus S. (jussa)


Lesenswert?

Martin T. schrieb:
> Und das es ja eine if Funktion ist wird das ganze nur einmal gemacht

aber auch nur, wenn die if-Abfrage auch wirklich nur einmal für jeden 
Sekundenwert aufgerufen wird, zB wenn sie nur nach einer Änderung des 
Sekundenwertes durchlaufen wird. Ansonsten wird sie ja bei 15.000s, 
15.001s, 15.002s,... aufgerufen, weil "Sekunde" ja wohl für eine ganze 
Sekunde den Wert 15 haben wird. In dieser Sekunde wird dann die ganze 
Zeit die Temperatur ausgelesen, und wenn die sich in der einen Sekunde 
nicht ändert, hast du natürlich immer denselben Wert eingelesen und in 
dem Array verschoben

von GG (Gast)


Lesenswert?

Martin T. schrieb:
> if(Sekunde==15 || Sekunde==30|| Sekunde==45 || Sekunde==0)

Wie lange braucht der Prozessor für den Verschiebe und Schreib Vorgang? 
Wenn er langsam ist, ist er nach 1/100s fertig. Und dann beginnt der 
nächste Schiebevorgang - immer wieder, bis endlich die Sekunde vorbei 
ist.

Wenn sonst nichts zu tun ist, musst du nach dem Verschieben warten, bis 
die Sekunde vergangen ist. Das ist für einen Anfänger die einfachste 
Lösung. Danach kannst du dann über Flags nachdenken.

von Nitram E. (slexx)


Lesenswert?

Erstmal danke für die ganzen Antworten :D Muss ich jetzt erstmal 
sortieren. Stimmt, daran haeb ich nicht gedacht. eine Sekunde ist zwar 1 
Sekunde aber der uC macht da weiterhin noch 10.000 Schritte.

Also wenn ich meinen Code nehme und die Schleife wirklich nur einmal 
mache dann würde das gehen oder?
Das mit dem FIFO hört sich interessant an...da muss ich mich mal mit 
auseinander setzen.

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Da wuerd' ich mal noch die funktion memmove() in den Ring schmeissen, so 
die libc das hergibt. Damit wird das ganze Geschiebe zu:
1
memmove(Temp+1,Temp,sizeof(Temp)-sizeof(Temp[0]));
2
Temp[0]= TempRead;

Gruss
WK

von Dirk B. (dirkb2)


Lesenswert?

Martin T. schrieb:
> Also wenn ich meinen Code nehme und die Schleife wirklich nur einmal
> mache dann würde das gehen oder?

Ja.

Martin T. schrieb:
> Das mit dem FIFO hört sich interessant an...da muss ich mich mal mit
> auseinander setzen.

Deinen Code kann man leicht nachvollziehen und der ist bei 5 Werten auch 
in Ordnung.

Wenn du schneller sein musst oder mehr Werte hast, kannst du die anderen 
Sachen nehmen.

Allerdings ist das jetzt gerade sehr übersichtlich um die andern 
Vorschläge zu verstehen.(ansehen und verstehen, brauchen tust du es hier 
nicht)

von MaWin (Gast)


Lesenswert?

Phil J. schrieb:
> Du schreibst die Zahl x von Arrayposition 4 nach 3. Von 3 nach 2... usw.

Na hier sind ja Profis unterwegs.

So geht es
[/c]
byte SekundeGeschoben=0;

setup..
loop...

if(Sekunde!=SekundeGeschoben && (Sekunde==15 || Sekunde==30|| 
Sekunde==45 || Sekunde==0))
{
  .
  .
  .
  Temp[4]= Temp[3];
  Temp[3]= Temp[2];
  Temp[2]= Temp[1];
  Temp[1]= Temp[0];
  Temp[0]= TempRead;
  SekundeGeschoben = Sekunde;
}
[/c]

wird das Problem lösen aber besser ist:
1
byte Temp[5];
2
byte ersteTemp=0;
3
4
// Auslesen von 5 Werten: 
5
for (i=0;i<5;i++) 
6
  Wohin= Temp[(ersteTemp+i)%5];
7
8
// Reinschreiben:
9
if(Sekunde!=SekundeGeschoben && (Sekunde==15 || Sekunde==30|| Sekunde==45 || Sekunde==0))
10
{
11
  ersteTemp=(ersteTemp+6)%5;
12
  Temp[ersteTemp]=TempRead;
13
  SekundeGeschoben = Sekunde;
14
}

von Peter D. (peda)


Lesenswert?

Wenn Du willst, daß etwas je Sekunde nur einmal gemacht wird, merke Dir 
die Sekunde:
1
{
2
  static uint8_t oldsec;
3
  if ( second != oldsec ){
4
    oldsec = second;
5
    // mache was
6
  }
7
}

von Nitram E. (slexx)


Lesenswert?

Habe es jetzt mal ausprobiert aber nicht mit einen Sensor sondern 
Seriell.
Ich denke das ist für mich die einfachste Lösung. :) Das klappt 
wunderbar und da mein Array max. 10 groß wird reichts aus.
1
byte temp[6];    //Array für die Temperaturdaten
2
byte tempRead;   //Variable zum vorspeichern 
3
4
byte stat = 2;   //Status-Variable damit die if Schleife nur einmal abläuft
5
6
void setup() 
7
{
8
  Serial.begin(19200);
9
}
10
11
void loop() 
12
{
13
   if(Serial.available())
14
  {
15
    tempRead = Serial.parseInt(); //Serielle Daten empf. und an tempRead übergeben
16
    Serial.println("Seriell Empfangen! - ");
17
    stat = 1;  //Status auf 1 setzen
18
  }
19
20
  if(stat==1)  //Wenn Status 1 dann....
21
  {
22
    stat=0;  //Status auf 0 setzen, somit wird die If-Anweisung nur einmal ausgeführt
23
    temp[5]=temp[4];
24
    temp[4]=temp[3];
25
    temp[3]=temp[2];
26
    temp[2]=temp[1];
27
    temp[1]=temp[0];
28
    temp[0]=tempRead; 
29
    Serial.print(temp[0]); Serial.print(" - ");Serial.print(temp[1]); Serial.print(" - ");
30
    Serial.print(temp[2]); Serial.print(" - ");Serial.print(temp[3]); Serial.print(" - ");
31
    Serial.print(temp[4]); Serial.print(" - ");Serial.println(temp[5]);
32
  }
33
}

: Bearbeitet durch User
von Nitram E. (slexx)


Lesenswert?

Peter D. schrieb:
> Wenn Du willst, daß etwas je Sekunde nur einmal gemacht wird, merke Dir
> die Sekunde:
>
1
> {
2
>   static uint8_t oldsec;
3
>   if ( second != oldsec ){
4
>     oldsec = second;
5
>     // mache was
6
>   }
7
> }
8
>

Ahhh dankeschön :)

von Begriffe (Gast)


Lesenswert?

Ändert an der Funktion des Programms nichts sollte man aber wissen:

>byte stat = 2;   //Status-Variable damit die if Schleife nur einmal abläuft

www.if-schleife.de

von Nitram E. (slexx)


Lesenswert?

Begriffe schrieb:
> Ändert an der Funktion des Programms nichts sollte man aber wissen:
>
>>byte stat = 2;   //Status-Variable damit die if Schleife nur einmal abläuft
>
> www.if-schleife.de

Haaahaaa....dann halt Abfrage! Jedenfalls wird diese dadurch dann nur 
einmal ABGEFRAGT!

von Falk B. (falk)


Lesenswert?

@ Rolf Magnus (rmagnus)

>> Die klassische Lösung für dein Problem wäre ein Ringpuffer.

Genau.

>Ob sich der lohnt, bei 10 Bytes, die alle 15 Sekunden mal verschoben
>werden sollen?

Ja. Erstens weil der OP dabei was lernt und 2. ist die Logik für diesen 
Ringpuffer fast schon trivial. Er braucht keine Füllstandserkennung wie 
ein FIFO, nur 2 Indizes für Schreib- und Lesezugriff und einfachste 
Modulo-Zählung. Wenn man dann die Anzeige schneller, größer, whatever 
machen will, kostet das nur wenig CPU-Last. Es gibt schon genug 
schlechte Software auf dieser Welt.

von Nitram E. (slexx)


Lesenswert?

Falk B. schrieb:
> @ Rolf Magnus (rmagnus)
>
>>> Die klassische Lösung für dein Problem wäre ein Ringpuffer.
>
> Genau.
>
>>Ob sich der lohnt, bei 10 Bytes, die alle 15 Sekunden mal verschoben
>>werden sollen?
>
> Ja. Erstens weil der OP dabei was lernt und 2. ist die Logik für diesen
> Ringpuffer fast schon trivial. Er braucht keine Füllstandserkennung wie
> ein FIFO, nur 2 Indizes für Schreib- und Lesezugriff und einfachste
> Modulo-Zählung. Wenn man dann die Anzeige schneller, größer, whatever
> machen will, kostet das nur wenig CPU-Last. Es gibt schon genug
> schlechte Software auf dieser Welt.

Hast ja auch recht damit, ich werde mich mal mit beidem beschäftigen. 
Aber für meine Zwecke ist das was ich jetzt habe völlig ausreichend. :D
Danke für die tolle Hilfe die man hier immer bekommt.

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.