Arduino Forum

International => Deutsch => Topic started by: Stalli on Jun 12, 2018, 12:14 pm

Title: D0-Schnittstellen-Projekt
Post by: Stalli on Jun 12, 2018, 12:14 pm
Hallo liebe Community,

Ich sitze zur Zeit an einer Studiums Arbeit, welche ich auf Grundlage von diesem Projekt https://www.msxfaq.de/sonst/bastelbude/smartmeter_d0_sml.htm aufbaue.

Mein Projekt ist die Entwicklung eines Konzeptes, welches durch Auslesen der D0-Schnittstelle Energiebewusstsein schaffen soll.

Leider komme ich zur Zeit schleppend voran, da zwar die Ausgabe meines Arrays funktioniert, aber leider bislang nicht die Aufnahme der IR-Signale durch die BPW 40.

Ich verwende zur Zeit ein WeMos D1 Mini und eine BPW 40, wobei der Emitter auf Masse liegt und der Kollektor mit dem RXD verbunden ist (Wie auch in der Quelle). Sowie das zur Verfügung gestellte Skript ohne WiFi-Schnittstelle und UDP-Übertragung.

Vorab wollte ich erstmal den Ablauf des Dateneingangs testen mittels einer Fernbedienung. Dies funktioniert leider nicht. Ich hänge in der while-Schleife fest, welche die Übertragungspause von 400ms simuliert.

Im Anhang ist der von mir getestete Code zu finden.

Ich hoffe jemand kann mir bei meinem Problem helfen. Anregungen, Tipps, etc. sind sehr willkommen

LG Stalli
Title: Re: D0-Schnittstellen-Projekt
Post by: Tommy56 on Jun 12, 2018, 12:55 pm
Stelle Deinen Code bitte direkt ins Forum, nicht als Anhang. Benutze dazu Codetags (</>-Button oben links im Forumseditor), Dann ist er für alle gut lesbar.

Gruß Tommy
Title: Re: D0-Schnittstellen-Projekt
Post by: Stalli on Jun 12, 2018, 12:59 pm
Code: [Select]
#include <ESP8266WiFi.h>
#include <WiFiUDP.h>
// extern "C" {  //required for system_get_chip_id()
// #include "user_interface.h"


  // Buffer for serial reading
  int  serIn;             // var that will hold the bytes-in read from the serialBuffer
  byte datagram[1000];    // array that will hold the different bytes
  int  serindex = 0;    // index of serInString[] in which to insert the next incoming byte

  int  serialbyte;        // Byte to store serial input data

  //
  //  Blink Function for Feedback of Status, takes about 1000ms
  //
  void blink(int count, int durationon, int durationoff, int delayafter) {
    for (int i = 0; i < count; i++) {
      digitalWrite(LED_BUILTIN, LOW);   // Turn the LED on
      delay(durationon);
      digitalWrite(LED_BUILTIN, HIGH);  // Turn the LED off by making the voltage HIGH
      delay(durationoff);
    }
    delay(delayafter);
  }

  void setup() {
    pinMode(LED_BUILTIN, OUTPUT);     // Initialize the LED_BUILTIN pin as an output
    blink(1, 5000, 500, 1000); // Signal startup
    Serial.begin(9600);   // Open serial communications and wait for port to open:
    while (!Serial) {
      ; // wait for serial port to connect.
    }
    Serial.println("ESP8266-DO-Logger init");
    blink(4, 100, 500, 2000);   // Signal Serial OK

  }

  void loop() {
    //
    // Clear Serial Data
    //
    Serial.println("C");
    while (Serial.available()) {
      while (Serial.available()) {
        serialbyte = Serial.read(); //Read Buffer to clear
      }
      //Serial.print("F");
      delay(10);  // wait approx 10 bytes at 9600 Baud to clear bytes in transmission
    }


    //
    // assume, that there is now a pause. Wait for start of transmission
    //
    Serial.println("W");
    int flashcount = 0;
    while (!Serial.available()) {
      flashcount++;
      // Serial.println(flashcount);
      if (flashcount == 400) {
        digitalWrite(LED_BUILTIN, LOW);       // Turn the LED on
      }
      else if (flashcount > 500) {
        digitalWrite(LED_BUILTIN, HIGH);      // Turn the LED off
        flashcount = 0;
      }
      else {
        delay(5);  // wait 5 ms for new packets
      }
    }

    // We got some bytes. read until next pause
    Serial.println("R");
    // Serial.println("Reading serial data");
    Serial.setTimeout(500);   // Set Timeout to 500ms.
    serindex = Serial.readBytes(datagram, 1000);
    // serindex = Serial.readBytesUntil('',datagram,1000);  // read all serial data and end with timeout.. How to read without looking for stop character
    //serindex = 0;
    //while (Serial.available() && (serindex < 1000)){
    //  while (Serial.available() && (serindex < 1000)){
    //    serialbyte = Serial.read();   // Read Data with a 1000ms timeout
    //    datagram[serindex] = serialbyte;
    //    serindex++;
    //  }
    //  delay(10);  // wait 10ms for more bytes
    //}

    if (serindex < 1000) {
      Serial.println("D");
      blink(5, 100, 100, 0);
      Serial.print("Datagram received. Total Bytes:"); Serial.println(serindex);
    }
    else {       // Error out of bounds during reading bytes from serial.
      blink(10, 100, 100, 2000);
    }

    // Serial.println("Sleep 10 Seconds");
    blink(100, 30, 70, 0);
  }
}
Title: Re: D0-Schnittstellen-Projekt
Post by: Rentner on Jun 12, 2018, 01:05 pm
Hallo,

