[137] Budujemy licznik (nie tylko) do magnetofonu cz. 3

[137] Budujemy licznik (nie tylko) do magnetofonu cz. 3

Ponieważ część szkicu związaną z wyświetlaniem stanu licznika dokładnie omówiłem w pierwszym artykule serii, skupię się teraz na elementach realizujących zamianę sygnałów z enkodera – przedstawionego w drugiej części – na zmianę wartości licznika.


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

const byte segmenty[7] = { 6, 5, 4, 3, 2, 1, 0 };  // Adresy portów kolejnych segmentów: od A do G
const byte katody[4] = { A0, A1, A2, A3 };         // Adresy portów wspólnych wyprowadzeń (katod) kolejnych wyświetlaczy.
const byte reset = 8;                              // Adres przycisku resetującego licznik.
const byte fotoLewy = A4;                          // Adresy portów fototranzystorów.
const byte fotoPrawy = A5;

volatile byte cyfry[4] = { 0, 0, 0, 0 };  // Tablica z cyframi, którą wyświetla przerwanie.
volatile byte aktywnaCyfra = 0;           // Aktualnie świecąca się cyfra w multipleksie.
int licznik = 0;                          // Zmienna przechowująca stan licznika obrotów.
bool poprzedniFotoLewy;                   // Zmienne poprzedniego stanu fototranzystorów.
bool poprzedniFotoPrawy;

const byte ksztalty[10] = {
  B1111110,  // 0, Tablica zawierająca wzorce znaków wyświetlacza siedmiosegmentowego.
  B0110000,  // 1, Schemat: A-B-C-D-E-F-G
  B1101101,  // 2
  B1111001,  // 3
  B0110011,  // 4
  B1011011,  // 5
  B1011111,  // 6
  B1110000,  // 7
  B1111111,  // 8
  B1111011   // 9
};
void setup() {
  for (byte x = 0; x < 7; x++)  // Deklaruj porty kolejnych segmentów wyświetlaczy.
    pinMode(segmenty[x], OUTPUT);

  for (byte x = 0; x < 4; x++) {    // Dla każdej katody wyświetlacza...
    pinMode(katody[x], OUTPUT);     // Deklaruj porty.
    digitalWrite(katody[x], HIGH);  // Odłącz napięcie.
  }
  pinMode(reset, INPUT_PULLUP);  // Deklaruj port przycisku resetującego licznik.
  pinMode(fotoLewy, INPUT);      // Deklaruj porty fototranzystorów.
  pinMode(fotoPrawy, INPUT);

  poprzedniFotoLewy = digitalRead(fotoLewy);  // Załaduj stany fototranzystorów.
  poprzedniFotoPrawy = digitalRead(fotoPrawy);

  Timer1.initialize(1000);             // Ustaw przerwania na milisekundę.
  Timer1.attachInterrupt(przerwanie);  // Włącz przerwania z określeniem miejsca lądowania.
}
void loop() {
  if (digitalRead(reset) == HIGH) {  // Jeśli wciśnięto przycisk resetu...
    licznik = 0;                     // Resetuj licznik.
    przeladuj();                     // Odśwież stan wyświetlacza.
  }
  bool aktualnyFotoLewy = digitalRead(fotoLewy);  // Załaduj stany fototranzystorów.
  bool aktualnyFotoPrawy = digitalRead(fotoPrawy);

  if (aktualnyFotoLewy != poprzedniFotoLewy || aktualnyFotoPrawy != poprzedniFotoPrawy) {  // Jeśli nastąpiła jakakolwiek zmiana stanu fotorezystorów...
    if (poprzedniFotoLewy != aktualnyFotoLewy && aktualnyFotoPrawy == LOW) {               // Zidentyfikuj interesującą nas sekwencję.
      licznik += (aktualnyFotoLewy == HIGH) ? 1 : -1;                                      // W zależności od stanu lewego fototranzystora zwiększ lub zmniejsz stan licznika.
    }
    poprzedniFotoLewy = aktualnyFotoLewy;  // Zapamiętaj stany fototranzystorów do kolejnej analizy.
    poprzedniFotoPrawy = aktualnyFotoPrawy;

    licznik = (licznik + 10000) % 10000;  // Ogranicz zliczanie do przedziału 0...9999
    przeladuj();
  }
}
void przeladuj() {
  cyfry[0] = (licznik / 1000) % 10;  // Załaduj do tablicy cyfry reprezentujące wartość licznika.
  cyfry[1] = (licznik / 100) % 10;
  cyfry[2] = (licznik / 10) % 10;
  cyfry[3] = licznik % 10;
}
void przerwanie() {             // Obsługa przerwania.
  for (byte x = 0; x < 4; x++)  // Odłącz napięcie od wszystkich katod wyświetlaczy.
    digitalWrite(katody[x], HIGH);

  byte y = ksztalty[cyfry[aktywnaCyfra]];  // Wyprowadź kształt do wyświetlenia.
  for (byte x = 0; x < 7; x++)             // Zaświeć odpowiednie segmenty aktywnej pozycji wyświetlacza.
    digitalWrite(segmenty[x], (y & (1 << (6 - x))));

  digitalWrite(katody[aktywnaCyfra], LOW);  // Zaświeć aktywny wyświetlacz.
  aktywnaCyfra = (aktywnaCyfra + 1) % 4;    // Zwiększ wartość aktywnego wyświetlacza modulo 4
}

