Array aus SD Karte laden

Gast #1707574
Lesenswert?

Hallo,

folgendes Problem:

Ich würde gerne ein Kennfeld aus einer Text-Datei in ein Array laden.

Ich verwende einen ATmega32 und programmiere mit AVR Studio/GGC

Das Kennfeld ist in der Textdatei besteht aus einer variablen Anzahl aus 
Stützstellen, z.B.:

(0;300) (500;200) (1000;300) ...

Das erste Element ist einen Drehzahl, das Zweite das dazugehörige 
Moment.

Das einlesen der Werte ist soweit kein Problem. Ich weiß nur nicht wie 
ich sie in ein Array ablegen kann, da die Anzahl der Wertepaar variabel 
ist.

Vielleicht kann mir da jemand weiterhelfen.


Gruß
Georg
#1707575
Lesenswert?

Georg schrieb:

> Das einlesen der Werte ist soweit kein Problem. Ich weiß nur nicht wie
> ich sie in ein Array ablegen kann, da die Anzahl der Wertepaar variabel
> ist.

Daran solltest du arbeiten:
Die darf zwar im File variabel sein, im Mega32 willst du aber ein fix 
dimensioniertes Feld haben. Du musst daher das Feld mit einer Größe 
anlegen, so dass du auf jeden Fall durchkommen wirst.

Natürlich gibt es auch Möglichkeiten, wie man sich Arrays dynamisch 
wachsen lassen kann. Auf einem Mega32 ist das allerdings nicht sinnvoll. 
Die Verwaltung des ganzen kostet dir mehr, als wie wenn du einfach den 
freien Speicher komplett in das Array steckst. Und wenn der freie 
Speicher aus ist, dann ist er aus. Da geht dann nichts mehr. Dann schon 
lieber soviel wie möglich in das Array investieren, als 10% vom speicher 
für die Verwaltung von dynamisch allokiertem Speicher zu reservieren.
#1707599
Lesenswert?

generell:

kommt auf die Auswertung an, wenn du mehr werte einlesen musst, als du 
speicher hast, z.b. den Mittelwert über 50 werte (vor und nach dem 
aktuell) rechnen willst, mach zwei buffer mit je 100 werten..


wenns nur um ein paar wenige werte geht, den maximalwert reservieren 
(wie schon vorgeschlagen)

oder in deinem fall z.b. Fix 101 werte.. (0%-100%) und jeden der 100ert 
werte durch z.b interpolieren ermitteln..) dann wäre nachherige zugriffe 
einfacher (einheitlicher)
Gast #1708530
Lesenswert?

Alles klar, benutze jetzt eine feste Anzahl an Werten.

Hab gerade noch ein anderes Problem und zwar werden Zeiche wie '(' oder 
'[' nicht erkannt.

