Hallo
Programmiere seit einiger Zeit in C. Nun habe ich ein Problem das die C
Profis sicher leicht lösen könnten.
Ich will den Inhalt von mehreren Registerwerten immer zusammen ändern
ohne jedem den Wert einzeln zuweisen zu müssen. So sollen 3
Pegisterwerte für die PWM Ausgabe gesetzt werden. Da geht z.B. über
PDM1=PDM2=PDM3=128;. Nun will ich den Wert Incrementieren und müsste
dann jeweils einen Wert nehmen und dann den anderen zuweisen. Ist so
etwas umständlich da ja unmittelbar nach jeder Operation eine
Wertezuweisung eingebaut werden müsste.
Ich konnte keine Funktion finden die es erlaubt alle 3 Werte mit einer
Variable zu ändern, also das ich z.B. PWM++ scheiben könnte und dann
alle 3 geänderten Werte ins jeweilige Register geschrieben würde.
Müsste doch irgendwie gehen, konnte dazu bisher nichts Finden.
Ich hoffe es ist klar was ich meine.
Danke
Clerner schrieb:> Ich konnte keine Funktion finden die es erlaubt alle 3 Werte mit einer> Variable zu ändern, also das ich z.B. PWM++ scheiben könnte und dann> alle 3 geänderten Werte ins jeweilige Register geschrieben würde.
Das geht auch einfach nicht. Es gibt auf CPU Ebene keinen Befehl der das
kann. Auf C Ebene kannst du dir natürlich eine Funktion schreiben welche
einen Wert bekommt und dann 3 Variabeln ändert, aber natürlich wird das
trotzdem nacheinander passieren.
> Müsste doch irgendwie gehen
Warum denkst du das?
Clerner schrieb:> Ich konnte keine Funktion finden die es erlaubt alle 3 Werte mit einer> Variable zu ändern, also das ich z.B. PWM++ scheiben könnte und dann> alle 3 geänderten Werte ins jeweilige Register geschrieben würde.
Wenn du Ahnung von µCs hättest, wüstest du das das nicht möglich ist.
Beschäftige dich doch mal wenigstens rudimentär mit Assembler.
Rein C technisch packt man das in eine Funktion. Weniger tippen, mehr
Struktur, bessere Lesbarkeit...
Clerner schrieb:> Ich konnte keine Funktion finden die es erlaubt alle 3 Werte mit einer> Variable zu ändern
geht auch nicht auch trotz Hochsprache!! Die CPU kann immer nur ein/e
Register/Speicherzelle im RAM bearbeiten oder kannst du Bus und Auto
gleichzeitig fahren ??
Das was du meinst ist der ANSCHEIN der Verarbeitungsgeschwindigkeit der
Befehle das es so aussieht als ob die CPU es "gleichzeitig" bearbeiten
würde.
Es wird alles Stumpf hintereinander verarbeitet.
inc pwm1
inc pwm2
inc pwm3
Auch das setzen geht nur nacheinander
lade 128 ins PWM1
lade 128 ins PWM2
lade 128 ins PWM3
So erkennst du das diese Routine, die es nicht gibt, auch nicht
umsetztbar wäre...
Als Tipp CPU läuft mit 4 Mhz = 250ns wenn ein Befehl einen Takt
bräuchte.
Wie lange jetzt eine das in C braucht weiß ich leder nicht da hängt
meistens ja noch ein wenig mehr dran...
C selbst bietet solch ein Sprachmittel nicht.
Je nach uC, wäre das simultane setzen von Registerwerten evtl. dennoch
möglich, wenn man gewisse Eigenschaften der Datentypen und der
unterliegenden Maschineninstruktionen ausnutzt.
Wie genau und mit welchen Nachteilen, müsste man sich dann überlegen,
wenn man den uC kennt. Insbesondere die Wortbreite und die verfügbaren
arithmetischen Befehle sind da interessant.
chris schrieb:> Auch das setzen geht nur nacheinander>> lade 128 ins PWM1> lade 128 ins PWM2> lade 128 ins PWM3
Das die Zuweisungen nicht in einem Takt erfolgen ist schon klar, ging
mir auch nicht um die Ausführungsgeschwindigkeit.
Deshalb ist diese Unterstellung fehl am Platze:
>Wenn du Ahnung von µCs hättest, wüstest du das das nicht möglich ist.
PDM1=PDM3=PDM3=128; akzeptiert der Compiler und es Funktioniert auch,
Ziel ist es halt nicht jedesmal alle drei Zuweisungen hinschreiben zu
müssen.
Die Zuweisung in eine Funktion zu schreiben geht natürlich nur müsste
ich dann wenn ich die 'berechnete Variable' habe immer danach die
Funktion aufrufen was vom Schreiben her aufs selbe rauskommt. dachte nur
das es eine Möglichkeit gibt das zu vereinfachen.
Clerner schrieb:> Da geht z.B. über> PDM1=PDM2=PDM3=128;
Das sieht zwar lustig aus, kann aber Seiteneffekte haben und dauert am
längsten, da 2 unnötige Lesezugriffe erfolgen. Diese Schreibweise
compiliert nämlich zu:
1
PDM3=128;
2
PDM2=PDM3;
3
PDM1=PDM2;
Es gibt nur wenige Architekturen, die ein direktes MOV von IO-Registern
implementiert haben (z.B. der 8051 kann ein "MOV SFR, SFR").
Sauber macht man es daher so:
1
PDM1=128;
2
PDM2=128;
3
PDM3=128;
Exakt gleichzeitig geht natürlich nicht, da eine CPU immer sequentiell
arbeitet.
Clerner schrieb:> [...]> PDM1=PDM3=PDM3=128; akzeptiert der Compiler und es Funktioniert auch,> Ziel ist es halt nicht jedesmal alle drei Zuweisungen hinschreiben zu> müssen.> [...]
Vielleicht verstehe ich Deine Absicht nicht.
Aber es scheint mir, dass Du eine Registerwert zuweisen willst, ohne dem
Compiler zu sagen, um welches Register es sich handelt. Das geht (wenn
man keine Tricks verwendet) definitiv nicht.
Die Form, die Du da geschrieben hast, ist meines Wissens, die kürzeste
mögliche Form in reinem C - ohne Berücksichtigung der konkreten
Registeradressen und Datentypen.
Clerner schrieb:> Ziel ist es halt nicht jedesmal alle drei Zuweisungen hinschreiben zu> müssen.
Das ist theoretisch ganz einfach: du brauchst einen Compiler, der
Gedanken lesen kann.
Aber wenn du wirklich Befehle ausgeführt haben willst, die du nicht
gegeben hast, wirst du wahrscheinlich unliebsame Überraschungen erleben.
Georg
> Da geht z.B. über> PDM1=PDM2=PDM3=128;. Nun will ich den Wert Incrementieren und müsste> dann jeweils einen Wert nehmen und dann den anderen zuweisen.
und wenn du zum Incrementieren einfach
PDM1=PDM2=++PDM3;
schreibst?
... das könnte man sogar noch in 'nem Macro verstecken
#define INC_PDM() (PDM1=PDM2=++PDM3)
Ich habe etwa folgende Idee:
1. Verlagerung des Inkrements zeitlich vor das setzen der Register.
unter der Voraussetzung, daß:
a) Die CPU eine größere Wortbreite hat, als die Register breit sind
b) Die Endianess passt oder mit wenig Aufwand passend gemacht werden
kann, falls nicht ohnehin lediglich Literale verwendet werden können
c) die fraglichen Register memory mapped innerhalb der Addressweite
eines vorhanden Datentyps liegen
d) der Speicher- resp. Datenbus die notwendige Wortbreite hat
und möglicherweise
d) die CPU Arithmetik (oder möglicherweise auch Logik-Befehle) hat, die
auf dieser großen Wortbreite operieren
mit dem evtl. (und wahrscheinlichen) Nachteil, dass der gesamte Vorgang
von Inkrementieren und setzen der Register länger dauert als das
einzelne Setzen mit Peters zweiter Variante ohne Rücklesen der Register,
aber
mit dem Vorteil, dass das setzen der Register simultan erfolgt.
also etwa:
1
// seien
2
volatileuint8_tPDM1,PDM2,PDM3;// mit zur Endianess passenden auf einander folgenden Adressen
3
4
uint32_tPWM_Wert=128+128<<8+128<<16;
5
6
PWM_Wert+=1+1<<8+1<<16;
7
8
PDM1=PWM_Wert;
Das ist zugegeben dirty, sollte aber funktionieren, denke ich. (Man
müsste natürlich noch berücksichtigen, dass angrenzende Register nicht
verändert werden sollen).
Aber: Hier verlasse ich eindeutig, dass was der C-Standard aussagt und
zusagt. Das ist ein Trick - keine einfach nur kürzere Ausdrucksweise.
Danke Achim
So komme ich da weiter, es funktioniert.
Hätte ja auch selbst darauf kommen können das bei der Parameterübergabe
auch gerechnet werden kann.
Mal so gefragt:
Wenn eh alle 3 Variablen oder Register immer den gleichen Wert
beinhalten sollen, warum nimmst du nicht einfach nur 1 Variable/Register
für deine 3 PWMs?
Bzw. noch weiter gedacht: vermutlich sind ja auch dann die PWMs
identisch, und man bräuchte auch nur 1 PWM.
Clerner schrieb:> So komme ich da weiter, es funktioniert.
Ändert aber nichts daran, daß Kettenzuweisungen bad practice sind.
Ein erfahrener Programmierer benutzt sowas nicht.
Clerner schrieb:> Deshalb ist diese Unterstellung fehl am Platze:>>Wenn du Ahnung von µCs hättest, wüstest du das das nicht möglich ist.
kam nicht von mir ;)
Joe F. schrieb:> Wenn eh alle 3 Variablen oder Register immer den gleichen Wert> beinhalten sollen, warum nimmst du nicht einfach nur 1 Variable/Register> für deine 3 PWMs?>> Bzw. noch weiter gedacht: vermutlich sind ja auch dann die PWMs> identisch, und man bräuchte auch nur 1 PWM.
Die Werte sind ja Registerwerte (Variable != Register) für jeweilige PWM
DutyCycles die jeweils für eine Phase zuständig sind, der Gedanke war ja
eben mittels einer Variable diese einzustellen. Ist also für eine
blockkommutierte BLDC Ansteuerung. Somit sind nur die DutyCycles
identisch aber nicht die PWMs.
Peter D. schrieb:> Kettenzuweisungen bad practice sind.
Ja, zumindest wenn die Möglichkeit besteht, dass sie unterschiedliche
Breite haben, Volatile sind, ...
Aber sobald er Funktionen oder Defines erlaubt, geht es ja auch ohne:
Ich vermute, wir haben das eigentliche Anliegen des TO nicht erkannt
(ich zumindest überhaupt nicht!). Es ging nicht um die Kettenzuweisung,
sondern darum, nicht 3 Mal die gleichen (und irgendwann vielleicht
komplexe) Rechenvorschriften kopieren zu müssen. Und da hat er nunmal
einfach Recht.
Clerner schrieb:> Somit sind nur die DutyCycles> identisch aber nicht die PWMs.
Und somit kannst du auch für alle 3 PWMs eine gemeinsame
Variable/Register für den Duty-Cycle benutzen.
Achim S. schrieb:> nicht 3 Mal die gleichen (und irgendwann vielleicht> komplexe) Rechenvorschriften kopieren zu müssen.
Ja, das war der Hintergedanke.
Achso, jetzt verstehe ich erst.
PDM1, PDM2, PDM3 sind Hardware-Register.
Da bleibt dir dann natürlich nur die Möglichkeit sie so schnell wie
möglich nacheinander zu beschreiben.
Anders gehts ja nicht.
Joe F. schrieb:> Und somit kannst du auch für alle 3 PWMs eine gemeinsame> Variable/Register für den Duty-Cycle benutzen.
Natürlich nicht, denn die PWM Kanäle haben jeder ein eigenes Register
(und somit eine eigenen festgelegten Namen) für den Duty Cycle das
einzeln beschrieben werden muß.
Es gibt zwar Prozessoren die auch ein gemeinsames DutyCycle Register für
alle PWM Kanäle aktivierbar haben, nur macht das keinen Sinn wenn man
z.B. 2 Motoren steuern will.
Hm. Ich habe irgendwie auch den Eindruck, dass mir die Absicht von
Clerner nicht klar ist.
Worum geht es?
1. Einen möglichst kurzen C-Text?
2. Eine möglichst kurze Ausführungszeit?
3. Ein simultanes Ändern der Register?
4. Eine Kombination davon?
5. Irgendwas ganz Anderes?
Schreibt man das mal ganz geradeaus hin, dann sollte das so aussehen:
1
PWM_Wert=<irgendeineGleichung>;
2
3
PDM1=PWM_Wert;
4
PDM2=PWM_Wert;
5
PDM3=PWM_Wert;
Ist das eine Lösung für Dich, Clerner? Oder was ist für Dich daran
unerwünscht oder problematisch?
hallo all,
das gelaber hier erscheint mir nutzlos/sinnfrei, wenn der to es nicht
schaft den uc (pic/avr/arm/...?) zu benennen! weil, der prozessor
kontext entscheidet dann über sinn/unsinn dieser frage.
mt
Theor schrieb:> Worum geht es?
Der TO ist C-Anfänger, möchte Code-kopien vermeiden und hat
unglücklicherweise geschrieben, dass er auf einem uC Register
beschreiben will.
Es geht weder um den konkreten uC-Typ noch um Register noch um
Performance, sondern einfach um einen Tipp, den Code zu verbessern.
Für das Problem, wie so was in C gelöst werden kann spielt der
Prozesseor eigentlich kaum eine Rolle, das Problem kann bei vielen
Controllern auftreten. Ich bin momentan mit einem dsPIC33 zu Gange.
Die Lösung von Dr.Sommer trifft es eigentlich recht gut. Leider habe ich
kein C++.
Es ging ja darum die 3Register in einem Rutsch zu beschreiben damit bei
komplexeren Rechnungen, so die nötig werden, nicht immer der ganze
Rattenschwanz für die Zuweisung mit rumkopiert werden muß. Also das
Ganze auch übersichtlicher zu machen indem nur eine Variable manipuliert
werden muß.