Salve a tutti! Sono stato per un bel po' assente da questo hobby causa lavoro. Ho ripreso adesso un progetto che non avevo completato qualche anno fa, un orologio con dei led WS2812B.
Il codice gestisce 24 led, un DS3231 e 3 pulsanti, funziona perfettamente su un Arduino UNO ma non appena lo carico su una scheda custom con MCU un ATiny84 con quarzo esterno a 16MHz sembra che si pianti tutto.
Ho fatto varie prove e funziona se carico il codice o solo per pilotare i led da DS3231 o solo per gestire i tre pulsanti (ho provato con varie librerie). A questo punto mi sembra palese che il problema sia la mancanza di risorse dell'Attiny84, ma mi piacerebbe studiare più a fondo la questione e capirci di più, quindi chiedo a voi qualche dritta su cosa andare a studiare.
Sotto vi lascio il codice con le parti salienti
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega328P__)
#include <Adafruit_NeoPixel.h>
#define DEBUG_MODE // attivazione automatica modalità DEBUG tramite seriale
#elif defined(__AVR_ATtiny84__) // ATtiny84
#include <tinyNeoPixel.h> //libreria per led WS2812B
#endif
#include <RTClib.h> //libreria per DS3231
#include <EasyButton.h>
#ifdef DEBUG_MODE
#define DBEGIN(speed) Serial.begin (speed)
#define DWHILE(...) while(!Serial){}
#define DPRINT(...) Serial.print (__VA_ARGS__)
#define DPRINTLN(...) Serial.println (__VA_ARGS__)
#else
#define DBEGIN(...) do {} while (0)
#define DWHILE(...) do {} while (0)
#define DPRINT(...) do {} while (0)
#define DPRINTLN(...) do {} while (0)
#endif
//MODALITÀ DEBUG
//###################################################
#define PIN 7 // pin di collegamento della linea data dei led WS2812
#define NUMPIXELS 24 //numero led
//############################################################
//definizione dei led in funzione della loro posizione
#define SEC 23 // led dei secondi
// definizione dei led che compongono le ore pentali
#define ORE_5_1 22
#define ORE_5_2 21
#define ORE_5_3 20
#define ORE_5_4 19
// definizione dei led che compongono le unità delle ore
#define ORE_1_1 15
#define ORE_1_2 16
#define ORE_1_3 17
#define ORE_1_4 18
// definizione dei led che compongono i minuti pentali
#define MIN_5_1 14
#define MIN_5_2 13
#define MIN_5_3 12
#define MIN_5_4 11
#define MIN_5_5 10
#define MIN_5_6 9
#define MIN_5_7 8
#define MIN_5_8 7
#define MIN_5_9 6
#define MIN_5_10 5
#define MIN_5_11 4
// definizione dei led che compongono le unità dei minuti
#define MIN_1_1 0
#define MIN_1_2 1
#define MIN_1_3 2
#define MIN_1_4 3
//###################################################################
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega328P__) // Arduino Leonardo o UNO
#define PUL_SET_PIN 6
#define PUL_PIU_PIN 4
#define PUL_MENO_PIN 12
#elif defined(__AVR_ATtiny84__) // ATtiny84
// definizione pin pulsanti
#define PUL_SET_PIN 1
#define PUL_PIU_PIN 2
#define PUL_MENO_PIN 3
#endif
// definizioni stati di funzionamento
#define RUN 1 // modalità di visualizzazione orario
#define MODIFICA_ORE 10 //Modalità impostazione orario
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega328P__)// Arduino Leonardo
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
#elif defined(__AVR_ATtiny84__) // ATtiny84
tinyNeoPixel pixels = tinyNeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
#endif
RTC_DS3231 rtc; // Istanza dell'oggetto RTC
//instanze della libreria EasyButton per la gestione dei pulsanti con disabilitazione pullup interno e stato attivo low
EasyButton pul_set(PUL_SET_PIN, 35, false, false);
EasyButton pul_piu(PUL_PIU_PIN, 35, false, false);
EasyButton pul_meno(PUL_MENO_PIN, 35, false, false);
//########################################
//char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
uint8_t stato = 0; //variabile per definire lo stato dell'orologio
uint8_t luminosita = 10; // impostazione della luminosità dei led
uint8_t ore = 0, minuti = 0, secondi = 0, minuti_unita = 0, minuti_cin = 0, ore_unita = 0, ore_cin = 0;
int8_t ultimi_minuti = -1; // imposto ultimi_minuti a -1 in modo che anche all'avvio sarà sempre verificato l'if per la funzione visualizza (anche con orario con minuti 00)
uint8_t i = 0;
const uint32_t ritenuta = 3000;
bool set_cliked = false, set_long_clicked = false, piu_clicked = false, meno_clicked = false;
//########################################
const uint8_t riga_D [4] = {ORE_5_1, ORE_5_2, ORE_5_3, ORE_5_4};
const uint8_t riga_C [4] = {ORE_1_1, ORE_1_2, ORE_1_3, ORE_1_4};
const uint8_t riga_B [11] = {MIN_5_1, MIN_5_2, MIN_5_3, MIN_5_4, MIN_5_5, MIN_5_6, MIN_5_7, MIN_5_8, MIN_5_9, MIN_5_10, MIN_5_11};
const uint8_t riga_A [4] = {MIN_1_1, MIN_1_2, MIN_1_3, MIN_1_4};
//########################################
void visualizza(); // funzione per visualizzazione dell'orario corrente
void imposta_orario(); // funzione per impostare l'orario tramite i pulsanti e salvarlo nell'RTC
void setup() {
//#################################
DBEGIN(9600);
DWHILE();
delay(300);
DPRINTLN("MODALITA' DEBUG ATTIVA");
//##############################
pixels.begin();
pixels.setBrightness(luminosita);
if (! rtc.begin()) {
DPRINTLN("RTC OFF");
while (1) delay(10);
}
if (rtc.lostPower()) {
DPRINTLN("RTC LOST POWER");
//modalità impostazione orario
stato = MODIFICA_ORE;
}
else{
DPRINTLN("Stato: RUN");
stato = RUN;
}
//Inizializzazione e configuzione pulsanti
pul_set.begin();
pul_piu.begin();
pul_meno.begin();
pul_set.onPressed(set_click);
pul_set.onPressedFor(ritenuta, set_long_click);
pul_piu.onPressed(piu_click);
pul_meno.onPressed(meno_click);
}
void loop() {
pul_set.read();
pul_piu.read();
pul_meno.read();
switch (stato){
case RUN:
visualizza();
if(set_long_clicked){
set_long_clicked = false;
DPRINTLN("Attivo modalità modifica orario");
stato = MODIFICA_ORE;
}
break; //fine RUN
case MODIFICA_ORE:
imposta_orario();
break; //fine MODIFICA_ORE
}
}
void visualizza(){
DateTime now = rtc.now();
ore = now.hour(), DEC;
minuti = now.minute(), DEC;
secondi = now.second(), DEC;
//lampeggio dei secondi
if(secondi%2 == 0){
pixels.setPixelColor(SEC, pixels.Color(255,255,255));
}
else{
pixels.setPixelColor(SEC, pixels.Color(0,0,0));
}
//############################################
if(minuti != ultimi_minuti){
DPRINT(ore);
DPRINT(":");
DPRINT(minuti);
DPRINT(":");
DPRINTLN(secondi);
DPRINTLN("\n");
ore_cin = ore / 5;
DPRINTLN(ore_cin);
ore_unita = ore % 5;
DPRINTLN(ore_unita);
minuti_cin = minuti / 5;
DPRINTLN(minuti_cin);
minuti_unita = minuti % 5;
DPRINTLN(minuti_unita);
pixels.clear();
//impostazione led per le unità dei minuti
for( i = 0; i < minuti_unita; i++){
pixels.setPixelColor(riga_A[i], pixels.Color(255,255,255));
}
//impostazione led per i minuti cin
for( i = 0; i < minuti_cin; i++){
pixels.setPixelColor(riga_B[i], pixels.Color(255,255,255));
}
//impostazione led per le unità delle ore
for( i = 0; i < ore_unita; i++){
pixels.setPixelColor(riga_C[i], pixels.Color(255,255,255));
}
//impostazione led per le ore cin
for( i = 0; i < ore_cin; i++){
pixels.setPixelColor(riga_D[i], pixels.Color(255,255,255));
}
ultimi_minuti = minuti;
}
pixels.show();
}
void imposta_orario(){
DPRINTLN("Stato: MODIFICA_ORE");
pixels.clear();
pixels.setPixelColor(SEC, pixels.Color(255,255,255));
pixels.show();
DPRINTLN("Attesa");
delay(10000); //funzione di appoggio per test funzionamento
stato = RUN; //alla fine della procedura di modifica imposto il nuovo stato
ultimi_minuti = -1; //imposto la variabile al -1 in modo da forzare subito l'aggiornamento della visualizzazione (in caso di impostazione orario con minuti = ai minuti precedentemente visualizzati)
}
// funzione di callback per le varie modalità di pressione per i pulsanti
void set_click(){
DPRINTLN("Cliccato SET");
set_cliked = true;
}
void set_long_click(){
DPRINTLN("Lunga Pressione SET");
set_long_clicked = true;
}
void piu_click(){
DPRINTLN("Cliccato PIU");
piu_clicked = true;
}
void meno_click(){
DPRINTLN("Cliccato MENO");
meno_clicked = true;
}