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
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.
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)
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?
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.
Georg schrieb:> Sonst noch jemand einen Tipp.
Aber natürlich:
Poste kompletten Code. Auf keinen Fall aber Codeschnipsel die du
abtippst.
Dann kann man sich auch auf die Suche nach den Fehlern machen, die du
a) wirklich begangen hast
b) selber nicht siehst
Aber ich tippe mal ins Blaue:
Deine Stringterminiierung stimmt nicht.
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. ;-)
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.
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
charReadBuffer
7
charmapBuffer[6];
8
uint16_tmap[MAP_SIZE][2];
9
uint8_tmap_index;
10
uint8_tbyte_count=0;
11
uint8_tnextMap=0;
12
13
voidget_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
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.
@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
Georg schrieb:> PS. Wie kommt es eigentlich zu der Kompiler-Warnung:> warning: pointer targets in passing argument 1 of 'Fread' differ in> signedness
Schau dir den Protoypen von Fread an.
Höchst wahrscheinlich will Fread einen Pointer auf einen unsigned char
habe, du übergibst ihm aber die Adresse eines char.
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
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?
Georg schrieb:> Wie bekomme ich die nun weg?
Die kannst du an dieser Stelle getrost wegcasten. Nach dem Motto: Wir
wissen das das passt, also geben wir der Funktion was sie haben will.