z.B.
1
if(strcmp(buffer,'['){
2
 ...
3
}

Hier wird nicht in die if-Struktur gesprungen, auch wenn in der 
Textdatei das entsprechende Zeichen vorhanden ist. In buffer steht 
jeweils ein eingelesenes Zeichen aus der Text-Datei.

Ander Zeichen werden gefunden

z.B.

if(strcmp(buffer,'a'){
...
}

... funktioniert.


Jemand eine Idee woran das liegen könnte?
#1708537
Lesenswert?

Georg schrieb:
> Alles klar, benutze jetzt eine feste Anzahl an Werten.
>
> Hab gerade noch ein anderes Problem und zwar werden Zeiche wie '(' oder
> '[' nicht erkannt.
>
> z.B.
>
1
> 
2
> if(strcmp(buffer,'['){
3
>  ...
4
> }
5
> 
6
>


Schmeiss dein C-Buch weg, und kauf dir ein neues. Deines taugt nichts, 
wenn es dir den Unterschied zwischen '[' und "[" und damit den 
Unterschied zwischen einem einzelnem Zeichen und einem String nicht klar 
macht.

> Jemand eine Idee woran das liegen könnte?

Könnte es sein, dass du gar kein C Buch hast?
Betsell dir am besten heute noch eines bei Amazon (oder einem sonstigen 
Buchhandel deiner Wahl). In der Zwischenzeit kannst du mit der 
Minimal-Kurzfassung aus der FAQ zum Thema "Strings" vorlieb nehmen.
http://www.mikrocontroller.net/articles/FAQ#Wie_funktioniert_String-Verarbeitung_in_C.3F
(Da gibt es einen Absatz der rot hervorgehoben ist. Wie gemünzt für 
deine Situation)

Und setz den Warning-Level deines Compilers wieder auf ein vernünftiges 
Mass hoch. Deine Version hätte nie ungestraft durch den Compiler gehen 
dürfen.

> if(strcmp(buffer,'a'){
> ...
> }
>
> ... funktioniert.

Zitat: Das glaub ich nicht, Tim.
Gast #1709027
Lesenswert?

Ja, ich denke die Stringterminierung war's.

Ich habe den buffer so deklariert
1
buffer[1]

da ich ja immer ein Zeichen einlese.

Da ich ja nun die FAQs gelesen habe,
;-)

 weiß ich, dass ein String ja immer auch aus einer 'Endmarkierung' 
besteht.

Nun habe ich den buffer so deklariert:
1
buffer[2]

Nun funktioniert es. Danke für den Hinweis!

Gruß
Georg

PS: Ich hoff ich hab das auch richtig erkannt und keinen totalen Mist 
erzählt. ;-)
#1709030
Lesenswert?

Georg schrieb:
> Ja, ich denke die Stringterminierung war's.
>
> Ich habe den buffer so deklariert
>
>
1
buffer[1]
>
> da ich ja immer ein Zeichen einlese.

... stellt sich die Frage, warum du dann überhaupt auf Strings setzt?
Einzelne Character zu bearbeiten geht einfacher und schneller

Aber ich seh schon: Du willst deinen Code nicht herzeigen, auf das man 
dir ein paar Techniken und Verfahren zeigen könnte, die dir das Leben 
einfacher machen könnten.
Gast #1709042
Lesenswert?

Hier der Code:
1
#define TORQUE 0
2
#define REV 1
3

4
char ReadBuffer[2];
5
char mapBuffer[6];
6
uint16_t map[50][2];
7
uint8_t map_index;
8
uint8_t byte_count=0;
9

10

11

12
void get_map(void){
13
  do{
14
    byte_count=Fread(ReadBuffer,1);
15
      if(byte_count!=1)break;
16
                        if(strcmp(ReadBuffer,"[")==0){
17
        mapBuffer[0] = '\0';
18
        do{
19
          byte_count=Fread(ReadBuffer,1);
20
          if(byte_count!=1)break;
21
          if(strcmp(ReadBuffer,";")==0)break;
22
          strcat(mapBuffer,ReadBuffer);
23
        }while(1);
24
        map[map_index][TORQUE]=atoi(mapBuffer);
25
        mapBuffer[0] = '\0';
26
        do{
27
          byte_count=Fread(ReadBuffer,1);
28
          if(byte_count!=1)break;
29
          if(strcmp(ReadBuffer,"]")==0)break;
30
          strcat(mapBuffer,ReadBuffer);
31
        }while(1);
32
        map[map_index][REV]=atoi(mapBuffer);
33
        }
34
        map_index++;
35
  }while(1);
36

37
}
#1709058
Lesenswert?

Du arbeitest gefährlich! Die strcat an mapBuffer sind alle nicht 
abgesichert. Mit einer Falscheingabe kannst du dein Programm ganz leicht 
-> BUMM!

Definiere dir char Arrays mit denen du auf Strings gehst nicht so auf 
knirsch! Lass dir ein wenig Platz um zumindest kleinere Fehler auffangen 
zu können.

Arbeite mit sizeof um Arraygrenzen zu prüfen, das mindeste sind aber ein 
paar #define um Arraygrößen festzulegen und dann mit diesen #define die 
Bereichsgrenzen im Programm zu prüfen.

Fread erwartet von dir lediglich die Adresse eines Speichers, an dem es 
die von dir vorgegebene Anzahl an Zeichen ablegen kann. Da du sowieso 
nur 1 Zeichen haben willst, kannst du ihm auch die Adresse eines char 
übergeben, in welches Fread das Zeichen reingibt. Dann brauchst du nicht 
die teuren Funktionen strcat, strcmp zur Weiterverarbeitung benutzen.

Wenns leicht geht, rechne auch immer damit, dass die Eingaben Fehler 
enthalten. Ein Leerzeichen da ein Tabulator dort. Schreib den Code nach 
Möglichkeit so, dass dir die nicht in die Quere kommen.
1
#define TORQUE 0
2
#define REV 1
3

4
#define MAP_SIZE 50
5

6
char ReadBuffer
7
char mapBuffer[6];
8
uint16_t map[MAP_SIZE][2];
9
uint8_t map_index;
10
uint8_t byte_count = 0;
11
uint8_t nextMap = 0;
12

13
void get_map(void)
14
{
15
  while( Fread( &ReadBuffer, 1 ) != -1 ) {
16

17
    if( ReadBuffer == '[' ) {
18

19
      nextMap = 0;
20
      while( Fread( &ReadBuffer, 1 ) != -1 ) {
21

22
        if( ReadBuffer == ';' )
23
          break;
24

25
        if( nextMap < sizeof( mapBuffer ) - 1 )
26
          mapBuffer[ nextMap++ ] = ReadBuffer;
27
      }
28
      mapBuffer[ nextMap ] = '\0';
29
      if( map_index < MAP_SIZE )
30
        map[map_index][TORQUE] = atoi( mapBuffer );
31

32
      nextMap = 0;
33
      while( Fread( &ReadBuffer, 1 ) != -1 ) {
34

35
        if( ReadBuffer == ']' )
36
          break;
37

38
        if( nextMap < sizeof( mapBuffer ) - 1 )
39
          mapBuffer[ nextMap++ ] = ReadBuffer;
40
      }
41
      mapBuffer[ nextMap ] = '\0';
42
      if( map_index < MAP_SIZE )
43
        map[map_index][REV] = atoi( mapBuffer );
44
    }
45
    map_index++;
46
  }
47
}

In dieser Funktion kommt der Code um eine Zahl einzulesen 2 mal vor. 
Wäre ein Kandidat um in eine Funktion ausgelagert zu werden. Der 
Codegröße und der Übersicht von get_map würde das zu Gute kommen. Oder 
hast du bemerkt, dass auch jedes Leerezeichen zwischen den Klammern 
ebenfalls den map_index um 1 erhöht. Ich habs auch nicht gesehen, ehe 
ich refakturiert habe
1
uint16_t get_number( char Terminator )
2
{
3
  uint8_t i = 0;
4

5
  while( Fread( &ReadBuffer, 1 ) != -1 ) {
6

7
    if( ReadBuffer == Terminator )
8
       break;
9

10
    if( i < sizeof( mapBuffer ) - 1 )
11
      mapBuffer[ i++ ] = ReadBuffer;
12
  }
13
  mapBuffer[ i ] = '\0';
14

15
  return atoi( mapBuffer );
16
}
17

18
void get_map(void)
19
{
20
  uint16_t torque;
21
  uint16_t rev;
22

23
  while( Fread( &ReadBuffer, 1 ) != -1 ) {
24

25
    if( ReadBuffer == '[' ) {
26
     
27
      torque = get_number( ';' );
28
      rev    = get_number( ']' );
29

30
      if( map_index < MAP_SIZE ) {
31
        map[map_index][TORQUE] = torque;
32
        map[map_index][REV]    = rev;
33

34
        map_index++;
35
      }
36
    }
37
  }
38
}
Gast #1709208
Lesenswert?

Du könntest auch einen ganz anderen Ansatz nehmen: Gib dem 
Microcontroller eine Binärdatei. Mach die Umwandlung von Text- in 
Binärdatei offline. Dann kannst du eine Skriptsprache deiner Wahl 
nehmen, mit der sich einfach Texte parsen lassen. Syntaxfehler erkennst 
du schon beim konvertieren, brauchst dich im Microcontroller nicht mehr 
drum kümmern. Und der Code im Microcontroller wird kleiner+schneller.
Gast #1709593
Lesenswert?

@Karl heinz Buchegger
Danke für die vielen Tipps, hab es so umgesetzt. Werde noch versuchen 
möglichst viele Fehleingaben abzufangen.

@sebastians
Danke für den Vorschlag. Finde es aber recht gut, einfach in eine 
Textdatei schreiben zu können.


Gruß
Georg

PS. Wie kommt es eigentlich zu der Kompiler-Warnung:
warning: pointer targets in passing argument 1 of 'Fread' differ in 
signedness
Gast #1709628
Lesenswert?

Ja, natürlich, so ist es.

Warum eigentlich
1
  while( Fread( &ReadBuffer, 1 ) != -1 ) {

sollte es nicht
1
  while( Fread( &ReadBuffer, 1 ) != 0 ) {


heißen?

Zumindest bleibt das Prog. in der Funktion get_map hängen.
#1709690
Lesenswert?

Mein Fehler
Durch deine dichte Schreibweise
1
    byte_count=Fread(ReadBuffer,1);
2
      if(byte_count!=1)break;
hab ich ein Minus gesehen, wo keines ist

Bau dir doch Leerzeichen ein. Das kostet dir nichts! Seit du 6 Jahre alt 
bist, hast du dein Gehirm darauf trainiert, dass beim Lesen dort wo ein 
Leerraum ist, ein neues Wort anfängt. Benutze dieses Training! Dann kann 
man auch Programmtext 'im ganzen Satz' lesen ohne erst mit den Augen vor 
und rück durch den Buchstabensalat zu müssen um rauszufinden wo etwas 
anfängt und wo es wieder aufhört.
1
    byte_count = Fread( ReadBuffer, 1 );
2
      if( byte_count != 1 )
3
        break;

Die Absicht ist daher:
Aus der Schleife raus, wenn Fread nicht 1 Zeichen lesen konnte. Die 
Schleife soll also laufen, solange Fread 1 Zeichen lesen kann
1
    while( Fread( &ReadBuffer, 1 ) == 1 ) {

(kommt an anderen Stellen auch noch vor)
Gast #1709706
Lesenswert?

Alles klar. Werde in Zukunft versuchen, übersichtlicher zu 
programmieren.

Noch mal zu der signed-warnung.

Ich benutze die Funktionen atoi() und Fread() ja jeweils mit der 
Variablen ReadBuffer. Fread() möchte einen unsigned char-Pointer und 
atoi einen char-Pointer.

Ich bekommen also bei einem der Funktionsaufrufe immer die 
signed-Warning.

Wie bekomme ich die nun weg?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren