[054] Tajemniczy wyświetlacz 5082 cz. 2

[054] Tajemniczy wyświetlacz 5082 cz. 2

Skoro podłączyliśmy nasze wyświetlacze dokładnie wszystko sprawdzając, czas na napisanie programu. Zaczniemy od zaimportowania biblioteki zegarowej TimeLib, która już występowała w moich projektach. Zaraz potem deklarujemy wszystkie linie łączące się z wyświetlaczami. Nie ma w tym żadnego porządku, po prostu połączyłem wszystko tak, by plątanina przewodów była jak najmniejsza. Nie ma tutaj także żadnych ograniczeń, możemy korzystać z dowolnych portów, byle nie wejść w paradę z klawiaturą, która wykorzystuje porty 4, 7 i 8. Powołam do życia także zmienną X, której zwykle używam jako notatniczka. Wiem oczywiście, że lokalne zmienne powinny być lokalnymi, ale to jest tak mały projekt, że byłaby to sztuka dla sztuki.


#include <TimeLib.h>  // To jest biblioteka obsługi zegara.

const byte input1 = 10;  // Adresy portów połączonych z wejściami BCD wszystkich wyświetlaczy.
const byte input2 = 2;
const byte input4 = 11;
const byte input8 = 12;

const byte enable6 = A1;  // Adresy portów połączonych z wejściami ENABLE poszczególnych wyświetlaczy.
const byte enable5 = A2;
const byte enable4 = A5;
const byte enable3 = A4;
const byte enable2 = 9;
const byte enable1 = A3;

const byte pstryczekGodzina = 4;  // Adres pstryczka zmiany godzin.
const byte pstryczekMinuta = 8;   // Adres pstryczka zmiany minut.
const byte pstryczekSekunda = 7;  // Adres pstryczka zerowania sekund.

byte x;  // Zmienna pomocnicza.

void setup() {

  pinMode(input1, OUTPUT);  // Deklaruj porty współpracujące z wyświetlaczami.
  pinMode(input2, OUTPUT);
  pinMode(input4, OUTPUT);
  pinMode(input8, OUTPUT);

  pinMode(enable1, OUTPUT);
  pinMode(enable2, OUTPUT);
  pinMode(enable3, OUTPUT);
  pinMode(enable4, OUTPUT);
  pinMode(enable5, OUTPUT);
  pinMode(enable6, OUTPUT);

  pinMode(pstryczekGodzina, INPUT_PULLUP);  // Deklaruj porty pstryczków jako wejścia podciągnięte wewnętrznie do wysokiego stanu.
  pinMode(pstryczekMinuta, INPUT_PULLUP);
  pinMode(pstryczekSekunda, INPUT_PULLUP);

  setTime(23, 59, 57, 01, 01, 2000);  // Ustaw przykładowy czas.
}
void loop() {

  wyswietl();  // Wyświetl czas.

  if (digitalRead(pstryczekGodzina) == HIGH) {  // Jeśli wciśnięto pstryczek zmiany godzin, to...
    x = hour();                                 // Pobierz aktualną godzinę.
    x++;                                        // Zwiększ jej wartość.
    if (x &gt; 23) {                               // Jeśli przekroczono maksymalną legalną wartość, to...
      x = 0;                                    // Zeruj jej wartość.
    }
    setTime(x, minute(now()), second(now()), 01, 01, 2000);  // Ustaw nową wartość godzin.
    while (digitalRead(pstryczekGodzina) == HIGH) {}         // Czekaj, aż pstryczek pozostanie puszczony.
  }

  if (digitalRead(pstryczekMinuta) == HIGH) {  // Jeśli wciśnięto pstryczek zmiany minut, to...
    x = minute();                              // Pobierz aktualną minutę.
    x++;                                       // Zwiększ jej wartość.
    if (x &gt; 59) {                              // Jeśli przekroczono maksymalną legalną wartość, to...
      x = 0;                                   // Zeruj jej wartość.
    }
    setTime(hour(now()), x, second(now()), 01, 01, 2000);  // Ustaw nową wartość minut.
    while (digitalRead(pstryczekMinuta) == HIGH) {}        // Czekaj, aż pstryczek pozostanie puszczony.
  }

  if (digitalRead(pstryczekSekunda) == HIGH) {             // Jeśli wciśnięto pstryczek zerowania sekund, to...
    setTime(hour(now()), minute(now()), 0, 01, 01, 2000);  // Zeruj sekundy.
  }

  delay(100);  // Tutaj jest miejsce na resztę programu (np. budzik itp.)
}

void wyswietl() {  // Procedura wyświetlająca czas.

  x = second() % 10;            // Młodsza cyfra sekund (reszta z dzielenia przez 10).
  wyslijBCD();                  // Zaświeć segmenty według wzorców z tablicy.
  digitalWrite(enable6, LOW);   // Aktywuj czytanie danych przez wyświetlacz.
  digitalWrite(enable6, HIGH);  // Zatrzaśnij wysłaną wartość.

  x = second() / 10;  // Starsza cyfra sekund.
  wyslijBCD();
  digitalWrite(enable5, LOW);
  digitalWrite(enable5, HIGH);

  x = minute() % 10;  // Młodsza cyfra minut.
  wyslijBCD();
  digitalWrite(enable4, LOW);
  digitalWrite(enable4, HIGH);

  x = minute() / 10;  // Starsza cyfra minut.
  wyslijBCD();
  digitalWrite(enable3, LOW);
  digitalWrite(enable3, HIGH);

  x = hour() % 10;  // Młodsza cyfra godzin.
  wyslijBCD();
  digitalWrite(enable2, LOW);
  digitalWrite(enable2, HIGH);

  x = hour() / 10;  // Starsza cyfra godzin.
  if (x == 0) {     // Wyświetl spację, jeśli godzina &lt; 10
    x = 10;         // Pod adresem dziesiątym znajduje się spacja.
  }
  wyslijBCD();
  digitalWrite(enable1, LOW);
  digitalWrite(enable1, HIGH);
}

void wyslijBCD() {  // Zaświeć segmenty według wzorców z tablicy.

  digitalWrite(input1, LOW);  // Zeruj wszystkie wejścia BCD wyświetlaczy.
  digitalWrite(input2, LOW);
  digitalWrite(input4, LOW);
  digitalWrite(input8, LOW);

  switch (x) {  // Wysyłamy wartość zakodowaną w BCD na poszczególne wejścia wyświetlaczy.
    case 1:
      digitalWrite(input1, HIGH);
      break;
    case 2:
      digitalWrite(input2, HIGH);
      break;
    case 3:
      digitalWrite(input1, HIGH);
      digitalWrite(input2, HIGH);
      break;
    case 4:
      digitalWrite(input4, HIGH);
      break;
    case 5:
      digitalWrite(input4, HIGH);
      digitalWrite(input1, HIGH);
      break;
    case 6:
      digitalWrite(input4, HIGH);
      digitalWrite(input2, HIGH);
      break;
    case 7:
      digitalWrite(input4, HIGH);
      digitalWrite(input2, HIGH);
      digitalWrite(input1, HIGH);
      break;
    case 8:
      digitalWrite(input8, HIGH);
      break;
    case 9:
      digitalWrite(input8, HIGH);
      digitalWrite(input1, HIGH);
      break;
    case 10:
      digitalWrite(input8, HIGH);
      digitalWrite(input4, HIGH);
  }
}

W sekcji setup, jak zwykle należy zadeklarować który port czym jest.

setTime(23, 59, 57, 01, 01, 2000);  // Ustaw przykładowy czas.

Ta linia definiuje początkowe parametry zegara. Takie, wydawałoby się dziwne ustawienie czasu początkowego pozwoli nam po resecie zobaczyć efekciarskie przewinięcie cyferek, a nie same smutne zera, jak to bywa zwykle w zegarkach po ich włączeniu.

W głównej pętli mamy cztery procedury: wyświetlanie czasu, zwiększanie godzin, zwiększanie minut i zerowanie sekund. Wyświetlanie od razu prowadzi do procedury wyswietl(), więc tam się przenieśmy.

