PIN und PORT-Konstanten eigener Bibli übergeben

Gast #4999784
Lesenswert?

Hallo, ich habe folgendes Problem:

Ich habe ein Atmel-Studio-Projekt mit je einer
- main.c
- hc165.c
- hc165.h
Datei. Jetzt will ich aus meiner main heraus die in der Datei hc165.c 
befindliche Funktion

"hc165_init(char Pin1[4],char Port1[6])" ausführen.
(Anm.: "PA3" wird als Chararray übergeben sowie "PORTA".

Mein Problem dabei ist folgendes....
ich weiß nicht, wie ich z.b. die
"Port1"-Variable sowie die
"Pin1"-Variable
an die Funktion übergeben kann, dass ich nachher in der Funktion einfach 
schreiben kann:

Port1 = (1<<Pin1);

und in Wirklichkeit hat es die Bedeutung wie z.b. PORTA = (1<<PA3);

Ich denke, das ließe sich irgendwie mit Makros lösen, oder ???

PS: Ich habe in der ursprünglichen Version mit Switch und Case alle 
Möglichkeiten abgefragt...also ob der Übergebene String bzw. Char-Array
an Stelle 5 ein A,B,C oder D enthält (z.B. PORTA,PORTB, etc)
und dann jeweils dem Port A oder B etc. zugewiesen.

Das müsste ich aber in jeder Funktion machen, die ich in meinem hc165.c 
- FIle benutze. Das gäbe Unmengen von Code......

Danke schon mal im Voraus,

LG
Moderator Persönliche Seite #4999846
Lesenswert?

Felix schrieb:
> Ich denke, das ließe sich irgendwie mit Makros lösen, oder ???

Für eine richtige Bibliothek nicht, da diese vorcompiliert binär
vorliegt.  Da geht nur die Variante mit der Übergabe eines Zeigers.

Falls „Bibliothek“ bei dir nur ein Platzhalter für „separate
Implementierungsdatei“ ist, d. h. alles wird gemeinsam im endgültigen
Projekt compiliert, dann geht das auch mit Makros.

Vorteil der Makro-Variante: der Compiler kann bei den entsprechenden
Ports wieder IN, OUT, CBI und SBI benutzen.  Bei der Variante mit den
Zeigern muss er auf die langsameren Speicherzugriffs-Implementierungen
ausweichen.

Nachteil der Makro-Variante: die Implementierung sieht extrem K***ke
aus und ist auf den ersten Blick völlig unverständlich.  Beispiel
(kein HC595 sondern HD44780):
1
/* single-bit macros, used for control bits */
2
#define SET_(what, p, m) GLUE(what, p) |= (1 << (m))
3
#define CLR_(what, p, m) GLUE(what, p) &= ~(1 << (m))
4
#define GET_(/* PIN, */ p, m) GLUE(PIN, p) & (1 << (m))
5
#define SET(what, x) SET_(what, x)
6
#define CLR(what, x) CLR_(what, x)
7
#define GET(/* PIN, */ x) GET_(x)
8

9
/* nibble macros, used for data path */
10
#define ASSIGN_(what, p, m, v) GLUE(what, p) = (GLUE(what, p) & \
11
                                                ~((1 << (m)) | (1 << ((m) + 1)) | \
12
                                                  (1 << ((m) + 2)) | (1 << ((m) + 3)))) | \
13
                                                ((v) << (m))
14
#define READ_(what, p, m) (GLUE(what, p) & ((1 << (m)) | (1 << ((m) + 1)) | \
15
                                            (1 << ((m) + 2)) | (1 << ((m) + 3)))) >> (m)
16
#define ASSIGN(what, x, v) ASSIGN_(what, x, v)
17
#define READ(what, x) READ_(what, x)

Zusammen mit defines.h:
1
/* HD44780 LCD port connections */
2
#define HD44780_RS A, 6
3
#define HD44780_RW A, 5
4
#define HD44780_E  A, 4
5
/* The data bits have to be not only in ascending order but also consecutive. */
6
#define HD44780_D4 A, 0

… werden sie dann im Code so benutzt:
1
  CLR(PORT, HD44780_RW);
2
  if (rs)
3
    SET(PORT, HD44780_RS);
4
  else
5
    CLR(PORT, HD44780_RS);
6
  ASSIGN(PORT, HD44780_D4, n);
Moderator Persönliche Seite #4999848
Lesenswert?

Mike H schrieb:
> Übergib einfach einen Zeiger auf den Port. PORTx  sind in den
> RAM-Adressraum gemappt.
>
> hc165_init(char *myport, char portbit)
> {
>   *myport |= (1 << portbit);
> }

Da fehlt eine "volatile"-Qualifikation.

Außerdem sollte man "char" nur für tatsächliche Zeichen benutzen,
sonst besser "uint8_t" (so sind die Ports auch im Header deklariert).
Gast #4999869
Lesenswert?

Felix schrieb:
> Danke schon mal im Voraus,

Die Vorredner stochern im Nebel. Oder ich blicke nicht durch.

Mir erschliesst sich nicht warum "ich" mehrere Ports mit HC165
initialisieren möchte.

Typischerweise - wenn ich mehrere HC165 habe - schliesse ich
diese kaskadiert an einen SPI Port an. Dazu muss ich nicht
variabel über eine Funktion mehrere Ports ansprechen, das SPI
initialisiere ich nur einmal zentral.

Jeweils einen HC165 an einen (eignen) Port hängen macht jedenfalls
wenig Sinn, dazu dann noch Soft-SPI?
#4999878
Lesenswert?

NuMal Langsam schrieb:
> Die Vorredner stochern im Nebel. Oder ich blicke nicht durch.

Durch den Nebel, in dem du stocherst? ;-)