W deklaracjach oczywiście będziemy potrzebowali portów enkodera oraz resetu – bo cóż to za licznik bez możliwości resetowania go w dowolnej chwili? Będą potrzebne jeszcze binarne zmienne przechowujące stany odczytanych sensorów: poprzedniFotoLewy i poprzedniFotoPrawy. Wszystkie zmiany nastąpią w pętli głównej. Na początek – obsłużymy sobie reset.

if (digitalRead(reset) == HIGH) {  // Jeśli wciśnięto przycisk resetu...
  licznik = 0;                     // Resetuj licznik.
  przeladuj();                     // Odśwież stan wyświetlacza.
}

Sprawa jest prosta, jeśli zostanie wciśnięty, licznik zostanie wyzerowany. Podprogram przeładuj natychmiast zamieni wartość licznika na reprezentanta składającego się z czterech cyfr; to już było w poprzednim szkicu.

if (aktualnyFotoLewy != poprzedniFotoLewy || aktualnyFotoPrawy != poprzedniFotoPrawy) {  // Jeśli nastąpiła jakakolwiek zmiana stanu fotorezystorów...

Następnie ładujemy stany sensorów do zmiennych, jako „aktualne”. Kolejna linia porównuje stany aktualne z poprzednimi. Warunek będzie spełniony tylko wówczas, jeśli nastąpiła jakaś zmiana.

if (poprzedniFotoLewy != aktualnyFotoLewy && aktualnyFotoPrawy == LOW) {               // Zidentyfikuj interesującą nas sekwencję.
  licznik += (aktualnyFotoLewy == HIGH) ? 1 : -1;                                      // W zależności od stanu lewego fototranzystora zwiększ lub zmniejsz stan licznika.
}
poprzedniFotoLewy = aktualnyFotoLewy;  // Zapamiętaj stany fototranzystorów do kolejnej analizy.
poprzedniFotoPrawy = aktualnyFotoPrawy;

Wtedy należy sprawdzić kolejny warunek, ponieważ mogą wystąpić dwa: zmiana z oświetlonego na zaciemniony lub odwrotnie. Odrzucamy jeden z nich i analizujemy kolejne dwie sytuacje, które już jednoznacznie określą, że właśnie nastąpił obrót o 360 stopni i w konkretną stronę. W zależności od niej albo zwiększymy stan licznika, albo zmniejszymy. Na końcu trzeba jeszcze koniecznie zapamiętać aktualny stan sensorów dla porównań w kolejnym przejściu pętli.

licznik = (licznik + 10000) % 10000;  // Ogranicz zliczanie do przedziału 0...9999
przeladuj();

Ponieważ licznik wyświetla maksymalnie cztery dziewiątki, w ten elegancji sposób ograniczymy zakres do tegoż właśnie. Teraz można już uczynić konwersję stanu licznika na cyfry do wyświetlenia przez procedury w przerwaniu, ale o tym już było, więc zapraszam do poprzednich artykułów. Po kompilacji możemy sobie przetestować układ i zbudować go już w formie finalnej. Ale to nie wszystko – ale o tym w czwartej, ostatniej części serii.

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