Cała procedura wyświetlania czasu będzie się odbywać od tyłu, czyli najpierw sekundy, dziesiątki sekund, minuty, dziesiątki minut, godziny i dziesiątki godzin – razem sześć bliźniaczych bloków. Biblioteka TimeLib zwraca nam godziny, minuty i sekundy, ale w postaci liczb naturalnych. My jednak potrzebujemy dwucyfrową liczbę zamienić na dwie cyfry. Trzeba użyć pewnego fortelu.

x = second() % 10;  // Młodsza cyfra sekund (reszta z dzielenia przez 10).

Pojedyncze sekundy uzyskamy dzięki funkcji reszty z dzielenia, oznaczonej znakiem procentów. Jeśli weźmiemy resztę z dzielenia sekund, na przykład 37 przez 10, otrzymamy 7 – i to jest interesująca nas pozycja pojedynczych sekund.

x = second() / 10;  // Starsza cyfra sekund.

Dziesiątki sekund uzyskać już łatwiej, należy wartość sekund podzielić przez 10. A że są to liczby naturalne, reszta przepadnie, ale nie jest nam już potrzebna. Identycznie będzie z minutami i godzinami.

Gdy już w X siedzi sobie sformatowana cyfra, należy ją wyświetlić na odpowiedniej pozycji. Będziemy się zatem odwoływać sześć razy do procedury przesyłania danych, sześć – bo mamy sześć cyfr. Zaczynamy od aktywacji konkretnego wyświetlacza, czyli otwarcia go na przyjmowanie danych. Zaczniemy od końca, czyli od sekund aż do dziesiątek godzin. Dane będziemy formować w procedurze wyslijBCD(), do której teraz się udamy.

void wyslijBCD() {  // Zaświeć segmenty według wzorców z tablicy.

  digitalWrite(input1, LOW);  // Zeruj wszystkie wejścia BCD wyświetlaczy.
  digitalWrite(input2, LOW);
  digitalWrite(input4, LOW);
  digitalWrite(input8, LOW);

  switch (x) {  // Wysyłamy wartość zakodowaną w BCD na poszczególne wejścia wyświetlaczy.
    case 1:
      digitalWrite(input1, HIGH);
      break;
    case 2:
      digitalWrite(input2, HIGH);
      break;
    case 3:
      digitalWrite(input1, HIGH);
      digitalWrite(input2, HIGH);
      break;
    case 4:
      digitalWrite(input4, HIGH);
      break;
    case 5:
      digitalWrite(input4, HIGH);
      digitalWrite(input1, HIGH);
      break;
    case 6:
      digitalWrite(input4, HIGH);
      digitalWrite(input2, HIGH);
      break;
    case 7:
      digitalWrite(input4, HIGH);
      digitalWrite(input2, HIGH);
      digitalWrite(input1, HIGH);
      break;
    case 8:
      digitalWrite(input8, HIGH);
      break;
    case 9:
      digitalWrite(input8, HIGH);
      digitalWrite(input1, HIGH);
      break;
    case 10:
      digitalWrite(input8, HIGH);
      digitalWrite(input4, HIGH);
  }
}

Jak już pokazywałem nieraz, wzorce możemy przechowywać w tablicach albo ładować bezpośrednio i to na wiele sposobów. Metoda z tablicami jest elegancka, ale niekoniecznie uzasadniona w każdym wypadku. Tutaj zaprezentuję metodę kombinowaną, czyli bezpośrednią, ale z dodaniem pewnego wstępnego warunku.

Spójrzmy na tablicę prawdy wyświetlacza, bo tak się to nazywa. Występuje tam 25 stanów niskich i 15 wysokich. Z tego wniosek, że bardziej będzie się opłacało ustawiać tylko stany wysokie tam, gdzie jest taka potrzeba, resetując na wstępnie wszystkie stany do poziomu niskiego. Policzmy sobie oszczędności: 15 instrukcji zamiast 40 – to jest zysk konkretny. Ale jeszcze trzeba na wstępie wyzerować wszystkie stany, więc musimy napisać 19 instrukcji – nadal zysk przekracza połowę.

