Forum: Mikrocontroller und Digitale Elektronik Atmega128: Werte vom Poti speichern


von Stefan M. (ronaldonho)


Lesenswert?

Hallo,

Ich möchte die Werte dich erzeuge mit dem Poti speichern und auf dem 
Display darstellen. Mit diesem Programm habe kann ich die Werte erzeugen 
und mit dem Poti am Mikrocontroller kann ich die Werte ändern.

int adcresult;
ADMUX = channel;
ADCSR = (ADCSR | 0b00000111);
ADCSR = ADCSR & ~(1<<ADFR);
ADCSR = ADCSR | (1<<ADEN);
ADCSR = ADCSR | (1<<ADSC);
while(ADCSR & (1<<ADSC));
adcresult = ADCL;
adcresult = adcresult | (ADCH<<8);
return(adcresult);

Jetzt möchte ich die Werte die erzeugt werden zwischenspeichern in einem 
Array. So das ich später darauf zugreifen kann. Wie kann ich das am 
einfachsten machen?

für Tipps oder Lösungen wäre ich sehr dankbar.
Danke Lg

von Egonwalter M. (heiner1234)


Lesenswert?

Hallo

1. Wieviele Werte willst Du speichern?
2. Wie oft soll gespeichert werden (zeitlich oder nach festgelegter 
Wertänderung)?

Zum Speichern mit array - am sinnvollsten wäre wohl ein Ringpuffer (der 
älteste Wert wird überschrieben)...

von Stefan M. (ronaldonho)


Lesenswert?

Hallo danke für deine Antwort.

1.) Ich möchte 100 einzelne Werte Speichern. Beim erreichen diesen 
Wertes, sollen die ersten Werte wieder überspringen werden.

2.) nach festgelegter Wert Änderung. Also ich bekomme ja vom ADC 
konstant Werte, den zeitlichen Abstand weiß ich nicht.

Der Ringpuffer hört sich sehr gut an, da der älteste Wert überschrieben 
Wird. Mir fällt jetzt aber keine Funktion ein, wo bei jeder Wertänderung 
ein Wert in den Array gespeichert wird.

Vllt. kannst du mir mehr davon erzählen

Danke

von HildeK (Gast)


Lesenswert?

Stefan M. schrieb:
> Mir fällt jetzt aber keine Funktion ein, wo bei jeder Wertänderung
> ein Wert in den Array gespeichert wird.

if (wert != alter_wert) speichere
alter_wert = wert ;

Stefan M. schrieb:
> adcresult = ADCL;
> adcresult = adcresult | (ADCH<<8);

Warum nicht
 adcresult = ADC;
oder gleich
 return (ADC);
ganz ohne die Variable 'adcresult'.

von Dietrich L. (dietrichl)


Lesenswert?

Stefan M. schrieb:
> wo bei jeder Wertänderung

Dabei solltest du berücksichtigen, dass du dazu noch etwas 
Datenaufbereitung brauchst. Nur ein ein Vergleich "letzter Wert mit 
aktuellem Wert" ist blöd: das niederstwertige Bit kann immer togglen, 
außerdem musst du mit Rauschen und Störungen rechnen.
Also brauchst du ein Filter und/oder einen Schwellwert.

von Stefan M. (ronaldonho)


Lesenswert?

Jetzt wo ihr es sagt, den alten Wert mit dem neuen Wert zu vergleichen 
ist doch nicht so ideal, da ich hier tatsächlich Rauschen haben und die 
Werte auch trotzdem speichern will, wenn sich der Wert nicht ändert. Die 
Werte kommen ja vom Adc Clock mit einer bestimmten Frequenz und wenn ich 
den Poti nicht drehe ändert sich der Wert auch nicht. Heißt das dann 
doch das ich die Werte zeitlich speichern muss oder wie läuft das genau 
ab?

von Jonas B. (jibi)


Lesenswert?

Ich wette die nächste Frage wird sein, "Wie kann ich wert aus Ringpuffer 
auslesen?".

Beschreibe mal dein Problem, anstatt deine Lösung zu beschreiben. Was 
willst du machen?

: Bearbeitet durch User
von Egonwalter M. (heiner1234)


Lesenswert?

Hallo

Die Funktion eines Ringpuffers ist Dir klar, nehme ich an (ein Element 
zeigt auf das nächste..)

Du musst also einen Ringpuffer mit 100 Elementen anlegen mittels einer 
Struktur:
1
#define NUMMER 100
2
3
struct Element {
4
    uint8_t zaehl;        /* Nummer des Elements */
5
    int adc_wert;                /* hier wird der ADC-Wert gespeichert*/
6
    struct Element *next;       /* Pointer auf sich selbst...*/
7
};
8
9
typedef struct Element element;
10
11
/*dann den Puffer erzeugen mit:*/
12
13
/* - - - hier werden NUMMER Elemente des Ringpuffers erzeugt - - - */
14
element *ring_erz(element *root) {
15
    element *New;
16
    uint8_t nummer;
17
    uint8_t i;
18
19
    nummer = 0;
20
    for(i = 0; i < NUMMER; i++) {
21
        New = (element *)malloc(sizeof(element)*1);        
22
        nummer++;
23
        New->zaehl = nummer;            /* "0" => leer!! */
24
        if(root == NULL) {
25
            New->next = New;  /* zeigt auf sich selbst, wenn es noch kein Element gibt */
26
            root = New;
27
        } else {
28
            New->next = root->next;                 /* New->next zeigt dahin, wohin root->next zeigt */
29
            root->next = New;                       /* root-> next zeigt auf das neue Element */
30
        }
31
    }
32
    return(New);
33
}

in der main:
1
 element *rptr = NULL;
2
    rptr = ring_erz(rptr);                      /* erzeugen des RingPuffers */

und dann den ADC Wert in die Array-Zelle schreiben und den 
"Schreibzeiger um 1 weiterzaehlen...

mfg

Heiner

von Jonas B. (jibi)


Lesenswert?

>Die Funktion eines Ringpuffers ist Dir klar, nehme ich an (ein Element
>zeigt auf das nächste..)

Das erwartest du von jemand der auf ein Array nicht "zugreifen" kann?
Ich glaub das geht schief.

von HildeK (Gast)


Lesenswert?

Stefan M. schrieb:
> Jetzt wo ihr es sagt, den alten Wert mit dem neuen Wert zu vergleichen
> ist doch nicht so ideal, da ich hier tatsächlich Rauschen haben und die
> Werte auch trotzdem speichern will, wenn sich der Wert nicht ändert.
Einen hast du ja schon gespeichert, nur die Folgewerte, die (fast) 
gleich sind, sollen dann nicht gespeichert werden.

Du kannst ja z.B. vier Messungen nacheinander machen, die Werte 
addieren, +2 zum Runden und durch 4 wieder teilen. Das ist schon mal ein 
einfaches Filter.
Dann kann man in vielen µCs noch den ADC-Power-Down verwenden, um 
Eigenstörungen zu reduzieren.
Man kann auch auf eine Änderung < epsilon abfragen und wenn wahr, das 
als 'gleich' ansehen. Das ergibt allerdings eine reduzierte Auflösung.
Lass einfach ein wenig Phantasie walten und überlege, welche 
Werteänderungen tatsächlich relevant sind und welche durch Rauschen 
verursacht wurden ...

von HildeK (Gast)


Lesenswert?

Egonwalter M. schrieb:
> Die Funktion eines Ringpuffers ist Dir klar,

Ich mache meine Ringpuffer immer wesentlich einfacher.
Auf die Stelle des Schreibzeigers schreiben, increment Zeiger, bei 
Überlauf wieder auf Null setzen. Der Schreibzeiger ist einfach ein 
uint8_t (bei 100 Werten).
Sind zwei, drei Zeilen Code.

von Egonwalter M. (heiner1234)


Lesenswert?

