回路を書いて動作を確認する
📌 このページの概要と目標
概要: いよいよ仕上げのユニットです。電子錠回路を例に、設計の一連の手順を学習します。
目標:
- 電子錠の仕様を理解し、内部ブロック構成を設計できる
- 立ち上がり検出回路を記述できる
- 10to4エンコーダ回路を記述できる
- 4ビット×4段シフトレジスタを記述できる
- 一致比較回路を記述できる
- 錠出力保持回路を記述できる
1. 電子錠回路の概要
Cシリーズの集大成!マンションのオートロックみたいな「電子錠」の回路を作ってみるよ🐾
これまで学んだ組み合わせ回路と順序回路を全部合体させて、一つのシステムを完成させよう!
このユニットでは電子錠の回路を例に、設計の一連の手順を学習します。電子錠はマンションのオートロックなどでよく見かけます。暗証番号を入力して錠を開くため、鍵が不要です。
💡 電子錠の動作概要
- テンキーにより暗証番号「5、9、6、3」を順番に入力
- 正しい4桁が入力された場合 → 電子錠が開く(LOCK=0)
- 誤った番号(例:「1、2、3、4」)を入力した場合 → 電子錠は開かない
- ロックキー(CLOSE)を押すと → 電子錠が閉じる(LOCK=1)
- ここで説明する電子錠は簡易版(暗証番号の設定機能・表示部は省略)
2. 仕様と入出力端子表
| 信号名 | 方向 | ビット幅 | 機能 |
|---|---|---|---|
CLK | 入力 | 1 | 動作クロック |
TENKEY[9:0] | 入力 | 10 | テンキー入力(0〜9の各キーに対応) |
CLOSE | 入力 | 1 | ロックキー(1のとき錠を閉じる) |
LOCK | 出力 | 1 | 錠の状態(1=施錠、0=解錠) |
3. 内部ブロック構成
電子錠の内部ブロックは以下の5つで構成します。
| ブロック名 | 回路種別 | 機能 |
|---|---|---|
| ① 立ち上がり検出 | 順序回路 | TENKEYの立ち上がりを検出し、1クロック分の1パルスを出力 |
| ② エンコーダ | 組み合わせ回路 | TENKEY[9:0](10ビット)→ 4ビット2進数に変換 |
| ③ 暗証番号入力レジスタ | 順序回路(シフトレジスタ) | 4ビット×4段のシフトレジスタで入力順に番号を格納 |
| ④ 一致比較 | 組み合わせ回路 | シフトレジスタの値と設定暗証番号を比較し、一致でMATCH=1 |
| ⑤ 電子錠出力 | 順序回路(FF) | MATCH=1で開状態を保持、CLOSE=1で閉状態に戻す |
4. ① 立ち上がり検出回路
ボタンを押したとき、人間にとっては「一瞬」でも、回路から見たら「何万クロックも押しっぱなし」状態なんだ🐾
だから、押された瞬間の「1クロックだけ」を切り取るエッジ検出が絶対に必要なんだよ!
TENKEYのいずれかのキーが押されたとき(立ち上がり)を検出し、CLKの1周期の間だけ1を出力する回路です。この信号を使ってエンコーダ出力を1桁ずつシフトレジスタに入力します。
// 立ち上がり検出: TENKEYの論理和の立ち上がりを1CLK分のパルスに変換
// TENKEY_OR: 10ビットTENKEYのOR(いずれか1つでも押されたら1)
wire TENKEY_OR;
assign TENKEY_OR = |TENKEY; // リダクションOR演算子
reg TENKEY_DLY;
wire PULSE;
// 1クロック遅延させてエッジ検出
always @( posedge CLK or negedge RB )
begin
if ( RB == 1'b0 )
TENKEY_DLY <= 1'b0;
else
TENKEY_DLY <= TENKEY_OR;
end
// PULSE: 現在は1、1クロック前は0 → 立ち上がりエッジを検出
assign PULSE = TENKEY_OR & ~TENKEY_DLY;
💡 立ち上がり検出の原理
TENKEY_OR:TENKEYの10ビットをリダクションOR → いずれか押されたら1TENKEY_DLY:TENKEY_ORを1クロック遅延させた信号PULSE = TENKEY_OR & ~TENKEY_DLY:現在=1、前=0 → 立ち上がりのみ1クロック分の1を出力
5. ② エンコーダ回路
TENKEY[9:0](10ビット)を4ビットの2進数に変換します。10ビットのまま記憶すると回路規模が大きくなるため、4ビットに変換してシフトレジスタに格納します。
// エンコーダ: 10ビットTENKEY → 4ビット2進数
function [3:0] ENCODE;
input [9:0] key;
begin
case ( key )
10'b0000000001: ENCODE = 4'd0; // キー0
10'b0000000010: ENCODE = 4'd1; // キー1
10'b0000000100: ENCODE = 4'd2; // キー2
10'b0000001000: ENCODE = 4'd3; // キー3
10'b0000010000: ENCODE = 4'd4; // キー4
10'b0000100000: ENCODE = 4'd5; // キー5
10'b0001000000: ENCODE = 4'd6; // キー6
10'b0010000000: ENCODE = 4'd7; // キー7
10'b0100000000: ENCODE = 4'd8; // キー8
10'b1000000000: ENCODE = 4'd9; // キー9
default: ENCODE = 4'd0;
endcase
end
endfunction
wire [3:0] ENC_OUT;
assign ENC_OUT = ENCODE( TENKEY );
6. ③ 暗証番号入力レジスタ
4ビット×4段のシフトレジスタに、キー入力のたびにエンコーダ出力を格納します。最新の4桁が常にREG[0]〜REG[3]に保持されます。
// 4ビット×4段シフトレジスタ
reg [3:0] REG [3:0]; // REG[0]〜REG[3]: 4段の4ビットレジスタ配列
always @( posedge CLK or negedge RB )
begin
if ( RB == 1'b0 ) begin
REG[0] <= 4'd0;
REG[1] <= 4'd0;
REG[2] <= 4'd0;
REG[3] <= 4'd0;
end
else if ( PULSE == 1'b1 ) begin
// PULSEが1のとき(キー押下検出時)にシフト
REG[3] <= REG[2]; // 古い値を上位にシフト
REG[2] <= REG[1];
REG[1] <= REG[0];
REG[0] <= ENC_OUT; // 最新の入力をREG[0]に格納
end
end
💡 シフトレジスタの動作
「5→9→6→3」の順で入力された場合:
| 入力順 | REG[3] | REG[2] | REG[1] | REG[0] |
|---|---|---|---|---|
| 「5」入力後 | — | — | — | 5 |
| 「9」入力後 | — | — | 5 | 9 |
| 「6」入力後 | — | 5 | 9 | 6 |
| 「3」入力後 | 5 | 9 | 6 | 3 |
7. ④ 一致比較回路
シフトレジスタの値と設定暗証番号「5、9、6、3」を比較し、4桁すべて一致した場合にMATCH=1を出力します。
// 一致比較: 暗証番号 = 5, 9, 6, 3(REG[3]が最初, REG[0]が最後)
wire MATCH;
assign MATCH = ( REG[3] == 4'd5 ) &
( REG[2] == 4'd9 ) &
( REG[1] == 4'd6 ) &
( REG[0] == 4'd3 );
8. ⑤ 電子錠出力回路
MATCH=1で解錠状態を保持し、CLOSE=1で施錠状態に戻す回路です。
// 電子錠出力: LOCK=1が施錠、LOCK=0が解錠
reg LOCK;
always @( posedge CLK or negedge RB )
begin
if ( RB == 1'b0 )
LOCK <= 1'b1; // リセット → 施錠状態
else if ( CLOSE == 1'b1 )
LOCK <= 1'b1; // CLOSE=1 → 施錠
else if ( MATCH == 1'b1 )
LOCK <= 1'b0; // MATCH=1 → 解錠
// それ以外 → LOCKの値を保持(変化なし)
end
9. 回路記述全体(解答例)
module ELECTRONIC_LOCK ( CLK, RB, TENKEY, CLOSE, LOCK );
input CLK, RB, CLOSE;
input [9:0] TENKEY;
output LOCK;
reg LOCK;
// ---- ① エンコーダ(function)----
function [3:0] ENCODE;
input [9:0] key;
begin
case ( key )
10'b0000000001: ENCODE = 4'd0;
10'b0000000010: ENCODE = 4'd1;
10'b0000000100: ENCODE = 4'd2;
10'b0000001000: ENCODE = 4'd3;
10'b0000010000: ENCODE = 4'd4;
10'b0000100000: ENCODE = 4'd5;
10'b0001000000: ENCODE = 4'd6;
10'b0010000000: ENCODE = 4'd7;
10'b0100000000: ENCODE = 4'd8;
10'b1000000000: ENCODE = 4'd9;
default: ENCODE = 4'd0;
endcase
end
endfunction
// ---- ② 立ち上がり検出 ----
wire TENKEY_OR;
reg TENKEY_DLY;
wire PULSE;
assign TENKEY_OR = |TENKEY;
always @( posedge CLK or negedge RB )
begin
if ( RB == 1'b0 ) TENKEY_DLY <= 1'b0;
else TENKEY_DLY <= TENKEY_OR;
end
assign PULSE = TENKEY_OR & ~TENKEY_DLY;
// ---- ③ エンコーダ出力 ----
wire [3:0] ENC_OUT;
assign ENC_OUT = ENCODE( TENKEY );
// ---- ④ 暗証番号入力レジスタ(4ビット×4段シフトレジスタ)----
reg [3:0] REG [3:0];
always @( posedge CLK or negedge RB )
begin
if ( RB == 1'b0 ) begin
REG[0] <= 4'd0; REG[1] <= 4'd0;
REG[2] <= 4'd0; REG[3] <= 4'd0;
end
else if ( PULSE == 1'b1 ) begin
REG[3] <= REG[2];
REG[2] <= REG[1];
REG[1] <= REG[0];
REG[0] <= ENC_OUT;
end
end
// ---- ⑤ 一致比較 ----
wire MATCH;
assign MATCH = ( REG[3] == 4'd5 ) &
( REG[2] == 4'd9 ) &
( REG[1] == 4'd6 ) &
( REG[0] == 4'd3 );
// ---- ⑥ 電子錠出力 ----
always @( posedge CLK or negedge RB )
begin
if ( RB == 1'b0 ) LOCK <= 1'b1;
else if ( CLOSE == 1'b1 ) LOCK <= 1'b1;
else if ( MATCH == 1'b1 ) LOCK <= 1'b0;
end
endmodule
⚠️ 設計上の重要ポイント
- PULSE(立ち上がり検出)を使わないとキーを押している間ずっとシフトが発生してしまう
- リダクションOR演算子
|TENKEYで10ビットの論理ORを1行で記述できる - LOCK出力の優先順位:リセット → CLOSE(施錠) → MATCH(解錠) → 保持
- シフトレジスタにはノンブロッキング代入(
<=)を使うこと
📝 C8 まとめ: 回路記述と動作確認(電子錠)
| ブロック | 回路種別 | 記述方法 |
|---|---|---|
| エンコーダ(10→4ビット変換) | 組み合わせ | function + case文 |
| 立ち上がり検出(1CLKパルス) | 順序 | always + assign(遅延&エッジ検出) |
| 暗証番号レジスタ(4×4シフト) | 順序 | reg配列 + always(PULSE制御) |
| 一致比較(4桁照合) | 組み合わせ | assign(&演算の連結) |
| 錠出力(状態保持) | 順序 | always(CLOSE/MATCH優先順位) |
