s

Interfaccia controllo Nema17

 

 

Grazie a quesa interfaccia porò controllare il motore nema17. Rotella rossa permette di impostare il passo da 1 ad 1/32 l'encoder di sinistra impostiamo il motiplicatore seconda riga dall'alto un click si attiva la modalità modifica il primo digit a sinistra lampeggia e ruotando l'encoder di sinistra possiamo impostare la cifra da 0 a 9, altro click si passa alla cifra subito a destra che inizia a lampeggiare ed è ora modificabie.Con un long press si esce dalla modalità modifica. Encoder di destra ruotando variamo i giri del motore le cifre s'incrementano da destra verso sinistra con un click il motore si arresta rpm = 0, con un long press si cambia la direzione freccia verde a destra altro long press freccia rossa a sinistra.

 

Per realizzare questa interfaccia ho utilizzato il linguaggio ad oggetti del C++ di Arduino:

 

 

#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <EncButton.h>
#include "Blink4.h" 
#include "VelDir.h" 
#include "Passo.h" 
#include "Etich.h" 

Adafruit_ST7735 tft(10, 9, 8);
EncButton eval(A0,A1,A2);
EncButton enc(A5, A4, A3);
EncButton pass(12,2,-1);

Blink4* dspDg;
VelDir* velDr;
Passo* setPs;
Etich* etic;

void setup() {
  tft.initR(INITR_BLACKTAB);
  tft.setRotation(1);
  tft.fillScreen(ST77XX_BLACK);

  dspDg = new Blink4(90, 40, &tft, &enc);  
  dspDg->drawAll(true);

  velDr = new VelDir(8, 126, &tft, &eval);
  velDr->setMax(900);
  velDr->draw();

  setPs = new Passo(&tft,&pass);

  etic = new Etich(&tft);
  etic->drawAll();
}

void loop() {
  dspDg->update();
  setPs->update();
  velDr->update();
}

 

Notare l'estrema pulizia del codice. Ho utilizzato quattro classi:

  • Blink4 - gestisce il moltiplicatore, encoder di sinistra
  • VelDir - gestisce il controllodela velocità, la direzione e lo stop delmotore, encoder di destra
  • VelDir - iposta il passo da 1 a 1/32
  • Etich - visualizza tutte le etichette

Blink4

#pragma once
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <EncButton.h>
#include "DS_Digit18pt7b.h"

class Blink4 {
  private:
    Adafruit_ST7735* tft;
    EncButton* enc;
    const GFXfont* font;
    int x, y, spz;
    int cifre[4];
    int xPos[4];
    const int blinkInterval = 400;
    unsigned long lastBlink = 0;
    bool visible = true;
    bool inEdit = false;
    int pos = 0;
    uint16_t color;
    uint16_t holdSec;
    
  public:   
    Blink4(int x, int y, Adafruit_ST7735* display, EncButton* encod )
    : x(x), y(y), tft(display), enc(encod), spz(16), font(&DS_Digit18pt7b),
     color(0xffff00), holdSec(400)
    { 
      enc->setEncReverse(true);
      setLpTm(holdSec);    
      calcCfr();
      calcPos();
    }

    void setSpaz(int spazio) {
      spz = spazio;
      calcPos();
    }

    void setFont(const GFXfont* fnt) {
      font = fnt;
    }
    
    void setColor(uint32_t hexColor) {
        color = hexToColor565(hexColor);
    }
    uint16_t getValue() {
      return cifre[0] * 1000 + cifre[1] * 100 + cifre[2] * 10 + cifre[3];
    }

    void setLpTm(uint16_t msRit){
      enc->setHoldTimeout(msRit);
    }
   
    void drawAll(bool allVisible) {
        tft->setFont(font);
        for (int i = 0; i < 4; i++) {
          bool vis = allVisible || (inEdit && i == pos && visible);
          drawDigit(i, vis);
        }
      }
    void update() {
      enc->tick();

      if (enc->click()) {
        if (!inEdit) {
          inEdit = true;
          pos = 0;
          visible = true;
          lastBlink = millis();
        } else {
          drawDigit(pos, true);
          pos = (pos + 1) % 4;
          visible = true;
          lastBlink = millis();
        }
      }

      if (enc->hold()) {
        inEdit = false;
        visible = true;
        drawAll(true);
      }

      if (inEdit) {
        bool changed = false;

        if (enc->right()) {
          drawDigit(pos, false);
          cifre[pos] = (cifre[pos] + 1) % 10;
          changed = true;
        } else if (enc->left()) {
          drawDigit(pos, false);
          cifre[pos] = (cifre[pos] + 9) % 10;
          changed = true;
        }

        if (changed || millis() - lastBlink >= blinkInterval) {
          visible = !visible;
          drawDigit(pos, visible);
          lastBlink = millis();
        }
      }
    }

private:
    void calcPos() {
        xPos[0] = x;
        for (int i = 1; i < 4; i++) {
            xPos[i] = xPos[i - 1] + spz;
        }
    }
    void calcCfr(){
      for (int i = 0; i < 4; i++) cifre[i] = 0;
    }

