www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik einfache Schreibweise um Pins zu schalten


Autor: R. F. (inet_surfer88)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich schalte in einem Programm häufig von einem Port einzelne Pins aus 
und ein.
Momentan mache ich das mit den Ausdrücken
PORTC |= (1 << 0);
 bzw.
PORTC &= ~(1 << 0);

Kann ich hier am Anfang der Datei eine Zuweisung machen, damit ich 
später im Programm z.B. anstelle
PORTC |= (1 << 0);
 nur noch
pinc0_ein;
 oder anstelle von
PORTC &= ~(1 << 0);
 nur noch
pinc0_aus;
 schreiben muss?

Das würde das Programm wesentlich "lesbarer" machen.


Gruß
inet_surfer88

Autor: Bernd N (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

struct bits {
    uint8_t b0:1;
    uint8_t b1:1;
    uint8_t b2:1;
    uint8_t b3:1;
    uint8_t b4:1;
    uint8_t b5:1;
    uint8_t b6:1;
    uint8_t b7:1;
} __attribute__((__packed__));

#define SBIT(port,pin) ((*(volatile struct bits*)&port).b##pin)

#define TestPin SBIT (PORTD, 7)

Jetzt kannst Du schreiben:

TestPin = 1;
TestPin = 0;

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
#define pinc0_ein PORTC |= (1 << 0)

Autor: Vlad Tepesch (vlad_tepesch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
klassischer fall für den präprozessor.

#define pinc0_aus do{PORTC &= ~(1 << 0);}while(0)
#define pinc0_an  do{PORTC |=  (1 << 0);}while(0)



noch besser (weil sauberer) wären aber inline funktionen.

#define LEDBIT  PIN0
#define LEDDDR  DDRC
#define LEDPORT PORTC
#define LEDPIN  PINC



static inline void LedOn    ( void ) { LEDPORT |=  (1 << LEDBIT); }
static inline void LedOff   ( void ) { LEDPORT &= ~(1 << LEDBIT); }
static inline void LedToggle( void ) { LEDPIN  |=  (1 << LEDBIT); }

static inline uint8_t LedIsOn( void ) { return LEDPORT &= (1 << LEDBIT);}





Edit:
Zu langsam
+ fehler korrigiert

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Natürlich kannst Du einen Macro machen.  Ich würde es mir aber nochmal 
überlegen.  Für Dich, der jetzt im Programm „drin” ist, ist ein Macro 
keine Hürde und macht das Programm lesbarer.  Für Dich in zwei Jahren 
oder einen anderen Leser ist das eine Indirektion mehr, die zunächst 
gelernt sein will, um sie als menschlicher Macro-Expander bereit zu 
halten.  Man muss erst mal nachsehen, was der Macro bedeutet, um das 
Programm zu verstehen.

Und schließlich halte ich
PORTC |= (1 << 0);
für eine sehr klare Formulierung, die ohne Überlegung jedem, der bloß ab 
und zu mit solchen Programmen zu tun hat, sofort und ohne weitere Umwege 
verständlich ist.  Es ist etwa so, wie wenn ein Englischanfänger in 
englischen Text die Übersetzungen reinschreibt: für den, der nur ein 
wenig damit vertraut ist, stört es später höchstens den Lesefluss.

Und natürlich wäre
LCD_STATUS |= (1<<LCD_RS)
noch die  viel bessere Formulierung.

Autor: Vlad Tepesch (vlad_tepesch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hc Zimmerer schrieb:
> Und schließlich halte ichPORTC |= (1 << 0);
> für eine sehr klare Formulierung, die ohne Überlegung jedem, der bloß ab
> und zu mit solchen Programmen zu tun hat, sofort und ohne weitere Umwege
> verständlich ist.

Naja, klar sit damit nur, dass man den Pin anschaltet, mehr nicht.
Normalerweise schaltet man den ja aber nicht um seiner selbst willen, 
sondern um irgend was zu bewirken.

Es ist somit viel besser, das Resultat zu benennen, als den Weg.
also, statt PinC0_ein, lieber Power_LED_ein(), oder latchData()

Das macht es zum einen einfacher, wenn man die Anschlüsse tauscht, oder 
gar das modul, was an dem Ausgangsport höngt.

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Und schließlich halte ich
>PORTC |= (1 << 0);
>für eine sehr klare Formulierung,

Wenn man den Pin dann später mal wechseln möchte
und das da oben an mehreren Stellen im Code steht,
wird es aber ne Menge Arbeit alle Codezeilen zu
ändern. Wenn ein #define in einer Headerdatei
verwendet wird muss man nur ein Zeile ändern.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hc Zimmerer schrieb:
> Und schließlich halte ichPORTC |= (1 << 0);
> für eine sehr klare Formulierung,

Für mich ist sowas total unleserlich.

Mich interessiert nicht, welchen Pin ich schubse, sondern wozu das nütze 
ist.
Also schreibe ich lieber:

  LED1 = LED_ON;
  MOTOR1_LEFT = MOTOR_STOP;
  // usw.

Und das geht eben sehr einfach mit dem SBIT Macro.

Außerdem muß man dann für jeden Pin auch nur einen Namen definieren.
Beim OR/AND muß man immer 2 Namen definieren, die Portadresse und die 
Pinnummer.

Leider habe ich noch keinen Weg gefunden, wie man automatisch den DDR- 
und PIN-Pin mit definieren kann. Ein #define innerhalb des #define geht 
nicht.


Peter

Autor: Tajas R. (tony)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hc Zimmerer schrieb:
> Und schließlich halte ich
>
> PORTC |= (1 << 0);
> 
> für eine sehr klare Formulierung

Dazu kann ich als PIC-User sagen, dass mir diese schreibweise zunächst 
mal alles andere als "klar vormuliert" vorkam. Da muss man erstmal 
überlegen, welches Bit da jetzt wie wohin geschoben, invertiert und 
ge-AND-et wird...

Da finde ich die PIC-C-18 Schreibweise deutlich schöner:
PORTBbits.RB1 = 1;
z.B.

Autor: R. F. (inet_surfer88)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vlad Tepesch schrieb:
> klassischer fall für den präprozessor.
>
>
> 
> #define pinc0_aus do{PORTC &= ~(1 << 0);}while(0)
> #define pinc0_an  do{PORTC |=  (1 << 0);}while(0)
> 
> 
>

Vielen Dank! Genau das was ich gesucht habe. Habe es gleich mal 
ausprobiert und es funktioniert wunderbar.

Gruß
inet_surfer88

Autor: Gast0 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
#define pinc0_aus do{PORTC &= ~(1 << 0);}while(0)
#define pinc0_an  do{PORTC |=  (1 << 0);}while(0)

Für was brauch ich denn da die do-while schleife drumrum? Das will mir 
nicht so ganz einleuchten.

Macht nicht
#define pinc0_an (PORTC |= (1<<0))
genau das gleiche?

Gruss,
Gast

Autor: R. F. (inet_surfer88)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gast0 schrieb:
>
> #define pinc0_aus do{PORTC &= ~(1 << 0);}while(0)
> #define pinc0_an  do{PORTC |=  (1 << 0);}while(0)
> 
>
> Für was brauch ich denn da die do-while schleife drumrum? Das will mir
> nicht so ganz einleuchten.
>
> Macht nicht
>
> #define pinc0_an (PORTC |= (1<<0))
> 
> genau das gleiche?
>
> Gruss,
> Gast


Hallo,

stimmt. Hatte ganz am Anfang schon jemand geschrieben. Als ich es 
ausprobiert hatte, habe ich allerdings eine Fehlermeldung bekommen. Muss 
allerdings ein Tippfehler gewesen sein. Habs jetzt nochmals ausprobiert 
und es funktioniert.

Autor: Uwe ... (uwegw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Dannegger schrieb:
> Leider habe ich noch keinen Weg gefunden, wie man automatisch den DDR-
> und PIN-Pin mit definieren kann. Ein #define innerhalb des #define geht
> nicht.

#define DDR(x) (*(&x - 1))      /* address of data direction register of 
port x */
#define PIN(x) (*(&x - 2))    /* address of input register of port x 
*/

und dann z.B. DDR(PORTB) oder PIN(PORTA)

Das beruht darauf, dass die Register an fortlaufenden Adressen liegen. 
Das habe ich in Peter Fleurys LCD-Lib gefunden. Ist aber nicht gerade 
eine saubere Methode. Denn diese Anordnung der Register ist ja nirgendwo 
garantiert. Beim Mega128/Mega64 ist das PINF-Register etwa getrennt von 
PORTF und DDRF abgelegt. Das fängt er an dieser Stelle dann mit
#if defined(_AVR_ATmega64_) || defined(_AVR_ATmega128_)
    /* on ATmega64/128 PINF is on port 0x00 and not 0x60 */
    #define PIN(x) ( &PORTF==&(x) ? _SFR_IO8(0x00) : (*(&x - 2)) )
#else
  #define PIN(x) (*(&x - 2))    /* address of input register of port x 
*/
#endif
ab. Das ist also extrem kritisch, wenn neue AVRs herauskommen, die 
ebenfalls so eine abweichende Anordnung haben.

Autor: Vlad Tepesch (vlad_tepesch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gast0 schrieb:
> Macht nicht#define pinc0_an (PORTC |= (1<<0))
> genau das gleiche?

in dem Fall ist es egal.
Spätestens, wenn es mehrere Anweisungen werden, ist essenziell.

#define SR_latch() {PORTC |= (1<<0); PORTC &= ~(1<<0);}

sieht auf den ersten Blick richtig aus.

Baut man das dann aber in ein if-else-konstrukt ein:


if(x>y)
  SR_latch();
else
  ++x;


geht es nicht:
da dann steht:

if(x>y)
  {PORTC |= (1<<0); PORTC &= ~(1<<0);};
else
  ++x;

das semikolon schließt die if-Anweisung unwiederuflich.


Daraus lernt man 2 sachen:
1. Macros, die Anweisungen kapseln immer in do{}while(0)
2. Macros, die Anweisungen kapseln nicht benutzen, dafür gibt es 
inline-Funktionen.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.