mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Array im RAM - Zugriff auf nicht genutzte Bits


Autor: Großes Fragezeichen (112)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo allerseits,

mal eine Frage bezüglich Datenloggern.
Es sollen eine Menge Daten in einem Array aufgenommen werden. Dieses 
muss wohl, da die Daten durch 10bit AD-Wandlung gewonnen werden, 
Fächergrößen von 16 Bit haben, also uint16_t.


Erzeugen würde ich es durch folgenden Code:

#define SPEICHERGROSSE 1000

uint16_t *Speicher;

uint16_t* Speicher_init()
{
Speicher = (uint16_t*) malloc(SPEICHERGROSSE* sizeof(uint16_t));
return *Speicher;
}


Ist es möglich, die übrigen 6 leeren Bits später dann noch zu belegen?


Außerdem noch eine weitere Frage:
Das Array soll Daten im RAM-Speicher aufnehmen. Das bedeutet doch, dass 
ich es zwangsläufig erst zur Laufzeit mittels malloc erzeugen darf, und 
ich nicht zu Beginn ein schön großes fixes Array anlegen kann, oder?

Autor: Pfff (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Ist es möglich, die übrigen 6 leeren Bits später dann noch zu belegen?

Ja.

> Das bedeutet doch, dass ich es zwangsläufig erst zur Laufzeit mittels >malloc 
erzeugen darf

Nein.

Autor: wonko (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie stellst Du Dir das vor ?
Ich würde eher die Gesamtgrösse verkleinern : ceil (1000 *16 /10)
Und dann mit Modulo und Rest die benötigten bits aus den, dann meistens 
zwei uint16_t Werten herausmaskieren und verschieben.

Du benötigst natürlich dann für lesen und schreiben in das array 
funktionen die die adresse und Wert entsprechend übersetzten.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Großes Fragezeichen schrieb:

> ich es zwangsläufig erst zur Laufzeit mittels malloc erzeugen darf, und
> ich nicht zu Beginn ein schön großes fixes Array anlegen kann, oder?

Doch, genau das willst du tun: Ein schönes großes fixes Array benutzen.

Denn: Du hast nur den Speicher den du hast. Da hilft dir auch malloc 
nichts. Maximal kriegst du also vom malloc auch nur den Speicher, den du 
in ein großes fixes Array buttern könntest.

Im besten Fall.

Im schlimmsten Fall kriegst du nämlich weniger, nämlich dann wenn der 
Speicher durch mehrere malloc fragmentiert ist. Und dann erhebt sich 
natürlich noch die Frage, was soll denn der Datenlogger machen, wenn er 
vom malloc keinen Speicher mehr kriegt? Da ist es besser für fixe 
Verhältnisse zu sorgen. Du dimensionierst dein Array auf 1000 Elemente 
und wenn die als ganzes in den Speicher passen, dann hast du auch 1000 
Elemente.

Autor: BlabLa (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

also zu deiner ersten Frage, ja es wäre noch möglich die restlichen 6 
Bit zu belegen, aber dafür muss man ein wenig mehr aufwand betreiben.
Kannst ja mal Google mit dem Stichwort Bitmaskierung bemühen.

Ich weiss jetzt nicht wie der Speicher genau von einem Mikrocontroller 
verwaltet wird, aber den dynamischen Speicher nimmt man in der Regel 
wenn man dyanmischen Speicher brauch.
Also wenn immer die selbe Menge an Daten anfallen oder dieser stark 
begrenzt ist nimm einen statischen Speicher.

Als kleinen leckerbissen kann ich dir noch eine Funktion geben die ich 
mal geschrieben hatte. Sie funktionierte unter Visual Studio 6.0 wie es 
auf einem Mikrocontroller aussieht weiss ich nicht, kannst es ja mal 
versuchen.
Ich möchte noch drauf hinweisen das in dieser Funktion mächtig getrickst 
wurde und man es normalerweise so nicht macht ;-)

// erstellen und verändern eines 1 Dimensionalen Arrays
void* onedimmem(void *array,int size)
{
   void *arraytemp;

   // Freigeben des reservierten Speichers
   if(size==0)
   {
      free(array);
      return NULL;
   }

   arraytemp = (void *)realloc(array,size);
   if(arraytemp == NULL)
   {
      printf("Die Zuweisung des Speicherplatzes war nicht 
erfolgreich\n");
      free(array);
      return NULL;;
   }
   array = arraytemp;

   return array;
}

Aufruf zum beispiel so:

*pressure = NULL; //Deklaration

pressure=(double*)onedimmem(pressure,3 * sizeof(double)); //speicher 
anlegen

pressure=(double*)onedimmem(pressure,6 * sizeof(double)); //Grösse 
verändern, der Vorteil bei dieser Methode ist das der Speicherinhalt 
bestehen bleibt

pressure=(double*)onedimmem(pressure,0); //Speicher Freigeben

Hoffe dir ein wenig geholfen zu haben.

Gruß
BlabLa

Autor: BlabLa (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bei der Deklaration fehlt ein Double vor dem Variablen namen, also
double *pressure = NULL; //Deklaration

Gruß
BlabLa

Autor: besucher (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Im schlimmsten Fall kriegst du nämlich weniger, nämlich dann wenn der
> Speicher durch mehrere malloc fragmentiert ist.

Das ist etwas missverständlich formuliert.

Wenn du 1.000 Elemente anforderst, kriegst du die entweder komplett oder 
du kriegst garnichts (malloc retourniert 0). Dass du weniger als 1.000 
Elemente bekommst - weil malloc vielleicht nur 389 Elemente 
zusammenkratzen konnte - das wird nicht passieren.

Und wenn doch, dann ist es keine Standard-C-Lib.

Autor: swarner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

verwende doch einfach Bit fields in einem struct. Mit dem struct kannst 
dann ein Array anlegen, und den 10 bit member dereferenzieren. Die 
restlichen 6 bits definierst Du entweder als anonym, oder belegst es 
gleich mit nem Namen - wie mit den 10 bits vorher.

also etwa:
struct sTest
{
    uint16_t  adc : 10;
    uint8_t   rest:  6;
};

struct sTest saArray[32];

zum Zugreifen dann:
b = saArray[n].adc



Siehe
http://en.wikipedia.org/wiki/C_syntax#Bit_fields

Mfg

Sascha Warner

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
swarner schrieb:

> verwende doch einfach Bit fields in einem struct. Mit dem struct kannst
> dann ein Array anlegen, und den 10 bit member dereferenzieren. Die
> restlichen 6 bits definierst Du entweder als anonym, oder belegst es
> gleich mit nem Namen - wie mit den 10 bits vorher.

Das musst du mir jetzt erklären.
Was versprichst du dir davon?
Damit kriegst du in 1000 Array Elemente doch wieder nur 1000 Datensätze 
unter.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
besucher schrieb:
> Karl heinz Buchegger schrieb:
>> Im schlimmsten Fall kriegst du nämlich weniger, nämlich dann wenn der
>> Speicher durch mehrere malloc fragmentiert ist.
>
> Das ist etwas missverständlich formuliert.

In der Tat.
Danke für die Klarstellung

Autor: swarner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du bekommst nur 1000 Datensaetze unter, kannst aber den .rest noch fuer 
was anderes verwenden, auch wenns nur 6 Bit sind. mit einer speziellen 
"Accessor" Funktion kannst da allerdings noch etwas dran rumbasteln, und 
8 bits reinmappen (in entsprechend mehrere aufeinanderfolgende 
Arrayindizes). Das struct machts halt etwas einfacher auf die Elemente 
zuzugreifen. Das ist alles :)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
swarner schrieb:
> Du bekommst nur 1000 Datensaetze unter, kannst aber den .rest noch fuer
> was anderes verwenden, auch wenns nur 6 Bit sind.

Im Prinzip ja.
Aber der TO hat ja nicht das Problem, dass er noch Zusatzinfo mit 
abspeichern muss.

> mit einer speziellen
> "Accessor" Funktion kannst da allerdings noch etwas dran rumbasteln, und
> 8 bits reinmappen (in entsprechend mehrere aufeinanderfolgende
> Arrayindizes). Das struct machts halt etwas einfacher auf die Elemente
> zuzugreifen. Das ist alles :)

In dem Fall, in dem du die 10 Bit aufeinanderfolgend ablegen willst, 
macht es die struct nicht wirklich einfacher. Eher komplizierter.

Autor: swarner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry,

ich dachte, es ginge darum, die restlichen 6 Bits doch noch fuer 
irgendwas nutzen zu koennen.

Autor: Großes Fragezeichen (112)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ok, erstmal sortieren...

es ist also für mein Programm egal, ob ich schreibe:

uint16_t *Speicher;
uint16_t* Speicher_init()
{
Speicher = (uint16_t*) malloc(100*sizeof(uint16_t));
return *Speicher;
}

oder ob ich direkt folgendes tue:

uint16_t Speicher[100];

Richtig ???



In beiden Varianten würde ich es ja durch eine Funktion der Art

for(int i=0; i<100; i++)
{
Speicher[i]=ADC_Messung();
}

beschreiben... ist es dann in beiden Varianten der RAM-Speicher, der 
gefüllt wird, obwohl der Mikrokontroller in Variante zwei fixen Speicher 
reserviert?

mfg

Autor: Huch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>obwohl der Mikrokontroller in Variante zwei fixen Speicher reserviert?
Nein. In beiden Varianten wird Speicher im RAM reserviert.
Kein "fixer" Speicher. Damit könnte man sinngemäß etwa Speicher im 
EEPROM oder Programmspeicher bezeichnen. Das aber ist hier nicht der 
Fall.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Großes Fragezeichen schrieb:
> ok, erstmal sortieren...
>
> es ist also für mein Programm egal, ob ich schreibe:
>
> uint16_t *Speicher;
> uint16_t* Speicher_init()
> {
> Speicher = (uint16_t*) malloc(100*sizeof(uint16_t));
> return *Speicher;
> }
>
> oder ob ich direkt folgendes tue:
>
> uint16_t Speicher[100];
>
> Richtig ???

richtig.
mit dem malloc riskierst du lediglich unvorhergesehen Probleme.
Durch die statische Definition taucht der Platzbedarf für das Array in 
der Speicherstatistik des Compilers auf und du kannst abschätzen, ob du 
den Platz im Speicher überhaupt noch hast. Mit dem malloc weißt du 
nichts dergleichen. Da bügelst du dir einfach über den Stack drüber, 
ohne den geringsten Anhaltspunkt zu haben, warum dein Programm Amok 
läuft.

> gefüllt wird, obwohl der Mikrokontroller in Variante zwei fixen Speicher
> reserviert?

In der Verwendung besteht kein Unterschied.

Autor: Norbert (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Warum nicht das Naheliegendste?

Jeweils 4 Meßwerte entgegen nehmen (und in fünf unsigned char 
speichern).

Von jedem der vier Meßwert die unteren 8 Bits in vier aufeinander 
folgende unsigned char speichern.
Die jeweils oberen 2 Bit der vier Meßwerte schieben und in das fünfte 
unsigned char speichern.

Fertig und jedes Bit genutzt!

Autor: Bastelmaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kann man das eventuel auch so mit struct machen?
struct sTest
{
    uint16_t  adc0 : 10;
    uint16_t  adc1 : 10;
    uint16_t  adc2 : 10;
    uint16_t  adc3 : 10;
};

struct sTest saArray[250];

Autor: Sam .. (sam1994)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bastelmaus schrieb:
> Kann man das eventuel auch so mit struct machen?struct sTest
> {
>     uint16_t  adc0 : 10;
>     uint16_t  adc1 : 10;
>     uint16_t  adc2 : 10;
>     uint16_t  adc3 : 10;
> };
>
> struct sTest saArray[250];

Da wären ja bei jedem uin16 6bits nicht genutzt.

Ich würde es wie einer da oben machen:

struct ADC_DATA
{
    uint8_t data[5]; //Hier sind eigentlich nur 4 Werte gespeichert
    void SetData(uint8_t index, uint16_t data);
    uint16_t GetData(uint8_t index);
};

Das ist sogar relativ konfortabel.


Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich finde ebenfalls Norberts Idee stark.
Um spezielle Zugriffsfunktionen kommt man sowieso nicht rum. Aber 
Norberts Idee garantiert dir, dass du zumindest an das Low-Byte ohne 
Bitgefummel rankommst.

Bitstrkturen.
Da ist nur sehr wenig vorgegeben und der Compiler hat viele Freiheiten. 
Nicht vergessen sollte ausserdem, dass Bitfelder auch nur 'syntaktischer 
Zucker sind'. D.h. die C-Syntax sieht sauber aus. Unter der Haube muss 
der Prozessor aber nach wie vor das ganze Bitgefummel machen.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.