Go Down

Topic: D0-Schnittstellen-Projekt (Read 1 time) previous topic - next topic

postmaster-ino

#15
Jun 14, 2018, 05:38 pm Last Edit: Jun 17, 2018, 05:29 pm by postmaster-ino
Hi

Ich habe Reaktionen mit dem Photo-Transistor des TCRT5000L.
Die IR-Diode hat 950nm, gleiche Werte beim CNY70, Den ich aber aktuell nicht angeschlossen habe - sollte damit also auch 'reagieren'.

Bisher habe ich es aber noch nicht geschafft, einem Arduino mit dem Photo-Transistor seriell lesen und auf dem Terminal ausgeben zu lassen - und das ganze Gelump am Laptop zum Zähler zu bringen :/
Bin noch oldschool und nutze lieber den PC - da ist 'mobil' aber eben nicht ;)

Bei meinen Vor-Versuchen bekomme ich zumindest 'Irgendwas', egal ob ich den Photo-Transistor GND-seitig einen PullUp runter ziehen lasse, oder den Photo-Transistor Vdd-Seitig einen PullDn hoch ziehen lasse.
Ob Das für eine serielle Erkennung ausreicht, ist noch ungewiss.
Die beiden Wege wollte ich testen, da mir nicht bekannt ist, ob ich bei IR-Licht vom Zähler ein HIGH oder ein LOW 'sehen' muß - da mir zumindest im Arduino kein Weg bekannt ist, das Signal 'umzudrehen' - in anderen Sprachen nutzte man P9600/T9600/N9600 (in der Richtung, ob P oder T gerade ungewiss, N aber mit Sicherheit), um das Signal vor der Erkennung 'umdrehen' zu können.
**Edit**
Zumindest bei SoftwareSerial geht Das mit 'true' als 3.tes Argument - wieder was gelernt
**/Edit**
Laut dem Link sollte IR=LOW passen, zumindest wird mir Das so bei 'Signalaufbereitung' suggeriert - ist aber noch nicht gegengeprüft.

MfG
anscheinend ist Es nicht erwünscht, einen Foren-internen Link als 'Homepage' einzubinden, damit JEDER nur einen Klick von combie's Liste zum Thema State-Maschine entfernt ist.
... dann eben nicht ...

postmaster-ino

#16
Jun 17, 2018, 05:49 pm Last Edit: Jun 17, 2018, 06:31 pm by postmaster-ino
Hi

Vereinzelt konnte ich Daten von meinem Zähler auslesen - Laptop, Steckbrett, I2C-Display und IR-LED an Dupont-Kabeln machen Das nicht einfacher ;)

Damit ich nicht stundenlang vor dem Zähler stehe und NICHTS bekomme, habe ich mir einen 2.ten Arduino als Sender programmiert - Kommunikation klappte, selbst gebaut, natürlich nicht - ein Hoch auf das WWW :)

So konnte ich die gesendeten Daten am Empfänger wieder sehen - natürlich bekam ich vom Zähler nicht das erwartete '0x1B' als Start-Kennung.
Der Zähler sendet 'Negativ' - Sender und Empfänger 'umgedreht' - konnte ich wieder meinen eigenen Sender mitschreiben, wie auch Daten vom Zähler auslesen.

Akut zeigt der Empfänger die Werte für den Bezug und die Lieferung an, wie die aktuelle Leistung - also zumindest von meinem Sender.
Ob das Zerlegen des Datenstrom am echten Zähler auch klappt - noch ungetestet.
1.8.0  2.8.0  (Wirkleistung gesamt, Bezug und Lieferung)
1.8.1  2.8.1  (Wirkleistung Tarif 1, Bezug und Lieferung)
1.8.2  2.8.2  (Wirkleistung Tarif 2, Bezug und Lieferung)
15.7.0   300 (OBIS Kennziffer, rechts die aktuelle Leistung)

