Hi
Ich habe derzeit eine struct die bisher 4 Byte groß ist, sich aber
später verdoppeln bis vervierfachen wird. Außerdem wird diese so 30 mal
benötigt.
16 * 30 = 480 Byte -> für den Mega8 verkraftbar, aber da diese alle
Konstant sind, wäre es doch viel besser sie in den Flash zu verlagern.
Da habe ich aber ein Problem: Ich habe eine Methode die die Struct
initialisiert und die Werte setzt, aber wie mache ich das direkt, ich
kann ja nicht die werte erst auf dem µC schreiben.
Das ist die Struct:
1
typedefstruct
2
{
3
uint16_ttime;
4
uint16_tbonus;
5
}Game;
Muss ich das auslesen über Pointer machen, oder gibts da ein Trick wie
man direkt Structs aus dem Flash lesen kann?
Samuel K. schrieb:> Danke, das funktioniert. Kannst du mir auch sagen wie ich da noch ein> Array reinpacke und initialisiere? Denn wenn ich einfach>
1
>uint16_t*MeinArray;
2
>
Das ist aber kein Array.
Das ist ein Pointer!
Du kannst natürlich diesen Pointer auch dazu benutzen, ihn auf ein
Array, welches seinerseits im Flash liegt, zeigen zu lassen.
Dann musst du mittels pgm_readword zuerst den Pointer aus dem Flash
holen und den dann mit den notwendigen Offsets dazu benutzen um die
eigentlichen Daten zu lesen. Ist ein 2-stufiger Prozess, aber machbar.
Da kommen aber 3 Warnungen, außerdem funktioniert mein Programm nur
halber. Ich wollte jetzt nur wissen, ob das obrige stimmt, und ich den
Fehler im rest des Progs suchen muss.
Das sind die Warnungen:
222 D:\Projekte\Atmega\Chessclock\Dev\chess.c [Warning] suggest
parentheses around comparison in operand of &
224 D:\Projekte\Atmega\Chessclock\Dev\chess.c [Warning] initialization
makes pointer from integer without a cast
225 D:\Projekte\Atmega\Chessclock\Dev\chess.c [Warning] assignment makes
pointer from integer without a cast
Samuel K. schrieb:> uint16_t *ptr = pgm_read_word(&(Games[modi].data)); //Zeile 224> temp.data = *ptr; //Zeile 225
Wieso * ?
ptr ist bereits die Adresse im Flash an der die Daten stehen.
Wenn du an die eigentlichen Array-Daten heranwillst, dann musst du
diesen Pointer seinerseits wieder in eine pgm_read_ ... Funktion
stecken.
> Da kommen aber 3 Warnungen,
dann geh sie der Reihe nach durch, lies die Warnung, denk darüber nach
was dir der COmpiler sagen will und korrigiere entsprechend.
> halber. Ich wollte jetzt nur wissen, ob das obrige stimmt,
das kommt drauf an, wie du temp.data weiter benutzt.
> 222 D:\Projekte\Atmega\Chessclock\Dev\chess.c [Warning] suggest> parentheses around comparison in operand of &
Da gehts um die Abfrage im if
* bist du sicher, dass du ein & haben willst
oder doch eher ein &&
> 224 D:\Projekte\Atmega\Chessclock\Dev\chess.c [Warning] initialization> makes pointer from integer without a cast
Rechts vom = steht ein INteger (nämlich das Ergebnis von pgm_read_word),
rechts steht eine Pointer Variable. Ohne casting ist so etwas illegal.
Man kann nicht einfach einem Pointer eine Zahl zuweisen
> 225 D:\Projekte\Atmega\Chessclock\Dev\chess.c [Warning] assignment makes> pointer from integer without a cast
Dasselbe in Grün, wobei ich mir ziemlich sicher bin, das du das so
eigentlich gar nicht willst.
Danke, ich hab nicht drangedacht das data ja ein pointer ist. Deswegen
wollte ich den Wert zuweisen.
Ich kann das doch einfach korriegieren indem ich *temp.data schreibe.
Die IF Abfrage ist so beabsichtigt, die soll nämlich die letzten 3 Bytes
rauspicken. Die sagen nämlich wie groß das Array ist. die IF prüft nur
ob im Array Elemente sind. Wenn die letzten 3 Bytes 0 sind, ist data =
0. Das hab ich von http://visual-c.itags.org/visual-c-c++/280042/. Das
hab ich dann (hoffentlich richtig) für das splitten in 5 und 3 Bytes
umgeändert.
Samuel K. schrieb:> Ich kann das doch einfach korriegieren indem ich *temp.data schreibe.
Nein.
data ist ein Pointer ins Flash!
Um an die Werte zu kommen, musst du pgm_read_xxxx benutzen!
> Die IF Abfrage ist so beabsichtigt, die soll nämlich die letzten 3 Bytes> rauspicken.
Bytes?
> Die sagen nämlich wie groß das Array ist. die IF prüft nur> ob im Array Elemente sind. Wenn die letzten 3 Bytes 0 sind, ist data => 0. Das hab ich von http://visual-c.itags.org/visual-c-c++/280042/. Das> hab ich dann (hoffentlich richtig) für das splitten in 5 und 3 Bytes> umgeändert.
Mir ist absolut nicht klar, was du da eigentlich machen willst. Ich
denke aber nicht, das dein Code das macht, was du eigentlich machzen
möchtest. Es ist immer gefährlich Code, den man nicht versteht einfach
so zu übernehmen.
Aber auf jeden Fall
if((temp.options << 5) & 0x1F > 0)
Dir ist klar, dass > eine höhere 'Wertigkeit' hat als & ?
Der COmpiler sieht das daher als
if((temp.options << 5) & (0x1F > 0))
und ich denke nicht, das du das haben willst.
heißen, oder stimmt das auch nicht.
EDIT: Sorry ich war z langsam um das zu kapieren.
Karl heinz Buchegger schrieb:> if((temp.options << 5) & (0x1F > 0))>> und ich denke nicht, das du das haben willst.
Nein, möchte ich nicht. Danke für dne Hinweis.
Das Option Byte gibt in den ersten 5 Bit versch. Optionen an. Der
restlichen 3 Bit geben die Größe des Arrays an. Übrigens hab ich den
Code ohne das > 0 in einem Interpreter getestet.
> heißen, oder stimmt das auch nicht.
Der * da vorne sieht unlogisch aus.
> Nein, möchte ich nicht. Danke für dne Hinweis.>> Das Option Byte gibt in den ersten 5 Bit versch. Optionen an. Der> restlichen 3 Bit geben die Größe des Arrays an. Übrigens hab ich den> Code ohne das > 0 in einem Interpreter getestet.
Ohne den tatsächlichen Vergleich > 0 ändert sich auch die Interpretation
Wenn ich aber das jetzt so schreibe kommen wieder diese Warnungen.
Irgendwie versteh ich das nicht.
224 D:\Projekte\Atmega\Chessclock\Dev\chess.c [Warning] initialization
makes pointer from integer without a cast
225 D:\Projekte\Atmega\Chessclock\Dev\chess.c [Warning] assignment makes
pointer from integer without a cast
1
uint16_t*ptr=pgm_read_word(&(Games[modi].data));
2
temp.data=pgm_read_word(ptr);
Ich habe vorher nicht wirklich gesagt was ich mit dem Code vorhabe: Ich
möchte mit dem Code den Teil vom Flash in den Ram kopieren, so benötige
ich nur den Speicherplatz der Struct Game.
Samuel K. schrieb:> Wenn ich aber das jetzt so schreibe kommen wieder diese Warnungen.> Irgendwie versteh ich das nicht.>
Was gibt es daran nicht zu verstehen?
Welchen Datentyp hast du links vom =
Welchen Datentyp hast du rechts vom =
Rechts vom = steht ein Integer (nämlich das Ergebnis von pgm_read_word),
rechts steht eine Pointer Variable. Ohne casting ist so etwas illegal.
Man kann nicht einfach einer Pointer Variablen eine Zahl zuweisen.
Das ist ein Datentypproblem! Du versuchst einer Pointervariablen einen
Nichtpointerzuzuweisen. Und das geht nun mal nicht einfach so.
temp.data = (uint16_t*)pgm_read_word(&(Games[modi].data));
Samuel K. schrieb:> Um das Zeug dann in den Ram zu kopieren, muss ich dann doch jedes elemnt> lesen und den Zeiger dem Temp.data zuweisen, oder ?
Welches Zeugs?
Die Array Daten?
Ja, das musst du. Aber erst mal brauchst du den Pointer darauf.
Und du brauchst Speicher, an dem du die Array Daten ablegst. Woher weißt
du wie groß das Array werden wird?
Daher: Es ist eventuell nicht so schlau, das komplette Array in den SRAM
zu kopieren. Hol dir in der Verarbeitung des Arrays das jeweils
benötigte Array Element aus dem Flash. Damit umgehst du eine Menge
Probleme.
Karl heinz Buchegger schrieb:> Hol dir in der Verarbeitung des Arrays das jeweils> benötigte Array Element aus dem Flash.
Das ganze wird ja eine Schachuhr. Problem: Es gibt voreingespielte
Zeit-Modi und Manuelle. Deswegen wird die Zeit erst in den Ram kopiert,
damit sie da beim manuellen Modus noch verändert werden kann. Die
Methode GetGame (in C eher funktion) soll einfach ein Game im Ram
anlegen und den gewünschten Zeitmodi vom Flash darauf kopieren. Das
Array wird höchtens 7 * 16bit groß, da man nur 3bits zur Größenangabe
hat.
Also ich muss:
1. Zeiger aus dem Flash lesen, der auf das Flash-Array zeigt und das
ganze zu einem Zeiger casten:
2. Die einzelnen Einträge im Array auslesen damit sie im Ram sind und
die Adresse vom ersten Eintrag speichern
1
uint16_tvalue[7];
2
for(inti=0;i<((temp.options<<5)&0x1F);i++)
3
{
4
value[i]=pgm_read_word(ptr+2*i);
5
if(i==0)
6
temp.data=(uint16_t*)&value;
7
}
8
returntemp;
3. Über temp.data müsste man dann auf das Array zugreifen können.
MAn könnte das auch besser mit malloc machen, aber damit hab ich noch
nie was gemacht.
Stimmt das so?
@shift
Danke, habs jetzt auch gemerkt.
Ich denke es muss (x << 5) & 224 heißen. bzw. 0xE0 in Hexa
Außerdem muss irgendwas gewaltig falsch sein: Wenn ich game_mode = 1
nehme, ist die Zeit vom 1. Spieler witklich game_mode = 1 und die vom
zweiten game_mode = 2.
irgendwo muss da ein Zeiger erhöht werden, so dass er dann auf den
nächsten Modi zeigt. Oder ich übersehe wiedermal einen Fehler den jeder
auf Anhieb sieht ;)
Samuel K. schrieb:> irgendwo muss da ein Zeiger erhöht werden, so dass er dann auf den> nächsten Modi zeigt. Oder ich übersehe wiedermal einen Fehler den jeder> auf Anhieb sieht ;)
Tu dir selbst einen Gefallen und verwende konstant dimensionierte
Arrays.
1
structgame{
2
uint16_tmember1;
3
uint16_tmember2;
4
uint16_tused_entries;
5
uint8_tarray[30];
6
};
7
8
structgameGames[]PROGMEM={
9
10
{5,8,3,{10,20,30}},
11
{0,1,5,{1,2,3,4,5}},
12
};
Da Dynamik reinzubringen lohnt nicht (Flash hast du genug) und im SRAM
mit dynamischer Allokierung rumzumurksen noch viel weniger.
Du bist noch nicht soweit um da mit Verpointerungen komplexere
Datenstrukturen aufzubauen. Ganz abgesehen lohnt das nicht wegen 7
Integer. Da kostet dich die Verwaltung mehr, als du mit dynamisch
verpointerten Arrays sparen kannst.
PS: Zum Einlesen aus dem Flash baust du dir eine pgm_read_block Funktion
nach dem Vorbild der sinngemäß gleichnamigen eeprom Funktion. Du willst
das so benutzen
Hör auf zu künsteln, wenn du nicht verstehst was das da macht.
Schreibs konventionell. Die paar Bytes für einen anständigen uint8_t
Zähler hast du allemal. Du brauchst da nicht in einem options Feld 3
Bits zu belegen.
OK, ich gebe mich für den Anfang geschlagen, aber sobald ich das Projekt
fertig hab würde ich es lieber so umändern wie ich es angefangen habe.
Das ich nicht soweit bin kann schon sein, ist schließlich mein 1.
größeres Projekt. Ich hab davor immer auf dem PC programmiert und musst
bis auf einmal nie Speicherplatz sparen.
Ja es sind 7 Words, wo von aber von den 30 Einträge durschnittlich ein
halber genutzt wird. 6.5 30 2 = 390 Byte einsparung. Nicht viel,
aber dazu kommt später noch ein Array gleicher Größe aber mit Bytes. ->
390 + 6.5 * 30 = 585 Byte. Immerhin 1/16 des Mega8.
Also ich würde mich freuen wenn es mir einmal anhand eines Beispiels
zeigen würde, wie es geht. Es muss nicht mal auf mein Projekt
abgerichtet sein.
Außerdem wundere ich mich immernoch, warum auf der Player2 Anzeige, wenn
ich game_mode 1 einstelle, gamemode 2 angezeigt wird.
Samuel K. schrieb:> Ja es sind 7 Words, wo von aber von den 30 Einträge durschnittlich ein> halber genutzt wird. 6.5 30 2 = 390 Byte einsparung. Nicht viel,> aber dazu kommt später noch ein Array gleicher Größe aber mit Bytes. ->> 390 + 6.5 * 30 = 585 Byte. Immerhin 1/16 des Mega8.
Du kriegst von Atmel kein Geld für nicht benutzten Speicher zurück.
Wenn du die Sache mit der Bitextraktion aus dem options Feld richtig
gemacht hättest, hätt ich mich breit schlagen lassen. Aber so ist das
momentan sinnlos. Da eröffnen wir einen Mehrfrontenkrieg, den du noch
nicht gewinnen kannst.
Der Schlüssel: mal dir die Situation auf Papier auf.
Ja, ich habe den verwechselt das die bits von rechts beginnen es muss
natürlich & 7 heißen.
Was heißt eigentlich das:
250 D:\Projekte\Atmega\Chessclock\Dev\chess.c invalid type argument of
'unary *' (have 'int')
Das kommt bei deinem Code.
Samuel K. schrieb:> 250 D:\Projekte\Atmega\Chessclock\Dev\chess.c invalid type argument of> 'unary *' (have 'int')
Ich hab jetzt die Codestelle nicht rausgesucht.
Aber schaun wir mal, ob wir das auch nicht so klären können.
unary *
Was ist ein 'unary *'
Da geht es offenbar um den Operator *
Normalerweise bezeichnet der eine Multiplikation.
a * b
und weil da links und rechts vom Operator jeweils ein Operand steht,
also 2 Operanden vorhanden sind, bezeichnet man ihn als 'binary *'. Ein
unary * ist das Gegenteil davon: Da hat der * nur 1 Operanden.
Das ganze ist wie bei -
j = a - b; das ist ein binary -
j = -a; hier handelt es sich um ein unary -
Wo kann ein unary * überhaupt vorkommen?
Na, bei der Dereferenzierung eines Pointers.
i = *Ptr;
i erhält den Wert, auf den Ptr zeigt.
da ist ein unary * im Spiel. Und klarerweise muss Ptr auch ein Pointer
Datentyp sein.
i = *5;
ergibt keinen Sinn. 5 ist ein int und kein Pointer. Einen int kann man
nicht dereferenzieren.
Nochmal zurück zur Fehlermeldung
invalid type argument of 'unary *' (have 'int')
Aha. unary * wird falsch verwendet. Wir wissen das er nur auf einen
Pointer angewendet werden kann. Der Compiler gibt noch einen Hinweis:
have int.
Anstelle eines Pointer Datentyps wurde also ein integer Datentyp
angegeben.
Nach dem Vorgeplänkel sehen wir uns den Code an:
Man beachte auch, wie jetzt plötzlich auch die Datentypen bei der
Initialisierung von destPtr und SrcPtr übereinstimmen. Rechts vom =
steht ein Ausdruck der einen Pointer ergibt, links vom = steht eine
Variable, die ein Pointer ist.
Danke, es funktioniert jetzt.
Karl heinz Buchegger schrieb:> Du kriegst von Atmel kein Geld für nicht benutzten Speicher zurück.
Das schon, aber ehrlich gesagt hab ich auch keine Lust am Ende evl.
jedes Byte rauszukürzen um das Programm fertigzustellen.