Serwis Edukacyjny
w I-LO w Tarnowie
obrazek

Materiały dla uczniów liceum

  Wyjście       Spis treści       Wstecz       Dalej  

Autor artykułu: mgr Jerzy Wałaszek

©2020 mgr Jerzy Wałaszek
I LO w Tarnowie

Bity w elektronice

Licznik synchroniczny

SPIS TREŚCI
Podrozdziały

Opis

W liczniku asynchronicznym (ang. asynchronous counter) przerzutniki są sterowane wyjściami przerzutników poprzedzających. Powoduje to, iż stan licznika nie ustala się od razu, lecz kolejno na poszczególnych przerzutnikach z opóźnieniem równym czasowi propagacji sygnału w przerzutniku. Jeśli impulsy zegarowe mają dużą częstotliwość i ich okres jest porównywalny z czasem propagacji przerzutnika, to sygnały wyjściowe licznika mogą podawać złe wartości zliczonych impulsów - sygnał wyjściowy nie ma czasu na odpowiednie ustalenie się.

obrazek

Powyżej przedstawiamy wykres czasowy stanów licznika, na które wpływają wewnętrzne czasy propagacji. W ich wyniku stany wyjściowe są przesunięte w czasie w stosunku do impulsów zegarowych. Opóźnienie to zwielokrotnia się dla starszych bitów licznika. Bit Q8 jest już tak opóźniony, iż licznik "gubi" stan 8, w którym powinien być ustawiony na 1 tylko bit Q8, a pozostałe bity wyzerowane. Sytuacja staje się jeszcze gorsza, gdy licznik asynchroniczny ma więcej bitów. Wtedy gubienie stanów może pojawić się przy odpowiednio mniejszych częstotliwościach sygnału zegarowego.

Z tego powodu zaprojektowano liczniki synchroniczne (ang. synchronous counter) , w których przerzutniki zmieniają swój stan jednocześnie z taktem zegarowym. Licznik synchroniczny posiada sieć logiczną, która steruje odpowiednio wejściami przerzutników na podstawie stanów ich wyjść. Sygnał zegarowy doprowadzany jest do każdego przerzutnika, zatem zmiana stanów będzie odbywała się wg napływających taktów zegarowych.

Na początek:  podrozdziału   strony 

Budowa licznika synchronicznego

Liczniki synchroniczne można budować z przerzutników D flip flop lub z przerzutników J-K Master/Slave. My skupimy się na tych drugich. Najpierw określimy tabelkę stanów wyjściowych poszczególnych przerzutników, z których będzie zbudowany nasz licznik. Stany te są kolejnymi liczbami całkowitymi w kodzie 8421.

C Wyjścia
QD QC QB QA
0 0 0 0 0
1 0 0 0 1
2 0 0 1 0
3 0 0 1 1
4 0 1 0 0
5 0 1 0 1
6 0 1 1 0
7 0 1 1 1
8 1 0 0 0
9 1 0 0 1
10 1 0 1 0
11 1 0 1 1
12 1 1 0 0
13 1 1 0 1
14 1 1 1 0
15 1 1 1 1

Aby określić sieć logiczną, przyjrzyjmy się tabelce stanów, które musi przyjmować nasz licznik dla kolejnych impulsów zegarowych. Z tabelki odczytujemy, iż wyjście QA zmienia swój stan na przeciwny po każdym impulsie zegarowym. Zatem do realizacji wyjścia QA wystarcza pojedynczy przerzutnik J-K MS pracujący jako przerzutnik T (oba wejścia J i K w stanie 1, czyli podłączone do Vcc poprzez opornik 1...10k).

Wyjście QB zmienia stan na przeciwny, gdy w poprzednim stanie wyjście QA znajdowało się w stanie 1. Zrealizujemy je za pomocą pojedynczego przerzutnika J-K MS, którego wejścia J i K będą połączone z wyjściem QA pierwszego przerzutnika. Jeśli wyjście QA znajdzie się w stanie 1, to na oba wejścia J i K drugiego przerzutnika zostanie podany stan 1. Będzie on wtedy pracował jako przerzutnik T, zatem przy kolejnym impulsie zegarowym zmieni swój stan na przeciwny. Jeśli wyjście QA przyjmie stan 0, to impuls zegarowy nie zmieni stanu wyjścia QB.

Wyjście QC zmienia stan na przeciwny, gdy w poprzednim cyklu licznika wyjścia QA i QB jednocześnie były w stanie wysokim. Teraz wysterujemy wejścia J i K trzeciego przerzutnika iloczynem logicznym stanów wyjść QA i QB.

Wyjście QD zmienia stan na przeciwny, gdy w poprzednim cyklu wszystkie trzy wyjścia QA, QB i QC znajdowały się w stanie wysokim 1. Wejścia J i K czwartego przerzutnika wysterujemy zatem iloczynem logicznym tych wyjść i w ten sposób otrzymamy 4 bitowy licznik synchroniczny:

