[112] Budujemy ze zrozumieniem - elektroniczny budzik cz. 6
![[112] Budujemy ze zrozumieniem - elektroniczny budzik cz. 6](/_next/image?url=https%3A%2F%2Farduino.pl%2Fimgproxy%2FI7W6GVcNksC9I40KsvdqdozHbDxjz4wrrhEOaTYaAzA%2Ff%3Awebp%2Fw%3A1200%2FbG9jYWw6Ly8vaW1hZ2VzLzAtNjgzLzFlYTVmLzNkYWVjLzAtNjgzMWVhNWYzZGFlYzk1MTAwOTYyMy5wbmc%3D.webp&w=3840&q=75)
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 < 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.
}