アフィリエイト広告
アフィリエイト広告

加算器でカウンタをつくる / 10進カウンタ

4ビット加算器を使った 10進カウンタを、ロジックICで作ります。アップカウンタ、ダウンカウンタの切り換え付きとしました。

前回は、4ビット加算器を使って 16進カウンタ (4ビットカウンタ) を作りました。

毎度のことですが、16進カウンタでは、出力を 7セグメントLEDに表示させるのがめんどうくさいです。なので、BCD で出力したい。BCD (Binary-Coded Decimal) とは、10進数を 2進数で表現する方式。要するに、10進カウンタの出力って BCD なんだな。

4ビット加算器による 10進カウンタ回路

ブロック図

4ビットカウンタを 10進カウンタにするには、フリップフロップの前に組み合わせ回路を付加する。これは分周器によるカウンタも同じ。加算器とストレージレジスタの間に、ゲート組み合わせ回路をはさみます。

図 1. 4ビット加算器による 10進カウンタ ブロック図

ゲート組み合わせ回路は、4ビット加算器の出力 S[0-3] を入力し、D[0-3] を出力してストレージレジスタに渡します。
アップカウンタとダウンカウンタとでは、ゲート組み合わせ回路の動作が異なりますので、切換信号 UD も入れて、アップダウンを切り換えてやりましょう。UD は加算器のアップダウンの切り換えをしている A[3] の信号を使うことができます。

その他のブロックに変更はありません。

真理値表と論理式

図 2. 10進カウンタ ゲート組み合わせ回路 真理値表

ゲート組み合わせ回路の真理値表です。
できあがってしまえばなんでもない真理値表ですが、ここはちょっといろいろ、悩みました。

まず、UD=0、アップカウンタの場合です。

初期状態のストレージレジスタの出力 Q は 0x0 で、加算器の入力 B に入ります。入力 A は アップカウンタのとき 0x1。したがって、加算器の出力 S は 0x1 になります。このときのゲート出力 D は 0x1、ストレージレジスタでラッチされ、出力 Q が 0x1 にカウントアップします。
すると、加算器の出力 S は 0x2 になるので、Q=0x2 とさらにカウントアップする。
こうしてカウントアップしていき、Q=0x9 になると S=0xA になる。このときにゲート組み合わせ回路により D=0x0 にすることで、Q=0x0 に戻ります。

次に、UD=1、ダウンカウンタの場合。

加算器は A=0xF を加算しますので、Q=0x0 のとき S=0xF になります。このときに、ゲート組み合わせ回路により D=0x9 とします。すると、S=0x8 となるので D=0x8 とする。出力は Q=0x8 にカウントダウンします。
こうしてカウントダウンしていき、Q=0x0 になると、S=0xF、D=0x9 と戻っていきます。

通常は加算器の出力をそのままストレージレジスタへ送るけど、0xA のとき、または0xF のとき、値を変化させてやる、という動きです。

真理値表より求めた論理式は、

D3 = S3 ( S1 + UD )
D2 = S3 ⋅ S2
D1 = S3 ⋅ S1
D0 = S0

となりました。

ゲート組み合わせ回路

図 3. ゲート組み合わせ回路図

論理式を基に、回路を作りました。

各ブロック内の未使用ゲートで作れちゃう回路です。が、ブレッドボードで組むときは、できるだけブロックごとにしておきたいので、別途ゲート IC を用意しようと思います。

VerilogHDL によるシミュレーション

回路を組む前に、ちゃちゃっとシミュレーションで確認しておきましょう。

回路記述

  1. module COUNTER_BY_ADDER_MOD10(
  2.   input wire CK, RST,
  3.   output reg [3:0] Q
  4. );
  5.   wire [3:0] S, D;
  6.   parameter [3:0] A = 4'b0001;
  7.   assign D[3] = S[3] & (~S[1] | A[3]);
  8.   assign D[2] = ~S[3] & S[2];
  9.   assign D[1] = ~S[3] & S[1];
  10.   assign D[0] = S[0];
  11.   always @(posedge CK or negedge RST) begin
  12.     if(1'b0 == RST)
  13.       Q <= 4'b0;
  14.     else
  15.       Q <= D;
  16.   end
  17.   assign S = A + Q;
  18. endmodule

ゲート組み合わせ回路は、論理式で記述しました。

テストベンチ

  1. module COUNTER_BY_ADDER_MOD10_TEST;
  2.   reg CK, RST;
  3.   wire [3:0] Q;
  4.   parameter STEP = 10;
  5.   COUNTER_BY_ADDER_MOD10 #(4'b0001) COUNTER_BY_ADDER_MOD10(CK, RST, Q);
  6.   always begin
  7.     CK = 0; #(STEP/2);
  8.     CK = 1; #(STEP/2);
  9.   end
  10.   initial begin
  11.     RST = 0; #STEP;
  12.     RST = 1; #(STEP*25);
  13.     RST = 0; #STEP;
  14.     $finish;
  15.   end
  16.   initial begin
  17.     $dumpfile("counter_by_adder_mod10.vcd");
  18.     $dumpvars(0, COUNTER_BY_ADDER_MOD10_TEST);
  19.   end
  20. endmodule

アップカウンタ、ダウンカウンタの切り換えは、パラメータ割り当てで行なっています。コンパイルしなおさないといけないので、テストベンチのなかで切り換えてもいいですね。

シミュレーション結果

図 4. 10進アップカウンタ シミュレーション結果

アップカウンタのシミュレーション結果です。

S=0xA のときに、D=0x0 となっています。

図 5. 10進ダウンカウンタ シミュレーション結果

ダウンカウンタのシミュレーション結果です。

こちらでは、S=0xF のときに D=0x9 となっています。

シミュレーションの結果は、設計通りになっているようです。

ブレッドボードのようす

図 6. ブレッドボードのようす

ということで、実際にゲート組み合わせ回路を追加しました。いちばん下のブレッドボードの右側部分です。
動画じゃないんで LEDバーの表示の動きがわかりませんが、ちゃんとカウントしています。

左下の押しボタンスイッチ START/STOP を押すたびに、カウンタが動作・停止します。停止後の再開は、カウント値を継続します。
また、Up-Down 切り替えスイッチを押すと、アップカウンタ、ダウンカウンタが切り換わります。動作中でも、停止中でも切り換わります。
まぁ、ユーザーインターフェースは、用途に応じてどのようにでも。

製作後記

加算器のおさらいからの派生で、カウンタ回路を作ってみました。こんな方法もあるよってことで。

加算器に関しては、桁上げ先見加算器とか、演算速度をあげる方法もあるんで、そうしたものもやってみる価値はあるかもしれないです。でも、加算を含めた演算処理に関しては、Arduino などを使うほうが現実的だよねぇって気がする。
かといって、なにもかも Arduino に頼るってもの現実的じゃないと思うわけで、なにをどっちでやらせるか、まぁそのときの状況に応じてですわな。

タイトルとURLをコピーしました