Hallo zusammen,
mal ein ganz allgemeine Frage zu den Atmel-Käferchen: Ist die Adresse
des Data-Direchtion-Registers eines Ports (z.B. DDRx) immer die nächste
Adresse als wie die Port-Ausgabeadresse (z.B. PORTx)? Ich habe mehrere
Datenblätter gewälzt (Atmega 8, 328, Attiny13) wo das zutrifft. Gibt es
eine allgemeine Aussage, dass das eben immer so ist?
Zum Hintergrund: Ich will die PORT und Pins, an denen ich Daten ausgebe,
in einem Makro definieren. Wenn ich es genau nehme und später nicht im
Code rumwerkeln will muss ich eben auch das DDRBx als MAkro definieren.
Wenn es aber immer eine feste Beziehung PORTx /DDRx gibt, kann ich mir
ja DDRx ausrechnen....
Gruß scheps
>Also eine Ausnahme gibts, hab den Käfer aber nimmer im Kopf.
ATMega128.
>Wenn es aber immer eine feste Beziehung PORTx /DDRx gibt, kann ich mir>ja DDRx ausrechnen....
Annahmen das irgendwas da ist wo es sein sollte sind der erste Schritt
in die Scheisse. Nenn das Kind beim Namen, dann hast du weniger Ärger.
Jeder controller hat ein pin definition file, das den namen einer
adresse zuweist. Welchen grund koennte es geben, dieses mitgelieferte
file nicht verwenden zu wollen?
Wenn du zB eine Lib schreiben willst in der der User nur PORTA eintippen
muss und nicht noch zusätzlich DDRA/PINA.
Wenns ne Lib gibt mit mehreren IOs ist sowas schon ganz nett ;)
Wenn du nen define im Kopf hast welches diese Funktionalität bietet und
dazu das Controllerdeffile nutzt, dann nur her damit.
T. roll schrieb:> Jeder controller hat ein pin definition file, das den namen einer> adresse zuweist. Welchen grund koennte es geben, dieses mitgelieferte> file nicht verwenden zu wollen?
Arbeitserleichterung und damit auch Fehlervermeidung in der
Programmierung.
Es ist ein Unterschied, ob bei
#define ERROR_LED_DDR DDRB
#define ERROR_LED_PORT PORTB
die beiden Angaben zusammenstimmen müssen, oder ob ich die eine Angabe
aus der anderen automatisch erzeugen kann. Im letzteren Fall gäbe es
keine Möglichkeit für Flüchtigkeitsfehler.
Martin Wende schrieb:> Wenn du nen define im Kopf hast welches diese Funktionalität bietet und> dazu das Controllerdeffile nutzt, dann nur her damit.
Ich habs noch nicht ausprobiert. Aber ich denke mit dem Token-Pasting
Preprozessor könnte da was gehen.
1
#include<avr/io.h>
2
3
#define DDR_OF_(x) DDR##x
4
#define PORT_OF_(x) PORT##x
5
#define PIN_OF_(x) PIN##x
6
7
#define DDR_OF(x) DDR_OF_(x)
8
#define PORT_OF(x) PORT_OF_(x)
9
#define PIN_OF(x) PIN_OF_(x)
10
11
12
#define LED_ B
13
14
#define LED_DDR DDR_OF(LED_)
15
#define LED_PORT PORT_OF(LED_)
16
#define LED_PIN PIN_OF(LED_)
17
18
intmain(void)
19
{
20
LED_DDR|=(1<<PB2);
21
}
Die ersten 6 Makros kommen natürlich sinnvollerweise in ein Header-File.
Wechselt man den Port, dann genügt es
Martin Wende schrieb:> Wenn du nen define im Kopf hast welches diese Funktionalität bietet und> dazu das Controllerdeffile nutzt, dann nur her damit.
In Assembler ist das mit einem Macro völlig problemlos zu realisieren:
;->@0 Namensprefix
; @1 Portkennung (ein Buchstabe)
; @2 Portbit (einstellige Zahl)
.MACRO DEFPIN
.EQU @0PORT=PORT@1
.EQU @0DDR=DDR@1
.EQU @0PIN=PIN@1
.EQU @0BIT=PORT@1@2
.ENDMACRO
Verwendung z.B. in einer Konfigurationsdatei für eine TWI-Lib:
DEFPIN TWI_SCL_,C,0
DEFPIN TWI_SDA_,C,1
Produziert dasselbe wie die etwas länglichere konventionelle
Deklaration:
.EQU TWI_SCL_PORT=PORTC
.EQU TWI_SCL_DDR=DDRD
.EQU TWI_SCL_PIN=PINC
.EQU TWI_SCL_BIT=PORTC0
.EQU TWI_SDA_PORT=PORTC
.EQU TWI_SDA_DDR=DDRD
.EQU TWI_SDA_PIN=PINC
.EQU TWI_SDA_BIT=PORTC1
Verhindert dabei sicher Tippfehler und damit Konstistenzprobleme
innerhalb einer Pindeklaration. Aber mit Macros ist noch viel mehr
möglich, z.B. eine automatische anwendungsweite Prüfung auf
Pin-Kollisionen zur Entwurfszeit.
Asm rules!
Nur noch malzum allgemeinen Verständnis: Grund für das Ganze ist, dass
ich verschiedene Pins schalten muss, die ggf über mehrere
Ports verteilt sind (!). PORT und PIN definiere ich in einem Makro, aber
ich wollte vermeiden das Data-Direction-Reg nochmal extra in nem Makro
zu definieren.
Das ergibt in meinem Progrämmchen 9 Makros (3 für Port, 3für Pin und
leider noch mal 3 fürs DDRx). die letzen 3 wollte ich mir sparen.
Ich hab mich jetzt für die Lösung entschieden:
Ich definiere die MAkros für PORTs und PINS
#define L1_PORT PORTA
#define L2_PORT PORTD
#define L3_PORT PORTD
#define L1_PIN 4
#define L2_PIN 6
#define L3_PIN 2
Dann durchlaufe ich im Programm eine Init-Funktion (die ich eh
durchlaufen muss, um noch andere Dinge zu machen). Da prüfe ich ob das
PORT
überhaupt definiert ist. Wenn er definiert ist wird geprüft ob das Makro
auf diesen Port zeigt und dann der entsprechende Pin im DDrx geschaltet.
Das könnte man sicher auch in ein MAkro packen, aber da hat der
Vorredner recht: Wenns zu kompliziert wird dann in eine Funktion:
#ifdef PORTA
if (L1_PORT == PORTA)
DDRA |= (1<<L1_PIN);
if (L2_PORT == PORTA)
DDRA |= (1<<L2_PIN);
if (L3_PORT == PORTA)
DDRA |= (1<<L3_PIN);
#endif
#ifdef PORTB
if (L1_PORT == PORTB)
DDRB |= (1<<L1_PIN);
if (L2_PORT == PORTB)
DDRB |= (1<<L2_PIN);
if (L3_PORT == PORTB)
DDRB |= (1<<L3_PIN);
#endif
usw PORTC , PORTD ...
Gruß scheps