Serwis Edukacyjny w I-LO w Tarnowie ![]() Materiały dla uczniów liceum |
Wyjście Spis treści Wstecz Dalej Autor artykułu: mgr Jerzy Wałaszek |
©2023 mgr Jerzy Wałaszek |
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ę.
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.
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).
Rzeczywisty licznik powinien dodatkowo posiadać funkcję zerowania przerzutników. W przeciwnym razie stan wyjść Q nie jest określony po włączeniu zasilania.
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ń:
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 |
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 |
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.
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.
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.
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 | ||||||||||||||||||||||||||||||||||||||
![]() |
![]() |
![]() |
||||||||||||||||||||||||||||||||||||
![]() |
||||||||||||||||||||||||||||||||||||||
Sygnał TB | ||||||||||||||||||||||||||||||||||||||
![]() |
![]() |
![]() |
||||||||||||||||||||||||||||||||||||
![]() |
||||||||||||||||||||||||||||||||||||||
Sygnał TC | ||||||||||||||||||||||||||||||||||||||
![]() |
![]() |
![]() |
||||||||||||||||||||||||||||||||||||
![]() |
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ń:
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 |
![]() |
Zespół Przedmiotowy Chemii-Fizyki-Informatyki w I Liceum Ogólnokształcącym im. Kazimierza Brodzińskiego w Tarnowie ul. Piłsudskiego 4 ©2023 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.