Ch8 應用範例
8.1 按鍵防彈跳
程式( 防彈跳 ):
module KEY_Debounce( CLK, RST, KEY_In, KEY_Out );
parameter DeB_Num = 4; // 取樣次數
parameter DeB_SET = 4'b0000; // 設置
parameter DeB_RST = 4'b1111; // 重置
input CLK, RST;
input KEY_In;
output KEY_Out;
reg KEY_Out = 1'b1;
reg [DeB_Num-1:0] Bounce = 4'b1111; // 初始化
always @( posedge CLK, negedge RST ) begin // 一次約200Hz 5ms
if( !RST )
Bounce <= DeB_RST; // Bounce重置
else begin // 取樣4次
integer i;
Bounce[0] <= KEY_In;
for( i=0; i<DeB_Num-1; i=i+1 )
Bounce[i+1] <= Bounce[i];
end
case( Bounce )
DeB_SET: KEY_Out <= 1'b0;
default: KEY_Out <= 1'b1;
endcase
end
endmodule
8.2 除頻器
程式( 除頻器 50MHz to 1kHz ):
module Freq_Divider( CLK, RST, CLK_Out ); /* 除頻器 Use 50MHz OSC */
// 除頻設定 1kHz 1ms
Parameter Div = 16'd50_000; // 除頻數(Even)
parameter Div2 = 16'd25_000; // Div/2
parameter DivW = 16; // Divide寬度
input CLK, RST;
output CLK_Out;
reg rCLK_Out;
reg [DivW-1:0] CLK_Cnt = 0;
always @( posedge CLK, negedge RST ) begin
if( !RST )
CLK_Cnt <= 0;
else if( CLK_Cnt == Div-1 )
CLK_Cnt <= 0;
else
CLK_Cnt <= CLK_Cnt + 1'b1;
end
always @( posedge CLK or negedge RST ) begin
if( !RST )
CLK_Out <= 0;
else if( CLK_Cnt <= Div2-1 )
CLK_Out = 0;
else
CLK_Out = 1'b1;
end
endmodule
8.3 LED流水燈
程式( 流水燈 ):
module LED_Water( CLK, RST, LED_Out );
input CLK, RST;
output [3:0] LED_Out;
reg [23:0] Delay_Count = 24'd0; // USE 50MHz OSC
reg [3:0] LED_State = 4'b0001;
always @( posedge CLK, negedge RST ) begin
if( !RST ) begin
Delay_Count <= 24'd0;
LED_State <= 4'b0001;
end
else if( Delay_Count == 24'd25_000_000 ) begin // 500ms
Delay_Count <= 24'd0;
if( LED_State == 4'b0000 )
LED_State <= 4'b0001;
else
LED_State <= LED_State << 1;
end
else
Delay_Count <= Delay_Count + 1'b1;
end
assign LED_Out = ~LED_State;
endmodule
8.4 掃描鍵盤
程式( 掃描鍵盤 ):
/* 掃描鍵盤 KEY_Row讀取, KEY_Col掃描 */
module KEY_Scan( CLK, RST, KEY_Row, KEY_Col, KEY );
/* STATE */
parameter Col_1 = 4'b1110;
parameter Col_2 = 4'b1101;
parameter Col_3 = 4'b1011;
parameter Col_4 = 4'b0111;
input CLK, RST;
input [3:0] KEY_Row;
output [3:0] KEY_Col;
output [15:0] KEY;
reg [15:0] KEY = 16'h0000;
reg [3:0] KEY_Col = Col_1;
always @( posedge CLK, negedge RST ) begin
if( !RST ) begin
KEY <= 16'b0;
KEY_Col <= Col_1;
End
else begin
case( KEY_Col )
Col_1: begin
KEY[3:0] <= KEY_Row;
KEY_Col <= Col_2;
end
Col_2: begin
KEY[7:4] <= KEY_Row;
KEY_Col <= Col_3;
end
Col_3: begin
KEY[11:8] <= KEY_Row;
KEY_Col <= Col_4;
end
Col_4: begin
KEY[15:12] <= KEY_Row;
KEY_Col <= Col_1;
end
default: KEY_Col <= Col_1;
endcase
end
end
endmodule
8.5 計數器 ( 七段顯示器 )
程式( Top_Module ):
module Top_Module( CLK, RST,SEL_Out, DIG_Out );
input CLK, RST;
output [5:0] SEL_Out;
output [7:0] DIG_Out;
wire [3:0] Cnt_Up;
wire CLK_1Hz;
Freq_Divider Freq_Div_1Hz(
.CLK(CLK),
.RST(RST),
.CLK_Out(CLK_1Hz)
);
Counter_Up Counter_Up(
.CLK(CLK_1Hz),
.RST(RST),
.Cnt(Cnt_Up)
);
Seg_Seven DIG_SEG(
.SEL_In(Cnt_Up),
.DIG_In(Cnt_Up),
.SEL_Out(SEL_Out),
.DIG_Out(DIG_Out)
);
endmodule
程式( 除頻 1MHz ):
/* 除頻器 Use 50MHz OSC */
module Freq_Divider( CLK, RST, CLK_Out );
input CLK, RST;
output CLK_Out;
reg CLK_Out;
reg [DivW-1:0] CLK_Cnt = 0;
// 除頻設定 1Hz 1s
parameter Div = 26'd50_000_000; // 除頻數(Even)
parameter Div2 = 26'd25_000_000; // Div/2
parameter DivW = 26; // Divide寬度
always @( posedge CLK,negedge RST ) begin
if( !RST )
CLK_Cnt <= 0;
else if( CLK_Cnt == Div-1 )
CLK_Cnt <= 0;
else
CLK_Cnt <= CLK_Cnt + 1'b1;
end
always @( posedge CLK,negedge RST ) begin
if( !RST )
CLK_Out <= 0;
else if( CLK_Cnt <= Div2-1 )
CLK_Out <= 0;
else
CLK_Out <= 1'b1;
end
endmodule
程式( 上數計數器 ):
/* 上數計數器 */
module Counter_Up( CLK, RST, Cnt );
/* 計數資訊 */
parameter Cnt_SB = 4; // 計數寬度
parameter Cnt_UP = 1'b1; // 計數值
parameter Cnt_Min = 4'd0; // 計數最小值
parameter Cnt_Max = 4'd8; // 計數最大值
input CLK, RST;
output [Cnt_SB-1:0] Cnt;
reg [Cnt_SB-1:0] Cnt = Cnt_Min;
always @( posedge CLK or negedge RST ) begin
if( !RST )
Cnt <= Cnt_Min;
else if( Cnt == Cnt_Max )
Cnt <= Cnt_Min;
else
Cnt <= Cnt + Cnt_UP;
end
endmodule
程式( 七段顯示器解碼 ):
/* 七段顯示器解碼(共陽) */
module Seg_Seven( SEL_In, DIG_In, SEL_Out, DIG_Out );
input [2:0] SEL_In; // Use PNP
input [3:0] DIG_In; // MSB D, C, B, A LSB
output [5:0] SEL_Out; // 七段顯示器選擇
output [7:0] DIG_Out; // MSB dp, g, f, e, d, c, b, a LSB
reg [5:0] SEL_Out;
reg [7:0] DIG_Out;
always @( SEL_In ) begin
case( SEL_In )
3'b000: SEL_Out <= 6'b000000; // all on
3'b001: SEL_Out <= 6'b111110; // 1
3'b010: SEL_Out <= 6'b111101; // 2
3'b011: SEL_Out <= 6'b111011; // 3
3'b100: SEL_Out <= 6'b110111; // 4
3'b101: SEL_Out <= 6'b101111; // 5
3'b110: SEL_Out <= 6'b011111; // 6
3'b111: SEL_Out <= 6'b111111; // all off
endcase
end
always @( DIG_In ) begin
case( DIG_In )
4'b0000: DIG_Out <= 8'b11000000; // 0
4'b0001: DIG_Out <= 8'b11111001; // 1
4'b0010: DIG_Out <= 8'b10100100; // 2
4'b0011: DIG_Out <= 8'b10110000; // 3
4'b0100: DIG_Out <= 8'b10011001; // 4
4'b0101: DIG_Out <= 8'b10010010; // 5
4'b0110: DIG_Out <= 8'b10000011; // 6
4'b0111: DIG_Out <= 8'b11111000; // 7
4'b1000: DIG_Out <= 8'b10000000; // 8
4'b1001: DIG_Out <= 8'b10010000; // 9
4'b1010: DIG_Out <= 8'b01111111; // dp
default: DIG_Out <= 8'b11111111; // off
endcase
end
endmodule