Forum: Mikrocontroller und Digitale Elektronik Arduino Präprozessor Pin Change Interrupt und Version automatisch zuweisen


von SG (Gast)


Lesenswert?

Hallo.

Ich lerne gerade Arduinos und C.
Gibt es ein Tutorial was ein paar "trickreiche" Beispiele zum 
Präprozessor verrät?
Oder erwarte ich da vielleicht zuviel?
Der Präprozessor ist ja nicht gerade umfangreich was den Befehlssatz 
betrifft.

Alle von mir bisher gesichteten Beispiele sind doch recht einfach 
gehalten:
    C Makros
        https://www.mikrocontroller.net/articles/C_Makros
    AVR Vordefinierte Makros:
        http://www.microchip.com/webdoc/avrassembler/avrassembler.wb_preprocessor.Pre-defined_macros.html
    AVR Assembler Preprocessor
        http://www.microchip.com/webdoc/avrassembler/avrassembler.wb_preprocessor.html
    Options for the C compiler avr-gcc
        Machine-specific options for the AVR
        http://www.nongnu.org/avr-libc/user-manual/using_tools.html
    http://public.beuth-hochschule.de/~kempfer/skript_c/Kap10.html
Mit "trickreich" meine ich z. B.:
    Beitrag "Re: AVR GCC Präprozessor #if funktioniert nicht !"

Erstmal zum "Aufwärmen":
Wie ist es möglich die "Version" aus Datumscode (vielleicht sogar der 
Datei) zusammenzusetzen?
Macht ihr sowas?
1
#define VERSION "Ver. 201804011155"  //"Ver. __CENTURY__ __YEAR__ __MONTH__ __DAY__ __HOUR__ __MINUTE__"  // Diese Version ist vom ersten April 5 vor Zwölf ;-)

Der Präprozessor macht mir gerade zu schaffen bei der Zuweisung der Pin 
Change Interrupts:
1
// Pinzuweisung Encoder:     Arduino-Pin
2
#define ENC_A           PD4  //     4 // CLK = A am Encoder
3
#define ENC_A_DD       DDD4           // zugehöriger Data-Direction-Pin
4
#define ENC_A_PIN     PIND            // zugehörige Port-Eingangadresse
5
#define ENC_A_DDR     DDRD            // zugehöriges Data-Direction-Register
6
#define ENC_B           PD5  //     5 // DT  = B am Encoder
7
#define ENC_B_DD       DDD5           // zugehöriger Data-Direction-Pin
8
#define ENC_B_PIN     PIND            // zugehörige Port-Eingangadresse
9
#define ENC_B_DDR     DDRD            // zugehöriges Data-Direction-Register
10
#define ENC_S           PB1  //     9 // SW  = Taster/Switch ist normally opened (NO) am Encoder
11
#define ENC_S_DD       DDB1           // zugehöriger Data-Direction-Pin
12
#define ENC_S_PIN     PINB            // zugehörige Port-Eingangadresse
13
#define ENC_S_DDR     DDRB            // zugehöriges Data-Direction-Register
14
15
#if (ENC_A_DDR == DDRD) || (ENC_B_DDR == DDRD) || (ENC_S_DDR == DDRD)  // funktioniert nicht weil nur Zahlen verglichen werden können
16
  #define PCIE2_USED
17
#endif
18
#if (ENC_A_DDR == DDRC) || (ENC_B_DDR == DDRC) || (ENC_S_DDR == DDRC)  // funktioniert nicht weil nur Zahlen verglichen werden können
19
  #define PCIE1_USED
20
#endif
21
#if (ENC_A_DDR == DDRB) || (ENC_B_DDR == DDRB) || (ENC_S_DDR == DDRB)  // funktioniert nicht weil nur Zahlen verglichen werden können
22
  #define PCIE0_USED
23
#endif

Im Programm wird dann zugewiesen:
1
#ifdef PCIE2_USED
2
  PCICR |= (1 << PCIE2);  // Pin-Change-Interrupts für PCINT[23:16] (PORTD).
3
#endif
4
#ifdef PCIE1_USED
5
  PCICR |= (1 << PCIE1);  // Pin-Change-Interrupts für PCINT[8:14] (PORTD). PCINT15 ist bei ATmega168 und ATmega328 nicht vorhanden.
6
#endif
7
#ifdef PCIE0_USED
8
  PCICR |= (1 << PCIE0);  // Pin-Change-Interrupts für PCINT[7:0] (PORTB).
9
#endif

Wie erledige ich die folgenden Zuweisungen automatisiert?
1
  PCMSK2 |= ((1 << PCINT20) | (1<<PCINT21));  // Pin-Change-Interrupts nur für ENC_A, ENC_B
2
  PCMSK0 |= (1 << PCINT1);  // Pin-Change-Interrupt nur für ENC_S (PORTB)

Grüße an Alle, die mir helfen. ;-)
SG

von Stefan F. (Gast)


Lesenswert?