Co tracimy? Czas. Oprócz wysłania czterech zer w każdym przypadku z wyjątkiem liczby zero dochodzi nam jedna, dwie bądź trzy instrukcje nadmiarowe, czyli odkręcanie tego, co na wstępie wyzerowaliśmy. Czy to ma sens? Zależy. Czasem potrzeba czasu, czasem bajtów. Moim celem nie jest tutaj wybór słusznej metody, tylko ukazanie, że mamy dwie.

if (x == 0) {  // Wyświetl spację, jeśli godzina &lt; 10
  x = 10;      // Pod adresem dziesiątym znajduje się spacja.
}

Na końcu serii wysyłek danych na wyświetlacz znajdziemy jeszcze fragment aktywujący dziesiąty stan. Co to takiego? Spacja. To jest kod wygaszonego wyświetlacza, a potrzebny on jest nam wtedy, gdy liczba godzin będzie niższa od dziesięciu. Zegar bez zera na początku wygląda po prostu lepiej.

Po wysłaniu danych wracamy do głównej pętli. Będziemy tam sprawdzać, czy aby nie przyciśnięto któregoś z przycisków: pstryczekGodzina zwiększa stan godzin, pstryczekMinuta – minut, a pstryczekSekunda zeruje sekundy.

if (digitalRead(pstryczekGodzina) == HIGH) {  // Jeśli wciśnięto pstryczek zmiany godzin, to...
  x = hour();                                 // Pobierz aktualną godzinę.
  x++;                                        // Zwiększ jej wartość.
  if (x &gt; 23) {                               // Jeśli przekroczono maksymalną legalną wartość, to...
    x = 0;                                    // Zeruj jej wartość.
  }
  setTime(x, minute(now()), second(now()), 01, 01, 2000);  // Ustaw nową wartość godzin.
  while (digitalRead(pstryczekGodzina) == HIGH) {}         // Czekaj, aż pstryczek pozostanie puszczony.
}

W przypadku godzin i minut procedury są bliźniacze. Jeśli wciśnięto przycisk, do aktualnej godziny dodaje się kolejną i sprawdza, czy aby wynik nie przekracza 23. Jeśli tak – godziny są zerowane. Następnie zmienna zostaje wprowadzona do biblioteki zegarowej. A ponieważ należy tutaj także określić dzień, miesiąc i rok, a te rzeczy nie biorą udziału w naszej zabawie, możemy wprowadzić cokolwiek.

Procedura regulacji minut różni się tylko warunkiem – zamiast 23, sprawdzamy czy nie przekroczono 59. Natomiast wciśnięcie przycisku zerującego sekundy natychmiastowo zeruje ten parametr biblioteki i nie robi nic nadto.

Na końcu wprowadziłem funkcję delay, ale z komentarzem. To nie jest tak, że nie mam pomysłu na to, co tu wstawić i wrzucam tę nielubioną instrukcję. Po prostu nie ma sensu odświeżać wyświetlacza z pełną mocą Arduino, jeśli cyfry zmieniają się i tak raz na sekundę. Oszczędza to energię, redukuje zakłócenia elektromagnetyczne i nijak nie wpływa na efekty końcowe. Miejsce to powinno się wypełnić dodatkowymi funkcjami zegara: budzikiem, termometrem i tak dalej. Ale to już pozostawiam zainteresowanym.

I to już wszystko. Cyferki wyglądają ślicznie, choć zegarek zjadający od trzech do pięciu watów, w zależności od godziny, to dziś rozpusta. Pragnę jeszcze zwrócić uwagę na jedno: oba środowiska dzieli pół wieku, a jednak bez problemów współpracują ze sobą. Bo współczesna elektronika, z pewnymi uproszczeniami, ma już ponad 50 lat.

Płytka edukacyjna TME-EDU-ARD-2Płytka edukacyjna TME-EDU-ARD-2Sprawdź tutaj

Przeczytaj również

Nasi partnerzy

TMETech Master EventTME EducationPoweredby
Copyright © 2024 arduino.pl