Tendenziell sind ALLE Obis-Kennzahlen im Datenstrom des Zähler enthalten, womit die Anzeige unten links obsolet wird.

Teilweise habe ich noch das Problem, daß von meinem Test-Sender statt der übertragenen 28 Zeichen (statt knappe 400 vom Zähler) nur 26 oder 27 erkannt werden - Das dann aber 'nahezu ewig' - noch kA, was mir Da falsch läuft.
In dieser Situation erkenne ich keine der Obis-Kennzahlen
, obwohl Die vorhanden sind (habe Pin10 zum Debug-Pin gemacht - damit wird der Datenstrom wieder im Terminal angezeigt).

Im Anhang meine aktuellen Spielzeuge - beide Nano sitzen auf dem gleichen Steckbrett und die IR-LED / IR-Transistor (eines TCRT5000L) sitzen sich direkt gegenüber.
Beide GND und Vdd sind verbunden - so ist es egal, ob ich den Sender, oder den Empfänger gerade am USB-Kabel hängen habe, um Dessen Code zu ändern - Beide laufen und ich bekomme meine seriellen Ausgaben.

Seid nicht zu hart mit mir ;)

MfG

**EDIT**
In Zeile 244 von xSerial_eHz.ino muß es
a = a - zeichen; heißen
statt a = a - zeichen + 1;
Mir fiel auf, daß die Erkennung nur bei gerader Byte-Anzahl klappte ...
**/Edit**

**Edit 2**
Von wegen es werden nicht alle Zeichen erkannt ...
Da ich ganz vorne millis() ausgeben lasse, habe ich
- nach 10 Sekunden eine zusätzliche Stelle
- nach 100 Sekunden eine Weitere
- ...
Wieder Mal saß der Fehler vor dem Monitor ...
**/Edit 2**
anscheinend ist Es nicht erwünscht, einen Foren-internen Link als 'Homepage' einzubinden, damit JEDER nur einen Klick von combie's Liste zum Thema State-Maschine entfernt ist.
... dann eben nicht ...

postmaster-ino

Hi

eHz-Reader

- LCD 2004 (4 Zeilen a 20 Zeichen, in meinem Fall I²C)
- Drehencoder (Alps, eBay)
- IR-LED eines TCRT5000L (CNY70 müsste auch gehen)

Per SoftwareSerial wird der Datenstrom eines eHz-Zähler aufgenommen.
Dieser wird im Display in den ersten zwei Zeilen angezeigt, obere Zeile als HEX, 2.te Zeile als ASCII (sofern nicht unter 0x21).
Weiter werden in der 2.ten Zeile die Bytes markiert, Die zur Berechnung herangezogen werden.
In der 3.ten Zeile kann man die Breite einstellen (8, 16, 24, 32 Bit),
in der 4.ten Zeile, ob Big- oder Little-Endian.

In der 4.ten Zeile wird neben der Zeichennummer des ersten angezeigten Zeichen auch die Telegramm-Länge angezeigt.
Auf meinem Schreibtisch 30 Byte.
Ganz Rechts steht der Wert des Test-'Byte' in DEZ - max 32 Bit, da Das vom Arduino selber noch berechnet wird - allerdings reichen 4 Byte Breite (=32 Bit) lauf den Informationen, Die ich im INet gefunden habe, für alle Werte, Die so ein Zähler ausspuckt.

Das ist mein erster Sketch in mehreren (ok, nur zwei) Tabs.

Leider bekomme ich beim Kompilieren Warnungen, Die mir nicht viel sagen - oha, mittlerweile bekomme ich auch Warnungen bei den 'constrain'-Zeilen, womit ich den Einstellbereich abgrenzen wollte (aber leider auch Krücken brauchte).

Auf einem NANO:
Der Sketch verwendet 7926 Bytes (25%) des Programmspeicherplatzes. Das Maximum sind 30720 Bytes.
Globale Variablen verwenden 1167 Bytes (56%) des dynamischen Speichers, 881 Bytes für lokale Variablen verbleiben. Das Maximum sind 2048 Bytes.