Lass solche Tricks besser sein. Sie machen früher oder später Probleme, 
spätestens wenn jemand damit weiter arbeiten muss, der sich mit den 
zahlreichen Haken und Ösen nicht auskennt.

Viel mehr als einfache Textersetzungen halte ich für nicht ratsam.

von Einer K. (Gast)


Lesenswert?

SG schrieb:
> Ich lerne gerade Arduinos und C.
> Gibt es ein Tutorial was ein paar "trickreiche" Beispiele zum
> Präprozessor verrät?
> Oder erwarte ich da vielleicht zuviel?

Erstens:
Arduino ist C++, und nicht C

Zweitens:
Die C++ Entwickler haben sich große Mühe gegeben, und werden das 
fortsetzen, die Nutzung des Präprozessors möglichst unnötig zu machen.

Drittens:
Du buddelst auf der falschen Baustelle.
Der Präprozessor lenkt dich nur vom (C++) lernen ab.

-------

OK, ich habe Verständnis dafür, wenn man die Fähigkeiten des 
Präprozessors kennenlernen will.
Aber danach kannst du 90% direkt wieder vergessen.
Denn das wird dir eher im Wege rum stehen, als nutzen.

von S. R. (svenska)


Lesenswert?

SG schrieb:
> Gibt es ein Tutorial was ein paar "trickreiche" Beispiele zum
> Präprozessor verrät?

Die meisten trickreichen Verwendungen des Präprozessors haben einen ganz 
bestimmten Grund. Meist handelt es sich um üble Hacks, um sich um 
bestimmte Probleme herumzuarbeiten - es geht eher selten darum, sie zu 
lösen.

> Der Präprozessor ist ja nicht gerade umfangreich was den Befehlssatz
> betrifft.

Der Präprozessor macht ziemlich stupide Textersetzung, mehr nicht. Die 
meiste höhere Funktionalität ergibt sich erst im Zusammenspiel mit der 
späteren Optimierung durch den Compiler.

SG schrieb:
> Wie ist es möglich die "Version" aus Datumscode (vielleicht sogar der
> Datei) zusammenzusetzen?

Der Präprozessor kennt immerhin das aktuelle Datum und die aktuelle 
Uhrzeit. Zusammenbauen kannst du die wie folgt:
1
#define HEUTE (__DATE__ " " __TIME__)
Wenn dir das Format nicht gefällt, hast du allerdings Pech gehabt.

SG schrieb:
> Der Präprozessor macht mir gerade zu schaffen bei der Zuweisung der Pin
> Change Interrupts:

Das ist schon jenseits der Grenze, wo die Verwendung des Präprozessors 
sinnvoll ist. Mach die ganzen Vergleiche einfach im C-Code. Da du am 
Ende sowieso nur Compiletime-Konstanten vergleichst, sollte der Compiler 
das sauber wegoptimieren. Lass ihn das einfach tun.

Den Präprozessor brauchst hierbei du nur, wenn du bestimmte Definitionen 
nicht immer zur Verfügung hast (je nach AVR-Typ). Allerdings solltest du 
nach AVR-Typ selektieren, nicht nach der Implikation daraus.

von SG (Gast)


Lesenswert?

Hallo.

Wie ich jetzt herausgefunden habe sind die folgenden Makros im 
Assembler-Präprozessor vordefiniert:
    _YEAR_, _MONTH_, _DAY_, _HOUR_, _MINUTE_, _SECOND_
http://www.microchip.com/webdoc/avrassembler/avrassembler.wb_preprocessor.Pre-defined_macros.html

Im C-Standard sind die vorgenannten Makros nicht definiert, nur 
_DATE_, _TIME_.
Im folgenden Link hat das auch jemand angeprangert:
https://www.avrfreaks.net/comment/1350721#comment-1350721

Wie krank ist das denn?
Wenn ich eins hasse ist es Ignoranz gekoppelt mit Dummheit!

Wie ist es dann möglich mit dem Präprozessor in C einen Datumsstempel 
"YYYYMMDD" und einen Zeitstempel "HHMMSS" (einfach) zu generieren?

Grüße
SG

von S. R. (svenska)


Lesenswert?

SG schrieb:
> Wie krank ist das denn?

Tja, das passiert halt, wenn man sich an Standards hält, anstatt die 
Wünsche einer beliebigen Zufallsperson ohne Ahnung...

SG schrieb:
> Wenn ich eins hasse ist es Ignoranz gekoppelt mit Dummheit!

Dabei ist Selbsthass doch so ungesund...

Du verwechselst übrigens zwei Programme (nämlich Atmels AVR-Assembler 
und gnu-as). Die haben miteinander nur wenig gemeinsam, eigentlich sogar 
garnichts. Und was Atmel mit ihrem Assembler macht, ist ihre Sache - was 
der GCC macht, nicht. Denn da gibt's nen Standard.

SG schrieb:
> Wie ist es dann möglich mit dem Präprozessor in C einen Datumsstempel
> "YYYYMMDD" und einen Zeitstempel "HHMMSS" (einfach) zu generieren?

Garnicht. Falsches Werkzeug.

