Seite 1 von 3

AskSin++ LCD Unterstützung

Verfasst: 23.10.2019, 10:14
von jp112sdl
Hallo zusammen,

ich habe mich in den letzten Tagen weiter mit LCD Displays beschäftigt.
  • Da ist zum einen das DENSITRON PC-6749-AAW von Pollin, für gerade mal 0,25 EUR! Es ist laut Datenblatt für 5V gedacht. Bei 3.3V ist die Anzeige erstmal sehr sehr blass, jedoch bekommt man gut lesbare Digits wenn man R4 überbrückt und an den Initialisierungsparametern feilt.

    Um dieses Display zu nutzen, braucht nur die "displays/Lcd6749.h" eingebunden werden. Codebeispiele befinden sich auch am Ende der Datei

    Code: Alles auswählen

    #include <displays/Lcd6749.h>
    #define LCD_CS   9
    #define LCD_WR   3
    #define LCD_DATA 7
    
    using namespace as;
    
    typedef LCD6749<LCD_CS, LCD_WR, LCD_DATA> LcdType;
    LcdType lcd;
    
    void foo() {
      lcd.init();
      //lcd.printWithUnit(24, LcdType::NO_DOT, 'G');     // 2 4 G
      //lcd.printWithUnit(24, LcdType::SINGLE_DOT, 'G'); // 2.4 G
      //lcd.printText("4:15");                           // 4:1 5
      //lcd.printNumberAsFloat(720);                     // 7.2 0
      //lcd.printNumberAsFloat(4);                       // 0.0 4
      lcd.printV(19);                                  // 1.9 V
      //lcd.printNumber(14);                             //   1 4
      //lcd.printNumber(14, true); //with leading zero   // 0 1 4
      }
    
    pollin_volt.jpeg
    polin_number.jpeg
  • Weiterhin habe ich mich mit dem 4 Segment Display von AliExpress befasst.
    Es ist mit 3,65 EUR recht teuer, aber für die Anzeige von Temperatur (°-Zeichen vorhanden) und Feuchte ideal und kompakt.

    Um dieses Display zu nutzen, braucht nur die "displays/Lcd4Seg.h" eingebunden werden.

    Code: Alles auswählen

    #include <displays/Lcd4seg.h>
    
    using namespace as;
    
    LCDToggleTH<LCD4SEG<6, 3, 7>> lcd;
    
    void foo() {
     lcd.init();
     lcd.setToggleTime(3);          //toggle display every 3 seconds
     lcd.setValues(256, 38, true); //25.6°C, 38rH, Low Battery
    }
    
    So reicht es dann aus, im Sketch nach der Messung die Werte neu zu setzen lcd.setValues(temperature, humidity, batlow);.
    Das Display wechselt automatisch in der angegebenen Zeit ( lcd.setToggleTime(seconds)) zwischen den Werten.
    Temp.jpeg
    Hum.jpeg
    batlow.jpeg

Re: AskSin++ LCD Unterstützung

Verfasst: 23.10.2019, 11:37
von papa
Das Ali-Display wollte ich Dir letztens auch schon vorschlagen. :-)

Re: AskSin++ LCD Unterstützung

Verfasst: 23.10.2019, 21:06
von harvey
Hi,
super Lösung, bei dem Preis kann man kaum was falsch machen.

Was mit auffällt:
Das Densitron Display hat ja eine "1Ziffer Punkte 2Ziffern" Aufteilung. Mir kam die Idee, ob durch
andere Codetabelle und andere Reihenfolge auch das Display "auf dem Kopf" verwendet werden kann.
Dann hätte es "2Ziffern Punkte 1Ziffer".
Bin ich nur drüber gestolpert, da ich es falsch rum gelesen hatte und die Zahlen nicht verstanden habe ...
... bis ich das Display von der anderen Richtung gelesen habe.

Kleine Problemchen habe ich noch bei der Verwendung von

Code: Alles auswählen

lcd.printWithUnit(device().battery().current(), LCD6749::SINGLE_DOT, 'v');
Bastel ich noch dran (neueste AsksinPP, aber Mecker über SINGLE_DOT ...) Ist bestimmt der uint8_t gegenüber uint16_t.

Mit etwas Kampf (Programmlänge, Anzahl Pins) habe ich auch mal ein hd44780 im 4Bit-mode ansgeschlossen, das klappt auch.
Ist aber schon etwas her.

Also VIELEN DANK, 5 Drähte sind schnell angeschlossen!
Harvey

Re: AskSin++ LCD Unterstützung

Verfasst: 23.10.2019, 21:25
von jp112sdl
harvey hat geschrieben:
23.10.2019, 21:06
Kleine Problemchen habe ich noch bei der Verwendung von
CODE: ALLES AUSWÄHLEN
lcd.printWithUnit(device().battery().current(), LCD6749::SINGLE_DOT, 'v');
Bastel ich noch dran (neueste AsksinPP, aber Mecker über SINGLE_DOT ...)
Hab das Beispiel im Original-Post korrigiert, das war noch falsch. Richtig muss es heißen

Code: Alles auswählen

lcd.printWithUnit(device().battery().current(), LcdType::SINGLE_DOT, 'v');
Ist nur eine enum.
harvey hat geschrieben:
23.10.2019, 21:06
Ist bestimmt der uint8_t gegenüber uint16_t.
Versteh ich grad nicht!?


Aber für Spannung nimmst am besten den kurzen Weg:

Code: Alles auswählen

lcd.printV(device().battery().current());
Da ist schon die Einheit mit dran.

Re: AskSin++ LCD Unterstützung

Verfasst: 23.10.2019, 21:29
von jp112sdl
harvey hat geschrieben:
23.10.2019, 21:06
Das Densitron Display hat ja eine "1Ziffer Punkte 2Ziffern" Aufteilung. Mir kam die Idee, ob durch
andere Codetabelle und andere Reihenfolge auch das Display "auf dem Kopf" verwendet werden kann.
Dann hätte es "2Ziffern Punkte 1Ziffer".
Man müsste den Font "umdrehen" und den Zeichenpuffer in umgekehrter Richtung befüllen die segmap[] [0]<>[2] umdrehen. Dann sollte das es gehen.
Am besten die Displayrotation per #define festlegen, damit auch nur der tatsächlich verwendete Font in den Flash wandert.

Aber ob es die Arbeit wert ist. Man kann das Display ja auch einfach korrekt orientiert einbauen :)

Re: AskSin++ LCD Unterstützung

Verfasst: 23.10.2019, 23:41
von harvey
Hi,
vielen Dank für die schnelle Problemlösung und Tips, ich versuchs mal.

Mir ging es auch nicht "nur" um das falschrum gelesene Display, sondern auch um die Position des Dezimalpunktes.
Also auf dem Kopf stehend könnten zwei Stellen, der "obere" Punkt des Doppelpunkts als Komma und eine Nachkommastelle
angezeigt werden, damit gehen schon mal positive Temperaturen 00,0 - 99,9 und negative bis -9,9 darzustellen.
Ich stelle aktuell Temperaturen als Number und habe mit dem Filzstift einen Dezimalpunkt auf das Display gemalt.

Danke und Gute Nacht!
Harvey

Re: AskSin++ LCD Unterstützung

Verfasst: 24.10.2019, 06:29
von jp112sdl
harvey hat geschrieben:
23.10.2019, 23:41
Also auf dem Kopf stehend könnten zwei Stellen, der "obere" Punkt des Doppelpunkts als Komma und eine Nachkommastelle
angezeigt werden
Ah, okay. Jetzt hab ichs :mrgreen:

Re: AskSin++ LCD Unterstützung

Verfasst: 24.10.2019, 13:07
von t0mk
Das ist ja eine gute Nachricht, dann kann ich all meine Temperatursensoren aufrüsten. Das erhöht den WAF, vielleicht darf ich dann noch weitere (sichtbar) aufstellen :)

Was gibt's denn bei Pollin noch so Interessantes/Lohnenswertes, damit die Versandkosten sich auch lohnen?

Re: AskSin++ LCD Unterstützung

Verfasst: 24.10.2019, 13:23
von jp112sdl
Ich möcht nur noch mal erwähnen, dass für Temperatur und Feuchte das Display von Ali besser geeignet wäre ;)

Re: AskSin++ LCD Unterstützung

Verfasst: 28.10.2019, 21:27
von harvey
Hi,
wie angedroht eine LCDREVERSED Version (wählbar über define LCDREVERSED).
Folgende Teile sind modifiziert:
- Die Zeichentabelle, die meisten Zeichen, insbesonders Zahlen sehen ganz brauchbar aus
- die Reihenfolge der Zeichen 1:23 ist jetzt umgedreht, damit also richtig bei gedrehtem Display
- im Text wird das 3. Zeichen als Punkt/Doppelpunkt verwendet, also AB:C
- der SINGLE_DOT ist jetzt oberer Teil des Doppelpunktes
- bei float > 999 fällt der Dezimalpunkt weg und es wird gerundet und skaliert

TODO:
float könnte auch negativ sein, von -0.1 bis -9.9 darstellen, von -10 bis -99 runden und skalieren

Aus meiner Sicht geht das für einfache Temperaturanzeigen sehr gut. Richtig ist, dass für umfangreichere Anzeigen
das Display doch etwas eingeschränkt ist, aber hey, der Preis :-)
Wahrscheinlich spiele ich noch etwas weiter mit dem Display rum.
Meine Codeänderungen sind frei benutzbar, aber ohne jede Garantie! Das eigentliche Lob gilt natürlich Jerome und papa.
Ein DIFF wäre glaube ich auch unübersichtlich, hier also das komplette Lcd6749.h

Code: Alles auswählen

  //- -----------------------------------------------------------------------------------------------------------------------
// AskSin++
// 2016-10-31 papa Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
// LCD6749 class
// 2019-10-20 jp112sdl Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
//- -----------------------------------------------------------------------------------------------------------------------

// https://www.pollin.de/p/lcd-modul-densitron-pc-6749-aaw-120818
// code based on https://www.mikrocontroller.net/topic/380929#4335859

#ifndef __LCD6749_H__
#define __LCD6749_H__

#define LCD6749_BUFSIZE 7

namespace as {