 uint16_t hexToColor565(uint32_t hexColor) {
    uint8_t r = (hexColor >> 16) & 0xFF;
    uint8_t g = (hexColor >> 8) & 0xFF;
    uint8_t b = hexColor & 0xFF;
    return tft->color565(r, g, b);  // o tft.color565(...) se non è un puntatore
  }

    void drawDigit(int p, bool vis) {
      tft->setFont(font);
      tft->setCursor(xPos[p], y);
      tft->setTextColor(vis ? color : ST77XX_BLACK, ST77XX_BLACK);
      tft->print(cifre[p]);
    }  
};

 

VelDir

#pragma once
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <EncButton.h>
#include "DS_Digit36pt7b.h"

class VelDir {
private:
    Adafruit_ST7735* tft;
    EncButton* enc;
    const GFXfont* font;
    int x, y;
    uint16_t color;
    int value = 0;
    int maxVal = 1000;
    bool dir = true; // true = destra, false = sinistra
    uint16_t arrowRightColor = ST77XX_GREEN;
    uint16_t arrowLeftColor = ST77XX_RED;
    uint16_t bgColor = ST77XX_BLACK;
    uint16_t txtColor = ST77XX_YELLOW;
    uint32_t holdSec;
    bool changed = true;
    int valuePrecedente = -9999;
    int prevValue = -1;
    bool prevDir = !dir;


public:
    VelDir(int x, int y, Adafruit_ST7735* display, EncButton* encod)
        : x(x), y(y), tft(display), enc(encod), font(&DS_Digit36pt7b),
          color(0xffff00), holdSec(400) {
        enc->setHoldTimeout(holdSec);
        enc->setEncReverse(true);
    }

    void setFont(const GFXfont* f) { font = f; }
    void setColor(uint16_t c) { txtColor = c; }
    void setHoldTm(uint32_t ms) { holdSec = ms; enc->setHoldTimeout(holdSec); }
    void setMax(int maxV) { maxVal = maxV; }

    int getValue() const { return dir ? value : -value; }
    bool getDir() const { return dir; }

    void draw() {
        drawValue();
        drawArrow();
        changed = false;
    }

void update() {
    enc->tick();

    if (enc->right() && value < maxVal) value++;
    if (enc->left() && value > 0) value--;
    if (enc->click()) value = 0;
    if (enc->hold()) dir = !dir;

    if (value != prevValue) {
        drawValue();
        prevValue = value;
    }

    if (dir != prevDir) {
        drawArrow();
        prevDir = dir;
    }
}


private: 
    uint16_t hexToColor565(uint32_t hexColor) {
        uint8_t r = (hexColor >> 16) & 0xFF;
        uint8_t g = (hexColor >> 8) & 0xFF;
        uint8_t b = hexColor & 0xFF;
        return tft->color565(r, g, b);
    }

    void drawArrow() {
        int cy = 60;
        int size = 14;

        // Cancella entrambe le aree prima di ridisegnare
        tft->fillRect(8, cy - size - 2, 30, size * 2 + 4, bgColor);     // area sinistra
        tft->fillRect(122, cy - size - 2, 30, size * 2 + 4, bgColor);   // area destra

        if (dir) {
            // Freccia a DESTRA (verde)
            int cx = 136;
            tft->fillTriangle(
                cx - size, cy - size,
                cx - size, cy + size,
                cx + size, cy,
                arrowRightColor
            );
        } else {
            // Freccia a SINISTRA (rossa)
            int cx = 22;
            tft->fillTriangle(
                cx + size, cy - size,
                cx + size, cy + size,
                cx - size, cy,
                arrowLeftColor
            );
        }
    }

   void drawValue() {
    static int lastDigits[4] = {-1, -1, -1, -1}; // memorizza cifre precedenti
    int digits[4] = {0, 0, 0, 0};
    int temp = value;

    // Estrae le cifre da destra verso sinistra
    for (int i = 3; i >= 0; i--) {
        digits[i] = temp % 10;
        temp /= 10;
    }

    tft->setFont(font);

    for (int i = 0; i < 4; i++) {
        int xPos = 10 + i * 36; // posizioni fisse per font monospazio
        if (digits[i] != lastDigits[i]) {
            // Cancella la cifra precedente
            tft->setTextColor(bgColor, bgColor);
            tft->setCursor(xPos, y);
            if (lastDigits[i] >= 0) tft->print(lastDigits[i]); // stampa con colore sfondo

            // Stampa nuova cifra
            tft->setTextColor(txtColor, bgColor);
            tft->setCursor(xPos, y);
            tft->print(digits[i]);

            lastDigits[i] = digits[i];
        }
    }
}

};

 

