Arduino Polska Forum

Pełna wersja: Synchronizowanie przekaźnika z wyświetlaczem LCD i modułem RTC
Aktualnie przeglądasz uproszczoną wersję forum. Kliknij tutaj, by zobaczyć wersję z pełnym formatowaniem.
Dzień dobry,

Niedawno zbudowałam swój pierwszy projekt z Arduino UNO, jakim jest zegar z intencjonalnym glitchem. Dołączyłam do niego przekaźnik w celu wydawania dźwięku klikania. Chciałabym go zsynchronizować z zegarem w taki sposób, żeby klikał razem z sekundami, poza na sekundy z końcówką 9, czyli np. gdy jest godzina 22:36:29. Wtedy miałby być cicho. 
Schemat projektu:
[attachment=1189]

Oraz kod:

Kod:
#include "virtuabotixRTC.h"//Library used
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);
virtuabotixRTC myRTC(2, 3, 4); //The order here is DAT,CLK,RST. You can change this depending on the wiring

char timeChar [8]; //number of digits for the format
uint8_t prevSeconds = 0; //

void setup()
{
 
  Serial.begin(9600);
 
  lcd.init();
  lcd.backlight();


 
  // Set the current date, and time in the following format:
  // seconds, minutes, hours, day of the week, day of the month, month, year
  //myRTC.setDS1302Time(30, 21, 00, 5, 07, 01, 2021); //Here you write your actual time/date as shown above
  //but remember to "comment/remove" this function once you're done
  //The setup is done only one time and the module will continue counting it automatically
}
void loop()
{

 
  myRTC.updateTime();
 
  if(myRTC.seconds != prevSeconds)  // Only update display if seconds have changed
  {
    prevSeconds = myRTC.seconds;
   
    // Start printing elements as individuals
   
    if(myRTC.seconds %10)
    {
      sprintf(timeChar, "%02d:%02d:%02d",myRTC.hours, myRTC.minutes, myRTC.seconds);
      if(myRTC.seconds == 9 || myRTC.seconds == 19 || myRTC.seconds == 29 || myRTC.seconds == 39 || myRTC.seconds == 49 || myRTC.seconds == 59)
      {
        // timeChar[0] = 'Z';
        // timeChar[4] = 'X';
        timeChar[0] = random("32, 128");
        timeChar[4] = random("32, 128");
      }
    }
    else
    {
      sprintf(timeChar, "D0:0M:%02d", myRTC.seconds);
    }
   
    lcd.print(timeChar);
  }
}
Na próbę wpisałam niezależnie od sekund:
Kod:
#include "virtuabotixRTC.h"//Library used
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);
virtuabotixRTC myRTC(2, 3, 4); //The order here is DAT,CLK,RST. You can change this depending on the wiring

char timeChar [8]; //number of digits for the format
uint8_t prevSeconds = 0; //

int Relaypin= 12;

void setup()
{
 
  Serial.begin(9600);
 
  lcd.init();
  lcd.backlight();


 
  // Set the current date, and time in the following format:
  // seconds, minutes, hours, day of the week, day of the month, month, year
  //myRTC.setDS1302Time(30, 21, 00, 5, 07, 01, 2021); //Here you write your actual time/date as shown above
  //but remember to "comment/remove" this function once you're done
  //The setup is done only one time and the module will continue counting it automatically
  pinMode(Relaypin, OUTPUT); // Define the Relaypin as output pin

}
void loop()
{
digitalWrite(Relaypin, HIGH); // Sends high signal
delay(1000); // Waits for 1 second
digitalWrite(Relaypin, LOW); // Makes the signal low
delay(1000); // Waits for 1 second

 
  myRTC.updateTime();
 
  if(myRTC.seconds != prevSeconds)  // Only update display if seconds have changed
  {
    prevSeconds = myRTC.seconds;
   
    // Start printing elements as individuals
   
    if(myRTC.seconds %10)
    {
      sprintf(timeChar, "%02d:%02d:%02d",myRTC.hours, myRTC.minutes, myRTC.seconds);
      if(myRTC.seconds == 9 || myRTC.seconds == 19 || myRTC.seconds == 29 || myRTC.seconds == 39 || myRTC.seconds == 49 || myRTC.seconds == 59)
      {
        // timeChar[0] = 'Z';
        // timeChar[4] = 'X';
        timeChar[0] = random("32, 128");
        timeChar[4] = random("32, 128");
      }
    }
    else
    {
      sprintf(timeChar, "D0:0M:%02d", myRTC.seconds);
    }
   
    lcd.print(timeChar);
  }
}

Jednak to wchodzi w interakcję z pracą zegara, tworzy dziwaczny błąd. Zgaduję, że rozwiązanie byłoby z funkcją 
prevSeconds = myRTC.seconds
jako nowicjuszka niestety nie mam pojęcia jak ją zaadaptować do kodu. Byłabym niezmiernie wdzięczna za pomoc.
Zanim podłączysz przekaźnik użyj LED lub buzera, może jakiś głośnik i generator dźwięku zastąpi przekaźnik w ogóle. A jeśli program zadziała, lecz tylko z przekaźnikiem będą problemy wyszukaj w Google "gasik przekaźnika", RC, był niedawno taki temat na innym forum, są opisy na blogach.
Nie jestem przekonany, że dobrze używasz tego zegara, może sam zegar jest po prostu do bani. Czytanie czasu w każdym obiegu loop sprawi, że 99% czasu działania tego programu pochłonie sprawdzanie jaka jest godzina, czy minęła już sekunda. A i tak będzie to mocno przybliżone, bo przecież jest opóźnienie, zegar musi przekazać dość dużo danych, zanim trafi w tę konkretną chwilę może być zajęty czymś innym. Robię tak z millis(), ale uC nie gada wtedy z urządzeniem zewnętrznym, nie muszę mu wysłać polecenia, odebrać wiadomości, przeanalizować w funkcjach i użyć wyników, cała funkcja czas() z millis() trwa kilka us.
Albo zrobiłbym to używając millis(), przykłady zobaczysz w ostatnich moich postach, czas z RTC synchronizował okresowo, może co minutę. Albo wziąłbym zegar RTC z wyjściem sygnału prostokątnego 1Hz, jak zegar odliczy nową sekundę to zmienia stan pinu, podłączasz to pod przerwanie zewnętrzne i informacja jest przekazana do Arduino w czasie nanosekund.
Jak nie chcesz używać millis, bo tu dokładność też będzie zależeć co jeszcze się pojawi w kodzie, można użyć dwóch wolnych timerów z UNO i ich przerwań.
[attachment=1190]
Nie wszystkie RTC mają wyprowadzone ten sygnał, a Twój nie ma go raczej wcale.
Używasz modulo, ta sekcja
Kod:
    if(myRTC.seconds %10)
    {
      sprintf(time ....
nie wykona się tylko dla liczby sekund podzielnej przez 10 bez reszty. Nie wiem czy o to Ci chodziło. 
Można przeprowadzić takie działanie i porównanie, że jeśli reszta z dzielenia przez 10 jest równa 9 to zrób cośtam (lub tylko wtedy nie rób), może tego bardziej szukasz?