es wäre schön wenn Du deine Skatche hier als code einstellst. dazu gibt es oben links den button </>.

Dann können wir Ihn alle sehen und müssen nicht den Anhang downloaden und öffnen.


Zu deinem Problem .

Mit Deinem Skatch kannst du nicht die Signale einer Fernbedienung einlesen. Der Skatch liest die Daten von der Seriellen Scnittstelle mit dem dazugeörigen Protokoll ein. Das mag für eine D0 Schnittstelle klappen  aber nicht mit einer Fernbedienung, die hat ein völlig anderes Protokoll.


Heinz
Title: Re: D0-Schnittstellen-Projekt
Post by: agmue on Jun 12, 2018, 01:12 pm
Vorab wollte ich erstmal den Ablauf des Dateneingangs testen mittels einer Fernbedienung.
Sollte mich wundern, wenn Deine Fernbedienung 9600 Baud Datenübertragungsrate einschließlich richtigem Protokoll liefern würde.

Ich verwende zur Zeit ein WeMos D1 Mini und eine BPW 40, wobei der Emitter auf Masse liegt und der Kollektor mit dem RXD verbunden ist (Wie auch in der Quelle).
Fehlt da nicht ein Widerstand?
Title: Re: D0-Schnittstellen-Projekt
Post by: Stalli on Jun 12, 2018, 01:16 pm
Zu deinem Problem .

Mit Deinem Skatch kannst du nicht die Signale einer Fernbedienung einlesen. Der Skatch liest die Daten von der Seriellen Scnittstelle mit dem dazugeörigen Protokoll ein. Das mag für eine D0 Schnittstelle klappen  aber nicht mit einer Fernbedienung, die hat ein völlig anderes Protokoll.

Danke für die Rückmeldung, das hab ich tatsächlich nicht bedacht.

Fehlt da nicht ein Widerstand?

Jaein, also ich habe natürlich nicht nur die angegebene Seite als Grundlage. Und auf verschiedenen anderen Seiten werden Widerstände ab 1k-20k verwendet.
Allerdings sollte in diesem Fall die Übertragung auch ohne Widerstand funktionieren.
Title: Re: D0-Schnittstellen-Projekt
Post by: Tommy56 on Jun 12, 2018, 01:22 pm
Allerdings sollte in diesem Fall die Übertragung auch ohne Widerstand funktionieren.
Das würde ich nicht unterschreiben. Du solltest Dich mal mit der Funktionsweise eines Transistors beschäftigen.
Ohne Pullup-Widerstand gibt es keinen HIGH-Pegel. Du kannst natürlich auch den internen Pullupwiderstand des Eingangs benutzen.