  const struct seg16fonts {
    char c;
    uint16_t s;
  } seg16font[65] PROGMEM  = {
        /* ABCDEFGHIJKLMNOP */
 #ifdef LCDREVERSED
  { '1', 0b0000011000000100 },
  { '2', 0b1101110000111000 },
  { '3', 0b1001111000111000 },
  { '4', 0b0010011000111000 },
  { '5', 0b1011101000111000 },
  { '6', 0b1111101000111000 },
  { '7', 0b0001100001111100 },
  { '8', 0b1111111000111000 },
  { '9', 0b1011111000111000 },
  { '0', 0b1111111001010100 },
  { '+', 0b0000000010111010 },
  { '-', 0b0000000000111000 },
  { '*', 0b0000000111111111 },
  { '/', 0b0000000001010100 },
  { '.', 0b0000100000000000 },    // no
  { ')', 0b0000000001000001 },
  { '$', 0b1011101010111010 },
  { '(', 0b0000000100000100 },
  { 'A', 0b0111111000111000 },
  { 'B', 0b1111100100011100 },
  { 'C', 0b1111100000000000 },
  { 'D', 0b1111111000000000 },  // bad = O
  { 'E', 0b1111100000011000 },
  { 'F', 0b0111100000011000 },
  { 'G', 0b1111101000100000 },
  { 'H', 0b0110011000111000 },
  { 'I', 0b1001100010010010 },
  { 'J', 0b1000111000000000 },
  { 'K', 0b0110000100011100 },
  { 'L', 0b1110000000000000 },
  { 'M', 0b0110011000010101 },
  { 'N', 0b0110011100010001 },
  { 'O', 0b1111111000000000 },
  { 'P', 0b0111110000111000 },
  { 'Q', 0b1111111100000000 },
  { 'R', 0b0111000100001100 },
  { 'S', 0b1011101000111000 },
  { 'T', 0b0001100010010010 },
  { 'U', 0b1110011000000000 },
  { 'V', 0b0110100001010100 },
  { 'W', 0b0110011101010000 },
  { 'X', 0b0000000101010101 },
  { 'Y', 0b0000000010010101 },
  { 'Z', 0b1001100001010100 },
  { '}', 0b0000000001011001 },
  { '_', 0b1000000000000000 },
  { '{', 0b0000000100110100 },
  { 'b', 0b1110001000111000 },
  { 'c', 0b1100000000111000 },
  { 'd', 0b1100011000111000 },
  { 'h', 0b0110001000111000 },
  { 'l', 0b0110000000000000 },
  { 'm', 0b0100001010111000 },
  { 'n', 0b0100001000111000 },
  { 'o', 0b1100001000111000 },
  { 'r', 0b0100000000011000 },
  { 't', 0b1110000000011000 },
  { 'u', 0b1100001000000000 },
  { 'v', 0b0100000001000000 },
  { 'w', 0b1100001010000000 },
  { '[', 0b1111100000000000 },
  { '|', 0b0000000010010010 },
  { ']', 0b1001111000000000 },
#else
  { '1', 0b0110000001000000 },
  { '2', 0b1101110000111000 },
  { '3', 0b1111100000111000 },
  { '4', 0b0000001010111010 },
  { '5', 0b1011101000111000 },
  { '6', 0b1011111000111000 },
  { '7', 0b1000000001111010 },
  { '8', 0b1111111000111000 },
  { '9', 0b1111101000111000 },
  { '0', 0b1111111001010100 },
  { '+', 0b0000000010111010 },
  { '-', 0b0000000000111000 },
  { '*', 0b0000000111111111 },
  { '/', 0b0000000001010100 },
  { '.', 0b0000100000000000 },
  { '(', 0b0000000001000001 },
  { '$', 0b1011101010111010 },
  { ')', 0b0000000100000100 },
  { 'A', 0b1110011000111000 },
  { 'B', 0b1111100010011010 },
  { 'C', 0b1001111000000000 },
  { 'D', 0b1111100010010010 },
  { 'E', 0b1001111000110000 },
  { 'F', 0b1000011000110000 },
  { 'G', 0b1011111000001000 },
  { 'H', 0b0110011000111000 },
  { 'I', 0b1001100010010010 },
  { 'J', 0b1000100010010010 },
  { 'K', 0b0000000011010011 },
  { 'L', 0b0001111000000000 },
  { 'M', 0b0110011101010000 },
  { 'N', 0b0110011100010001 },
  { 'O', 0b1111111000000000 },
  { 'P', 0b1100011000111000 },
  { 'Q', 0b1111111000000001 },
  { 'R', 0b1100011000110001 },
  { 'S', 0b1011101000111000 },
  { 'T', 0b1000000010010010 },
  { 'U', 0b0111111000000000 },
  { 'V', 0b0000011001010100 },
  { 'W', 0b0110011000010101 },
  { 'X', 0b0000000101010101 },
  { 'Y', 0b0000000101010010 },
  { 'Z', 0b1001100001010100 },
  { '{', 0b0000000001011001 },
  { '_', 0b0001100000000000 },
  { '}', 0b0000000100110100 },
  { 'b', 0b0011111000111000 },
  { 'c', 0b0001110000111000 },
  { 'd', 0b0111110000111000 },
  { 'h', 0b0010011000111000 },
  { 'l', 0b0000111000000000 },
  { 'm', 0b0010010000101010 },
  { 'n', 0b0010010000111000 },
  { 'o', 0b0011110000111000 },
  { 'r', 0b0000010000110000 },
  { 't', 0b0001000010111010 },
  { 'u', 0b0011110000000000 },
  { 'v', 0b0000010000000100 },
  { 'w', 0b0010010000000101 },
  { '[', 0b1001111000000000 },
  { '|', 0b0000000010010010 },
  { ']', 0b1111100000000000 },
#endif
  { ' ', 0b0000000000000000 },
  { 0, 0xFFFF }
  };

