[112] Budujemy ze zrozumieniem - elektroniczny budzik cz. 6

[112] Budujemy ze zrozumieniem - elektroniczny budzik cz. 6

Czas omówić dość już skomplikowany szkic, który gościł w poprzednim artykule, wstępnie tylko przedstawiony. A więc...


const byte segmentA = 5;  // Adresy portów kolejnych segmentów: od A do G
const byte segmentB = 6;
const byte segmentC = 9;
const byte segmentD = 10;
const byte segmentE = 11;
const byte segmentF = 12;
const byte segmentG = 13;
const byte wspolne1 = A0;  // Adresy portów wspólnych wyprowadzeń kolejnych wyświetlaczy.
const byte wspolne2 = A1;
const byte wspolne3 = A2;
const byte wspolne4 = A3;
const byte dwukropek = 3;  // Adres diody dwukropka.
const byte alarm = 8;      // Adres diody alarmu.
const byte buzzer = 2;     // Adres buzzera.
const byte plus = 7;       // Adresy portów klawiatury.
const byte minus = 4;

const byte opoznienieDlugie = 100;  // Współczynniki autorepetycji klawiatury.
const byte opoznienieKrotkie = 5;
const byte opoznienieKrotkieAlarm = 50;
const byte opoznienieDlugieAlarm = 250;
const byte czasAutoKonca = 3;  // Czas w sekundach opuszczania trybu edycji

const byte tablica[17] = {
  B1000000,  // 0, Tablica zawierająca wzorce znaków wyświetlacza siedmiosegmentowego.
  B1111001,  // 1, Schemat: G-F-E-D-C-B-A
  B0100100,  // 2
  B0110000,  // 3
  B0011001,  // 4
  B0010010,  // 5
  B0000010,  // 6
  B1111000,  // 7
  B0000000,  // 8
  B0010000,  // 9
  B1111111,  // spacja
  B0111111,  // minus
  B0001000,  // A
  B1000111,  // L
  B0100011,  // o
  B0101011,  // n
  B1001000   // N
};

int licznikPrzerwan = 0;  // Licznik ramek odmierzających 2,5 ms
byte aktywnaCyfra = 1;    // Numer aktywnej cyfry na wyświetlaczu dla multipleksera.
byte sekundy = 0;         // Licznik sekund.
byte minuty = 0;          // Licznik minut.
byte godziny = 0;         // Licznik godzin.
byte minutyAlarmu = 0;    // Licznik minut alarmu.
byte godzinyAlarmu = 6;   // Licznik godzin alarmu.
byte cyfra1 = 11;         // Bufor kolejnych pozycji wyświetlacza.
byte cyfra2 = 11;
byte cyfra3 = 11;
byte cyfra4 = 11;
byte autoKoniec = czasAutoKonca;     // Licznik w sekundach do automatycznego opuszczania procedur ustawiania czasu i alarmu.
bool trybEdycji = LOW;               // Flaga aktywności edycji czasu lub alarmu.
bool przelacznikTrybuAlarmu = HIGH;  // Flaga przełączania edycji alarmu między jego włączeniem z regulacją i wyłączeniem.
bool wlaczAlarm = LOW;               // Flaga trwania alarmu.

W deklaracjach przybyło teraz zarówno zmiennych, w szczególności flag, czyli bitów, które pośredniczą między przerwaniami, a pętlą główną (albo też poszczególnymi fragmentami programów), zezwalając na przykład na emitowanie pisków alarmu. Rozbudowałem także tablicę o kilka literek do wyświetlania wspomnianych komunikatów.

while (digitalRead(minus) == LOW) {  // Po resecie pikaj w pętli nieskończonej, aż zostanie wciśnięty przycisk minus.
  zapikajPoczwornie();
  delay(500);
}

Zanim wejdziemy w główną pętlę, trzeba przejść przez nieskończoną pętlę pikania, kiedy to na wyświetlaczu będą tkwić kreski. One pojawią się dlatego, że na wstępie, w deklaracjach bufora cyfr umieściłem adres jedenastej pozycji tablicy – a tam właśnie siedzą owe kreski. Jedyną możliwością opuszczenia pętli jest wciśnięcie przycisku minus.

Główna pętla składa się z bloków edycji czasu, alarmu, deaktywacji alarmu i obsługi budzenia.

