Forum: Mikrocontroller und Digitale Elektronik AVR Port und Pin in Array ablegen und dann per Schleife drauf zugreifen


von Sascha P. (poggie)


Lesenswert?

Hi Jungs
ich muss einige LEDs auf meinem ATMega schalten und wollte mir ein Array 
mit Pin und Port anlegen damit ich da mit einer schleife drüber laufen 
kann um die LEDs zu setzen.
Funktioniert nur leider noch nicht so wie es soll
Was mache ich falsch?
Folgend der korrespondierende Teil meines Codes
1
#define PortSet(PORT,PIN) (PORT |= (1 << PIN))
2
#define LED1_PORT     PORTA
3
#define LED1_PIN    PA2
4
5
typedef struct {
6
  volatile uint8_t * ledPort[NumberOfChannels];
7
  volatile uint8_t * ledPin[NumberOfChannels];
8
9
} Output_leds_t;
1
Output_leds_t Output_leds;
2
3
*Output_leds.ledPort[0] = LED1_PORT ;
4
*Output_leds.ledPort[1] = PORTA;
5
*Output_leds.ledPort[2] = PORTB;
6
7
*Output_leds.ledPin[0] = LED1_PIN;
8
*Output_leds.ledPin[1] = PA3;
9
*Output_leds.ledPin[2] = PA4;

1
for(i...){
2
 PortSet(*Output_leds.ledPort[i],*Output_leds.ledPin[i]);
3
}
Danke Sascha

von Tom M. (tomm) Benutzerseite


Lesenswert?

Sascha P. schrieb:
> PortSet(*Output_leds.ledPort[i],*Output_leds.ledPin[i]);

Übersetzt das der Compiler ohne Beanstandung?

Vermutlich gibt's da ein Problem mit dem I/O Adressraum. Der Compiler 
verwendet nach Möglichkeit die sbi/cbi Befehle für effiziente 
Bitoperationen.

Aus dem Manual, Knackpunkt im letzten Satz:

All ATmega32 I/Os and peripherals are placed in the I/O space. The I/O 
locations are accessed by the IN and OUT instructions, transferring data 
between the 32 general purpose working regis- ters and the I/O space. 
I/O Registers within the address range $00 - $1F are directly bit- 
accessible using the SBI and CBI instructions. In these registers, the 
value of single bits can be checked by using the SBIS and SBIC 
instructions. Refer to the Instruction Set section for more details. 
When using the I/O specific commands IN and OUT, the I/O addresses $00 - 
$3F must be used. When addressing I/O Registers as data space using LD 
and ST instructions, $20 must be added to these addresses.

Funktioniert es, wenn du zu ledPort 0x20 addierst?

von Tom M. (tomm) Benutzerseite


Lesenswert?

Sascha P. schrieb:
> Funktioniert nur leider noch nicht so wie es soll

Und für's nächste Mal:
- wie soll es denn?
- was tut es wirklich?

von Stefan E. (sternst)


Lesenswert?

Das passt doch alles hinten und vorne nicht. Hast du die '*' nach 
optischen Gesichtspunkten verteilt (damit alles schön gleichmäßig 
aussieht)?

Formuliere bitte mal in Worten,
a) was du in ledPort speichern möchtest
b) was du in ledPin speichern möchtest

PS: Die Struct/Array-Konstruktion finde ich auch nicht gerade optimal. 
Wäre es nicht sinnvoller, die Struct für eine LED zu machen, und dann 
ein Array aus LEDs zu bilden?

von Sascha P. (poggie)


Lesenswert?

Hallo,
danke schon mal für eure Rückmeldung

Vielleicht fangen wir einfach noch mal ganz von vorne an.

Ich möchte gerne in einem Array sowohl den Port (z.B. PORTA )als auch 
den Pin (z.B. PA2) für einige LEDs ablegen, sodass ich in einer for 
Schleife über das Array iterieren und dann die entsprechende LED 
einschalten kann.

Dazu ist es meiner Meinung nach notwendig entweder, so wie ich es 
vorgeschlagen habe die Ports und Pins in einem Array zu speichern oder 
wie Stefan es vorgeschlagen hat, ein struct für die LED mit Pin und Port 
anzulegen und davon dann ein Array für die gesamte Anzahl der LEDs zu 
bilden. (Sollte ja egal sein wie rum man es macht)

Wenn ich mein Macro verwende
1
#define PortSet(PORT,PIN) (PORT |= (1 << PIN))
2
3
PortSet(LED1_PORT,LED1_PIN);
Dann leuchtet die gewählte LED.
Wenn ich jetzt aber versuche die Register Adressen ( daher auch die 
ganzen * ) in meinem Array zu speichern, kompiliert der Code 
anstandslos, die LEDs gehen aber nicht an.

@Tom: Dein Vorschlag mit +0x20 bei Port funktioniert leider nicht.
@Stefan:
>Formuliere bitte mal in Worten,
>a) was du in ledPort speichern möchtest
>b) was du in ledPin speichern möchtest

in ledPort soll der PORT an dem die LED angeschlossen ist gespeichert 
werden z.B. PORTA
in ledPin soll der PIN an dem die LED angeschlossen ist gespeichert 
werden z.B. PA2
Hinter den Bezeichnungen PORTx und PAx verbergen sich doch meines 
Verständnissen nach auch entsprechende Register somit möchte ich jetzt 
gerne in meinem Array die Port und Pin Adressen speichern, sodass ich 
sie an mein Macro übergeben kann, welches mir dann die Ausgangsports 
setzt.

Ich hoffe ich konnte mich jetzt etwas verständlicher ausdrücken, was ich 
will/ brauche.

von Stefan E. (sternst)


Lesenswert?

Sascha P. schrieb:
> Ich hoffe ich konnte mich jetzt etwas verständlicher ausdrücken, was ich
> will/ brauche.

Mir ist völlig klar, was du willst, und wie der Code dazu aussehen 
würde. Ich hatte gehofft, mit dem "in Worte fassen" dich selber dazu zu 
bringen, etwas besser zu erkennen, was was ist.

Sascha P. schrieb:
> in ledPin soll der PIN an dem die LED angeschlossen ist gespeichert
> werden z.B. PA2
> Hinter den Bezeichnungen PORTx und PAx verbergen sich doch meines
> Verständnissen nach auch entsprechende Register

Wenn das so wäre, wozu sollte man dann dieses
1
PORT |= (1 << PIN)
überhaupt brauchen? Wenn sich hinter PA2 ein Register für diesen Pin 
verbergen würde, würde man den Pin dann nicht einfach mit "PA2 = 1;" 
setzen? Du kannst ein solches Konstrukt nicht parametrisieren, wenn du 
seine Funktionsweise gar nicht richtig verstanden hast.

von Sascha P. (poggie)


Lesenswert?

Hallo Stefan
danke für deine Rückmeldung.
Beim Pin war ich wohl etwas unpräzise, wenn ich den Wert dahinter als 
Register bezeichnet habe.
Die Definition ist mir bekannt:
1
/* Data Register, Port A */
2
#define    PA7      7
3
#define    PA6      6
Aber ob ich nun nen Pointer darauf anlege und ihn später dereferenziere. 
oder den Wert da direkt als uint8_t reinschreibe sollte doch egal sein.
Die Sternchen für die LED Pins sollten daher ok sein.

Nun zu den Ports:

Als Beispiel ist PORTD für den ATMega8535 folgend definiert:
1
/* Data Register, Port D */
2
#define PORTD  _SFR_IO8(0x12)

Wenn ich das jetzt richtig verstanden habe brauche ich jetzt einen 
volatile uint8_t pointer auf die Adresse dieses Registers.
Das habe ich versucht zu erreichen indem ich als Wert im Array an der 
Stelle i  (*Output_leds.ledPort[i]= Register) die Registernummer 
speichere.
1
*Output_leds.ledPort[0] = LED1_PORT ;
2
*Output_leds.ledPort[1] = PORTA;

Denke ich mal wieder zu kompliziert oder wo ist mein Fehler?

Gruß
Sascha

von Stefan E. (sternst)


Lesenswert?

Sascha P. schrieb:
> Die Definition ist mir bekannt:
1
/* Data Register, Port A */
2
#define    PA7      7
3
#define    PA6      6
> Aber ob ich nun nen Pointer darauf anlege und ihn später dereferenziere.
> oder den Wert da direkt als uint8_t reinschreibe sollte doch egal sein.
> Die Sternchen für die LED Pins sollten daher ok sein.

Nein. Du kannst keinen Pointer auf ein Zahlliteral bilden.

Sascha P. schrieb:
> Wenn ich das jetzt richtig verstanden habe brauche ich jetzt einen
> volatile uint8_t pointer auf die Adresse dieses Registers.

Richtig.

Sascha P. schrieb:
> Das habe ich versucht zu erreichen indem ich als Wert im Array an der
> Stelle i  (*Output_leds.ledPort[i]= Register) die Registernummer
> speichere.

Das tust du doch aber gar nicht. Die Zeile nimmt den Inhalt des 
Array-Elements, interpretiert ihn als Zeiger, und schreibt dann dort, wo 
dieser Zeiger hin zeigt, den Inhalt des Registers.

von Sascha P. (poggie)


Lesenswert?

Shit habs genau vertauscht.

Jetzt geht's aber !!!

Zusammenfassend habe ich es nun folgend gelöst:


1
#define PortSet(PORT,PIN) (PORT |= (1 << PIN))
2
3
#define NumberOfChannels   16
4
5
#define LED1_PORT     PORTA
6
#define LED1_PIN    PA2
7
#
8
#
9
#
10
#define LED16_PORT     PORTD
11
#define LED16_PIN    PD4
12
13
14
typedef struct {
15
  volatile uint8_t * ledPort[NumberOfChannels];
16
  volatile uint8_t  ledPin[NumberOfChannels];
17
18
} Output_leds_t;
19
20
Output_leds.ledPort[0] = &LED1_PORT;
21
Output_leds.ledPin[0] = LED1_PIN;
22
23
PortSet(*Output_leds.ledPort[i],Output_leds.ledPin[i]);

Danke dir Stefan

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.