Die Bedienung ist, so denke ich, recht einfach.
Sobald der Encoder betätigt wird, schaltet der Cursor auf dem LCD auf Blinken.
2 Modi
Inaktiv: Die Zeile des Cursor kann geändert werden - hierbei blinkt der Cursor auf der ersten Stelle
Aktiv: Die Werte/Anzeige der Zeile kann geändert werden - hierbei blinkt der Cursor auf der zweiten Stelle der Zeile

Im inaktivem Modus verlischt der Cursor nach 2 Sekunden ohne Betätigung.
Im aktivem Mode bleibt der Cursor an.

Umschalten mittels Button im Encoder

So richtig fluffig läuft der Sketch nicht, denke die SoftwareSerial und das Pollen des Drehencoder vertragen sich nicht so sonderlich - für meinen Versuch, die Obis-Kennzahl für meinen aktuellen Verbrauch (bzw. Einspeisung) auszulesen, sollte Das aber ausreichend sein.
(Die im INet gefundenen Obis-Kennzahlen, z.B. für aktuellen Verbrauch, scheint mein Zähler nicht auszugeben - deshalb dieser Sketch).

Stichwort Sketch: Im nächsten Post sollte sich Dieser wiederfinden - noch nicht ganz sicher, ob ich mit der Zeichenbegrenzung hinkomme ... gebt mir bitte ein paar Minuten Zeit :)

MfG
anscheinend ist Es nicht erwünscht, einen Foren-internen Link als 'Homepage' einzubinden, damit JEDER nur einen Klick von combie's Liste zum Thema State-Maschine entfernt ist.
... dann eben nicht ...

postmaster-ino

eHz-Reader (benötigt im 2.ten Tab 'Drehencoder.h'
Code: [Select]
#include <LiquidCrystal_I2C.h>

/*
   Anzeige des ausgelesenen Datenstrom in oberen zwei Zeilen des 4002 LCD
   1. Zeile HEX
   2. Zeile ASCII
   3. Zeile Balken, welche Bytes zusammen gerechnet werden, je nach Richtung little oder bigendian
   4. Nummer erstes angezeigte Zeichen, Zeichenanzahl, Breite des Anzeigewert, berechneter Wert

   1B1B1B1B30313233343536
    . . . . 0 1 2 3 4 5 6       <0x21 als Space
            --->            ... oder <----- 24 Big-Endian
     0v385 16b 1234567890        0 Startzeichen (oder ggf. Beginn Marker) v385 Maxzeichen

   Durchscrollbar per Drehencoder
   oberen 2 Zeilen verschieben Anfangszeichen
   3.te Zeile zusammen zu rechnende Stelle
   4.te Zeile Breite des zusammen zu rechnenden Wert
*/

#include <SoftwareSerial.h>

#define rxPin 3
#define txPin 4
const uint32_t baudrate = 9600;         //Baudrate der SoftSerial
const uint16_t bufferlenght = 400;      //Anzahl an Platz für einzulesende Zeichen
byte buffer[bufferlenght];              //in diesem Array
uint32_t lastmillis = millis();         //Zeitpunkt der letzten Übertragung, um die Pause dazwischen erfassen zu können
uint16_t readpointer = 0;               //Lese-Zeiger im Ringspeicher
uint16_t writepointer = 0;              //Schreib-Zeiger im Ringspeicher
uint16_t anzeigeab = 3;                 //Anzeige der Daten ab Zeichen x
byte wertberechnenab = 5;               //Offset zur Anzeige, ab wo der Wert berechnet wird
byte wertbreite = 3;                    //Breite des Wert in Zusatzbytes (0...3 für 8...32 Bit)
boolean bigendian = false;              //Wert als BigEndian berechnen?

const byte wartezeit = 10;              //nach so vielel ms ohne Erkennung sind wir in der Pause
boolean endeerkannt = true;            //das Ende wurde erkannt, beim nächsten Empfang wird der READ-Zeiger erst auf den WRITE-Zeiger gesetzt, damit 'frische' Daten gelesen werden

const byte maxterminal = 20;            //maximal ... Bytes (a 2 Zeichen) von Vorne/Hinten - bis zur doppelten Anzahl werden alle Zeichen ausgegeben

SoftwareSerial XSERIAL =  SoftwareSerial(rxPin, txPin, true);  //false -> nicht negiertes Signal, mein eHz braucht true

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4); // set the LCD I2C-address, LCD-chars, LCD-rows

//RotaryEncoder myencoder(leftPin, rightPin, pulsesPerClick);  //Klasse im Nachbar-Tab
#include "Drehencoder.h"
RotaryEncoder myencoder(4, 5, 4);   //Phasen des Encoder
const byte myencoderbuttonpin = A0;  //Button des Encoder A0=14
uint32_t mybuttonmillis = 0;        //Betätigungszeit
const byte myentpreller = 20;       //ms Entprellzeit
boolean mybutton = HIGH;            //Button wird auf GND getastet, per PullUp nach Vdd gezogen - in Ruhe HIGH
byte aktzeile = 0;                  //aktuelle Zeile, in Der der Drehencoder 'arbeitet'
boolean myaktiv = false;            //durch Butten-Druck wird zwischen aktiv und passiv gewechselt
//passiv zum Wechseln der Reihen, aktiv zum Verändern der Werte
boolean cursoraktiv = false;         //soll der Cursor auf dem LCD angezeigt werden? Wird bei AKTIV immer angezeigt, bei Passiv nur, wenn vergedreht wird
boolean cursorisaktiv = false;       //Zustand des Cursor
uint32_t cursorab = millis();       //Anzaige des Cursor ab 'Uhrzeit'
const uint32_t cursortime = 2000;   //Zeit in ms, bis der Cursor ausgeblendet wird

void setup()
{
  pinMode(myencoderbuttonpin, INPUT_PULLUP);
  XSERIAL.begin(9600);
  Serial.begin(9600);
  Serial.println("xSerial Empfaenger eHz-Reader");
  Serial.println("Start Listening...");
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0);              //X,Y
  lcd.print("eHz - Reader");
  lcd.setCursor(0, 1);
  lcd.print("... ");
  delay(2000);
  lcd.clear();
  myencoder.init();
}
anscheinend ist Es nicht erwünscht, einen Foren-internen Link als 'Homepage' einzubinden, damit JEDER nur einen Klick von combie's Liste zum Thema State-Maschine entfernt ist.
... dann eben nicht ...

postmaster-ino

