Orologio analogico con tft

Ciao a tutti, vorrei disegnare tramite un tft un orologio analogico con lancetta dei sec. min. e h.
Ho gia un piccolo problema che non riesco a risolvere, in quanto collegandomi alla funzione millis() riesco a far disegnare con cadenza di 1sec l’avanzamento della lancetta dei secondi, ma non riesco a capire come cancellare la lancetta precedentemente disegnata, in quanto sul display vedo disegnate la bellezza di 60 linee. Spero di essere stato chiaro, vi posto il codice.

#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_TFTLCD.h> // Hardware-specific library

#define BLACK   0x0000
#define BLUE    0x001F
#define RED     0xF800
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF

#define LCD_CS A3
#define LCD_CD A2
#define LCD_WR A1
#define LCD_RD A0
#define LCD_RESET A4

Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);

unsigned long dts;
unsigned long t = 1000;

float xs, ys, a = 0.00;

void setup() {
  Serial.begin(9600);
  tft.begin(0x9341);
  tft.setRotation(0);
  tft.fillScreen(0x0000);
  tft.drawCircle(120, 160, 100, 0xFFE0);
  delay(1000);
  tft.drawCircle(120, 160, 85, 0x001F);
}
void loop() {
  dts = millis() - t;
  if (dts >= 1000) {
    t = millis();
    Serial.println(t);
    Serial.println(a);
    if (a >= 0.00) {
      if (a <= 6.28) {
        xs = 120 + (85 * cos(a));
        ys = 160 + (85 * sin(a));
        tft.drawLine(120, 160, xs, ys, 0x07E0);
        a = a + 0.10472;
      }
    }
    if (a >= 6.28) {
      a = 0.00;
    }
  }
}

Grazie per gli aiuti

Per "cancellare" la lancetta (o qualsiasi altra cosa senza fare dei clear di tutto l'LCD) il sistema piu semplice credo sia ridisegnare la "vecchia" lancetta subito prima di disegnare la nuova, ma con il colore di sfondo ...

Solo come idea ... metti che hai lo sfondo nero e le lancette bianche, al primo secondo disegni in bianco la lancetta in posizione "secondo01" (e ti memorizzi xs ed ys in un'altro paio di variabili), poi al successivo secondo, con i valori che ti sei appena salvato nelle variabili, subito prima di disegnare "secondo02" in bianco, disegni di nuovo "secondo01" in nero, disegni "secondo02" in bianco, ed aggiorni le variabili con la posizione "secondo02" ... e cosi via ...

Dirla cosi sembra complicata, ma in realta' non lo e' ... ;)

Ciao, t ringrazio per la risposta e immaginavo che la soluzione fosse quella, però ho un dubbio. Se io faccio questo gioco di cancellare la lancetta precedente è possibile che quando 2 lancette si sovrappongano per quel secondo,vengano cancellate tutti e due? Es. Lancetta secondi segna 10s Lancetta Min segna 10 min Nn vorrei che quando cancello quella dei 10sec, cancello per 1 solo secondo anche quella dei Min. In questo caso, credo che debbo fare una comparazione tra le due lancette e stabilire che quando hanno la stessa posizione, privilegiare quella dei Min( a livello di visualizzazione) rispetto a quella dei sec. Grz, spero di essermi spiegato.

Si, ma presumo che tu usi lancette di spessori diversi per ore, minuti e secondi ... o qualcosa di simile ... basta fare le scritture sempre nella stessa sequenza (prima ore, poi minuti, poi secondi) ogni volta ...

Si, diciamo che è più un effetto grafico che verrà un po' così.. grz

allora sto facendo delle prove, ma non riesco a sviluppare la funzione millis() per cancellare la vecchia variabile salvata in precedenza. qualche sugggerimento?

aspetta, quale funzione ? … non ti serve sviluppare una specifica funzione apposta, lo fai insieme ai tuoi tft.drawLine originali … voglio dire, prima definisci delle coppie di variabili per le lancette che userai per salvarci i valori da usare (una coppia per ogni lancetta, intanto fai dei test con una sola lancetta, quella dei secondi, per vedere come funziona, poi riporti il tutto anche per le altre), poi dove tu hai il tuo comando, ad esempio quello che usa xs ed ys, definisci una coppia di variabili esempio xsp ed ysp (uso p per precedente) , poi dove disegni la lancetta con (l’ho preso dal tuo listato)

tft.drawLine(120, 160, xs, ys, 0x07E0)

lo modifichi per fargli disegnare subito prima la lancetta del colore di sfondo con le coordinate precedenti (che avrai ovviamente salvato nelle altre due variabili quando hai disegnato la lancetta precedente, e che aggiornerai subito dopo aver disegnato quella nuova … tipo cosi, ad esempio …

tft.drawLine(120, 160, xsp, ysp, coloredisfondo) <-disegni lancetta con colore di sfondo su vecchia lancetta
tft.drawLine(120, 160, xs, ys, 0x07E0) ← disegni la tua nuova lancetta
xsp=xs ← salvi coordinate per disegnare la prossima lancetta con colore di sfondo
ysp=ys ← salvi coordinate per disegnare la prossima lancetta con colore di sfondo

dovrebbe bastare questo … premetto pero’ che sto andando a memoria, non avendo in casa quel tft per provare … devi testarlo tu …

Grazie, mi sono spiegato male e mi sono perso in un bicchiere d’acqua…
risolto cosi

#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_TFTLCD.h> // Hardware-specific library

#define BLACK   0x0000
#define BLUE    0x001F
#define RED     0xF800
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF

#define LCD_CS A3
#define LCD_CD A2
#define LCD_WR A1
#define LCD_RD A0
#define LCD_RESET A4

Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);

unsigned long dts;
unsigned long t = 1000;

float xs , ys , a = 0.00;
float xsn, ysn;

void setup() {
 Serial.begin(9600);
 tft.begin(0x9341);
 tft.setRotation(0);
 tft.fillScreen(0x0000);
 tft.drawCircle(120, 160, 100, 0xFFE0);
 delay(1000);
 tft.drawCircle(120, 160, 85, 0x001F);
 xs = 120 + (85 * cos(a));
 ys = 160 + (85 * sin(a));
 tft.drawLine(120, 160, xs, ys, 0x07E0);
}
void loop() {
 dts = millis() - t;
 if (dts >= 1000) {
   t = millis();
   if (a >= 0.00) {
     xsn = 120 + (85 * cos(a));
     ysn = 160 + (85 * sin(a));
     tft.drawLine(120, 160, xs, ys, 0x0000);
     tft.drawLine(120, 160, xsn, ysn, 0x07E0);
     xs = xsn;
     ys = ysn;
     a = a + 0.10472;
   }
 }
}

In pratica nel setup disegno la lancetta dei secondi sullo zero con coordinate xs,ys. Nel loop ad ogni aumento di 6 gradi che corrisponde ai secondi (360gradi\60sec=6 gradi\sec.) definisco le nuove coordinate del secondo successivo (xsn,ysn), cancello la vecchia coordinata colorandola di nero (come il mio sfondo) e disegno quella nuova associando le variabili delle coordinate vecchie a quelle nuove.
Funziona.
Adesso proseguo con i minuti e le ore.

Ricordati solo, per evitare che ti restino lancette "tagliate" dai redraw precedenti, di disegnarle con la stessa sequenza in cui sono posizionate sul quadrante di un vero orologio (prima ore, poi minuti, poi secondi), e di disegnarle tutte e tre ad ogni secondo, anche se non si spostano nel frattempo (scalando dal conteggio del tempo quello necessario a fare tutti i disegni, in modo da non sfalsare il tempo ... o ancora meglio usando un RTC, ma quello e' un'altro discorso ;) )