Poniżej podajemy funkcje logiczne sterujące poszczególnymi wejściami przerzutników. Funkcje te tworzą dobrze zdefiniowany ciąg, który można rozszerzać na dowolną (rozsądną) ilość przerzutników J-K. Zamiast bramek AND mogą być wykorzystane wielowejściowe przerzutniki J-K (w tym właśnie celu się je produkuje - redukcja dodatkowych elementów).

TA = JA = KA = 1
TB = JB = KB = QA
TC = JC = KC = QAQB
TD = JD = KD = QAQBQC
...

Rzeczywisty licznik powinien dodatkowo posiadać funkcję zerowania przerzutników. W przeciwnym razie stan wyjść Q nie jest określony po włączeniu zasilania.

Na początek:  podrozdziału   strony 

Symulacja w języku C++

Przerzutniki są nieco trudniejsze w symulacji, ponieważ posiadają pamięć swojego stanu. W naszej symulacji przerzutnik JK będziemy symulować za pomocą funkcji:
int JK(int J, int K, int Q)
{
  if((J == K) && J) return 1 - Q;
  if(J) return 1;
  if(K) return 0;
  return Q;
}

Stan przerzutnika będzie pamiętany poza nim w zmiennej przekazywanej w parametrze Q. Wartością funkcji jest nowy stan przerzutnika, który należy zapamiętać w zmiennej przechowującej jego stan. Każde wywołanie odpowiada impulsowi zegarowemu na wejściu C przerzutnika.

Postępujemy standardowo. Najpierw numerujemy przerzutniki i bramki:

Określamy sieć połączeń:

YB5 = AND(QA,QB)
YB6 = AND(QA,QB,QC)
QB = JK(QA,QA)
QA = JK(1,1)
QC = JK(YB5,YB5)
QD = JK(YB6,YB6)

Stany przerzutników będą pamiętane w zmiennych QA, QB, QC i QD. Przed rozpoczęciem symulacji zmienne te zerujemy, po czym wykonujemy 16 razy pętlę z programem sieci. Powinniśmy otrzymać na wyjściach kolejne liczby w kodzie 8421 wg poniższej tabelki:
NR Wyjścia
QD QC QB QA
0 0 0 0 0
1 0 0 0 1
2 0 0 1 0
3 0 0 1 1
4 0 1 0 0
5 0 1 0 1
6 0 1 1 0
7 0 1 1 1
8 1 0 0 0
9 1 0 0 1
10 1 0 1 0
11 1 0 1 1
12 1 1 0 0
13 1 1 0 1
14 1 1 1 0
15 1 1 1 1
C++
// Symulacja licznika synchronicznego
// (C)2020 mgr Jerzy Wałaszek
// I LO w Tarnowie

#include <iostream>

using namespace std;

// Funkcje bramek

int AND(int a, int b, int c = 1)
{
    return (a & b & c);
}

// Funkcja przerzutnika JK

int JK(int J, int K, int Q)
{
  if((J == K) && J) return 1 - Q;
  if(J) return 1;
  if(K) return 0;
  return Q;
}

int main( )
{
  // Stany przerzutników
  int QA,QB,QC,QD;

  // Stany wyjściowe bramek
  int YB5,YB6;

  int i;

  // Zerujemy stany przerzutników

  QA = QB = QC = QD = 0;

  cout << " NR | QD QC QB QA" << endl;

  for(i = 0; i < 16; i++)
  {
    // Wyniki

    if(i < 10) cout << "  "; else cout << " ";
    cout << i << " |  "
         << QD << "  "
         << QC << "  "
         << QB << "  "
         << QA << endl;

    // Symulujemy sieć

    YB5 = AND(QA,QB);
    YB6 = AND(QA,QB,QC);
    QB = JK(QA,QA,QB);
    QA = JK(1,1,QA);
    QC = JK(YB5,YB5,QC);
    QD = JK(YB6,YB6,QD);

  }
  cout << endl;

  return 0;
}
Wynik:
 NR | QD QC QB QA
  0 |  0  0  0  0
  1 |  0  0  0  1
  2 |  0  0  1  0
  3 |  0  0  1  1
  4 |  0  1  0  0
  5 |  0  1  0  1
  6 |  0  1  1  0
  7 |  0  1  1  1
  8 |  1  0  0  0
  9 |  1  0  0  1
 10 |  1  0  1  0
 11 |  1  0  1  1
 12 |  1  1  0  0
 13 |  1  1  0  1
 14 |  1  1  1  0
 15 |  1  1  1  1

Na początek:  podrozdziału   strony 

Symulacja interaktywna