Part 2 ... loop()
Code: [Select]
void loop()
{
  //Dreh-Encoder aktualisieren
  myencoder.poll();   //Änderungen aufnehmen

  //Wenn neue Daten anliegen, Diese einlesen
  if (XSERIAL.available())
  {
    if (endeerkannt == true) {
      readpointer = writepointer;         //Read-Pointer auf aktuellen Write-Pointer umsetzen
      endeerkannt = false;                //Ende-Erkennung auf false
    }
    char aktubyte = XSERIAL.read();
    lastmillis = millis();                  //'Uhrzeit' des jetzigen Empfang
    buffer[writepointer] = aktubyte;        //im Buffer eintragen
    writepointer = incpointer(writepointer); //Zeiger erhöhen
    if (writepointer == readpointer) {       //wenn der Schreib-Zeiger auf den Lese-Zeiger aufläuft,
      readpointer = incpointer(readpointer); //Diesen ebenfalls verschieben
    }
  }

  if (millis() - lastmillis >= wartezeit && writepointer != readpointer && endeerkannt == false) {
    //Sende-Pause erkannt
    endeerkannt = true;
    //WRITE-Pointer stellt das Ende der Daten dar, READ-Pointer den Start
    uint32_t wert = 0;
    uint16_t aktuzeichen = 0;
    byte zeichennr = 0;

    Serial.print("Anzeigestart ab ");
    Serial.println(anzeigeab);
    //Start-Position der Anzeige ausgeben
    lcd.setCursor(0, 3);
    printlcdnummer(anzeigeab, 100, 10);

    do {
      byte zeichen = buffer[(aktuzeichen + readpointer) % bufferlenght]; //Pointer im Buffer halten
      if (aktuzeichen >= anzeigeab) {
        //hier ab erstem gefordertem Zeichen
        if (zeichennr < 10) {
          //hier bis 10.te geforderte Zeichen

          //Cursor 1.te Zeile für HEX
          lcd.setCursor(zeichennr * 2, 0);
          printlcdnummer(zeichen, 0x10, 16);

          //Cursor 2.te Zeile für ASCII und Marker für Breite
          lcd.setCursor(zeichennr * 2 , 1);
          if (wertberechnenab <= zeichennr && zeichennr <= wertberechnenab + wertbreite) {
            if (bigendian) {
              wert = (uint32_t)(wert << 8) + zeichen;
              if (zeichennr == wertberechnenab && wertbreite != 0) {
                lcd.print("<");
              } else {
                lcd.print("-");
              }
            } else {
              wert += (uint32_t) zeichen << ((zeichennr - wertberechnenab) * 8);
              if (zeichennr == wertberechnenab + wertbreite && wertbreite != 0) {
                lcd.print(">");
              } else {
                lcd.print("-");
              }
            }
            //lcd.print("-");
          } else {
            lcd.print(" ");
          }
          lcd.write(max(0x20, zeichen));
          zeichennr++;
        }
      }
      aktuzeichen = incpointer(aktuzeichen);
    } while (zeichennr < 10);     //bis 10 Zeichen ausgegeben sind

    //Wert der xbit breiten Zahl in DEZ rechts unten ausgeben
    lcd.setCursor(10, 3);
    printlcdnummer(wert, 1000000000, 10);   //Dezimal max 10stellig ausgeben, führende Nullen durch Space ersetzen

    int16_t anzahl = writepointer - readpointer;
    if (anzahl < 0) anzahl += bufferlenght;         //1-Zeiler IF
    lcd.setCursor(3, 3);
    lcd.print("v");
    printlcdnummer(anzahl, 100, 10);

    //Bitbreite ausgeben
    lcd.setCursor(15, 2);
    printlcdnummer(wertbreite * 8 + 8, 10, 10); //Dezimal, max 2 stellig
    lcd.print("bit");

    //Anzeige, ab welchem Byte der berechnete Wert kommt
    lcd.setCursor(0,2);
    lcd.print("Wert ab ");
    printlcdnummer(wertberechnenab+anzeigeab,100,10);  // Dezimal, max 3-stellig
    lcd.print(" in ");
  }

  //Drehencoder-Erkennung
  //per Button Aktivieren/Deaktivieren
  //Aktiviert Cursor in Zeile anzeigen, Wert der Zeile veränderbar
  // Zeile 0 Start der Anzeige
  // Zeile 1 Offset für Wertberechnung
  // Zeile 2 Breite der Wertberechnung
  // Zeile 3 Little/Big Endian Umschaltung

  //NICHT Aktiviert Cursor zwischen Zeilen wechseln, in Zeile 3
  //nach x Sekunden ohne Encoder-Erkennung Cursor ausblenden

  //*******************************************************
  //Drehencoder-Auswertung

  int anders = myencoder.getChange(); //Änderung seit der letzten Abfrage der 'Change's, Wert -1...0...1 da .poll (in diesem Beispiel 4) Änderungen erfassen muß
  if (anders) {
    //Am Encoder wurde gedreht, anders ist positiv oder negativ, je nach Drehrichtung
    if (!cursoraktiv) {
      cursoraktiv = true;
      Serial.println("Encoder ");
    }
    cursorab = millis();
    if (myaktiv) {
      //Wertänderung
      switch (aktzeile) {
        case 0:
          if (anders < int(-anzeigeab)) {
            anzeigeab = 0;
          } else {
            anzeigeab = constrain((int)anders + anzeigeab, 0, bufferlenght - 1); break;  //rechnet 'anders' zu aktueller Anzeige-Ab-Stelle hinzu und begrennzt den Wert auf den Buffer
          }
          break;
        case 1:
          if (anders < int(-wertberechnenab)) {
            wertberechnenab = 0;
            Serial.println("Werteberechnenab 0");
          } else {
            wertberechnenab += anders;
            if (wertberechnenab > 9 - wertbreite) {
              wertberechnenab = 9 - wertbreite;
            }
          }
          break;
        case 2:
        if(anders<int(-wertbreite)){
          wertbreite=3;               //wenn unter Null gesprungen werden soll, oben wieder anfangen
        }else{
          wertbreite=(wertbreite+anders)%4;
        }
        break;
        case 3:
        bigendian=1-bigendian;
        break;

      }
    } else {
      //Änderung der Zeile
      aktzeile = (aktzeile + anders) % 4;

    }
  }
  boolean buttonpress = digitalRead(myencoderbuttonpin);
  boolean change = false;
  if (buttonpress != mybutton) {
    //Änderung am Button
    if (!cursoraktiv) {
      cursoraktiv = true;
      Serial.println("Button ");
    }
    cursorab = millis();
    if (millis() - mybuttonmillis > myentpreller) {
      //erneuter Druck, letzte Erkennung ist > Entprellzeit her
      mybuttonmillis = millis();
      Serial.println("Neuer Druck");
    } else {
      //wir sind in der Entprell-Zeit, hier prüfen, ob Diese vorbei ist
      if (millis() - mybuttonmillis == myentpreller) {
        Serial.println("Druck erkannt");
        mybutton = buttonpress;//~mybutton;
        change = true;
      }
    }
  }
  if (change == true) {
    if (mybutton == LOW) {
      //Button wurde gedrückt
      myaktiv = 1 - myaktiv;
      Serial.print("Aktiv auf ");
      Serial.println(myaktiv);
    } else {
      //Button wurde gelöst
    }
    change = false;
  }
  if (myaktiv) {
    cursorab = millis(); //Cursor an lassen
  }
  if (millis() - cursorab > cursortime) {
    cursoraktiv = false;
  }


  if (cursorisaktiv != cursoraktiv) {
    if (cursoraktiv) {
      //lcd.cursor();
      lcd.blink();
      Serial.println ("Cursor AN");
    } else {
      //lcd.noCursor();
      lcd.noBlink();
      Serial.println("Cursor AUS");
    }
    cursorisaktiv = cursoraktiv;
  }
  lcd.setCursor(myaktiv, aktzeile);

}

