Forum: Mikrocontroller und Digitale Elektronik XC8 compiler - Register schreiben wie bei Atmel


von DMDDE (Gast)


Lesenswert?

Hallo!

Zur Zeit beschäftige ich mich mit MPLABX und dem XC8 Compiler. Bislang 
hatte ich nur mit Atmel zu tun.

Wie kann ich Register mit dem XC8 wie bei Atmel beschreiben?

Beispiel Atmel:

REGISTER = (1<<XYZ)|(3<<ABC); //alle Bits in einem Rutsch geschrieben

XYZ und ABC werden vom AVR Studio erkannt und somit funktioniert das 
ganze recht easy mit einem Schreibbefehl.

Beispiel XC8:

REGISTER = (1<<7)|(3<<2); //funktioniert, ist aber etwas unleserlich, da 
anonym

REGISTERbits.XYZ = 1; //funktioniert auch, aber somit immer nur 
teilweise

REGISTER = (1<<XYZ); //funktioniert nicht!

aus dem XC8 Handbuch konnte ich auch keine passenden Infos ziehen.

Also, wie kann ich auf die einzelnen "Bits" zugreifen ohne sie zu 
anonymisieren?

von STK500-Besitzer (Gast)


Lesenswert?

Irgendwo müssten das Macro "XYZ" definiert sein.
Dazu könntest du einfach sämtlich .h-Dateien deines Compilers 
durchforsten.

von DMDDE (Gast)


Lesenswert?

ja, natürlich sind diese definiert... ich bekomme ja auch Zugriff auf 
diese Bits, aber immer nur indem ich das Register mit "bits" teilweise 
öffne.

REGISTERbits.XYZ = ...

Damit kann ich aber immer nur auf eine Stelle schreiben.

REGISTER = (1<<REGISTERbits.XYZ); //funktioniert auch nicht

oder bastelt der compiler aufeinanderfolgende Schreibbefehle zu einem 
zusammen?

Quasi:

REGISTERbits.XYZ = 1;        |
REGISTERbits.ABC = 3;        |___ wird zu einem Schreibbefehl 
verwurstet?

von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

@  DMDDE (Gast)

>ja, natürlich sind diese definiert... ich bekomme ja auch Zugriff auf
>diese Bits, aber immer nur indem ich das Register mit "bits" teilweise
>öffne.

>REGISTERbits.XYZ = ...

Logisch. Weil man sich bei den Leuten vom XC8 Compiler für dieses 
Konzept entscheiden hat. Bei avr gcc hat man sich, warum auch immer, für 
ein anderes Konzept entschieden.

>Damit kann ich aber immer nur auf eine Stelle schreiben.

>REGISTER = (1<<REGISTERbits.XYZ); //funktioniert auch nicht

Logisch.

>oder bastelt der compiler aufeinanderfolgende Schreibbefehle zu einem
>zusammen?

Nein.

>REGISTERbits.XYZ = 1;        |
>REGISTERbits.ABC = 3;        |___ wird zu einem Schreibbefehl
>verwurstet?

Nein, das darf/kann er nicht, weil die Register volatile sind. Das MUSS 
er 1:1 umsetzen, ohne Umformung und Zusammenfassung.

Eigentlich ist der Ansatz mit den einzelnen Registerbists besser, denn 
damit kann man nicht aus Versehen Bits in einem Register schreiben, die 
gar nicht existieren.
Der avr gcc Ansatz ist deutlich fehleranfälliger, denn der Compiler kann 
nicht prüfen, ob die Bits in dem Register wirklich exisitieren.

PORTA = (1<<PC5); ist eigentlich Unsinn, denn das Bit PC5 gibt es dort 
nicht. Durch "Zufall" ist PC5 == PA5

Wirklich problematisch sit es eher bei Steuerregistern, z.B. beim Timer

TCCR0A = (1<<WGM03); ist totaler Unsinn, denn das Bit liegt in TCCR0B. 
Darüber sind schon viele Leute gestolpert. Und der Compiler kann 
keinerlei Fehlermeldung erzeugen.

Schau mal ob in deinen Registerdefinitionen auch die Registetr als 
Gesamtkonstrukt vorhanden sind, etw so.

REGISTERbits.all

Dann könnte man wieder die gute, alte Atmel-Schiene fahren ;-) Aber dann 
musst du dir auch die gesamten Headerfiles mit allen Definitionen 
irgendwie erzeugen. Viel Spaß.

Als Alternative, falls es dir um Speicherlatz und Geschwindigkeit geht, 
kann man mit einer nicht volatilen Kopie arbeiten. Wie das geht, findet 
man im Dokument im Anhang, Seite 15

Example 15. Optimization Using a Shadow Register

Das ist zwar für einen anderen Prozessor, erklärt die Sache aber sehr 
gut!

von Jupp Strupp (Gast)


Lesenswert?

Falk B. schrieb:
> PORTA = (1<<PC5); ist eigentlich Unsinn, denn das Bit PC5 gibt es dort
> nicht. Durch "Zufall" ist PC5 == PA5

ja, das stimmt! Kann man alles sehen, wie man will! ;) und der compiler 
macht es auch so.

mir geht es nicht um geschwindigkeit, sondern um eine kompakte (eine 
zeile), leserliche schreibweise.

ich danke dir für deine hilfreiche Antwort!

von Falk B. (falk)


Lesenswert?

WENN man sich dazu entschließen sollte, das mit #defines und avr gcc 
Style zu machen, dann bitte richtig. Also eher so

1
#define MY_REG_BIT_XYZ (1<<5)
2
#define MY_REG_BIT_ABC (1<<3)
3
4
REG = MY_REG_BIT_XYZ | MY_REG_BIT_ABC;

Die (1<<Bitnummer) Schreibweise ist nur eine Altlast der Atmel-Include 
Files! Sinnlose Tipparbeit. Die BitNUMMER braucht man in C so gut wie 
gar nicht, sie waren nur für die sbis/sbic cbi/sbi Befehle des 
AVR-Assemblers nötig.

von Thomas E. (picalic)


Lesenswert?

Servus,

auch die Einzelbits der Register sind definiert, so daß man sie in einem 
Ausdruck verrechnen kann, z.B.:
1
    INTCON |= _INTCON_T0IE_MASK | _INTCON_GIE_MASK;

Wenn man für irgendwas die Bitnummer braucht, geht es so:
1
    INTCON |= 1 << _INTCON_GIE_POSITION;

: Bearbeitet durch User
von Jupp Strupp (Gast)


Lesenswert?

Thomas E. schrieb:
> auch die Einzelbits der Register sind definiert, so daß man sie in
> einem Ausdruck verrechnen kann, z.B.: [...]

habs eben auch entdeckt. durch die strikte struktur gibt es eigentlich 
wirklich keine verwechselungen... neben POSN (POSITION) und MASK gibt es 
auch noch SIZE (bzw. LENGTH). ich denke das kann sehr hilfreich sein.

im vergleich zu gcc erscheint es mir sehr "diszipliniert". aber ob es 
mir gefällt... wer weiß! xD

ich denke nach ein paar programmen hat man das auch verinnerlicht. 
nicht, dass es mir dann bei atmel "komisch" vorkommt! :D

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.