E beh, vediamo quando gli arriva se riusciamo a tirare fuori un LED pulsante in modo corretto
Intanto sullo schema vedo già un problema di alimentazione, quel modulo dcf funziona a 3.3V, e temo che anche la sua uscita non si possa collegare direttamente ad un pin di Arduino.
Per l'alimentazione potrebbe bastare resistenza da 330 Ω e zener da 3.3V
Non ho capito la funzione di tutti quei pulsanti.
Il LED dcf error (che lampeggerebbe quasi sempre) mi sembra meno utile di un LED sync ok (che invece indicherebbe ora sincronizzata e ricezione perfetta)... o meglio, per completezza, cioè capire sia quando le cose non vanno bene, sia quando vanno, servirebbero tutti e due. Più uno per gli impulsi grezzi emessi dal modulo... così si vede visivamente lo stato della ricezione e dell'orientamento dell'antenna.
Per quanto riguarda leggere la trama DCF77 a mano mi sono divertito a riscrivere in C più o meno il procedimento di quello che quattordici anni fa ho scritto in assembly per PIC16F628 (Arduino ancora non esisteva :'(). Non c'è niente di testato... meglio non quotare il codice visto che sicuramente sarà da correggere.
La trama di 59 bit (ricevuta domenica 7 settembre 2003 alle 12:37) è fatta così :
I dati sono inviati in formato BCD compatto, i bit meno significativi vengono trasmessi per primi. I bit rossi sono il controllo di parità pari (in pratica facendo lo xor dei bit ricevuti, compresa la parità, il risultato deve sempre essere zero). Il primo bit è sempre 0 (forse), il ventunesimo sempre 1 (sicuro).
void dcf()
{
byte pulse = digitalRead(dcfPin);
switch (dcfStat)
{
case 0: // restart processo
dcfCnt = 0;
dcfStat = 1;
nBit = 1;
bitXor = 0;
break;
case 1: // attesa secondo di sync
if (pulse) { dcfStat = 0; break; }
if (++dcfCnt == 400) dcfStat = 2;
break;
case 2: // attesa impulso
if (pulse) { dcfCnt = 0; dcfStat = 3; }
break;
case 3: // misura impulso
++dcfCnt;
if (!pulse)
{
if (dcfCnt < 16) { dcfStat = 8; break; } // errore corto
if (dcfCnt < 60) bitRx = 0;
else if (dcfCnt<104) bitRx = 1;
else { dcfStat = 8; break; } // errore lungo
dcfStat = 4;
}
break;
case 4: // elabora bit
if (nBit == 1 && bitRx) { dcfStat = 8; break; } // errore start0
if (nBit == 21 && !bitRx) { dcfStat = 8; break; } // errore start1
bitXor ^= bitRx;
if (nBit == 29 && bitXor) { dcfStat = 8; break; } // errore parita`
if (nBit == 36 && bitXor) { dcfStat = 8; break; } // errore parita`
rxData = (rxData >> 1) | (unsigned int)(bitRx << 15);
dcfCnt = 0;
if (nBit == 36) // fine sezione ore minuti
{
rxData >>= 1;
rxMinute = rxData & 0x0F;
rxData >>= 4;
rxMinute = 10*(rxData & 7) + rxMinute;
rxData >>= 4;
rxHour = rxData & 0x0F;
rxData >>= 4;
rxHour = 10*(rxData & 3) + rxHour;
if (rxMinute > 59
|| rxHour > 23) { dcfStat = 8; break; } // errore valori
dcfStat = 6 ;
break;
}
dcfStat = 5;
break;
case 5: // attesa 600 ms
if (++dcfCnt == 240) { ++nBit; dcfStat = 2; }
break;
case 6: // attesa 24 sec
if (++dcfCnt == 9600)
{
if (rxMinute == (priorRxMinute + 1) % 60
&& rxHour == priorRxHour) rxOK = true;
priorRxMinute = rxMinute;
priorRxHour = rxHour;
dcfCnt = 0;
nBit = 1;
bitXor = 0;
dcfStat = 2;
}
break;
case 8: // errore generale di ricezione
rxError = true;
dcfStat = 0;
}
}
La funzione dcf va chiamata alla frequenza di multiplex (2.5ms in base a quanto scritto in questo post), legge il pin dcfPin (può essere un pin qualsiasi) e imposta a true due flag rxOK o rxError. Scrive l'ora ricevuta nelle variabili rxMinute (da 0 a 59) e rxHour (da 0 a 23). Effettua controlli su:
- durata singoli impulsi
- valore corretto dei bit di start e parità
- valore orario sensato
- da per buona l'ora (rxOK=true) quando si ricevono due trame consecutive OK con differenza di un solo minuto
Nota: ricava solo l'orario, fino al 36esimo bit, e ignora i successivi 23.
Per funzionare usa il seguente gruppo di definizioni/variabili globali:
#define dcfPin A2 // pin Arduino input impulsi dcf
byte nBit; // numero del bit letto 1..60
byte dcfStat = 0; // stato processo dcf
unsigned int dcfCnt; // contatore 16 bit processo dcf
byte bitRx; // valore bit appena ricevuto
byte bitXor; // xor di tutti i bit ricevuti
unsigned int rxData; // scorrimento bit ricevuti in campo 16 bit
byte rxMinute; // minuto appena ricevuto
byte rxHour; // ora appena ricevuta
byte priorRxMinute = 0; // minuto ricevuto precedente
byte priorRxHour = 0; // ora ricevuta precedente
bool rxOK = false; // true quando ricevuti dati OK
bool rxError = false; // true quando errore qualsiasi