Gruß Tommy
Title: Re: D0-Schnittstellen-Projekt
Post by: Stalli on Jun 12, 2018, 01:29 pm
Das würde ich nicht unterschreiben. Du solltest Dich mal mit der Funktionsweise eines Transistors beschäftigen.
Ohne Pullup-Widerstand gibt es keinen HIGH-Pegel. Du kannst natürlich auch den internen Pullupwiderstand des Eingangs benutzen.

Gruß Tommy
Ich habe jetzt eine andere Schaltung gefunden, mit 1k Vorwiderstand und probier diese mal aus.

Es heißt bei der "einfachen" Schaltung, dass man lediglich den Transistor beim Hochladen der Datei abdunkeln oder abziehen sollte um den HIGH-Pegel zu entgehen...

Wahrscheinlich gilt hier wie immer nicht nur auf ein Pferd setzen ;)
Aber deswegen, hab ich mir auch gedacht frag ich lieber mal in der Community nach, damit ich weitere Meinungen höre und andere Blickwinkel erkennen kann.
Title: Re: D0-Schnittstellen-Projekt
Post by: Stalli on Jun 12, 2018, 01:47 pm
Hat denn jemand ne Idee, wie ich den Input inklusive Speicherung testen kann.?
Da ich erst in gut 2-3 Wochen mit der Lieferung einer modernen Messeinrichtung rechne, welche mir der Lehrstuhl zur Verfügung stellt.

Nochmals Danke für die Hilfe, an jeden der mir bislang geantwortet hat.
Ich freue mich auf weiteren Input von Euch.

Stalli

Title: Re: D0-Schnittstellen-Projekt
Post by: HotSystems on Jun 12, 2018, 01:49 pm
Ich habe jetzt eine andere Schaltung gefunden, mit 1k Vorwiderstand und probier diese mal aus.

Es heißt bei der "einfachen" Schaltung, dass man lediglich den Transistor beim Hochladen der Datei abdunkeln oder abziehen sollte um den HIGH-Pegel zu entgehen...

Wahrscheinlich gilt hier wie immer nicht nur auf ein Pferd setzen ;)
Aber deswegen, hab ich mir auch gedacht frag ich lieber mal in der Community nach, damit ich weitere Meinungen höre und andere Blickwinkel erkennen kann.
Ich sehe allerdings noch nicht, wie du das Abfragen der D0 mit einem Fototransistor bewerkstelligen willst.

Ein simpler Fototransistor ist da sicher nicht ausreichend.


Edit:
OK....nochmal nachgelesen, soll doch funktionieren. Alles gut !
Title: Re: D0-Schnittstellen-Projekt
Post by: agmue on Jun 12, 2018, 02:02 pm
Hat denn jemand ne Idee, wie ich den Input inklusive Speicherung testen kann.?
Ich nutze dafür einen Mega2560, der hat mehrere serielle Schnittstellen. Eine hängt an USB, die anderen sind zum Testen frei. Bei Dir wäre ein Arduino mit 3,3V besser (dafür würde ich meinen Teensy nehmen).

Dann öffne ich zweimal die IDE und zweimal den seriellen Monitor und los geht das Testen.

Auch wenn Test und Realität dann nicht ganz übereinstimmen, hast Du bis dahin genug gelernt, um den letzten Dreh auch noch hinzubekommen.
Title: Re: D0-Schnittstellen-Projekt
Post by: Stalli on Jun 12, 2018, 02:19 pm
Bei Dir wäre ein Arduino mit 3,3V besser (dafür würde ich meinen Teensy nehmen).

Der Wemos D1 mini hat auch einen 3,3 V Ausgang...