  const uint8_t segmap[3][16] PROGMEM= {
#ifdef LCDREVERSED
    { 0x60, 0x62, 0x63, 0x53, 0x47, 0x46, 0x44, 0x50,
      0x54, 0x61, 0x45, 0x51, 0x55, 0x52, 0x56, 0x57 },
    { 0x40, 0x42, 0x43, 0x33, 0x27, 0x26, 0x24, 0x30,
      0x34, 0x41, 0x25, 0x31, 0x35, 0x32, 0x36, 0x37 },
    { 0x14, 0x16, 0x17, 0x07, 0x03, 0x02, 0x00, 0x04,
      0x10, 0x15, 0x01, 0x05, 0x11, 0x06, 0x12, 0x13 }
#else
    { 0x14, 0x16, 0x17, 0x07, 0x03, 0x02, 0x00, 0x04,
      0x10, 0x15, 0x01, 0x05, 0x11, 0x06, 0x12, 0x13 },
    { 0x40, 0x42, 0x43, 0x33, 0x27, 0x26, 0x24, 0x30,
      0x34, 0x41, 0x25, 0x31, 0x35, 0x32, 0x36, 0x37 },
    { 0x60, 0x62, 0x63, 0x53, 0x47, 0x46, 0x44, 0x50,
      0x54, 0x61, 0x45, 0x51, 0x55, 0x52, 0x56, 0x57 }
#endif
  };

template<uint8_t CS, uint8_t WR, uint8_t DT>
class LCD6749 {

public:
  enum dots { NO_DOT, SINGLE_DOT, DOUBLE_DOT, BOTH_DOTS };

private:
  uint8_t _cs, _wr, _data, _lcdbuffer[LCD6749_BUFSIZE];

  void CS_low()          { digitalWrite(_cs, LOW); delayMicroseconds(1); }
  void CS_high()         { delayMicroseconds(1);   digitalWrite(_cs, HIGH); }
  void DATA(uint8_t x)   { if ((x)==0) digitalWrite(_data, LOW); else digitalWrite(_data, HIGH); }
  void WR_pulse()        { digitalWrite(_wr, LOW); delayMicroseconds(3); digitalWrite(_wr, HIGH); delayMicroseconds(3); }
  void clearBuffer(void) { memset(_lcdbuffer, 0, LCD6749_BUFSIZE); }


  uint16_t char2seg(char c) {
    for (uint8_t j=0; pgm_read_byte(&(seg16font[j]).c); j++) {
      if (pgm_read_byte(&(seg16font[j]).c) == c) {
        return (pgm_read_word(&(seg16font[j]).s));
      }
    }
    return 0;
  }

  void updateDisplay(uint8_t dot) {
    CS_low();
    DATA(1); WR_pulse();
    DATA(0); WR_pulse();
    DATA(1); WR_pulse();

    for (uint8_t i = 0; i < 6; i++) { DATA(0); WR_pulse(); }

#ifdef LCDREVERSED
    if (dot & 0x01) _lcdbuffer[2]|=0b00000010;
#else
    if (dot & 0x01) _lcdbuffer[2]|=0b00001000;
#endif
    if (dot & 0x02) _lcdbuffer[2]|=0b00000110;
    for (uint8_t i=0; i<LCD6749_BUFSIZE; i++) {
      uint8_t mask= 0x01;
      while (mask) {
        DATA(_lcdbuffer[i] & mask);
        WR_pulse();
        mask<<=1;
      }
    }
    DATA(1);
    CS_high();
  }

  void updateBuffer(uint8_t pos, char c) {
    uint8_t segno= 0;
    uint16_t mask= 0x8000;
    for ( ; segno<16; segno++, mask>>=1) {
      if (char2seg(c) & mask) {
        uint8_t code= pgm_read_byte(&(segmap[pos][segno]));
        _lcdbuffer[code>>4] |= 1<<(code&7);
      }
    }
  }