// Funktion erhöht den übergebenen Zeigerwert um 1, bzw gibt 0 zurück, wenn wir aus dem Buffer rauslaufen würden
uint16_t incpointer(uint16_t position) {
  return (position < bufferlenght - 1) ? position + 1 : 0;
  //wenn die übergebene Position unter der Obergrenze liegt
  //gibt Position +1 zurück, sonst 0
}


//Funktion unterdrückt führende Nullen bzw. gibt führende Space aus
void printlcdnummer(uint32_t wert, uint32_t testwert, byte base) {
  while (wert < testwert) {
    if (base == 16) {
      if (testwert > 1)     //wenn testwert Null ist, wird für die eigentliche Zahl ebenfalls ein führendes Zeichen ausgegeben -> zwei Nullen (bzw. ein Space+Null bei Base 10)
      lcd.print("0");       //bei HEX alle führenden Nullen anzeigen
    } else {
      if (testwert > 1)       //ACHTUNG IF-Abfragen sind 2-zeilig!! (keine Klammern, deshalb gehört der folgende Befehl zur IF)
        lcd.print(" ");       //sonst (hier nur DEZ) führende Nullen durch Space ersetzen
    }
    testwert = testwert / base;
  }
  lcd.print(wert, base);
}
anscheinend ist Es nicht erwünscht, einen Foren-internen Link als 'Homepage' einzubinden, damit JEDER nur einen Klick von combie's Liste zum Thema State-Maschine entfernt ist.
... dann eben nicht ...