Passo

#pragma once
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <EncButton.h>
#include "ARLRDBD10pt7b.h"

class Passo {
private:
    Adafruit_ST7735* tft;
    EncButton* enc;
    int x, y;
    const GFXfont* font;
    uint16_t textColor;
 
public:
    Passo(Adafruit_ST7735* display, EncButton* encod): tft(display), enc(encod), 
        font(&ARLRDBD10pt7b){    
        tft->setFont(font);
        enc->setEncReverse(true);
    }

    void setFont(const GFXfont* newFont) {
        if (newFont) {
            font = newFont;
            tft->setFont(font);
        }
    }

    void setColor(uint32_t hexColor) {
        textColor = hexToColor565(hexColor);
        tft->setTextColor(textColor);
    }

    void setCursor(int newX, int newY) {
        x = newX;
        y = newY;
        tft->setCursor(x, y);
    }

    void draw(const String& text) {
        tft->setCursor(x, y);
        tft->print(text);
    }

    void update() {
    static int value = 0;  // mantiene il valore tra 0 e 5
    static int lastValue = -1;
    tft->setFont(font);
    enc->tick();  // aggiorna lo stato dell'encoder

    if (enc->right() && value < 5) {
        value++;
    } else if (enc->left() && value > 0) {
        value--;
    }

    if (value != lastValue) {
        static const char* values[] = { "1", "1/2", "1/4", "1/8", "1/16", "1/32" };

        // Cancella il valore precedente scrivendolo in nero
        tft->setTextColor(0x0000, 0x0000);  // nero su nero
        tft->setCursor(98, 14);
        tft->print(values[lastValue >= 0 ? lastValue : 0]);

        // Scrive il nuovo valore in bianco su sfondo nero
        tft->setTextColor(0xFFFF, 0x0000);  // giallo su nero
        tft->setCursor(98, 14);
        tft->print(values[value]);

        lastValue = value;
    }
}

private:
 uint16_t hexToColor565(uint32_t hexColor) {
    uint8_t r = (hexColor >> 16) & 0xFF;
    uint8_t g = (hexColor >> 8) & 0xFF;
    uint8_t b = hexColor & 0xFF;
    return tft->color565(r, g, b);  // o tft.color565(...) se non è un puntatore
    }
};

 

Etich

#pragma once
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include "ARLRDBD8pt7b.h"
#include "ARLRDBD14pt7b.h"  // Font di default

class Etich {
private:
    Adafruit_ST7735* tft;
    int x, y;
    const GFXfont* font;
    uint16_t textColor;
 
public:
    Etich(Adafruit_ST7735* display): tft(display){    
        tft->setFont(&ARLRDBD8pt7b);
        setColor(0x00ff00);
    }

    void setFont(const GFXfont* newFont) {
        if (newFont) {
            font = newFont;
            tft->setFont(font);
        }
    }

    void setColor(uint32_t hexColor) {
        textColor = hexToColor565(hexColor);
        tft->setTextColor(textColor);
    }

    void setCursor(int newX, int newY) {
        x = newX;
        y = newY;
        tft->setCursor(x, y);
    }

    void setCenter(int newY, String str) {
    y = newY;
    // Usa getTextBounds per ottenere le dimensioni del testo
    int16_t x1, y1;
    uint16_t textWidth = 0, textHeight = 0;
    tft->getTextBounds(str.c_str(), 0, 0, &x1, &y1, &textWidth, &textHeight);
    
    // Calcola la posizione orizzontale centrata
    int centerX = (tft->width() - textWidth) / 2;
    setCursor(centerX, y);
    tft->print(str);
  }

    void draw(const String& text) {
        tft->setCursor(x, y);
        tft->print(text);
    }
    void drawAll() {
        setCursor(7, 33);
        draw("Multiplier:");
        setCursor(40, 12);
        draw("Passo: ");
        setFont(&ARLRDBD14pt7b);
        setCursor(50, 68);
        draw("RPM");
    }
private:
 uint16_t hexToColor565(uint32_t hexColor) {
    uint8_t r = (hexColor >> 16) & 0xFF;
    uint8_t g = (hexColor >> 8) & 0xFF;
    uint8_t b = hexColor & 0xFF;
    return tft->color565(r, g, b);  // o tft.color565(...) se non è un puntatore
    }
};