if (digitalRead(minus) == HIGH) {    // Jeśli wciśnięto przycisk minus...
  delay(2000);                       // Zaczekaj dwie sekundy.
  if (digitalRead(minus) == HIGH) {  // Jeśli wciąż przycisk będzie wciśnięty...

W pierwszym bloku mamy ową opóźnioną detekcję wciśnięcia przycisku minus: wymaga się, by był trzymany przez dwie sekundy. Jeśli po tym czasie nadal będzie wciśnięty, przystąpimy do regulacji czasu.

trybEdycji = HIGH;  // Ustaw flagę trybu edycji.

Zacząć trzeba będzie od ustawienia tak zwanej flagi edycji. Dzięki temu przerwania nie będą nam ładować na wyświetlacz zegarka ani sterować dwukropkiem.

digitalWrite(dwukropek, HIGH);  // Włącz dwukropek.
digitalWrite(buzzer, HIGH);     // Zapikaj pojedynczo.
delay(opoznienieDlugieAlarm);
digitalWrite(buzzer, LOW);
zerujSekundy();  // Zeruj licznik sekund i ramek.
autoKoniec = 0;  // Zeruj licznik sekund do automatycznego opuszczania procedury ustawiania czasu.

Następnie włączymy na stałe dwukropek, zapikamy, wyzerujemy licznik sekund i ramek – gdyby akurat edycja czasu miała miejsce w ostatnich sekundach minuty, co by nam dodało jedną bez wciskania klawiaturki i zerujemy nową, istotną zmienną o nazwie autoKoniec. Jest ona zwiększana w przerwaniach co sekundę i wykorzystujemy ją do zakończenia regulacji zarówno czasu jak i alarmu. W jaki sposób?

while (autoKoniec < czasAutoKonca) {  // Automatycznie opuść procedurę po trzech sekundach bezczynności.

Znany już proces zwiększania bądź zmniejszania czasu odbywa się w nieskończonej pętli i trwa dopóki autoKoniec nie osiągnie trzech sekund (użyłem stałej, żeby każdy mógł sobie dobrać ten czas do własnych upodobań).

void regulujCzasPlus() {
  autoKoniec = 0;  // Zeruj licznik sekund do automatycznego opuszczania procedury ustawiania czasu.
}
void regulujCzasMinus() {
  autoKoniec = 0;
}

Ale każdorazowe wciśnięcie klawiatury – już w podprogramach regulujCzas – zeruje tę wartość. Dopiero jeśli nie udamy się tam przez trzy sekundy, warunek pętli ustawiania czasu nie spełni się i opuścimy ją.

digitalWrite(buzzer, HIGH);  // Zapikaj pojedynczo.
delay(opoznienieDlugieAlarm);
digitalWrite(buzzer, LOW);
zerujSekundy();    // Zeruj licznik sekund i ramek.
trybEdycji = LOW;  // Zeruj flagę trybu edycji.

Na końcu pikamy, znowu zerujemy sekundy, ramki i opuszczamy ten blok. Regulacja alarmu jest podobna, z tym że nie ma tu opóźnień na samym początku.

if (digitalRead(plus) == HIGH && przelacznikTrybuAlarmu == HIGH) {  // Jeśli wciśnięto przycisk plus i można edytować alarm...

Jest za to coś innego – flaga przełącznika trybu alarmu przelacznikTrybuAlarmu.

przelacznikTrybuAlarmu = LOW;            // Przestaw przełącznik.
trybEdycji = HIGH;                       // Ustaw flagę trybu edycji.
digitalWrite(dwukropek, HIGH);           // Włącz dwukropek.
digitalWrite(alarm, HIGH);               // Włącz diodę alarmu.
zapikajPodwojnie();                      // Zapikaj dwukrotnie.
ladujAlarm();                            // Ładuj czas alarmu do buforów wyświetlacza.
autoKoniec = 0;                          // Zeruj licznik sekund do automatycznego opuszczania procedury ustawiania alarmu.
while (autoKoniec < czasAutoKonca) {     // Automatycznie opuść procedurę po trzech sekundach bezczynności.
  if (digitalRead(plus) == HIGH) {       // Obsługa pstryczka plus w trybie alarmu. Jeśli go wciśnięto...
    zwiekszAlarm();                      // Zwiększ czas alarmu.
    delay(opoznienieDlugie);             // Opóźnienie przed autorepetycją.
    while (digitalRead(plus) == HIGH) {  // Dopóki przycisk plus jest trzymany...
      zwiekszAlarm();                    // Zwiększaj czas alarmu.
      delay(opoznienieKrotkie);          // Opóźnienie autorepetycji.
    }
    delay(opoznienieDlugie);  // Opóźnienie przed wyjściem z procedury.
  }
  if (digitalRead(minus) == HIGH) {  // Obsługa pstryczka minus w trybie alarmu.
    zmniejszAlarm();
    delay(opoznienieDlugie);
    while (digitalRead(minus) == HIGH) {
      zmniejszAlarm();
      delay(opoznienieKrotkie);
    }
    delay(opoznienieDlugie);
  }
}
cyfra1 = 12;  // Załaduj komunikat "AL On"
cyfra2 = 13;
cyfra3 = 0;
cyfra4 = 15;
zapikajPodwojnie();  // Zapikaj dwukrotnie.
delay(1000);         // Zaczekaj sekundę.
ladujCzas();         // Ładuj do bufora wyświetlacza zawartość zegara.
trybEdycji = LOW;    // Zeruj flagę trybu edycji.

Jeśli jest ustawiona, przycisk plus włączy budzenie i pozwoli zmienić jego czas.

if (digitalRead(plus) == HIGH && przelacznikTrybuAlarmu == LOW) {  // Jeśli wciśnięto przycisk plus i nie można edytować alarmu...
  przelacznikTrybuAlarmu = HIGH;                                   // Przestaw przełącznik.
  trybEdycji = HIGH;                                               // Ustaw flagę trybu edycji.
  digitalWrite(dwukropek, HIGH);                                   // Włącz dwukropek.
  digitalWrite(alarm, LOW);                                        // Wyłącz diodę alarmu.
  cyfra1 = 16;                                                     // Załaduj komunikat "No AL"
  cyfra2 = 14;
  cyfra3 = 12;
  cyfra4 = 13;
  digitalWrite(buzzer, HIGH);  // Zapikaj pojedynczo.
  delay(opoznienieKrotkieAlarm);
  digitalWrite(buzzer, LOW);
  delay(1000);                                                        // Zaczekaj sekundę.
  ladujCzas();                                                        // Ładuj do bufora wyświetlacza zawartość zegara.
  while (digitalRead(minus) == HIGH || digitalRead(plus) == HIGH) {}  // Czekaj na puszczenie przycisków.
  trybEdycji = LOW;                                                   // Zeruj flagę trybu edycji.
}

Jeśli będzie wyzerowana – przycisk ten wyłączy funkcję budzenia bez jakichkolwiek regulacji. To jest właśnie ów patent z podwójną funkcjonalnością przycisku plus i mówię na to efekt długopisu – bo działa jak pstryczek w długopisie, raz wysuwający wkład, a raz chowający go. Oczywiście na końcu każdej z procedur należy tę flagę odwrócić.

Dodatkowym elementem obu procedur jest wyświetlenie komunikatu przez sekundę: Al On lub No AL – na samym końcu, już przy wyjściu z nich. Jak widać, procedura wyłączenia budzika pozbawiona jest wszystkich elementów związanych z nastawianiem czasu, bo nic się tu nie nastawia.

while (wlaczAlarm == HIGH) {        // Jeśli nadeszła pora alarmu...
  zapikajPoczwornie();              // Zapikaj poczwórnie.
  delay(500);                       // Zaczekaj pół sekundy.
  if (digitalRead(plus) == HIGH) {  // Powtarzaj dopóki nie zostanie wciśnięty przycisk kasowania alarmu.
    wlaczAlarm = LOW;               // Zeruj flagę alarmu.
  }
}

W końcu obsługa alarmu, to znaczy budzenia, włącza się z chwilą, gdy przerwania wystawią flagę zrównania czasu zegara z czasem alarmu wlaczAlarm, o ile tylko flaga aktywności alarmu alarm, czyli dioda świecąca zezwala na to. Tutaj pozostaniemy do chwili dłuższego wciśnięcia przycisku plus. Gdy się to stanie, trzeba będzie jeszcze pamiętać o wyzerowaniu flagi, bo przerwania o to nie dbają.

void przerwanie() {                                                  // Tutaj lądujemy za każdym razem, gdy wewnętrzny timer odliczy 2500 mikrosekund.
  licznikPrzerwan++;                                                 // Zwiększ licznik ramek odmierzających 2,5 ms
  if (licznikPrzerwan == 400) {                                      // Jeśli osiągnął 400 (2,5 ms * 400 = 1 sekunda)...
    licznikPrzerwan = 0;                                             // Zeruj go oraz...
    digitalWrite(dwukropek, !digitalRead(dwukropek) || trybEdycji);  // Zmień stan dwukropka, albo go ustaw, jeśli jesteś w trybie edycji.
    sekundy++;                                                       // Zwiększaj liczbę sekund.
    autoKoniec++;                                                    // Zwiększ licznik do automatycznego opuszczania procedur ustawiania czasu i alarmu.
    if (sekundy == 60) {                                             // Jeśli osiągnął 60...
      sekundy = 0;                                                   // Zeruj go oraz...
      zwiekszCzas();                                                 // Zwiększ czas.
      if (trybEdycji == LOW) {                                       // Gdy akurat nie ustawiamy czasu lub alarmu...
        ladujCzas();                                                 // Ładuj czas do buforów wyświetlacza.
      }
      if (minutyAlarmu == minuty && godzinyAlarmu == godziny && digitalRead(alarm) == HIGH) {  // Gdy czas na alarm...
        wlaczAlarm = HIGH;                                                                     // Ustaw flagę alarmu.
      }
    }
  }

Same przerwania pracują podobnie jak poprzednio, z tym że dopisałem tu pułapki na aktywność trybu edycji. Wówczas nie będzie działać dwukropek ani nie będzie się pojawiał zegar.

O procedurach edycji wartości pisałem w poprzednich częściach serii – skróciły się znacznie, bo bazują na bajtach zawierających pełne wartości minut i godzin. Skomplikowało to jednak procedury wyciągania kształtów znaków z tablicy grafik. Pozostałe podprogramy są po prostu elementami występującymi więcej niż raz w różnych miejscach szkicu. Obniża to nieco czytelność – wszak trzeba skakać po całym programie, odnajdując elementy układanki, ale oszczędza bajtów.

Budzik pracuje idealnie i właściwie można go używać już bez żadnych zmian. Ale to nie koniec, acz o tym napiszę w kolejnym, ostatnim już artykule serii. Na koniec wrzucam kompletny szkic budzika na obecnym etapie.

#include <TimerOne.h>  // Biblioteka obsługi przerwań.

const byte segmentA = 5;  // Adresy portów kolejnych segmentów: od A do G
const byte segmentB = 6;
const byte segmentC = 9;
const byte segmentD = 10;
const byte segmentE = 11;
const byte segmentF = 12;
const byte segmentG = 13;
const byte wspolne1 = A0;  // Adresy portów wspólnych wyprowadzeń kolejnych wyświetlaczy.
const byte wspolne2 = A1;
const byte wspolne3 = A2;
const byte wspolne4 = A3;
const byte dwukropek = 3;  // Adres diody dwukropka.
const byte alarm = 8;      // Adres diody alarmu.
const byte buzzer = 2;     // Adres buzzera.
const byte plus = 7;       // Adresy portów klawiatury.
const byte minus = 4;

const byte opoznienieDlugie = 100;  // Współczynniki autorepetycji klawiatury.
const byte opoznienieKrotkie = 5;
const byte opoznienieKrotkieAlarm = 50;
const byte opoznienieDlugieAlarm = 250;
const byte czasAutoKonca = 3;  // Czas w sekundach opuszczania trybu edycji

const byte tablica[17] = {
  B1000000,  // 0, Tablica zawierająca wzorce znaków wyświetlacza siedmiosegmentowego.
  B1111001,  // 1, Schemat: G-F-E-D-C-B-A
  B0100100,  // 2
  B0110000,  // 3
  B0011001,  // 4
  B0010010,  // 5
  B0000010,  // 6
  B1111000,  // 7
  B0000000,  // 8
  B0010000,  // 9
  B1111111,  // spacja
  B0111111,  // minus
  B0001000,  // A
  B1000111,  // L
  B0100011,  // o
  B0101011,  // n
  B1001000   // N
};

int licznikPrzerwan = 0;  // Lcznik ramek odmierzających 2,5 ms
byte aktywnaCyfra = 1;    // Numer aktywnej cyfry na wyświetlaczu dla multipleksera.
byte sekundy = 0;         // Licznik sekund.
byte minuty = 0;          // Licznik minut.
byte godziny = 0;         // Licznik godzin.
byte minutyAlarmu = 0;    // Licznik minut alarmu.
byte godzinyAlarmu = 6;   // Licznik godzin alarmu.
byte cyfra1 = 11;         // Bufor kolejnych pozycji wyświetlacza.
byte cyfra2 = 11;
byte cyfra3 = 11;
byte cyfra4 = 11;
byte autoKoniec = czasAutoKonca;     // Licznik w sekundach do automatycznego opuszczania procedur ustawiania czasu i alarmu.
bool trybEdycji = LOW;               // Flaga aktywności edycji czasu lub alarmu.
bool przelacznikTrybuAlarmu = HIGH;  // Flaga przełączania edycji alarmu między jego włączeniem z regulacją i wyłączeniem.
bool wlaczAlarm = LOW;               // Flaga trwania alarmu.

void setup() {
  pinMode(segmentA, OUTPUT);
  pinMode(segmentB, OUTPUT);
  pinMode(segmentC, OUTPUT);
  pinMode(segmentD, OUTPUT);
  pinMode(segmentE, OUTPUT);
  pinMode(segmentF, OUTPUT);
  pinMode(segmentG, OUTPUT);
  pinMode(wspolne1, OUTPUT);
  pinMode(wspolne2, OUTPUT);
  pinMode(wspolne3, OUTPUT);
  pinMode(wspolne4, OUTPUT);
  pinMode(dwukropek, OUTPUT);
  pinMode(alarm, OUTPUT);
  pinMode(buzzer, OUTPUT);
  pinMode(plus, INPUT_PULLUP);
  pinMode(minus, INPUT_PULLUP);

  digitalWrite(dwukropek, HIGH);       // Włącz dwukropek.
  Timer1.initialize(2500);             // Ustaw licznik na 2500 mikrosekund.
  Timer1.attachInterrupt(przerwanie);  // Włącz przerwanie z określeniem miejsca lądowania.

  while (digitalRead(minus) == LOW) {  // Po resecie pikaj w pętli nieskończonej, aż zostanie wciśnięty przycisk minus.
    zapikajPoczwornie();
    delay(500);
  }
  ladujCzas();  // Wyświetl czas zamiast kresek.
}
void loop() {
  // Edycja czasu =============================================================================================================================================
  if (digitalRead(minus) == HIGH) {    // Jeśli wciśnięto przycisk minus...
    delay(2000);                       // Zaczekaj dwie sekundy.
    if (digitalRead(minus) == HIGH) {  // Jeśli wciąż przycisk będzie wciśnięty...
      trybEdycji = HIGH;               // Ustaw flagę trybu edycji.
      digitalWrite(dwukropek, HIGH);   // Włącz dwukropek.
      digitalWrite(buzzer, HIGH);      // Zapikaj pojedynczo.
      delay(opoznienieDlugieAlarm);
      digitalWrite(buzzer, LOW);
      zerujSekundy();                          // Zeruj licznik sekund i ramek.
      autoKoniec = 0;                          // Zeruj licznik sekund do automatycznego opuszczania procedury ustawiania czasu.
      while (autoKoniec < czasAutoKonca) {     // Automatycznie opuść procedurę po trzech sekundach bezczynności.
        if (digitalRead(plus) == HIGH) {       // Obsługa pstryczka plus w trybie ustawiania czasu. Jeśli go wciśnięto...
          regulujCzasPlus();                   // Zeruj licznik sekund do automatycznego opuszczania procedury ustawiania czasu, zwiększ czas i wyświetl go.
          delay(opoznienieDlugie);             // Opóźnienie przed autorepetycją.
          while (digitalRead(plus) == HIGH) {  // Dopóki przycisk plus jest trzymany...
            regulujCzasPlus();                 // Zeruj licznik sekund do automatycznego opuszczania procedury ustawiania czasu, zwiększ czas i wyświetl go.
            delay(opoznienieKrotkie);          // Opóźnienie autorepetycji.
          }
          delay(opoznienieDlugie);  // Opóźnienie przed wyjściem z procedury.
        }
        if (digitalRead(minus) == HIGH) {  // Obsługa pstryczka minus w trybie ustawiania czasu.
          regulujCzasMinus();
          delay(opoznienieDlugie);
          while (digitalRead(minus) == HIGH) {
            regulujCzasMinus();
            delay(opoznienieKrotkie);
          }
          delay(opoznienieDlugie);
        }
      }
      digitalWrite(buzzer, HIGH);  // Zapikaj pojedynczo.
      delay(opoznienieDlugieAlarm);
      digitalWrite(buzzer, LOW);
      zerujSekundy();    // Zeruj licznik sekund i ramek.
      trybEdycji = LOW;  // Zeruj flagę trybu edycji.
    }
  }
  // Edycja alarmu - włączanie i ustawianie ===================================================================================================================
  if (digitalRead(plus) == HIGH && przelacznikTrybuAlarmu == HIGH) {  // Jeśli wciśnięto przycisk plus i można edytować alarm...
    przelacznikTrybuAlarmu = LOW;                                     // Przestaw przełącznik.
    trybEdycji = HIGH;                                                // Ustaw flagę trybu edycji.
    digitalWrite(dwukropek, HIGH);                                    // Włącz dwukropek.
    digitalWrite(alarm, HIGH);                                        // Włącz diodę alarmu.
    zapikajPodwojnie();                                               // Zapikaj dwukrotnie.
    ladujAlarm();                                                     // Ładuj czas alarmu do buforów wyświetlacza.
    autoKoniec = 0;                                                   // Zeruj licznik sekund do automatycznego opuszczania procedury ustawiania alarmu.
    while (autoKoniec &lt; czasAutoKonca) {                              // Automatycznie opuść procedurę po trzech sekundach bezczynności.
      if (digitalRead(plus) == HIGH) {                                // Obsługa pstryczka plus w trybie alarmu. Jeśli go wciśnięto...
        zwiekszAlarm();                                               // Zwiększ czas alarmu.
        delay(opoznienieDlugie);                                      // Opóźnienie przed autorepetycją.
        while (digitalRead(plus) == HIGH) {                           // Dopóki przycisk plus jest trzymany...
          zwiekszAlarm();                                             // Zwiększaj czas alarmu.
          delay(opoznienieKrotkie);                                   // Opóźnienie autorepetycji.
        }
        delay(opoznienieDlugie);  // Opóźnienie przed wyjściem z procedury.
      }
      if (digitalRead(minus) == HIGH) {  // Obsługa pstryczka minus w trybie alarmu.
        zmniejszAlarm();
        delay(opoznienieDlugie);
        while (digitalRead(minus) == HIGH) {
          zmniejszAlarm();
          delay(opoznienieKrotkie);
        }
        delay(opoznienieDlugie);
      }
    }
    cyfra1 = 12;  // Załaduj komunikat "AL On"
    cyfra2 = 13;
    cyfra3 = 0;
    cyfra4 = 15;
    zapikajPodwojnie();  // Zapikaj dwukrotnie.
    delay(1000);         // Zaczekaj sekundę.
    ladujCzas();         // Ładuj do bufora wyświetlacza zawartość zegara.
    trybEdycji = LOW;    // Zeruj flagę trybu edycji.
  }
  // Edycja alarmu - wyłączanie ===============================================================================================================================
  if (digitalRead(plus) == HIGH && przelacznikTrybuAlarmu == LOW) {  // Jeśli wciśnięto przycisk plus i nie można edytować alarmu...
    przelacznikTrybuAlarmu = HIGH;                                   // Przestaw przełącznik.
    trybEdycji = HIGH;                                               // Ustaw flagę trybu edycji.
    digitalWrite(dwukropek, HIGH);                                   // Włącz dwukropek.
    digitalWrite(alarm, LOW);                                        // Wyłącz diodę alarmu.
    cyfra1 = 16;                                                     // Załaduj komunikat "No AL"
    cyfra2 = 14;
    cyfra3 = 12;
    cyfra4 = 13;
    digitalWrite(buzzer, HIGH);  // Zapikaj pojedynczo.
    delay(opoznienieKrotkieAlarm);
    digitalWrite(buzzer, LOW);
    delay(1000);                                                        // Zaczekaj sekundę.
    ladujCzas();                                                        // Ładuj do bufora wyświetlacza zawartość zegara.
    while (digitalRead(minus) == HIGH || digitalRead(plus) == HIGH) {}  // Czekaj na puszczenie przycisków.
    trybEdycji = LOW;                                                   // Zeruj flagę trybu edycji.
  }
  // Obsługa alarmu ===========================================================================================================================================
  while (wlaczAlarm == HIGH) {        // Jeśli nadeszła pora alarmu...
    zapikajPoczwornie();              // Zapikaj poczwórnie.
    delay(500);                       // Zaczekaj pół sekundy.
    if (digitalRead(plus) == HIGH) {  // Powtarzaj dopóki nie zostanie wciśnięty przycisk kasowania alarmu.
      wlaczAlarm = LOW;               // Zeruj flagę alarmu.
    }
  }
}
// Obsługa przerwań ===========================================================================================================================================
void przerwanie() {                                                  // Tutaj lądujemy za każdym razem, gdy wewnętrzny timer odliczy 2500 mikrosekund.
  licznikPrzerwan++;                                                 // Zwiększ licznik ramek odmierzających 2,5 ms
  if (licznikPrzerwan == 400) {                                      // Jeśli osiągnął 400 (2,5 ms * 400 = 1 sekunda)...
    licznikPrzerwan = 0;                                             // Zeruj go oraz...
    digitalWrite(dwukropek, !digitalRead(dwukropek) || trybEdycji);  // Zmień stan dwukropka, albo go ustaw, jeśli jesteś w trybie edycji.
    sekundy++;                                                       // Zwiększaj liczbę sekund.
    autoKoniec++;                                                    // Zwiększ licznik do automatycznego opuszczania procedur ustawiania czasu i alarmu.
    if (sekundy == 60) {                                             // Jeśli osiągnął 60...
      sekundy = 0;                                                   // Zeruj go oraz...
      zwiekszCzas();                                                 // Zwiększ czas.
      if (trybEdycji == LOW) {                                       // Gdy akurat nie ustawiamy czasu lub alarmu...
        ladujCzas();                                                 // Ładuj czas do buforów wyświetlacza.
      }
      if (minutyAlarmu == minuty && godzinyAlarmu == godziny && digitalRead(alarm) == HIGH) {  // Gdy czas na alarm...
        wlaczAlarm = HIGH;                                                                     // Ustaw flagę alarmu.
      }
    }
  }
  digitalWrite(wspolne1, LOW);  // Wygaś wszystkie cyfry.
  digitalWrite(wspolne2, LOW);
  digitalWrite(wspolne3, LOW);
  digitalWrite(wspolne4, LOW);

  switch (aktywnaCyfra) {  // Załaduj kształty aktywnej cyfry z tablicy...
    case 1:                // Na pierwszą pozycję wyświetlacza.
      digitalWrite(segmentA, bitRead(tablica[cyfra1], 0));
      digitalWrite(segmentB, bitRead(tablica[cyfra1], 1));
      digitalWrite(segmentC, bitRead(tablica[cyfra1], 2));
      digitalWrite(segmentD, bitRead(tablica[cyfra1], 3));
      digitalWrite(segmentE, bitRead(tablica[cyfra1], 4));
      digitalWrite(segmentF, bitRead(tablica[cyfra1], 5));
      digitalWrite(segmentG, bitRead(tablica[cyfra1], 6));
      digitalWrite(wspolne1, HIGH);  // Włącz aktywną cyfrę.
      aktywnaCyfra = 2;              // Ustaw numer aktywnej cyfry dla kolejnego wejścia w przerwanie.
      break;
    case 2:  // Na drugą pozycję wyświetlacza.
      digitalWrite(segmentA, bitRead(tablica[cyfra2], 0));
      digitalWrite(segmentB, bitRead(tablica[cyfra2], 1));
      digitalWrite(segmentC, bitRead(tablica[cyfra2], 2));
      digitalWrite(segmentD, bitRead(tablica[cyfra2], 3));
      digitalWrite(segmentE, bitRead(tablica[cyfra2], 4));
      digitalWrite(segmentF, bitRead(tablica[cyfra2], 5));
      digitalWrite(segmentG, bitRead(tablica[cyfra2], 6));
      digitalWrite(wspolne2, HIGH);
      aktywnaCyfra = 3;
      break;
    case 3:  // Na trzecią pozycję wyświetlacza.
      digitalWrite(segmentA, bitRead(tablica[cyfra3], 0));
      digitalWrite(segmentB, bitRead(tablica[cyfra3], 1));
      digitalWrite(segmentC, bitRead(tablica[cyfra3], 2));
      digitalWrite(segmentD, bitRead(tablica[cyfra3], 3));
      digitalWrite(segmentE, bitRead(tablica[cyfra3], 4));
      digitalWrite(segmentF, bitRead(tablica[cyfra3], 5));
      digitalWrite(segmentG, bitRead(tablica[cyfra3], 6));
      digitalWrite(wspolne3, HIGH);
      aktywnaCyfra = 4;
      break;
    case 4:  // Na czwarta pozycję wyświetlacza.
      digitalWrite(segmentA, bitRead(tablica[cyfra4], 0));
      digitalWrite(segmentB, bitRead(tablica[cyfra4], 1));
      digitalWrite(segmentC, bitRead(tablica[cyfra4], 2));
      digitalWrite(segmentD, bitRead(tablica[cyfra4], 3));
      digitalWrite(segmentE, bitRead(tablica[cyfra4], 4));
      digitalWrite(segmentF, bitRead(tablica[cyfra4], 5));
      digitalWrite(segmentG, bitRead(tablica[cyfra4], 6));
      digitalWrite(wspolne4, HIGH);
      aktywnaCyfra = 1;
      break;
  }
}
// Podprogramy ================================================================================================================================================
void zwiekszCzas() {      // Procedura zwiększająca czas z uwzględnieniem przeładowań jednostek.
  minuty++;               // Zwiększ licznik minut.
  if (minuty == 60) {     // Jeśli osiągnął 60...
    minuty = 0;           // Zeruj go oraz...
    godziny++;            // Zwiększ licznik godzin.
    if (godziny == 24) {  // Jeśli osiągnął 24...
      godziny = 0;        // Zeruj go
    }
  }
}
void zmniejszCzas() {      // Procedura zmniejszająca czas z uwzględnieniem przeładowań jednostek.
  minuty--;                // Zmniejsz licznik minut.
  if (minuty == 255) {     // Jeśli osiągnął 255...
    minuty = 59;           // Załaduj wartość równą 59 oraz...
    godziny--;             // Zmniejsz licznik godzin.
    if (godziny == 255) {  // Jeśli osiągnął 255...
      godziny = 23;        // Załaduj wartość równą 23
    }
  }
}
void zwiekszAlarm() {           // Procedura zwiększająca czas alarmu z uwzględnieniem przeładowań jednostek.
  autoKoniec = 0;               // Zeruj licznik sekund do automatycznego opuszczania proceduy ustawiania alarmu.
  minutyAlarmu++;               // Zwiększ licznik minut alarmu.
  if (minutyAlarmu == 60) {     // Jeśli osiągnął 60...
    minutyAlarmu = 0;           // Zeruj go oraz...
    godzinyAlarmu++;            // Zwiększ licznik godzin alarmu.
    if (godzinyAlarmu == 24) {  // Jeśli osiągnął 24...
      godzinyAlarmu = 0;        // Zeruj go
    }
  }
  ladujAlarm();  // Ładuj czas alarmu do buforów wyświetlacza.
}
void zmniejszAlarm() {           // Procedura zmniejszająca czas alarmu z uwzględnieniem przeładowań jednostek.
  autoKoniec = 0;                // Zeruj licznik sekund do automatycznego opuszczania proceduy ustawiania alarmu.
  minutyAlarmu--;                // Zmniejsz licznik minut alarmu.
  if (minutyAlarmu == 255) {     // Jeśli osiągnął 255...
    minutyAlarmu = 59;           // Załaduj wartość równą 59 oraz...
    godzinyAlarmu--;             // Zmniejsz licznik godzin alarmu.
    if (godzinyAlarmu == 255) {  // Jeśli osiągnął 255...
      godzinyAlarmu = 23;        // Załaduj wartość równą 23
    }
  }
  ladujAlarm();  // Ładuj czas alarmu do buforów wyświetlacza.
}
void ladujCzas() {
  if (godziny < 10) {       // Wyświetl spację, jeśli godzina < 10
    cyfra1 = 10;            // Pod adresem dziesiątym znajduje się spacja.
  } else {                  // Wyświetl wartość dziesiątek godzin, jeśli godzina > 9
    cyfra1 = godziny / 10;  // Załaduj do bufora wyświetlacza dziesiątki godzin.
  }                         // Pozostałe cyfry ładują się już w sposób prosty.
  cyfra2 = godziny % 10;    // Załaduj do bufora wyświetlacza jednostki godzin.
  cyfra3 = minuty / 10;     // Załaduj do bufora wyświetlacza dziesiątki minut.
  cyfra4 = minuty % 10;     // Załaduj do bufora wyświetlacza jednostki minut.
}
void ladujAlarm() {
  if (godzinyAlarmu < 10) {       // Wyświetl spację, jeśli godzina alarmu < 10
    cyfra1 = 10;                  // Pod adresem dziesiątym znajduje się spacja.
  } else {                        // Wyświetl wartość dziesiątek godzin alarmu, jeśli godzina alarmu > 9
    cyfra1 = godzinyAlarmu / 10;  // Załaduj do bufora wyświetlacza dziesiątki godzin alarmu.
  }                               // Pozostałe cyfry ładują się już w sposób prosty.
  cyfra2 = godzinyAlarmu % 10;    // Załaduj do bufora wyświetlacza jednostki godzin alarmu.
  cyfra3 = minutyAlarmu / 10;     // Załaduj do bufora wyświetlacza dziesiątki minut alarmu.
  cyfra4 = minutyAlarmu % 10;     // Załaduj do bufora wyświetlacza jednostki minut alarmu.
}
void koniecRegulacjiCzasu() {
  licznikPrzerwan = 0;      // Zeruj licznik przerwań.
  sekundy = 0;              // Zeruj sekundnik.
  delay(opoznienieDlugie);  // Opóźnienie przed wyjściem z procedury.
}
void zapikajPodwojnie() {  // Zapikaj podwójnie.
  digitalWrite(buzzer, HIGH);
  delay(opoznienieKrotkieAlarm);
  digitalWrite(buzzer, LOW);
  delay(opoznienieKrotkieAlarm);
  digitalWrite(buzzer, HIGH);
  delay(opoznienieKrotkieAlarm);
  digitalWrite(buzzer, LOW);
  delay(opoznienieKrotkieAlarm);
}
void zapikajPoczwornie() {  // Zapikaj poczwórnie.
  zapikajPodwojnie();
  zapikajPodwojnie();
}
void regulujCzasPlus() {
  autoKoniec = 0;  // Zeruj licznik sekund do automatycznego opuszczania proceduy ustawiania czasu.
  zwiekszCzas();   // Zwiększ czas.
  ladujCzas();     // Wyświetl czas.
}
void regulujCzasMinus() {
  autoKoniec = 0;
  zmniejszCzas();
  ladujCzas();
}
void zerujSekundy() {
  licznikPrzerwan = 0;  // Zeruj licznik przerwań.
  sekundy = 0;          // Zeruj sekundnik.
}

Powiązane tematy

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

Przeczytaj również

Nasi partnerzy

TMETech Master EventTME EducationPoweredby
Copyright © 2025 arduino.pl