: Bearbeitet durch User
von SG (Gast)


Lesenswert?

Hallo.

S. R. schrieb:
> Dabei ist Selbsthass doch so ungesund...

Bitte keine Beleidigungen oder Angriffe auf meine Person.
Bitte sachlich bleiben.

S. R. schrieb:
> Garnicht. Falsches Werkzeug.

Ich suche Lösungen.
Was ist das richtige Werkzeug?

Grüße
SG

von I <3 Makefiles (Gast)


Lesenswert?

> S. R. schrieb:
>> Garnicht. Falsches Werkzeug.
>
> Ich suche Lösungen.
> Was ist das richtige Werkzeug?

Die Buildumgebung definiert dies und übergibt von aussen Defines mit 
Schalter "-D" dem Compiler.

von SG (Gast)


Lesenswert?

Hallo.

Nochmal zur Verdeutlichung meiner Anforderung:
Ich sehe ein, daß für ausgelieferte Software eine Versionsnumer sinnvoll 
ist. Darum geht es mir aber nicht.

Während der Entwicklungszeit ist es doch sehr vorteilhaft zu wissen und 
auf dem Display der Applikation zu lesen, welcher Stand (Datum und 
Uhrzeit) gerade im µC läuft (wird nach dem Einschalten kurz angezeigt).
Ich finde es drängt sich förmlich auf die Versionsnummer in dieser Zeit 
mit einem Datums- und Zeitstempel (automatisiert durch den Präprozessor) 
zu belegen.
Ist doch einfach und sinnvoll.

Buildumgebung ist die Arduino IDE.

Ich werde dann wohl _DATE_, _TIME_ nutzen.
Danke für die angebotene Hilfe.
Trotz der nicht gelösten Fragen hilft eine Diskussion zu mehr Einsicht.
Ein Forum dient der Effizienz.

Nachtrag: Ich bitte zukünftig darum sachlich zu bleiben.
Solche Antworten von S. R. empfinde ich als verletzend.
Wer keine Hilfe und Unterstützung geben will oder kann soll doch einfach 
nicht antworten.

Grüße
SG

von Einer K. (Gast)


Lesenswert?

SG schrieb:
> sachlich
Auf mich machst du einen leicht irren Eindruck.

von Stefan F. (Gast)


Lesenswert?

I <3 Makefiles hat die richtige Antwort gegeben. Der Zeitstempel-String 
soll außerhalb vom Compiler/Präprozessor erzeugt werden und als 
Definition (mit dem Parameter -D) an gcc übergeben werden.

Deswegen verwendet man normalerweise ein Makefile oder ein anderes Build 
Script, wo man solche Sachen einbauen kann. Nur im Zeitalter der IDE 
sind Build Scripte aus der Mode gekommen.

Aber: Alle mir bekannten AVR Entwicklungsumgebungen unterstützen 
Makefiles immer noch. man muss sie nur erstellen und einbinden. 
Kopiervorlagen findet man reichlich im Internet.

Unter Linux konstruiert man solche Zeitstempel ganz einfach mit dem Date 
Befehl. Aus dem Bauch heraus würde ich erwarten, dass die Powershell von 
Windows das auch irgendwie kann. Ansonsten wäre das nun ein guter Grund, 
mal Linux auszuprobieren. Dort fühlt sich gcc sowieso mehr zuhause und 
läuft auch viel schneller.

von S. R. (svenska)


Lesenswert?

SG schrieb:
>> Garnicht. Falsches Werkzeug.
> Ich suche Lösungen.

Wie ich bereits schrieb, der Präprozessor ist geeignet für Workarounds, 
nicht für Lösungen.

SG schrieb:
> Solche Antworten von S. R. empfinde ich als verletzend.

Tschuldigung, du hast da aber eine absolute Steilvorlage hingelegt. 
Zumal ich dir schon vorher deutlich beschrieben hatte, was geht und was 
nicht.

Jemanden als dumm und ignorant zu beschimpfen, obwohl er nur das getan 
hat, was er tun musste, ist selbst dumm und ignorant.

> sachlich

Wenn es dir nur um ein "dieses Build war von $TAG, $UHRZEIT" geht, dann 
kann der Präprozessor das. Ansonsten gehört sowas in die Buildumgebung 
(denn nur die kann automatisiert auch git-Hashes oder svn-Revisionen 
auslesen), und zu guter Letzt kannst du den Präprozessor-String auch im 
Code parsen.

Aber das wurde dir alles schon genannt.

von SG (Gast)


Lesenswert?

Ich mag Politiker und inhaltslose Phrasen nicht.

von Peter D. (peda)


Lesenswert?

SG schrieb:
> Wie ist es dann möglich mit dem Präprozessor in C einen Datumsstempel
> "YYYYMMDD" und einen Zeitstempel "HHMMSS" (einfach) zu generieren?

Mit einer Batch kannst Du Dir jedes beliebige Format zusammen basteln:
https://stackoverflow.com/questions/4248220/how-can-i-retrieve-the-seconds-part-of-time-in-cmd

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.