H.Joachim Seifert schrieb:
> Idee: die Parameter als Konstanten im flash abzulegen und diese alle am
> Stück und nicht verstreut im Programmcode, noch dazu verhackstückelt im
> Befehl:
>
1 | > flash unsigned int DEAD_TIME_VALUE=DEAD_TIME/8;
|
2 | > flash unsigned int START_UP_DELAY_VALUE=START_UP_DELAY/16;
|
3 | >
|
> Macht der Compiler (CodeVision) aber nicht, unabhängig von irgendwelchen
> Optimierungsstufen. Assemblercode bleibt der gleiche, ist je auch
> effektiver (schneller und kürzer) - nur möchte ich dies ausnahmsweise
> nicht.
> Liegt das an meinem Compiler (bzw. machen andere das anders)?
> Lösungsmöglichkeiten?
Vorab:
Wenn ich dich richtig verstehe, dann möchtest du ihm die Möglichkeit
geben, direkt im Flash die Werte zu ändern. Dieses Vorgehen finde ich
eher zweifelhaft, denn eigentlich ist das ganz genau der Grund, warum
man ein EEPROM mit hat. Aber seis drum, es geh ums Prinzip:
Was passiert den in deinen Ursprungsfällen?
Was da passiert, nennt man Constant Folding. D.h. Der Compiler kennt ja
die Werte der konstanten Variablen, und weil er weiß, dass diese
konstant sind, kann er selbstverständlich deren Werte überall dort
benutzen, wo er sonst einen Variablenzugriff machen müsste.
Daraus folgt sofort eine Strategie, wie du den Compiler da aushebeln
kannst. Verstecke die tatsächlichen Werte vor ihm, und er kann kein
Constant Folding mehr betreiben.
Wie kannst du das machen?
Ganz einfach: Wenn der Compiler nur Deklarationen und keine Definitionen
der Konstanten sieht, dann weiß er zwar, dass es diese Konstanten gibt,
nur bringt ihm das nix, weil er deren Werte nicht kennt
constants.c
1 | #define DEAD_TIME 200
|
2 | #define DEAD_TIME_VALUE DEAD_TIME/8
|
3 |
|
4 | flash unsigned int DEAD_TIME_VALUE = DEAD_TIME/8;
|
5 | flash unsigned int START_UP_DELAY_VALUE = START_UP_DELAY/16;
|
constants.h
1 | extern flash unsigned int DEAD_TIME_VALUE;
|
2 | extern flash unsigned int START_UP_DELAY_VALUE;
|
main.c
1 | #include "constants.h"
|
2 |
|
3 | int main()
|
4 | {
|
5 | ....
|
6 | OCR0A = DEAD_TIME_VALUE;
|
7 |
|
8 | ....
|
9 | }
|
Jetzt hat der Compiler keine andere Wahl. Er muss für DEAD_TIME_VALUE
und START_UP_DELAY_VALUE Platz im Flash reservieren und für eine
Intialisierung mit den entsprechenden Werten sorgen.
Sagte ich schon, dass ich von derartigen Vorgehensweisen "Wir patchen
die Werte direkt im Speicher" nicht viel halte? Setz ihm wenigstens eine
Entwicklungsumgebung so auf, dass er die Werte direkt im Header-File
ändert und dann auf 'make' clickt (oder was auch immer benutzt wird) und
dann kriegt er ein neu zu flashendes Programm. Denn das wäre nicht das
erste mal, dass das tatsächlich laufende Programm mit dem was in Source
Form vorliegt nicht übereinstimmt, was dann regelmässig zu Katzenjammer
führt, wenn er sich den µC ruiniert und die Patchung nicht dokumentiert
wurde (was sie mit Sicherheit nicht wird, dass kann ich dir jetzt schon
sagen)
Warum ignorierst du eigentlich die weltweit übliche Konvention (und das
dürfte so ziemlich die einzige Konvention sein, an die sich tatsächlich
99% aller C-Programmierer halten), nach der Namen in Grossbuchstaben
ausschliesslich für Makros reserviert sind, und umgekehrt Makronamen
ausschliesslich in Grossbuchstaben geschrieben werden, sodass man beim
Code lesen, wenn man auf einen Namen in Grossbuchstaben trifft, sofort
mit Sicherheit weiß, dass es sich dabei um ein Makro handelt?
Diese Konvention hat einen triftigen Grund, weil gerade Makros, die als
Funktionsersatz dienen, gefährlich sind. Es ist daher im eigentlich
Source Code u.U lebenswichtig zu wissen, ob etwas eine echte Funktion
oder ein Makro ist. Ein
1 | #define MIN(x,y) ((x)<(y) ? (x) : (y))
|
darf ich nun mal nicht so ...
1 | int main()
|
2 | {
|
3 | int i = 5; j = 8, k;
|
4 |
|
5 | k = MIN( i++, j++ );
|
... benutzen. D.h. ich 'darf' natürlich schon, nur sind die Ergebnisse
nicht die, die man naiv erwarten würde. k kriegt den Wert 7 und nicht 6,
wie man beim unbedarften Drüberlesen erwarten würde.
Aber da MIN in Grossbuchstaben geschrieben ist und ich mich an die
Konvention halte, weiß ich, das das ein Makro ist und dass ich
vorsichtig sein muss.
Während ich bei ...
1 | int main()
|
2 | {
|
3 | int i = 5; j = 8, k;
|
4 |
|
5 | k = min( i++, j++ );
|
... keinerlei Hemmungen zu haben brauche. min ist nicht groß
geschrieben, daher kein Makro sondern eine Funktion. Ich darf es als
nach Herzenslust benutzen, wie ich will.
Das funktioniert aber nur, wenn du dich an die Konvention hältst:
Makronamen in Grossbuchstaben und Namen in Grossbuchstaben
aussschliesslich nur für Makros.