  void sendCmd(uint8_t cmd) {
    CS_low();
    DATA(1); WR_pulse();
    DATA(0); WR_pulse();
    DATA(0); WR_pulse();
    uint8_t mask= 0x80;
    while (mask) {
      DATA(cmd&mask);
      WR_pulse();
      mask>>=1;
    }
    DATA(1); WR_pulse();
    CS_high();
  }

public:
  LCD6749 () : _cs(0), _wr(0), _data(0) {}
  virtual ~LCD6749() {}

  void init() {
    _cs = CS;
    _wr = WR;
    _data= DT;
    pinMode(_cs,   OUTPUT);
    pinMode(_wr,   OUTPUT);
    pinMode(_data, OUTPUT);

    sendCmd(0b00000001); // system enable
    sendCmd(0b00101010); // 1/2 Bias, 4 commons
    sendCmd(0b00000011); // turn on LCD

    clearBuffer();
  }

  void clear() {
    clearBuffer();
    updateDisplay(NO_DOT);
  }

  void printChar(uint8_t pos, char c, uint8_t dot) {
    updateBuffer(pos, c);
    updateDisplay(dot);
  }

  void printV(uint8_t value) {
    printWithUnit(value, SINGLE_DOT, 'V');
  }

  void printWithUnit(uint8_t value, uint8_t dot, char c) {
    clearBuffer();
    char localBuffer[3];
    snprintf(localBuffer, 3, "%2i", value);
    updateBuffer(0, value < 10 ? '0' : localBuffer[0]);
    updateBuffer(1,localBuffer[1]);
    updateBuffer(2,c);
    updateDisplay(dot);
  }

  void printText(const char * t, uint8_t dot=NO_DOT) {
    clearBuffer();

#ifdef LCDREVERSED
    if (strlen(t) > 2) {
      if ( t[2]=='.' ) dot = SINGLE_DOT;
      if ( t[2]==':' ) dot = DOUBLE_DOT;
    }
#else
    if (strlen(t) > 1) {
      if ( t[1]=='.' ) dot = SINGLE_DOT;
      if ( t[1]==':' ) dot = DOUBLE_DOT;
    }
#endif

    uint8_t j = 0;
    for (uint8_t i = 0; i < min(strlen(t), dot > NO_DOT ? 4 : 3); i++) {
#ifdef LCDREVERSED
      if (dot > NO_DOT && i == 2) i++;
#else
      if (dot > NO_DOT && i == 1) i++;
#endif
      updateBuffer(j, t[i]);
      j++;
    }

    updateDisplay(dot);
  }

  void printNumberAsFloat(uint16_t number) {
    if (number > 999) {
      number = (number + 5) / 10;
      printNumber(number, true, NO_DOT);
    } else { 
      printNumber(number, true, SINGLE_DOT);
    }
  }

  void printNumber(int16_t number, bool leadingZero) {
    printNumber(number, leadingZero, NO_DOT);
  }

  void printNumber(int16_t number, bool leadingZero, uint8_t dot) {
    clearBuffer();
    char localBuffer[4]={};
    snprintf(localBuffer, 4, "%3i", number);
    for (uint8_t i = 0; i < strlen(localBuffer); i++) {
      if (localBuffer[i] == 32 && leadingZero == true) localBuffer[i] = '0';
      updateBuffer(i, localBuffer[i]);
    }
    updateDisplay(dot);
  }
};

}

/*
  //printWithUnit(24, LCD6749::NO_DOT, 'G');     // 2 4 G
  //printWithUnit(24, LCD6749::SINGLE_DOT, 'G'); // 2.4 G
  //printText("4:15");                           // 4:1 5
  //printNumberAsFloat(720);                     // 7.2 0
  //printNumberAsFloat(4);                       // 0.0 4
  //printV(19);                                  // 1.9 V
  //printNumber(14);                             //   1 4
  //printNumber(14, true); //with leading zero   // 0 1 4
*/

#endif
cu
Harvey