Ti ringrazio per i consigli sopracitati, appena proseguo nello sketch faccio sapere se ho problemi. Per quanto riguarda RTC speravo fosse inclusa nello starter kit ma nn c'è, la comprerò a parte come ho fatto cn il tft.

Se deciderai di acquistarlo piu avanti, ti consiglio il 3231, perche' e' piu preciso del 1302 ;)

Grazie del consiglio

Questo è il codice finito per quanto riguarda la funzionalità delle lancette, in seguito lo amplierò meglio con una grafica più carina

#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_TFTLCD.h> // Hardware-specific library

#define BLACK   0x0000
#define BLUE    0x001F
#define RED     0xF800
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF

#define LCD_CS A3
#define LCD_CD A2
#define LCD_WR A1
#define LCD_RD A0
#define LCD_RESET A4

Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);

unsigned long dts;
unsigned long t = 1000;

float xs , ys , xm, ym, xh, yh, a = 0.00 , b = 0.00, c = 0.00;
float xsn, ysn, xmn, ymn, xhn, yhn;

void setup() {
  Serial.begin(9600);
  tft.begin(0x9341);
  tft.setRotation(0);
  tft.fillScreen(0x0000);
  tft.drawCircle(120, 160, 100, 0xFFE0);
  //disegno lancetta secondi
  xs = 120 + (85 * cos(a));
  ys = 160 + (85 * sin(a));
  tft.drawLine(120, 160, xs, ys, 0x07E0);
  //disegno lancetta minuti
  xm = 120 + (85 * cos(b));
  ym = 160 + (85 * sin(b));
  tft.drawLine(120, 160, xm, ym, 0xFFFF);
  //disegno lancetta ore
  xh = 120 + (70 * cos(c));
  yh = 160 + (70 * sin(c));
  tft.drawLine(120, 160, xh, yh, 0x001F);
}
void loop() {

  dts = millis() - t;
  if (dts >= 1000) {
    t = millis();
    a = a + 0.10472;
    xsn = 120 + (85 * cos(a));
    ysn = 160 + (85 * sin(a));
    tft.drawLine(120, 160, xs, ys, 0x0000);
    tft.drawLine(120, 160, xsn, ysn, 0x07E0);
    xs = xsn;
    ys = ysn;
    if (a >= 6.28) {
      a = 0.00;
      b = b + 0.10472;
      xmn = 120 + (85 * cos(b));
      ymn = 160 + (85 * sin(b));
      tft.drawLine(120, 160, xm, ym, 0x0000);
      tft.drawLine(120, 160, xmn, ymn, 0xFFFF);
      xm = xmn;
      ym = ymn;
    }
    if (b >= 6.28) {
      b = 0.00;
      c = c + 0.52359;
      xhn = 120 + (70 * cos(c));
      yhn = 160 + (70 * sin(c));
      tft.drawLine(120, 160, xh, yh, 0x0000);
      tft.drawLine(120, 160, xhn, yhn, 0x001F);
      xh = xhn;
      yh = yhn;
    }
  }
  if (xsn = xm , ysn = ym ) {
    tft.drawLine(120, 160, xm, ym, 0xFFFF);
  }
  if (xsn = xh, ysn = yh) {
    tft.drawLine(120, 160, xh, yh, 0x001F);
  }
  if (xmn = xh, ymn = yh) {
    tft.drawLine(120, 160, xh, yh, 0x001F);
  }
}

Appena arriverà anche il modulo RTC cercherò di implementarlo.

Ho fatto un update inserendo i minuti (ogni 5 min) sull’orologio ma mi trovo con questo effetto grafico che non capisco se dipende dal codice errato o dalla bassa qualità del display.
Questo è il codice:

for (a = 0.00; a < 6.28; a = a + 0.52359) {
    xs = 120 + (120 * cos(a));
    ys = 160 + (120 * sin(a));
    tft.drawLine(120, 160, xs, ys, 0x07E0);
    xs = 120 + (90 * cos(a));
    ys = 160 + (90 * sin(a));
    tft.drawLine(120, 160, xs, ys, 0x0000);
  }

In pratica disegno una linea colorata e per un tratto la ri-disegno di colore nero cosi che si vede solo la parte finale della linea.
Quello che ottengo è questo:


P.S lasciare stare i puntini al di fuori della circonferenza.

Mi è arrivato il modulo DS3231 che mi hai consogliato. Ho guardato tramite la libreria da scaricare all'interno di Arduino i relativi esempi e mi chiedevo se vi fosse un modo di utilizzarlo senza la libreria, in quanto credo che mi aiuterebbe a migliorare l'utilizzo dei componenti esterni ad arduino lavorando sui registri e la capacità di lettura dei datasheet. Da quello che ho capito la libreria "Wire" sia d'obbligo utilizzarla. Grazie.

aljfox: ... mi chiedevo se vi fosse un modo di utilizzarlo senza la libreria ...

Ovviamente SI, del resto la libreria è solo del codice che quacun'altro ha scritto :D

In particolare, i DS1307, DS3231, ecc. ecc. sono particolarmente semplici da utilizzare ... si tratta di caricare o leggere i valori di registri che sono a determinati indirizzi di memoria. Ovviamente occorre studiare bene il datasheet e capire, appunto, l'organizzazione della memoria e cosa doverci scrivere/poterci leggere.

Dato che tali chip lavorano su bus I2C, [u]bus NON proprio banale da utilzzare/gestire[/u], senza reinventare l'acqua calda con notevole dispendio di forze, si usa la libreria Wire che, appunto, si occupa di tutta la gestione di detto bus e che comunque è indipendente dai chip con cui parli.

Guglielmo

P.S.: ... onestamente, per quei chip, NON ho mai usato una "libreria" ... mi sono scritto quelle poche funzioni che realmente mi servivano/come mi servivano ... e via.

Quindi per logica: -Studio libreria Wire; -Studio datasheet; -Inizio a scrivere il software.

SI, studiati il reference della libreria Wire, studiati il datasheet, per la parte che riguarda i vari registri e come le informazioni sono memorizzate in essi e ... vai ;D

Guglielmo

P.S.: ... tipicamente data/ora non sono memorizzate in binario ma in BCD ... un paio di funzioncine di conversione da/verso e passa la paura.

Grazie Guglielmo, sarà un po lunga xke è la prima volta che provo, se combino qualcosa posto.

Guarda, dato che [u]le ho già messe più volte qui sul forum[/u], le ripubblico anche per te ...

// ------------------- decToBcd -------------------------

uint8_t decToBcd(uint8_t val) {
  return ( (val / 10 * 16) + (val % 10) );
}

// ------------------- bcdToDec -------------------------

uint8_t bcdToDec(uint8_t val) {
  return ( (val / 16 * 10) + (val % 16) );
}

... sono le due funzioncine che ti occorrerrano per le conversioni di alcuni valori da e verso il BCD ... così, anche in questo caso, evitiamo di reinventare l'acqua calda :D

Guglielmo