postmaster-ino

#20
Jun 19, 2018, 10:21 pm Last Edit: Jun 19, 2018, 10:25 pm by postmaster-ino
Part 3, Drehencoder.h
Code: [Select]
// Quelle: https://miscsolutions.wordpress.com/2011/10/16/five-things-i-never-use-in-arduino-projects/

// bisher klappt die Erkennung super - kein Verzählen festgestellt

// Class to interface Arduino to rotary encoders
// D Crocker, Escher Technologies Limited, October 2011.
// This code may be freely used for any purpose
// but is supplied without warranty.
//
// Declare a rotary encoder like this:
//
// RotaryEncoder encoder(leftPin, rightPin, pulsesPerClick);
//
// where pulsesPerClick is normally 4.
// Every 1 millisecond or so, call:
//
// encoder.poll();
//
// To find how much the encoder has moved since you last asked, do this:
//
// int movement = encoder.getChange();

class RotaryEncoder
{
    byte state;
    byte pin0, pin1;
    byte ppc;
    char change;

  public:
    byte readState()
    {
      return (digitalRead(pin0) == HIGH ? 1u : 0u)
             | (digitalRead(pin1) == HIGH ? 2u : 0u);
    }

    //public:
    RotaryEncoder(byte p0, byte p1, byte pulsesPerClick) :
      pin0(p0), pin1(p1), ppc(pulsesPerClick), change(0), state(0) {}

    void init();
    void poll();
    int getChange();
};

void RotaryEncoder::init()
{
  pinMode(pin0, INPUT_PULLUP);
  pinMode(pin1, INPUT_PULLUP);
  //digitalWrite(pin0, 1);  // enable internal pullup
  //digitalWrite(pin1, 1);  // enable internal pullup
  change = 0;
  state = readState();
}

void RotaryEncoder::poll()
{
  // State transition table
  static char tbl[16] =
  { 0, +1, -1, 0,
    // position 3 = 00 to 11, can't really do anythin, so 0
    -1, 0, -2, +1,
    // position 2 = 01 to 10, assume a bounce, should be 01 -> 00 -> 10
    +1, +2, 0, -1,
    // position 1 = 10 to 01, assume a bounce, should be 10 -> 00 -> 01
    0, -1, +1, 0
    // position 0 = 11 to 10, can't really do anything
  };

  unsigned int t = readState();
  int movement = tbl[(state << 2) | t];
  if (movement != 0)
  {
    change += movement;
    state = t;
  }
}

int RotaryEncoder::getChange()
{
  int r;
  noInterrupts();
  if (change >= ppc - 1)
  {
    r = (change + 1) / ppc;
  }
  else if (change <= 1 - ppc)
  {
    r = -((1 - change) / ppc);
  }
  else
  {
    r = 0;
  }
  change -= (r * ppc);
  interrupts();
  return r;
}


Denke, an diesem Code kann man noch eine ganze Menge verbessern - wenn ich damit die benötigten Kennzahlen meiner Zähler ausgelesen bekomme, soll mir Das aber schon reichen.

Da stecke ich dann lieber die Zeit in den folgenden Sketch, statt Den hier von 'läuft' auf 'läuft und sieht gut aus' umzubauen.

Vll. kann's ja Wer gebrauchen (oder Seinen Nutzen aus dem Konvolut an Try & Error ziehen)

MfG
anscheinend ist Es nicht erwünscht, einen Foren-internen Link als 'Homepage' einzubinden, damit JEDER nur einen Klick von combie's Liste zum Thema State-Maschine entfernt ist.
... dann eben nicht ...

Go Up