Ich meinte mit Testen in erster Linie eine alternative Abfrage von IR-Signalen, da ich ja noch keine mMe besitze und das ganze mit einer Fernbedienung wohl nicht zu bewerkstelligen ist...
Title: Re: D0-Schnittstellen-Projekt
Post by: HotSystems on Jun 12, 2018, 02:45 pm
Der Wemos D1 mini hat auch einen 3,3 V Ausgang...

Ich meinte mit Testen in erster Linie eine alternative Abfrage von IR-Signalen, da ich ja noch keine mMe besitze und das ganze mit einer Fernbedienung wohl nicht zu bewerkstelligen ist...
Das ist ja kein übliches IR-Signal, sondern ein serielles Datensignal, welches per Licht (evtl. IR) gesendet wir.
Da musst du das entsprechende Datenprotokoll auslesen.
Title: Re: D0-Schnittstellen-Projekt
Post by: agmue on Jun 12, 2018, 02:56 pm
Ich meinte mit Testen in erster Linie eine alternative Abfrage von IR-Signalen, da ich ja noch keine mMe besitze und das ganze mit einer Fernbedienung wohl nicht zu bewerkstelligen ist...
Wenn Du einen Empfänger testen möchtest, brauchst Du auch einen Sender. Oder?

Der eine Arduino sendet, der andere empfängt. Du kannst die direkt verbinden oder eine IR-LED und einen IR-Transistor dazwischenhängen. Mit LED und Transistor spielt die Versorgungsspannung der Arduinos dann keine Rolle mehr.

PS.: Den Begriff "Arduino" verwende ich üblicherweise sehr viel weiter gefaßt, als Uwe das mag, denn ein Wemos D1 mini ist natürlich keiner, auch wenn er sich über die Arduino-IDE programmieren läßt.
Title: Re: D0-Schnittstellen-Projekt
Post by: Stalli on Jun 14, 2018, 03:26 pm
Servus, hab gestern mal den ganzen Tag gebastelt und einiges ausprobiert.
Zuerst habe ich anstelle des BPW40 mal einen Photowiderstand dazwischen gesetzt, um zu überprüfen ob überhaupt der Abbruch des Counters, welcher gesetzt wird, während man auf einen Input wartet. Hat funktioniert.

Anschließend habe ich geguckt ob ich überhaupt einen INPUT auf der BWP40 besitze auch dies war der Fall. Hab den Phototransistor einfach mit meiner Handytaschenlampe angestrahlt und einen einfachen Speichercode dazu geschrieben.

Nur beim Wiederzusammenführen von meinem Ausgangscode und der BWP40 hatte ich keinen Abbruch und somit keinen Input.

Was mich ein wenig stutzig macht ist natürlich, dass die Abbruch-Sequenz und somit die Input-Speicherung mit einer Photodiode funktioniert. Daher kann man ja theoretisch ausschließen, dass der Code explizit auf IR-Dateneingänge ausgelegt ist.
Title: Re: D0-Schnittstellen-Projekt
Post by: postmaster-ino on Jun 14, 2018, 05:38 pm
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 (https://www.msxfaq.de/sonst/bastelbude/smartmeter_d0_sml.htm) sollte IR=LOW passen, zumindest wird mir Das so bei 'Signalaufbereitung' suggeriert - ist aber noch nicht gegengeprüft.

MfG
Title: Re: D0-Schnittstellen-Projekt
Post by: postmaster-ino on Jun 17, 2018, 05:49 pm
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**
Title: Re: D0-Schnittstellen-Projekt
Post by: postmaster-ino on Jun 19, 2018, 10:17 pm
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
Title: Re: D0-Schnittstellen-Projekt
Post by: postmaster-ino on Jun 19, 2018, 10:20 pm
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();
}
Title: Re: D0-Schnittstellen-Projekt
Post by: postmaster-ino on Jun 19, 2018, 10:21 pm
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);
}
Title: Re: D0-Schnittstellen-Projekt
Post by: postmaster-ino on Jun 19, 2018, 10:21 pm
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