Forum: Mikrocontroller und Digitale Elektronik AVR Register setzen


von Mathias F. (savag)


Lesenswert?

Hallo,
ich verwende einen ATmega16U4 und möchte die ADC`s benutzen.
Nun ist es so das in dem Register ADMUX Bit 0 ... 4 geändert wird und
in dem Register ADCSRB NUR Bit 5. Die anderen Bit´s müssen unberührt 
bleiben.
Um das ganze zu vereinfachen wollte ich nun ein #define machen.
aber wie kann ich die beiden Register in einer zeile zusammenfassen??

#define ADMUX &= 0b00010000 | ADCSRB &= 0b00100000

Vielen Dank für alles hilfreiche

von Falk B. (falk)


Lesenswert?

@ Mathias Feld (savag)

>Nun ist es so das in dem Register ADMUX Bit 0 ... 4 geändert wird und
>in dem Register ADCSRB NUR Bit 5. Die anderen Bit´s müssen unberührt
>bleiben.

Wie dui schon richtg erkannt hast, braucht man dazu Bitmanipulation.

>Um das ganze zu vereinfachen wollte ich nun ein #define machen.
>aber wie kann ich die beiden Register in einer zeile zusammenfassen??

Wozu sollte das gut sein? Schreib lieber eine normale Funtkion.

von Mathias F. (savag)


Lesenswert?

Hi,
das mit der Funktion wäre meine nächste wahl gewesen.
Dachte, vielleicht gibt es da eine möglichkeit die ich nicht kenne.
Werde aber die variante mit der Funktion aufgreifen.

von Karl H. (kbuchegg)


Lesenswert?

Eine Funktionjn zu schreiben ist sicherlich die bessere Wahl.

Allerdings muss man als C-Programmierer auch mit Makros umgehen können.
Dabei lässt man sich immer vom Gedanken leiten: Makros sind einfach nur 
eine Textersetzung. Makros sind einfach nur eine Textersetzung. Makros 
sind einfach nur eine Textersetzung.

Nicht mehr.

Das bedeutet bei der Entwicklung eines Makros:
Die erste Frage lautet nicht: wie muss ich das schreiben?
Sondern die erste Frage lautet: was muss eigentlich nach der 
Textersetzung rauskommen?

in deinem Fall.
Im Endeffekt muss nach der Textersetzung rauskommen
1
int main()
2
{
3
...
4
   ADMUX &= 0b00010000;
5
   ADCSRB &= 0b00100000;
6
...

soweit so gut. C erfodert von dir nicht, dass du jede Anweisung in eine 
neue Zeile schreibst. d.h. du darfst das auch so schreiben.
1
int main()
2
{
3
...
4
   ADMUX &= 0b00010000;  ADCSRB &= 0b00100000;
5
...

Nachdem jetzt klar ist, wie eigentlich das Ergebnis aussehen soll, 
überlegt man sich, weche Textersetzung man haben möchte, so dass der 
Zieltext sich einfacher präsentiert.
Anstatt dem ganzen Wust, möchtest du gerne schreiben
1
int main()
2
{
3
...
4
   SET_ADC;
5
...

jetzt ist es aber leicht zu sehen, welcher Text durch welchen anderen 
Text ersetzt werden soll. Wenn in der letzten Version der Text "SET_ADC" 
durch den Text "ADMUX &= 0b00010000;  ADCSRB &= 0b00100000" ersetzt 
wird, dann entsteht nach der Textersetzung genau das richtige.

Daher
1
#define SET_ADC  ADMUX &= 0b00010000;  ADCSRB &= 0b00100000
2
3
int main()
4
{
5
...
6
  SET_ADC;
7
...

erzeugt genau das, was du willst.

Laut den Regeln darf allerdings ein Makro auch über mehr als 1 Zeile 
gehen. Alles was dazu nötig ist, ist das man in die letzte Spalte einer 
Zeile einen '\' reinschreibt.
1
#define SET_ADC  ADMUX &= 0b00010000;   \
2
                 ADCSRB &= 0b00100000
3
4
int main()
5
{
6
...
7
  SET_ADC;
8
...

Am Prinzip der Textersetzung ändert sich dadurch nichts. Immer noch 
sorgt das Makro dafür, dass im eigentlichen Code der Text "SET_ADC" 
durch einen anderen Text ersetzt wird. Und nach wie vor ist das Ergebnis 
dieser Textersetzung genau das gewünschte.


PS: die Schreibweise 0b00010000 ist an dieser Stelle Müll. Anstatt sich 
da Gedanken darüber zu machen, wie man einen 2-Zeiler durch etwas 
kürzeres ersetzen kann, solltest du dir lieber Gedanken machen, wie du 
diese Binärkonstante besser schreiben kannst. Nicht umsonst hat dir 
Atmel in den Header Files die ganzen Bitnamen vordefiniert. Benutze sie!

von Mathias F. (savag)


Lesenswert?

SUUUPER Antwort,
das war genau das was ich gesucht habe. Habe schon gesehen das Atmel das 
vordefiniert. Jedoch ist es im Datenblatt als Binär angegeben. Wollte es 
auch so gleich übernehmen das ich später auch auf einen Blick die 
Zuordnung im Datenblatt habe.

Habe mittlerweile eine Funktion gebaut, aber dies wird mir mit 
sicherheit nochmal über den Weg laufen und ich finde diese Methode auch 
nicht schlecht.

Nochmals vielen Dank für die tolle beschreibung.

von Karl H. (kbuchegg)


Lesenswert?

Mathias Feld schrieb:
> SUUUPER Antwort,
> das war genau das was ich gesucht habe. Habe schon gesehen das Atmel das
> vordefiniert. Jedoch ist es im Datenblatt als Binär angegeben.

Im Datenblatt hat jedes Bit einen Namen. Und genau dieselben Namen hast 
du durch die Header zur Verfügung.

Anstatt
1
  ADCSRB &= 0b00100000;
kannst du daher genausogut auch
1
  ADCSRB &= ( 1 << MUX5 );

(was zwar immer noch falsch ist, aber zumindest lesbar falsch. Richtig 
wäre
1
  ADCSRB &= ~( 1 << MUX5 );
um das Bit MUX5 im ADCSRB zu löschen.
)

Der UNterschied zwischen beiden Schreibweisen besteht darin, dass du in 
der zweiten Version direkt im Code stehen hast, dass du hier irgendwas 
mit dem MUX5 Bit anstellen willst, während du in der ersten Version erst 
mal das Datenblatt konsultieren musst um rauszufinden, dass dieses 
einsame 1 Bit an der Bitposition MUX5 steht.

: Bearbeitet durch User
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.