HildeK schrieb:
> Egonwalter M. schrieb:
>> Die Funktion eines Ringpuffers ist Dir klar,
>
> Ich mache meine Ringpuffer immer wesentlich einfacher.
> Auf die Stelle des Schreibzeigers schreiben, increment Zeiger, bei
> Überlauf wieder auf Null setzen. Der Schreibzeiger ist einfach ein
> uint8_t (bei 100 Werten).
> Sind zwei, drei Zeilen Code.

Hmmm.... Ja und? Mein Schreibzeiger zahl ist auch ein uint8_t ...

Zeig' doch mal Deinen Code ;-))

edit: Eigentlich benötigt man die Variable "zahl" in der Struktur nicht 
(verkettete Liste, die einen Ring bildet; der Strukturpointer next zeigt 
auf das nächste Element)

: Bearbeitet durch User
von Egonwalter M. (heiner1234)


Lesenswert?

Hallo Stefan M

Am einfachsten dürfte es dennoch sein, wenn Du einen INT-Array mit 100 
Werten definierst, z.B

int adc_val[100]

und diesen dann mit den ADC Werten füllst - wenn der ADC Wert eine von 
Dir definierte Grenze überschritten hat, speicherst Du den Wert im 
Array:
adc_val[0] = gemessener ADC Wert, dann zählst Du den Array-Index um 1 
weiter usw...; wenn Du beim max. Array-Index (99!!!) bist, fängst Du 
wieder bei 0 an.
Ganz einfach; ebenso geht das Auslesen

Achja wenn Du den ADC Wert speicherst - das muss eine atomare Operation 
sein, kann sonst durch Interrupt verfälscht werden ...

: Bearbeitet durch User
von HildeK (Gast)


Lesenswert?

Egonwalter M. schrieb:
> Zeig' doch mal Deinen Code ;-))
1
    temp[i] = adc_value;  // Wert in Ringpuffer merken
2
    i = (i+1)%BUF_LEN;
BUF_LEN ist die Dimension vom Array 'temp'.

von Egonwalter M. (heiner1234)


Lesenswert?

HildeK schrieb:
> Egonwalter M. schrieb:
>> Zeig' doch mal Deinen Code ;-))
>
1
>     temp[i] = adc_value;  // Wert in Ringpuffer merken
2
>     i = (i+1)%BUF_LEN;
3
>
> BUF_LEN ist die Dimension vom Array 'temp'.
1
if((++i) == BUF_LEN)i = 0;

würde genauso gehen - viele Wege führen nach Rom

von HildeK (Gast)


Lesenswert?

Egonwalter M. schrieb:
> würde genauso gehen - viele Wege führen nach Rom

Ja, und je nach Compiler gibt das sogar effizienter compilierten Code.
Der Modulooperator muss nämlich mehr können und auch noch was anderes 
und legt den Code dafür an, auch wenn er in dem Kontext nicht gebraucht 
wird.
Aber er ist sehr anschaulich.
Selbst das hier ist schneller als '%':
1
// am verständlichsten (und das wären dann mit der Ringpufferzuweisung drei Zeile:
2
  i++;
3
  if (i==BUFF_LEN) i=0;
4
5
// oder auch:
6
  i++;
7
  i = (i == BUFF_LEN ) ? 0 : i;

Ja, viele Wege führen nach Rom.
Und auch aus Verständnisgründen habe ich die Increments immer gerne 
extra.
Ein einigermaßen guter Compiler macht das selbe daraus.

Nur deiner oben schien mir etwas ausufernd. Vielleicht habe ich auch 
einfach andere beabsichtigte Funktionen in deinem Code nicht verstanden 
😀

von Egonwalter M. (heiner1234)


Lesenswert?

HildeK schrieb:

> Nur deiner oben schien mir etwas ausufernd. Vielleicht habe ich auch
> einfach andere beabsichtigte Funktionen in deinem Code nicht verstanden
> 😀

Ja, der oben aufgeführte Code mit der Struktur und dem Ringpuffer 
anlegen ist für die Zwecke des TO "over the top" und für den TO eh' 
nicht zielführend (besser Array anlegen usw).

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.