Go Down

Topic: Wie Headerdatei in andere .h / .cpp einbinden ? (Read 281 times) previous topic - next topic

Doc_Arduino

Hallo,

habe Codeteile ausgelagert und habe nun das Problem ein Headerfile in eine andere Headerdatei bzw. Implementationsdatei verwendbar zu machen. Im Grunde ist die PortBitDefinitionen.h in der Encoder.cpp eingebunden. Reicht irgendwie nicht aus. Ich weiß nicht warum. Mein Buch hilft mir da nicht weiter. Habe mich schon mit der Mehrfachbedeutung von static gequält.
Wie gehts richtig? Wo ist der Fehler?

Ich erhalte folgende Fehlermeldung.

Code: [Select]

Arduino: 1.8.8 (Windows 10), Board: "Arduino/Genuino Mega or Mega 2560, ATmega2560 (Mega 2560)"

C:\Users\Worker\AppData\Local\Temp\ccWcxECc.ltrans0.ltrans.o: In function `main':

<artificial>:(.text.startup+0x1f8): undefined reference to `getInPort(unsigned char)'

<artificial>:(.text.startup+0x204): undefined reference to `getMaske(unsigned char)'

<artificial>:(.text.startup+0x218): undefined reference to `getInPort(unsigned char)'

<artificial>:(.text.startup+0x224): undefined reference to `getMaske(unsigned char)'


Sketch:
Code: [Select]

#include <Encoder.h>

Encoder Encoder1 (36, 37 ,4 ,10, 20);  // Phase A/B, Raster, min, max
int Encoder1_Direction;
int Encoder1_Counter;
byte Encoder1_Modulo;

void setup() {
  Serial.begin(250000);
 
  pinMode(36, INPUT_PULLUP);
  pinMode(37, INPUT_PULLUP);
}

void loop() {

  update_Encoder();
 
  serieller_Monitor();
}


void update_Encoder ()
{   
  Encoder1.encode();
  Encoder1_Direction = Encoder1.getDirection();
  Encoder1_Counter   = Encoder1.getRelCounter(); 
  Encoder1_Modulo    = abs( Encoder1_Counter % 31 );     // Wertebereich 0 ... 30
}

void serieller_Monitor ()
{
  static const unsigned int INTERVAL = 250;
  static unsigned long last_ms = 0;

  if (millis() - last_ms < INTERVAL) return; // Zeit noch nicht erreicht, Funktion abbrechen
 
  last_ms += INTERVAL;
  Serial.print(Encoder1_Direction); Serial.print('\t');
  Serial.print(Encoder1_Counter); Serial.print('\t');
  Serial.print(Encoder1_Modulo);
  Serial.println();
}
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

DrDiettrich

Ich vermute mal, daß <artificial> mit der IDE oder anderen C++ Fietschers zu tun hat. Da fällt mir sofort Encoder Encoder(...) auf, womit der Konstruktor vor dem Beginn des Programmcodes aufgerufen wird. Das war schon ein Fehler in meinem allerersten C++ Programm, weil der Konstruktor irgendwas benutzen wollte, das zu diesem Zeitpunkt noch garnicht verfügbar war.

Falls das auch hier der Fall ist, hilft die übliche Aufteilung in einen Konstruktor, der nichts tut, und eine begin() Methode, welche in setup() die eigentliche Initialisierung durchführt.

combie

Naja...

Hier hat es eher damit zu tun, dass die Funktions- Deklarationen wild rumstehen und keine Definition haben.

Quote
Code: [Select]
uint8_t getPortBit(const uint8_t pin);

uint8_t getMaske(const uint8_t pin);

Register getOutPort(const uint8_t pin);

Register getDdrPort(const uint8_t pin);

Register getInPort(const uint8_t pin);
Es ist völlig daneben, Funktionen aufzurufen, welche nicht existieren.
Kein Wunder, dass der Linker dabei ins Essen bricht.
Das ist seine Pflicht.



Des weiteren, machen die #include <PortBitDefinitionen.h> nur Sinn, wenn es eine Library ist.
Wenn die Dateien im Sketch Ordner liegen, wäre #include "PortBitDefinitionen.h" viel angemessener.
Aber das ist ja geheim.


Quote
Falls das auch hier der Fall ist, hilft die übliche Aufteilung in einen Konstruktor, der nichts tut, und eine begin() Methode, welche in setup() die eigentliche Initialisierung durchführt.
Durchaus richtig.
Verstöße zeigen ihre Folgen aber meist erst zur Laufzeit.
Schreie nach Besserem, bis du es auch erhältst.
Das noch Bessere verabschiedet sich rechtzeitig vor deinem Lärm.

Quelle: Martin Gerhard Reisenberg

Doc_Arduino

Hallo,

ich hatte mich in der Zwischenzeit weiter belesen, kam aber noch nicht zur Lösung. Deswegen habe ich die Klasse in der PortBitDefinitionen.h wieder entfernt. Es ist erstmal wieder eine Headerdatei ohne Implementationsdatei. Diese soll bewusst nicht im Sketchordner rumliegen sondern bewusst im libraries Ordner, damit ich auch in späteren Programmen darauf zugreifen kann und diese Datei nicht von Sketch zu Sketch mitschleppen muss. Die Encoderklasse ist nun ein Klassentemplate. Ein Klassentemplate soll man erstmal nicht auftrennen in Headerdatei und Implementationsdatei. Das ist/wäre aufwendiger. Man müsste diese erst nach der Deklaration einbinden. Mach ich erstmal nicht. Dabei ist wie erwartet der RAM Verbrauch geschrumpft, aber diesmal der Flash deutlich angestiegen. Ob das nur am Code auslagern liegt bin ich noch dran rauszufinden.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Doc_Arduino

Hallo,

wenn ich heute weiter so darüber nachdenke darf PortBitDefinitionen.h keine Klasse werden. Eine Klasse mit alles private wäre sinnlos und käme aufs gleiche raus wie gleich ganz ohne Klasse. Das muss eine reine "Header" Funktionssammlung bleiben auf die man "frei" zugreifen muss. Ich möchte ja keine festen Objekte erstellen. Damit liege ich richtig - oder?
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

combie

Quote
Damit liege ich richtig - oder?
Jain!

Es ist schon sinnvoll, den Geltungsbereich möglichst weit einzuschränken.
Wenn du das willst, gibt es mehrere Möglichkeiten.

Freie Auswahl, du hast!
Schreie nach Besserem, bis du es auch erhältst.
Das noch Bessere verabschiedet sich rechtzeitig vor deinem Lärm.

Quelle: Martin Gerhard Reisenberg

Doc_Arduino

#6
Dec 16, 2018, 05:12 pm Last Edit: Dec 16, 2018, 05:39 pm by Doc_Arduino
Hallo,

wegen dem Flash, RAM habe ich den template Konstruktor nochmal ausgetestet. Wenn man meint man kann ihm gut unter die Arme greifen so irrt man. Es kann gut gehen, kann aber auch schief.

Bsp. mit 4 Instanzen.

Wenn ich alle Member vom template Konstruktor der Initialisierungsliste übergebe, dann komme ich auf
Flash 3116 Byte, RAM 774 Byte

Entferne ich die pins aus der Initialisierungsliste, sodass er diese aus dem template Konstruktor direkt verwenden kann so komme ich auf
Flash 2568 Byte, RAM 276 Byte

Treibe ich das Spiel weiter mit dem relativen Zählumfang relMin und relMax, dann geht das plötzlich mit dem Flash nach hinten los.
Flash 3504 Byte, RAM 268 Byte

Als Zusatzmaßnahme habe ich wieder "deinen" namespace verwendet.
Das static Attribut vor den Arrays soll ein zusätzlicher Zugriffsschutz sein, damit nur Objkete Zugriff haben. Ob das im Zusammenhang mit constexpr sinnvoll ist kann ich jedoch nicht sagen. Wirft keine Warnungen und Flash, Ram bleibt unverändert. Den funktionsfähigen Code hänge ich ran. Wenn da kein überflüssiger Murks drin steht ??  bin ich mit dem erstmal zufrieden.

Code: [Select]

#include <Encoder_template.h>

// ---------------------------------------------------------------------------------------

Encoder <37, 36, 4, 10, 20> Encoder1;   // Phase A/B
Encoder <37, 36, 4,  0, 10> ALPS_EM20B; // Phase A/B / Raster/ RelMin / RelMax
Encoder <40, 41, 2,  0, 20> ALPS_EC11;  // Phase A/B / Raster/ RelMin / RelMax
Encoder <40, 41, 2>         ALPS;       // Phase A/B / Raster

int Encoder1_AbsCounter;
int ALPS_EM20B_AbsCounter;
int ALPS_EC11_AbsCounter;
int ALPS_AbsCounter;

void setup() {
  Serial.begin(250000);
  
  Encoder1.init();
  ALPS_EM20B.init();
  ALPS_EC11.init();
  ALPS.init();
}

void loop() {
  update_Encoder();
}


// ****** Funktionen ******
void update_Encoder ()
{
  Encoder1.encode();
  Encoder1_AbsCounter = Encoder1.getAbsCounter();
  
  ALPS_EM20B.encode();
  ALPS_EM20B_AbsCounter = ALPS_EM20B.getAbsCounter();

  ALPS_EC11.encode();
  ALPS_EC11_AbsCounter = ALPS_EC11.getAbsCounter();

  ALPS.encode();
  ALPS_AbsCounter = ALPS.getAbsCounter();
}
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

combie

Quote
Als Zusatzmaßnahme habe ich wieder "deinen" namespace verwendet.
Nöö....
Bei mir stecken die Arrays in einem anonymen namespace.



Quote
Das static Attribut vor den Arrays soll ein zusätzlicher Zugriffsschutz sein, damit nur Objkete Zugriff haben.
Wo haste denn diese lustige Idee her?
Zumindest verstehen ich dich nicht.


Quote
Treibe ich das Spiel weiter mit dem relativen Zählumfang relMin und relMax, dann geht das plötzlich mit dem Flash nach hinten los.
Das sachte ich ja schon....
Auch mit Begründung.


Schreie nach Besserem, bis du es auch erhältst.
Das noch Bessere verabschiedet sich rechtzeitig vor deinem Lärm.

Quelle: Martin Gerhard Reisenberg

Doc_Arduino

Das mit static habe ich aus dem Buch "Der C++ Programmierer". Habe mir folgendes notiert.
Mit 'static' versehene Methoden sind nicht global sichtbar. Sie sind nur in der eigenen Übersetzungseinheit sichtbar.
Meine Notizen.
Code: [Select]

ONE DEFINITION RULES

Header Dateien (*.h)
====================

extern int global;                // Deklaration globaler Variablen
extern const int GLOBALE_KONSTANTE;        // Deklaration globaler Konstanten
const int MAXI = 88;                // Definition von Konstanten die nur in der Übersetzungseinheit sichtbar sind

struct Punkt {                    // Definition eines Datentyps
    int x;
    int y;
};

enum Wochenende {Samstag, Sonntag};        // Definition eines Datentyps


> Variablen ohne das Schlüsselwort 'extern' sind global. Wird die Headerdatei mehrfach eingebunden so wird die Variable mehrfach angelegt.

> Globale Variablen sollen immer 'extern' deklariert werden und die Definition soll nur in einer Übersetzungseinheit vorkommen.

> Konstanten ohne das Schlüsselwort 'extern' sind nicht global und beziehen sich nur auf die Übersetzungseinheit.


Implementationsdateien (*.cpp)
==============================

extern const int GLOBALE_KONSTANTE = 1;    // Definition und Initialisierung einer Konstanten (nur einmal im Programm    )

void meineFunktion (int x) {            // Funktionsdefinition
    // ... Programmcode
}

int global;                    // Definition globaler Objekte (nur einmal im Programm)
Punkt einPunkt;                    // Definition globaler Objekte (nur einmal im Programm)
Wochenende einWochenende;            // Definition globaler Objekte (nur einmal im Programm)

===============================================================================================================

> Variablen die außerhalb von main() und jeglichen anderen Funktionen definiert sind heißen 'global'. Sie sind in allen Programmteilen gültig, auch in anderen Dateien. Eine globale Variable muss in einer anderen Datei nur als 'extern' deklariert werden um dort benutzbar zu sein.

> Mit 'static' versehene Methoden sind nicht global sichtbar. Sie sind nur in der eigenen Übersetzungseinheit sichtbar.


Anonymer namespace geht nicht, weil das nicht alles in der gleichen Übersetzungseinheit ist. Wird in PortBitList.h definiert/deklariert und in Encoder_template.h verwendet. Was ich mir jedoch sparen kann ist 'static' wenn ich einen benannten namespace verwende.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

combie

Quote
Mit 'static' versehene Methoden sind nicht global sichtbar. Sie sind nur in der eigenen Übersetzungseinheit sichtbar.
Ist wohl so!

Hat aber nichts mit diesem zu tun:
Quote
Das static Attribut vor den Arrays soll ein zusätzlicher Zugriffsschutz sein, damit nur Objkete Zugriff haben.
-----

Quote
Anonymer namespace geht nicht, weil das nicht alles in der gleichen Übersetzungseinheit ist
Natürlich geht das!

Du bist immer so schnell im zuordnen/urteilen....

Die Arrays können natürlich in einen anonymen namespace. (Siehe die CombiePin.h)

Denn:
Wenn du das nutzen willst, musst die jeweilige *.h einbinden.
Damit ist es in der Übersetzungseinheit.

Jetzt kann es natürlich sein, dass dein Wort "Übersetzungseinheit", eine andere Bedeutung hat, als mein Wort "Übersetzungseinheit"
Ich werde mich dann nicht deiner Begriffsbestimmung anschließen.


Schreie nach Besserem, bis du es auch erhältst.
Das noch Bessere verabschiedet sich rechtzeitig vor deinem Lärm.

Quelle: Martin Gerhard Reisenberg

Doc_Arduino

Hallo,

ich bin/war der Meinung das eine Übersetzungseinheit immer die Kombination aus einer Header und ihrer Implementationsdatei ist. Weil diese für sich übersetzt werden können. Offensichtlich falsch. Sobald noch eine andere Lib inkludiert wird, wird die Übersetzungseinheit größer.

Deine CombiePin hat 3 namespaces. Okay eine anonyme und 2 mit Namen. Warum überhaupt drei?
Dein namespace Pin bindet deinen anonymen namespace automatisch mit ein. Man hat auf alles Zugriff innerhalb Pin
mit using namespace Combie::Pin
So verstehe ich das. Richtig?

Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Doc_Arduino

Hallo,

jetzt weiß ich endlich wie ich den anonymen namespace richtig nutzen muss ... hatte zu groß gedacht ... 
PortBitList.h
Code: [Select]

#pragma once

using Register = volatile uint8_t *;

namespace
{
    // Die Arrays sind automatisch generierter Code, bitte nicht haendisch aendern
    // Der Index ist jeweils die Arduino Pinnummer
        
    // UNO, Nano, Pro Mini usw.
    #if defined(__AVR_ATmega328P__) | defined(__AVR_ATmega328__) | defined(__AVR_ATmega168P__) | defined(__AVR_ATmega168__)  
     constexpr uint8_t portBit[]   = {0,1,2,3,4,5,6,7,0,1,2,3,4,5,0,1,2,3,4,5};
     constexpr uint8_t pinMaske[]  = {0b1,0b10,0b100,0b1000,0b10000,0b100000,0b1000000,0b10000000,0b1,0b10,0b100,0b1000,0b10000,0b100000,0b1,0b10,0b100,0b1000,0b10000,0b100000};
     constexpr Register portList[] = {&PORTD,&PORTD,&PORTD,&PORTD,&PORTD,&PORTD,&PORTD,&PORTD,&PORTB,&PORTB,&PORTB,&PORTB,&PORTB,&PORTB,&PORTC,&PORTC,&PORTC,&PORTC,&PORTC,&PORTC};
     constexpr Register ddrList[]  = {&DDRD,&DDRD,&DDRD,&DDRD,&DDRD,&DDRD,&DDRD,&DDRD,&DDRB,&DDRB,&DDRB,&DDRB,&DDRB,&DDRB,&DDRC,&DDRC,&DDRC,&DDRC,&DDRC,&DDRC};
     constexpr Register pinList[]  = {&PIND,&PIND,&PIND,&PIND,&PIND,&PIND,&PIND,&PIND,&PINB,&PINB,&PINB,&PINB,&PINB,&PINB,&PINC,&PINC,&PINC,&PINC,&PINC,&PINC};
    // #endif

    // Leonardo, Micro, usw.
    #elif defined(__AVR_ATmega32U4__)
     constexpr uint8_t portBit[]   = {2,3,1,0,4,6,7,6,4,5,6,7,6,7,3,1,2,0,7,6,5,4,1,0};                    
     constexpr uint8_t pinMaske[]  = {0b100,0b1000,0b10,0b1,0b10000,0b1000000,0b10000000,0b1000000,0b10000,0b100000,0b1000000,0b10000000,0b1000000,0b10000000,0b1000,0b10,0b100,0b1,0b10000000,0b1000000,0b100000,0b10000,0b10,0b1};
     constexpr Register portList[] = {&PORTD,&PORTD,&PORTD,&PORTD,&PORTD,&PORTC,&PORTD,&PORTE,&PORTB,&PORTB,&PORTB,&PORTB,&PORTD,&PORTC,&PORTB,&PORTB,&PORTB,&PORTB,&PORTF,&PORTF,&PORTF,&PORTF,&PORTF,&PORTF};
     constexpr Register ddrList[]  = {&DDRD,&DDRD,&DDRD,&DDRD,&DDRD,&DDRC,&DDRD,&DDRE,&DDRB,&DDRB,&DDRB,&DDRB,&DDRD,&DDRC,&DDRB,&DDRB,&DDRB,&DDRB,&DDRF,&DDRF,&DDRF,&DDRF,&DDRF,&DDRF};
     constexpr Register pinList[]  = {&PIND,&PIND,&PIND,&PIND,&PIND,&PINC,&PIND,&PINE,&PINB,&PINB,&PINB,&PINB,&PIND,&PINC,&PINB,&PINB,&PINB,&PINB,&PINF,&PINF,&PINF,&PINF,&PINF,&PINF};
    // #endif  

    // Mega
    #elif defined(__AVR_ATmega2560__) | defined(__AVR_ATmega1280__)
     constexpr uint8_t portBit[]   = {0,1,4,5,5,3,3,4,5,6,4,5,6,7,1,0,1,0,3,2,1,0,0,1,2,3,4,5,6,7,7,6,5,4,3,2,1,0,7,2,1,0,7,6,5,4,3,2,1,0,3,2,1,0,0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7};
     constexpr uint8_t pinMaske[]  = {0b1,0b10,0b10000,0b100000,0b100000,0b1000,0b1000,0b10000,0b100000,0b1000000,0b10000,0b100000,0b1000000,0b10000000,0b10,0b1,0b10,0b1,0b1000,0b100,0b10,0b1,0b1,0b10,0b100,0b1000,0b10000,0b100000,0b1000000,0b10000000,0b10000000,0b1000000,0b100000,0b10000,0b1000,0b100,0b10,0b1,0b10000000,0b100,0b10,0b1,0b10000000,0b1000000,0b100000,0b10000,0b1000,0b100,0b10,0b1,0b1000,0b100,0b10,0b1,0b1,0b10,0b100,0b1000,0b10000,0b100000,0b1000000,0b10000000,0b1,0b10,0b100,0b1000,0b10000,0b100000,0b1000000,0b10000000};
     constexpr Register portList[] = {&PORTE,&PORTE,&PORTE,&PORTE,&PORTG,&PORTE,&PORTH,&PORTH,&PORTH,&PORTH,&PORTB,&PORTB,&PORTB,&PORTB,&PORTJ,&PORTJ,&PORTH,&PORTH,&PORTD,&PORTD,&PORTD,&PORTD,&PORTA,&PORTA,&PORTA,&PORTA,&PORTA,&PORTA,&PORTA,&PORTA,&PORTC,&PORTC,&PORTC,&PORTC,&PORTC,&PORTC,&PORTC,&PORTC,&PORTD,&PORTG,&PORTG,&PORTG,&PORTL,&PORTL,&PORTL,&PORTL,&PORTL,&PORTL,&PORTL,&PORTL,&PORTB,&PORTB,&PORTB,&PORTB,&PORTF,&PORTF,&PORTF,&PORTF,&PORTF,&PORTF,&PORTF,&PORTF,&PORTK,&PORTK,&PORTK,&PORTK,&PORTK,&PORTK,&PORTK,&PORTK};
     constexpr Register ddrList[]  = {&DDRE,&DDRE,&DDRE,&DDRE,&DDRG,&DDRE,&DDRH,&DDRH,&DDRH,&DDRH,&DDRB,&DDRB,&DDRB,&DDRB,&DDRJ,&DDRJ,&DDRH,&DDRH,&DDRD,&DDRD,&DDRD,&DDRD,&DDRA,&DDRA,&DDRA,&DDRA,&DDRA,&DDRA,&DDRA,&DDRA,&DDRC,&DDRC,&DDRC,&DDRC,&DDRC,&DDRC,&DDRC,&DDRC,&DDRD,&DDRG,&DDRG,&DDRG,&DDRL,&DDRL,&DDRL,&DDRL,&DDRL,&DDRL,&DDRL,&DDRL,&DDRB,&DDRB,&DDRB,&DDRB,&DDRF,&DDRF,&DDRF,&DDRF,&DDRF,&DDRF,&DDRF,&DDRF,&DDRK,&DDRK,&DDRK,&DDRK,&DDRK,&DDRK,&DDRK,&DDRK};
     constexpr Register pinList[]  = {&PINE,&PINE,&PINE,&PINE,&PING,&PINE,&PINH,&PINH,&PINH,&PINH,&PINB,&PINB,&PINB,&PINB,&PINJ,&PINJ,&PINH,&PINH,&PIND,&PIND,&PIND,&PIND,&PINA,&PINA,&PINA,&PINA,&PINA,&PINA,&PINA,&PINA,&PINC,&PINC,&PINC,&PINC,&PINC,&PINC,&PINC,&PINC,&PIND,&PING,&PING,&PING,&PINL,&PINL,&PINL,&PINL,&PINL,&PINL,&PINL,&PINL,&PINB,&PINB,&PINB,&PINB,&PINF,&PINF,&PINF,&PINF,&PINF,&PINF,&PINF,&PINF,&PINK,&PINK,&PINK,&PINK,&PINK,&PINK,&PINK,&PINK};
    // #endif

    // ATtiny841
    #elif defined(__AVR_ATtiny841__) | defined(__AVR_ATtiny441__)
     constexpr uint8_t portBit[]   = {0, 1, 2, 7, 6, 5, 4, 3, 2, 1, 0};                    
     constexpr uint8_t pinMaske[]  = {0b1,0b10,0b100,0b10000000,0b1000000,0b100000,0b10000,0b1000,0b100,0b10,0b1};
     constexpr Register portList[] = {&PORTB,&PORTB,&PORTB,&PORTA,&PORTA,&PORTA,&PORTA,&PORTA,&PORTA,&PORTA,&PORTA};
     constexpr Register ddrList[]  = {&DDRB,&DDRB,&DDRB,&DDRA,&DDRA,&DDRA,&DDRA,&DDRA,&DDRA,&DDRA,&DDRA};
     constexpr Register pinList[]  = {&PINB,&PINB,&PINB,&PINA,&PINA,&PINA,&PINA,&PINA,&PINA,&PINA,&PINA};
    // #endif

    #else
          #error "This AVR type is currently not yet supported."
    #endif
}

constexpr uint8_t getPortBit(const uint8_t pin)
{
  return portBit[pin];
};

constexpr uint8_t getMaske(const uint8_t pin)
{
  return pinMaske[pin];
};

constexpr Register getOutPort(const uint8_t pin)
{
  return portList[pin];
};

constexpr Register getDdrPort(const uint8_t pin)
{
  return ddrList[pin];
};

constexpr Register getInPort(const uint8_t pin)
{
  return pinList[pin];
};

inline __attribute__((always_inline)) void digitalSwitch(uint8_t pin, uint8_t state) {
    if (state) *getOutPort(pin) |= getMaske(pin);
    else *getOutPort(pin) &= ~getMaske(pin);
}
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

combie

Quote
jetzt weiß ich endlich wie ich den anonymen namespace richtig nutzen muss
Fein!
Schreie nach Besserem, bis du es auch erhältst.
Das noch Bessere verabschiedet sich rechtzeitig vor deinem Lärm.

Quelle: Martin Gerhard Reisenberg

Doc_Arduino

Hallo,

falls hier noch paar andere mitlesen und das nutzen, ich habe noch paar Datentypen angepasst, angenehmer Effekt war, Flash/RAM ist noch um paar Bytes gesunken.  Flash 2448 Byte, RAM 264 Byte mit obigen einfachen "sinnlosen" Testsketch.

Mit 2 Instanzen und alle Rückgabewerte genutzt macht dann  Flash 3312 Byte, RAM 256 Byte.
Der relative Counter ist auf einen Wertebereich int festgelegt, der Absolute auf long.

Code: [Select]

/*
   Doc Arduino - german Arduino Forum
   IDE 1.8.8
   Arduino Mega2560
   17.12.2018
 */

#include <Encoder_template.h>

// ---------------------------------------------------------------------------------------

Encoder <36, 37, 4, -10, 10> ALPS_EM20B; // Phase A/B / Raster/ RelMin / RelMax
Encoder <40, 41, 2,   0, 20> ALPS_EC11;  // Phase A/B / Raster/ RelMin / RelMax

struct t_encoder {
  char direction;
  int  relativ;
  long absolut;
  byte phase_A;
  byte phase_B;
};

t_encoder alps_EM20B;
t_encoder alps_EC11;


void setup() {
  Serial.begin(250000);
  
  ALPS_EM20B.init();
  ALPS_EC11.init();
}

void loop() {

  update_Encoder();

  Ausgabe();
 
}


// ****** Funktionen ******

void update_Encoder ()
{  
  ALPS_EM20B.encode();
  alps_EM20B.direction = ALPS_EM20B.getDirection();
  alps_EM20B.relativ = ALPS_EM20B.getRelCounter();
  alps_EM20B.absolut = ALPS_EM20B.getAbsCounter();
  alps_EM20B.phase_A = ALPS_EM20B.getA();
  alps_EM20B.phase_B = ALPS_EM20B.getB();

  ALPS_EC11.encode();
  alps_EC11.direction = ALPS_EC11.getDirection();
  alps_EC11.relativ = ALPS_EC11.getRelCounter();
  alps_EC11.absolut = ALPS_EC11.getAbsCounter();
  alps_EC11.phase_A = ALPS_EC11.getA();
  alps_EC11.phase_B = ALPS_EC11.getB();
}

void Ausgabe()
{
  bool state = false;
  static long enc1_old_abs = 0;
  static long enc2_old_abs = 0;
  
  if (alps_EM20B.absolut != enc1_old_abs) {
    state = true;
    enc1_old_abs = alps_EM20B.absolut;
  }

  if (alps_EC11.absolut != enc2_old_abs) {
    state = true;
    enc2_old_abs = alps_EC11.absolut;
  }

  if (state) {
    serieller_Monitor();
  }
}


void serieller_Monitor ()
{  
  Ueberschriftszeile();

  Serial.print(alps_EM20B.direction,DEC);   Serial.print('\t');
  Serial.print(alps_EM20B.relativ);  Serial.print('\t');
  Serial.print(alps_EM20B.absolut);  Serial.print('\t');
  Serial.print(alps_EM20B.phase_A);  Serial.print('\t');
  Serial.print(alps_EM20B.phase_B);  Serial.print('\t');
  
  Serial.print(alps_EC11.direction,DEC);    Serial.print('\t');
  Serial.print(alps_EC11.relativ);   Serial.print('\t');
  Serial.print(alps_EC11.absolut);   Serial.print('\t');
  Serial.print(alps_EC11.phase_A);   Serial.print('\t');
  Serial.print(alps_EC11.phase_B);
    
  Serial.println();
}


void Ueberschriftszeile ()
{
  static int counter = 33;

  counter++;

  if (counter < 30) return; // Zeilen noch nicht erreicht, Funktion abbrechen

  counter = 0;
 
  Serial.print(F("DIR"));   Serial.print('\t');
  Serial.print(F("rel"));   Serial.print('\t');
  Serial.print(F("abs"));   Serial.print('\t');
  Serial.print(F(" A "));   Serial.print('\t');
  Serial.print(F(" B "));   Serial.print('\t');

  Serial.print(F("DIR"));   Serial.print('\t');
  Serial.print(F("rel"));   Serial.print('\t');
  Serial.print(F("abs"));   Serial.print('\t');
  Serial.print(F(" A "));   Serial.print('\t');
  Serial.print(F(" B "));

  Serial.println();
}



Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Go Up