W poniższym symulatorze licznika synchronicznego możesz prześledzić opisane sygnały sterujące wejściami poszczególnych przerzutników. Wejście C jest wejściem zegarowym, które zmienia stan przerzutników przy przejściu z 1 na 0, czyli stany wyjściowe licznika zmieniają się synchronicznie z opadającym zboczem sygnału zegarowego, co jest typowe dla przerzutników typu J-K.

Symulator
Na początek:  podrozdziału   strony 

Synchroniczne liczniki modulo n

Idea działania asynchronicznych liczników modulo n polegała na zerowaniu licznika po osiągnięciu stanu n. Wadą tego rozwiązania jest to, iż przez krótką chwilę na wyjściu licznika pojawia się stan n. Wady tej nie posiadają liczniki synchroniczne, w których kolejne stany powstają ze stanów poprzednich przetworzonych przez odpowiednią sieć logiczną sterującą przerzutnikami. Poniżej podajemy dokładną procedurę projektowania takich liczników. Jeśli zrozumiesz ten materiał, to będziesz w stanie nie tylko zaprojektować dowolny licznik synchroniczny, ale również układ generujący dowolne kody binarne.

Zaprojektujemy licznik synchroniczny zliczający modulo 7. Do jego budowy będziemy potrzebowali trzech przerzutników J-K MS oraz kilka bramek NAND.

KROK 1

Określamy tabelkę stanów dla poszczególnych przerzutników. Napływające impulsy zegarowe będą powodowały przejście przerzutników przez kolejno zdefiniowane stany licznika. Po stanie 6 następuje wyzerowanie licznika i cykl rozpoczyna się od początku.

Stan QC QB QA
0 0 0 0
1 0 0 1
2 0 1 0
3 0 1 1
4 1 0 0
5 1 0 1
6 1 1 0
0 0 0 0

Przerzutniki w liczniku synchronicznym są sterowane wspólnym sygnałem zegarowym. Będą zatem pracowały w poniższym układzie:

Zadanie polega na określeniu sygnałów sterujących wejściami J i K (oznaczonymi tutaj jako ?). Wybieramy układ przerzutnika T - wejścia J i K połączone razem do wspólnego sygnału cyfrowego. Jeśli sygnał ten będzie posiadał poziom 1, to impuls zegarowy C spowoduje zmianę stanu przerzutnika J-K na przeciwny. Jeśli sygnał sterujący wejściami J i K będzie posiadał poziom 0, to impuls zegarowy nie spowoduje zmiany stanu przerzutnika.

KROK 2

Dla każdego stanu licznika określamy, które przerzutniki muszą przełączyć swój stan na przeciwny przy przejściu licznika do stanu następnego.

Przykładowo załóżmy, iż licznik znajduje się w stanie 5, czyli:

QC = 1, QB = 0 i QA = 1.

Następnym stanem jest stan 6, czyli

QC = 1, QB = 1 i QA = 0.

Zatem przy przejściu ze stanu 5 do stanu 6:

przerzutnik C pozostaje w stanie 1
przerzutnik B przełącza się z 0 na 1
przerzutnik A przełącza się z 1 na 0

Umówmy się, iż konieczność przełączenia stanu przerzutnika będziemy oznaczali przez 1, a pozostanie w obecnym stanie będziemy oznaczali przez 0. Utworzymy zatem następującą tabelkę przełączeń:

Stan Wyjścia Przejście
stanu
Przełączanie
QC QB QA TC TB TA
0 0 0 0 0 → 1 0 0 1
1 0 0 1 1 → 2 0 1 1
2 0 1 0 2 → 3 0 0 1
3 0 1 1 3 → 4 1 1 1
4 1 0 0 4 → 5 0 0 1
5 1 0 1 5 → 6 0 1 1
6 1 1 0 6 → 0 1 1 0
0 0 0 0 0 → 1 0 0 1

Przerzutnik A przełącza swój stan na przeciwny w każdym stanie licznika za wyjątkiem stanu 6, w którym wyjście QA ma poziom 0. W następnym stanie licznika 0 wyjście QA również ma poziom 0, zatem zmiana stanu przerzutnika A nie jest konieczna i dlatego w komórce tabelki jest wpis 0.

Przerzutnik B przełącza swój stan w co drugim stanie licznika. W stanie 6 dodatkowo musi on być przełączony, ponieważ wyjście QB ma poziom 1.

Przerzutnik C przełącza swój stan tylko przy stanie licznika 3 (z 0 na 1) i 6 (z 1 na 0). Sygnały TA, TB i TC podamy na wejścia J i K odpowiednich przerzutników.

Jeśli dany sygnał TA, TB lub TC będzie miał poziom logiczny 0, to impuls zegarowy nie spowoduje przełączenia stanu wyjściowego przerzutnika. Jeśli natomiast sygnał sterujący wejściami J i K przyjmie poziom logiczny 1, to impuls zegarowy przełączy stan przerzutnika na przeciwny, co wynika z tabelki przejść dla przerzutnika J-K MS.

KROK 3

Na podstawie tabelki przełączeń przerzutników określamy funkcje logiczne TA, TB i TC, które będą sterowały wejściami J i K przerzutników w liczniku synchronicznym. Wykorzystamy mapy Karnaugha do minimalizacji funkcji logicznych.

Sygnał TA
Obszar TA1
obrazek  0  1
00 1 1
01 1 1
11 0 X
10 1 1
Obszar TA2
obrazek  0  1
00 1 1
01 1 1
11 0 X
10 1 1
Sygnał TB
Obszar TB1
obrazek  0  1
00 0 1
01 0 1
11 1 X
10 0 1
Obszar TB2
obrazek  0  1
00 0 1
01 0 1
11 1 X
10 0 1
Sygnał TC
Obszar TC1
obrazek  0  1
00 0 0
01 0 1
11 1 X
10 0 0
Obszar TC2
obrazek  0  1
00 0 0
01 0 1
11 1 X
10 0 0

Napiszemy teraz prosty program w języku C++, który sprawdzi działanie naszego licznika. Wykorzystamy tutaj funkcję przerzutnika J-K, którą podaliśmy wcześniej w tym rozdziale. Licznik ma generować na wyjściu stany:

NR QC QB QA
0 0 0 0
1 0 0 1
2 0 1 0
3 0 1 1
4 1 0 0
5 1 0 1
6 1 1 0
0 0 0 0
1 0 0 1

Rozpoczynamy od ponumerowania przerzutników i bramek (stan przerzutników będzie przechowywany w zmiennych QA, QB i QC):

Teraz określamy sieć połączeń:

YB4 = NAND(QB,QC)
YB5 = NAND(NOT(QA),YB4)
YB6 = NAND(QA,QB)
YB7 = NAND(YB6,YB4)
QA = JK(YB4,YB4)
QB = JK(YB5,YB5)
QC = JK(YB7,YB7)
C++
// Symulacja licznika synchronicznego modulo 7
// (C)2020 mgr Jerzy Wałaszek
// I LO w Tarnowie

#include <iostream>

using namespace std;

// Funkcje bramek

int NAND(int a, int b, int c = 1)
{
    return (a & b & c) ^ 1;
}

// Funkcja przerzutnika JK

int JK(int J, int K, int Q)
{
  if((J == K) && J) return 1 - Q;
  if(J) return 1;
  if(K) return 0;
  return Q;
}

int main( )
{
  // Stany przerzutników
  int QA,QB,QC;

  // Stany wyjściowe bramek
  int YB4,YB5,YB6,YB7;

  int i;

  // Zerujemy stany przerzutników

  QA = QB = QC = 0;

  cout << " NR | QC QB QA" << endl;

  for(i = 0; i < 9; i++)
  {
    // Wyniki

    // Obliczamy wartość w liczniku

    int v = QC * 4 + QB * 2 + QA;

    cout << "  "
         << v << " |  "
         << QC << "  "
         << QB << "  "
         << QA << endl;

    // Symulujemy sieć

    YB4 = NAND(QB,QC);
    YB5 = NAND(QA ^ 1,YB4);
    YB6 = NAND(QA,QB);
    YB7 = NAND(YB6,YB4);
    QA = JK(YB4,YB4,QA);
    QB = JK(YB5,YB5,QB);
    QC = JK(YB7,YB7,QC);

  }
  cout << endl;

  return 0;
}
Wynik:
 NR | QC QB QA
  0 |  0  0  0
  1 |  0  0  1
  2 |  0  1  0
  3 |  0  1  1
  4 |  1  0  0
  5 |  1  0  1
  6 |  1  1  0
  0 |  0  0  0
  1 |  0  0  1

Poniżej możesz prześledzić działanie tego licznika w symulacji interaktywnej. Przycisk C wprowadza sygnał zegarowy, który zmienia synchronicznie stan przerzutników J-K. Zmiania stanu następuje przy przejściu C z 1 na 0, czyli przy ujemnym zboczu, co jest typowe dla przerzutników J-K.

Symulator
Na początek:  podrozdziału   strony 

Zespół Przedmiotowy
Chemii-Fizyki-Informatyki

w I Liceum Ogólnokształcącym
im. Kazimierza Brodzińskiego
w Tarnowie
ul. Piłsudskiego 4
©2020 mgr Jerzy Wałaszek

Materiały tylko do użytku dydaktycznego. Ich kopiowanie i powielanie jest dozwolone
pod warunkiem podania źródła oraz niepobierania za to pieniędzy.

Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl

Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.
Informacje dodatkowe.