Hi!
ich bastle gerade etwas mit einem Atmega2560 in c++ herum. Ich möchte
gern in einer for-Schleife die Ports beschreiben.
Also mit
1
i=0PORTA|=(....);
2
i=1PORTC|=(....);
3
i=2PORTD|=(....);
4
...
Der Übersichtlichkeit halber habe ich die entsprechenden Ports definiert
als
1
#define CC0 PORTA
2
#define CC1 PORTC
3
#define CC2 PORTD
4
...
und hatte auf eine Möglichkeit gehofft, in der Schleife jetzt dynamisch
a la CCi zuzugreifen. Aber die Möglichkeit gibt es ja in c++ nicht. Bin
aber überfordert ob man einen Pointer auf PORTA setzen kann? Was sagt
die Schwarmintelligenz?
Ja, man kann. Schließlich verbirgt sich hinter den PORTn-Defines nichts
anderes als ein Pointer. Schau dir die Definition im Header an. Das
nutzt dir aber letztendlich nicht viel, weil die Port-Register nicht
direkt hintereinander im Adressraum angeordnet sind.
Am saubersten ist da ein switch oder ein if/else if, oder aber ein Array
mit den Port-Pointern mit Zugriff über den Index.
Oliver
Hmm, ich hatte das _SFR_IO8(0X02) schon gesehen aber kann damit nicht
viel anfangen. Eine switch-Anweisung wird da halt übel ausladend bei 7
Ports. Hätte das echt gern als Schleife gemacht.
Edit: Ah also das _SFR_IO8(0X02) in ein Array legen und dann auf die
Adresse zugreifen geht? Dann werd ich damit mal rumprobieren.
Hannes J. schrieb:> ich hatte das _SFR_IO8(0X02) schon gesehen aber kann damit nicht viel> anfangen.
Das ist auch nur ein Makro. Und das Drama löst sich in der sfr_defs.h
(ein Stück weit) auf:
Jetzt musst du nur noch das Makro _MMIO_BYTE() auflösen und den
__SFR_OFFSET suchen, und du kannst dann daraus die Adresse berechnen.
Oder im Netz nach diesen Makros suchen. Diese Frage hatten schon einige
vor dir:
https://www.avrfreaks.net/forum/how-does-macro-mmioword-actually-work
Und zum Schluss findest du heraus, dass das "nur" eine RAM-Adresse ist,
die du sogar im Datenblatt wiederfindest... ;-)
Stefanus F. schrieb:> Ja, aber alle anderen Methoden sind unterm Strich auch nicht eleganter.
Man könnte mit dem Index über eine Pointertabelle fahren...
> Jetzt musst du nur noch das Makro _MMIO_BYTE() auflösen und den> __SFR_OFFSET suchen, und du kannst dann daraus die Adresse berechnen.>> Oder im Netz nach diesen Makros suchen. Diese Frage hatten schon einige> vor dir:> https://www.avrfreaks.net/forum/how-does-macro-mmioword-actually-work> Und zum Schluss findest du heraus, dass das "nur" eine RAM-Adresse ist,> die du sogar im Datenblatt wiederfindest... ;-)> [...]> Man könnte mit dem Index über eine Pointertabelle fahren...
Ah danke für die erhellende Antwort! Damit kann ich mich doch mal
außeinandersetzen. :)
Hannes J. schrieb:> Eine switch-Anweisung wird da halt übel ausladend bei 7> Ports. Hätte das echt gern als Schleife gemacht.
Switch kann man auch in einer Schleife aufrufen.
Du kannst Ports über deren Adresse ansprechen, nur wird das viel
aufwändiger als ein Switch, da die Adressen 16bittig sind.
Auch sind die Ports nicht hintereinander angeordnet, d.h. Du must Dir
die Adresse erst aus einem Array der Portadressen holen.
Bei nur 7 Case ist ein Switch daher schneller und weniger Code.
Peter D. schrieb:>> Switch kann man auch in einer Schleife aufrufen.
Schon klar, mit Schleife brauche ich aber keine switch mehr und mit
switch keine Schleife.
> Du kannst Ports über deren Adresse ansprechen, nur wird das viel> aufwändiger als ein Switch, da die Adressen 16bittig sind.> Auch sind die Ports nicht hintereinander angeordnet, d.h. Du must Dir> die Adresse erst aus einem Array der Portadressen holen.> Bei nur 7 Case ist ein Switch daher schneller und weniger Code.
Dazu ein paar Fragen..
Genau das ist was ich machen will, warum meinst du sollte das mit
Schleife aufwändiger werden als switch? Wenn ich die Adressen in ein
Array packe kann ich das doch in der Schleife durchgehen,
dereferenzieren und ich hab was ich will? Ob 8 oder 16 Bit macht doch
keinen Unterschied, außer dass ich uint16_t* schreibe anstatt uint8_t*?
Eine switch kommt mir hier fehl am Platze vor, weil im Prinzip in jedem
Port die gleiche Operation erfolgt, nur mit unterschiedlichen Daten. Ich
hätte also 14x den gleichen Befehl anstatt 2x.
Was mich jetzt noch verwirrt: Die Adressen der meisten Ports haben 8
Bit. Erst ab Port H sind es mehr. Port H hat bspw. die Adresse 0x102. Am
Ende der Macro-Kette werden die aber alle gecasted auf (*(volatile
uint8_t *)(mem_addr)). Da wird doch die führende 1 abgeschnitten? Warum
dann überhaupt 0x102?
Oliver S. schrieb:> Du hast Dir die Makros immer noch nicht angesehen.>> Oliver
Um ehrlich zu sein, doch..
Axel S. schrieb:> Genauso würde ich das machen.>>
Was so nebenbei nicht geht ...
PORTA |= (....);
Bedeutet Read - modify - write
Und das geht so nicht. Denn wenn man das Port A lesen moechte muss man
PINA lesen.
Also eher : PORTA = PINA | (..)
Name H. schrieb:> Was so nebenbei nicht geht ...>> PORTA |= (....);>> Bedeutet Read - modify - write>> Und das geht so nicht. Denn wenn man das Port A lesen moechte muss man> PINA lesen.
Das stimmt zwar, mit
1
PORTA|=(....);
möchte man aber nicht die Eingänge lesen, sondern einzelne Ausgänge
setzen, ohne die schon gesetzten zu löschen.
Oliver