NuMal Langsam schrieb:
> Mir erschliesst sich nicht warum "ich" mehrere Ports mit HC165
> initialisieren möchte.
Ralf G. schrieb:
> Das ist mir allerdings vollig unverständlich:
> Felix schrieb:
>> "hc165_init(char Pin1[4],char Port1[6])" ausführen.
>> (Anm.: "PA3" wird als Chararray übergeben sowie "PORTA".

Die Antwort darauf könnte den Nebel etwas lichten.
Moderator Persönliche Seite #4999894
Lesenswert?

Ralf G. schrieb:
>>> (Anm.: "PA3" wird als Chararray übergeben sowie "PORTA".
>
> Die Antwort darauf könnte den Nebel etwas lichten.

Wobei das natürlich die ineffizienteste Form ist, das als String zu
übergeben.  Sowas macht man vielleicht in einem Interpreter, aber in
einem C-Programm?

Sorry, diese Anmerkung hatte ich so nicht wahr genommen.  Dafür passt
natürlich der von mir gepostete Makro-Salat ganz und gar nicht.
Gast #4999897
Lesenswert?

Jörg W. schrieb:

> Da fehlt eine "volatile"-Qualifikation.

Hab den Code auch nur mal so aus dem Ärmel geschüttelt also keine Gewähr 
für Fehler. Würde mich aber mal interessieren wo da volatile fehlt und 
vor allem warum.

> Außerdem sollte man "char" nur für tatsächliche Zeichen benutzen,
> sonst besser "uint8_t" (so sind die Ports auch im Header deklariert).

Stimmt
Moderator Persönliche Seite #4999903
Lesenswert?

Mike H schrieb:
> Würde mich aber mal interessieren wo da volatile fehlt und vor allem
> warum.

Dann schau dir doch mal an, wie bpsw. "PORTA" im Headerfile
deklariert ist …  Der Grund ist einfach, dass IO-Register inhärent
volatile sind, d. h. der Compiler darf beim Zugriff auf diese
nichts wegwerfen.

Ansonsten:

http://nongnu.org/avr-libc/user-manual/FAQ.html#faq_port_pass
Gast #4999919
Lesenswert?

Jörg W. schrieb:
> Mike H schrieb:
>> Würde mich aber mal interessieren wo da volatile fehlt und vor allem
>> warum.
>
> Dann schau dir doch mal an, wie bpsw. "PORTA" im Headerfile
> deklariert ist …  Der Grund ist einfach, dass IO-Register inhärent
> volatile sind, d. h. der Compiler darf beim Zugriff auf diese
> nichts wegwerfen.
>
> Ansonsten:
>
> http://nongnu.org/avr-libc/user-manual/FAQ.html#fa...

Hab es auch gefunden aber ich verstehe es trotzdem nicht ganz.

PORTA muss volatile sein, da man ja den Wert unmittelbar (also nicht 
über Register) ändern möchte. Soweit ist alles klar.

myport ist aber ein Zeiger auf eine Speicherzelle. Ich möchte ja nicht 
den Wert von myport ändern (d.h. die Stelle auf die er zeigt) sondern 
den Wert der referenzierten Speicherzelle.
#4999964
Lesenswert?

Felix schrieb:
> "hc165_init(char Pin1[4],char Port1[6])" ausführen.
> (Anm.: "PA3" wird als Chararray übergeben sowie "PORTA".

Was soll das bringen, außer extreme Verschwendung von RAM und CPU-Zeit?
Du weißt doch schon zur Compilezeit die Pinbelegung, warum soll sich 
dann die CPU zur Laufzeit damit abquälen und alles mühsam 
interpretieren.

Ich mache sowas einfach über Defines, hier mal ein Ausschnitt einer 
"hardware.h":
1
#define LED_GN          PORT_A4
2
#define LED_GN_oe        DDR_A4
3
#define LED_RD          PORT_A5
4
#define LED_RD_oe        DDR_A5
5
#define xADC0           PORT_B0
6
#define xADC0_oe         DDR_B0
7
#define SCK             PORT_B1
8
#define SCK_oe           DDR_B1
9
#define MOSI            PORT_B2
10
#define MOSI_oe          DDR_B2
11
#define xDAC0           PORT_B4
12
#define xDAC0_oe         DDR_B4
13
#define xDAC1           PORT_B5
14
#define xDAC1_oe         DDR_B5
#5000345
Lesenswert?

Je nach Anwendungszweck kann man es auch mit hook-Funktionen lösen. Zum 
Beispiel hab ich einen UART-Treiber der soll (optional) vor dem Senden 
einen beliebigen Pin auf High und nach dem Senden wieder auf Low setzen 
können.

Dazu ruft mein Treiber einfach zwei leere und als weak deklarierte 
Hook-Funktionen auf:
1
#define WEAK __attribute((weak))
2

3
/*
4
 * empty default hooks, 
5
 * application can override these
6
 */
7

8
WEAK void uart_on_tx_begin(void) {}
9

10
WEAK void uart_on_tx_end(void) {}
11

12

13
// und weiter unten irgendwo im Interrupt (sinngemäß)
14

15
    if (fifo_get(tx_fifo, &b)) {
16
        if (state == RX) {
17
            uart_on_tx_begin();
18
            state = TX;
19
        }
20
        UART->D = b;
21
        // und 
22
        // so
23
        // weiter
24

25
// und woanders:
26
    if (UART->S & UART_S_TC_MASK) {
27
        uart_on_tx_end();
28
        state = RX;
29
        // und 
30
        // so
31
        // weiter


und in der Anwendung dann kann (muss aber nicht) die beiden schwachen 
leeren Funktionen mit eigenen Implementationen überschreiben:
1
/*
2
 * implement hook functions from UART module
3
 * to activate or deactivate the transceiver
4
 * and also to drive the blinkenlight.
5
 */
6

7
void uart_on_tx_begin(void) {
8
    gpio_max485_de_high();
9
    gpio_txled_high();
10
}
11

12
void uart_on_tx_end(void) {
13
    gpio_max485_de_low();
14
    gpio_txled_low();
15
}

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren