• Witaj na Forum Arduino Polska! Zapraszamy do rejestracji!
  • Znajdziesz tutaj wiele informacji na temat hardware / software.
Witaj! Logowanie Rejestracja


Ocena wątku:
  • 0 głosów - średnia: 0
  • 1
  • 2
  • 3
  • 4
  • 5
Arduino MEGA problem z DCF
#1
Dzień dobry Wszystkim

Na stare lata stwierdziłem, że nauczę się czegoś nowego i wziąłem się za arduino.
Po miganiu diodą, termometrach i sterowaniu lampką przyszła pora na poważniejszy (dla mnie) projekt czyli zegarek.
A że wala się u mnie trochę lamp to postawiłem od razu z grubej rury zrobić zegarek na lampach nixie z566.
Prototyp już mam, nawet działa ale nie wiem dlaczego działa i tu moja prośba o naprowadzenie dlaczego to działa tak a nie inaczej.

Płytka to arduino mega, bo nie ogarniam jeszcze rejestrów i steruję wszystkimi lampami poprzez 4 układy DM74141N.
Do tego moduł DCF 77 i zegar DS3231.

Zacząłem od testowania czy lampy działają i czy mogę nimi stertować. Działają, 1 sukces.
Potem przyszła pora na na DCF i synchronizację czasu z zapisanie go do DS3221.
Użyłem tego kodu znalezionego na forum:

Kod:
#include <Wire.h>

#define DEBUGMODE 0  // 1 or 0 to show or not show debug messages
#define DCFPIN 2    // data pin of DCF77 module
#define DCF_INPUTMODE INPUT_PULLUP  // INPUT or INPUT_PULLUP
#define INVERTEDSIGNAL true  // false= normal signal, true= inverted signal

#include "jursDCFtime.h"

void setup() {
  Serial.begin(9600);
  Serial.println(F("\nDCF77 and RTC test sketch by 'jurs'"));
  if (RTCinit()) Serial.println(F("RTC OK"));
  else Serial.println(F("RTC FAIL"));
  pinMode(DCFPIN, DCF_INPUTMODE);
}

unsigned long lastPrintTimeMillis;

void loop() {
  sTime time;
  if (dcfUpdate())
  {
    RTCwriteTime(lastValidDCFtime);
    Serial.println("DCF77 TIME TELEGRAM RECEIVED!");
   
  }
  if (millis()-lastPrintTimeMillis>=1000) // each second
  { // read time from RTC and print it to Serial
    lastPrintTimeMillis+=1000;
    char buf[21];
    RTCreadTime(time);
    snprintf(buf,sizeof(buf),"%02d.%02d.%04d  %02d:%02d:%02d", time.bDay, time.bMonth, time.iYear, time.bHour, time.bMinute, time.bSecond);
    Serial.println(buf); // print date and time
  }
}

Zegar się ślicznie zsynchronizował i zapisał czas do DS3221. 2 sukces.

No to dołączyłem powyższy kod do programu zegara i... nie działa.
Nie wiem dlaczego kod włożony do programu zegara nie chce synchronizować czasu.

Jak odpalę kod samej synchronizacji (ten powyżej) to pięknie działa i mam czas zapisany w DS3231.
Wgram po tym program zegara i pięknie godzinę pokazuje.
Resetuję RTC poprzez wyjęcie baterii i mogę czekać godzinę i zero synchronizacji.
Wgram kod samej synchronizacji i po 2 mim mam czas.

Wyjaśnijcie proszę staremu staremu człowiekowi dlaczego. Pewnie robię gdzieś błąd ale go nie widzę.
Poniżej kod zegara, którego używam.

Kod:
#include <Wire.h>

#define DEBUGMODE 0  // 1 or 0 to show or not show debug messages
#define DCFPIN 2    // data pin of DCF77 module
#define DCF_INPUTMODE INPUT_PULLUP  // INPUT or INPUT_PULLUP
#define INVERTEDSIGNAL true  // false= normal signal, true= inverted signal

#include "jursDCFtime.h"

#define A1 22
#define B1 24
#define C1 26
#define D1 28
#define A2 30
#define B2 32
#define C2 34
#define D2 36
#define A3 38
#define B3 40
#define C3 42
#define D3 44
#define A4 46
#define B4 48
#define C4 50
#define D4 52

char A[4] = {A4, A3, A2, A1};
char B[4] = {B4, B3, B2, B1};
char C[4] = {C4, C3, C2, C1};
char D[4] = {D4, D3, D2, D1};

int zero;
int one;
int two;
int three;
int hour;
int minute;

void setup() {
  {Serial.begin(9600);
  Serial.println(F("\nDCF77 and RTC test sketch by 'jurs'"));
  if (RTCinit()) Serial.println(F("RTC OK"));
  else Serial.println(F("RTC FAIL"));
  pinMode(DCFPIN, DCF_INPUTMODE);

  }
 
  unsigned long lastPrintTimeMillis;
 
  pinMode(A1, OUTPUT);
  pinMode(B1, OUTPUT);
  pinMode(C1, OUTPUT);
  pinMode(D1, OUTPUT);
  pinMode(A2, OUTPUT);
  pinMode(B2, OUTPUT);
  pinMode(C2, OUTPUT);
  pinMode(D2, OUTPUT);
  pinMode(A3, OUTPUT);
  pinMode(B3, OUTPUT);
  pinMode(C3, OUTPUT);
  pinMode(D3, OUTPUT);
  pinMode(A4, OUTPUT);
  pinMode(B4, OUTPUT);
  pinMode(C4, OUTPUT);
  pinMode(D4, OUTPUT);

  for (char i = 0; i < 4; i++) {
    digitalWrite(A[i], HIGH);
    digitalWrite(B[i], HIGH);
    digitalWrite(C[i], HIGH);
    digitalWrite(D[i], HIGH);
  }

}

unsigned long lastPrintTimeMillis;

void loop() {
  sTime time;
  if (dcfUpdate())
  {
    RTCwriteTime(lastValidDCFtime);
    Serial.println("DCF77 TIME TELEGRAM RECEIVED!");
   
  }
  if (millis()-lastPrintTimeMillis>=1000) // each second
  { // read time from RTC and print it to Serial
    lastPrintTimeMillis+=1000;
    char buf[21];
    RTCreadTime(time);
    snprintf(buf,sizeof(buf),"%02d.%02d.%04d  %02d:%02d:%02d", time.bDay, time.bMonth, time.iYear, time.bHour, time.bMinute, time.bSecond);
    Serial.println(buf); // print date and time
   
  }
  {
  hour = time.bHour;
  minute = time.bMinute;
  zero = (hour / 10);
  one = hour % 10;
  two =  (minute / 10);
  three = minute % 10;
//Serial.println(zero);
// Serial.println(one);
// Serial.println(two);
// Serial.println(three);
  writenumber(0, zero);
  writenumber(1, one);
  writenumber(2, two);
  writenumber(3, three);
  delay(1000);
  }

}

void writenumber(int a, int b) {
  switch (b) {
    case 0:
      digitalWrite(A[a], LOW);
      digitalWrite(B[a], LOW);
      digitalWrite(C[a], LOW);
      digitalWrite(D[a], LOW);
      break;
    case 1:
      digitalWrite(A[a], HIGH);
      digitalWrite(B[a], LOW);
      digitalWrite(C[a], LOW);
      digitalWrite(D[a], LOW);
      break;
    case 2:
      digitalWrite(A[a], LOW);
      digitalWrite(B[a], HIGH);
      digitalWrite(C[a], LOW);
      digitalWrite(D[a], LOW);
      break;
    case 3:
      digitalWrite(A[a], HIGH);
      digitalWrite(B[a], HIGH);
      digitalWrite(C[a], LOW);
      digitalWrite(D[a], LOW);
      break;
    case 4:
      digitalWrite(A[a], LOW);
      digitalWrite(B[a], LOW);
      digitalWrite(C[a], HIGH);
      digitalWrite(D[a], LOW);
      break;
    case 5:
      digitalWrite(A[a], HIGH);
      digitalWrite(B[a], LOW);
      digitalWrite(C[a], HIGH);
      digitalWrite(D[a], LOW);
      break;
    case 6:
      digitalWrite(A[a], LOW);
      digitalWrite(B[a], HIGH);
      digitalWrite(C[a], HIGH);
      digitalWrite(D[a], LOW);
      break;
    case 7:
      digitalWrite(A[a], HIGH);
      digitalWrite(B[a], HIGH);
      digitalWrite(C[a], HIGH);
      digitalWrite(D[a], LOW);
      break;
    case 8:
      digitalWrite(A[a], LOW);
      digitalWrite(B[a], LOW);
      digitalWrite(C[a], LOW);
      digitalWrite(D[a], HIGH);
      break;
    case 9:
      digitalWrite(A[a], HIGH);
      digitalWrite(B[a], LOW);
      digitalWrite(C[a], LOW);
      digitalWrite(D[a], HIGH);
      break;
  }
}

void off(int a) {
  digitalWrite(A[a], HIGH);
  digitalWrite(B[a], HIGH);
  digitalWrite(C[a], HIGH);
  digitalWrite(D[a], HIGH);
}
 
Odpowiedź
#2
Dodałeś na końcu ostatniego programu delay(1000). DCF wysyła przez minutę dane czasu, a odbiornik ma stale nasłuchiwać czy to właśnie teraz przylatuje, a nie zajrzeć tam co 1s na 63ns czy akurat w tym okienku czasowym przyleci jakaś informacja. Szansa na trafienie zmniejszyła się parę mln razy.



Masz przykład w pierwszym jak używać millis, jeśli w docelowym programie chcesz używać DCF to możesz zrobić pętlę w setup, która niestety zatrzyma uruchomienie właściwego programu na 2 minuty, albo na wieczność jak będzie problem z odczytem DCF, zaktualizuje czas i przejdzie do twojego loop z delay 1000, albo tak zrobić loop, by działał z millis.

Loop zresztą nie musi czytać wiecznie tego DCF, jak odczyta raz to można zmienić jakąś zmienną odczytUdany=1 i wstawić ją do if warunkującego uruchomienie tej części loop. Jak już to można zliczać sekundy i jeśli minie doba to znowu próbować odczytać na nowo DCF, może RTC się rozjeżdża i wymaga aktualizacji, ale jak w dobę zgubi sekundę to i tak jest kiepski.

Kod:
if(kolejny warunek z millis)
{
//tu wstawic aktualizacje z millis
  hour = time.bHour;
  minute = time.bMinute;
  zero = (hour / 10);
  one = hour % 10;
  two =  (minute / 10);
  three = minute % 10;
//Serial.println(zero);
// Serial.println(one);
// Serial.println(two);
// Serial.println(three);
  writenumber(0, zero);
  writenumber(1, one);
  writenumber(2, two);
  writenumber(3, three);
  delay(1000);
  }
Można też raz w loop odczytać stan millis do zmiennej uint32_t, potem 

wykorzystywać ją w różnych blokach programu by żyły swoim rytmem.

Kod:
uint32_t Poprzedni1,Poprzedni2,Poprzedni3,Poprzedni4,Interwal1,Interwal2,Interwal3,Interwal4;
void loop() {
  // put your main code here, to run repeatedly:
uint32_t licznikMillisTegoObieguLoop=millis();

if((uint32_t)(licznikMillisTegoObieguLoop-Poprzedni1))>Interwal1)
{
  Poprzedni1=licznikMillisTegoObieguLoop;
  //inne instrukcje wywolywane co Interval1
}

if((uint32_t)(licznikMillisTegoObieguLoop-Poprzedni2))>Interwal2)
{
  Poprzedni2=licznikMillisTegoObieguLoop;
  //inne instrukcje wywolywane co Interval2
}


if((uint32_t)(licznikMillisTegoObieguLoop-Poprzedni3))>Interwal3)
{
  Poprzedni3=licznikMillisTegoObieguLoop;
  //inne instrukcje wywolywane co Interval3
}



if((uint32_t)(licznikMillisTegoObieguLoop-Poprzedni4))>Interwal4)
{
  Poprzedni4=licznikMillisTegoObieguLoop;
  //inne instrukcje wywolywane co Interval4
}


}


dodanie rzutowania (uint32_t) pozwala by program działał z millis dłużej niż 54 dni.

Jak program się bardzo rozbuduje to problem może powrócić, niektóre funkcje mogą trwać z kilkanaście ms, ale jako zegar sam w sobie to pewnie nie będzie problemu. Wtedy można jakoś z tym powalczyć, zidentyfikować takie funkcje, jak można to je wrzucić w taki blok programu, który będzie pomijany przez te 2 minuty aktualizacji DCF.
 
Odpowiedź
#3
Oooo , dziękuję bardzo za naprowadzenie.

W sumie mogę synchronizację wywoływać tylko raz, podczas startu, i dopiero jak się uda odpalać resztę.

Puki co problemu z sygnałem DCF nie mam (mam dobry odbiornik).
Pewnie z czasem, jak się poduczę, to zamienię to na czas pobierany z NTP.

Jeszcze raz dziękuję i pozdrawiam.
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości