北郵22信通一枚~
跟隨課程進(jìn)度更新北郵信通院數(shù)字系統(tǒng)設(shè)計的筆記、代碼和文章
持續(xù)關(guān)注作者 迎接數(shù)電實(shí)驗(yàn)學(xué)習(xí)~
獲取更多文章,請?jiān)L問專欄:
北郵22級信通院數(shù)電實(shí)驗(yàn)_青山如墨雨如畫的博客-CSDN博客
目錄
一.代碼部分
1.1? counter_24.v
1.2? divide.v
1.3? debounce.v
二.管腳分配
三.實(shí)驗(yàn)效果
一.代碼部分
1.1? counter_24.v
module counter_24
(
input clk,rst,hold,
output [8:0] seg_led_1,
output [8:0] seg_led_2,
output reg [7:0] led
);
wire clk_lh;
wire hold_pulse;
reg hold_flag;
reg back_to_zero_flag;
reg [6:0] seg [16:0];
reg [3:0] cnt_ge;
reg [3:0] cnt_shi;
initial
begin
seg[0] = 7'h3f;
seg[1] = 7'h06;
seg[2] = 7'h5b;
seg[3] = 7'h4f;
seg[4] = 7'h66;
seg[5] = 7'h6d;
seg[6] = 7'h7d;
seg[7] = 7'h07;
seg[8] = 7'h7f;
seg[9] = 7'h6f;
seg[10] = 7'hf7;
seg[11] = 7'h7c;
seg[12] = 7'h39;
seg[13] = 7'h5e;
seg[14] = 7'h79;
seg[15] = 7'h71;
end
debounce debounce_1
(
.clk(clk),
.rst(rst),
.key(hold),
.key_pulse(hold_pulse)
);
divide # (.WIDTH(32),.N(12000000)) divide_1
(
.clk(clk),
.rst_n(rst),
.clkout(clk_lh)
);
always @ (posedge hold_pulse)
if(!rst==1)
hold_flag <= 0;
else
hold_flag <= ~hold_flag;
always @ (*)
if(!rst==1)
back_to_zero_flag <= 0;
else if( cnt_shi==0 && cnt_ge==0)
back_to_zero_flag <= 1;
else
back_to_zero_flag <= 0;
always @ (posedge clk_lh or negedge rst)
begin
if(!rst==1)
begin
cnt_ge <= 4'd4;
cnt_shi <=4'd2;
end
else if(hold_flag==1)
begin
cnt_ge <= cnt_ge;
cnt_shi <= cnt_shi;
end
else if(cnt_shi==0 && cnt_ge==0)
begin
cnt_shi <= cnt_shi;
cnt_ge <=cnt_ge;
end
else if(cnt_ge==0)
begin
cnt_ge <=4'd9;
cnt_shi <= cnt_shi-1;
end
else
begin cnt_ge <= cnt_ge-1; end
end
//計時完成點(diǎn)亮led
always @ (back_to_zero_flag)
begin
if(back_to_zero_flag == 1)
led = 8'b0;
else
led = 8'b1111_1111;
end
assign seg_led_1[8:0] = {2'b00,seg[cnt_ge]};
assign seg_led_2[8:0] = {2'b00,seg[cnt_shi]};
endmodule
1.2? divide.v
module divide ( clk,rst_n,clkout);
input clk,rst_n; //輸入信號,其中clk連接到FPGA的C1腳,頻率為12MHz
output clkout; //輸出信號,可以連接到LED觀察分頻的時鐘
//parameter是verilog里常數(shù)語句
parameter WIDTH = 3; //計數(shù)器的位數(shù),計數(shù)的最大值為 2**WIDTH-1
parameter N = 5; //分頻系數(shù),請確保 N < 2**WIDTH-1,否則計數(shù)會溢出
reg [WIDTH-1:0] cnt_p,cnt_n; //cnt_p為上升沿觸發(fā)時的計數(shù)器,cnt_n為下降沿觸發(fā)時的計數(shù)器
reg clk_p,clk_n; //clk_p為上升沿觸發(fā)時分頻時鐘,clk_n為下降沿觸發(fā)時分頻時鐘
//上升沿觸發(fā)時計數(shù)器的控制
always @ (posedge clk or negedge rst_n ) //posedge和negedge是verilog表示信號上升沿和下降沿
//當(dāng)clk上升沿來臨或者rst_n變低的時候執(zhí)行一次always里的語句
begin
if(!rst_n)
cnt_p<=0;
else if (cnt_p==(N-1))
cnt_p<=0;
else cnt_p<=cnt_p+1; //計數(shù)器一直計數(shù),當(dāng)計數(shù)到N-1的時候清零,這是一個模N的計數(shù)器
end
//上升沿觸發(fā)的分頻時鐘輸出,如果N為奇數(shù)得到的時鐘占空比不是50%;如果N為偶數(shù)得到的時鐘占空比為50%
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
clk_p<=0;
else if (cnt_p<(N>>1)) //N>>1表示右移一位,相當(dāng)于除以2去掉余數(shù)
clk_p<=0;
else
clk_p<=1; //得到的分頻時鐘正周期比負(fù)周期多一個clk時鐘
end
//下降沿觸發(fā)時計數(shù)器的控制
always @ (negedge clk or negedge rst_n)
begin
if(!rst_n)
cnt_n<=0;
else if (cnt_n==(N-1))
cnt_n<=0;
else cnt_n<=cnt_n+1;
end
//下降沿觸發(fā)的分頻時鐘輸出,和clk_p相差半個時鐘
always @ (negedge clk)
begin
if(!rst_n)
clk_n<=0;
else if (cnt_n<(N>>1))
clk_n<=0;
else
clk_n<=1; //得到的分頻時鐘正周期比負(fù)周期多一個clk時鐘
end
assign clkout = (N==1)?clk:(N[0])?(clk_p&clk_n):clk_p; //條件判斷表達(dá)式
//當(dāng)N=1時,直接輸出clk
//當(dāng)N為偶數(shù)也就是N的最低位為0,N(0)=0,輸出clk_p
//當(dāng)N為奇數(shù)也就是N最低位為1,N(0)=1,輸出clk_p&clk_n。正周期多所以是相與
endmodule
1.3? debounce.v
module debounce (clk,rst,key,key_pulse);
parameter N = 1; //要消除的按鍵的數(shù)量
input clk;
input rst;
input [N-1:0] key; //輸入的按鍵
output [N-1:0] key_pulse; //按鍵動作產(chǎn)生的脈沖
reg [N-1:0] key_rst_pre; //定義一個寄存器型變量存儲上一個觸發(fā)時的按鍵值
reg [N-1:0] key_rst; //定義一個寄存器變量儲存儲當(dāng)前時刻觸發(fā)的按鍵值
wire [N-1:0] key_edge; //檢測到按鍵由高到低變化是產(chǎn)生一個高脈沖
//利用非阻塞賦值特點(diǎn),將兩個時鐘觸發(fā)時按鍵狀態(tài)存儲在兩個寄存器變量中
always @(posedge clk or negedge rst)
begin
if (!rst) begin
key_rst <= {N{1'b1}}; //初始化時給key_rst賦值全為1,{}中表示N個1
key_rst_pre <= {N{1'b1}};
end
else begin
key_rst <= key; //第一個時鐘上升沿觸發(fā)之后key的值賦給key_rst,
//同時key_rst的值賦給key_rst_pre
key_rst_pre <= key_rst; //非阻塞賦值。
//相當(dāng)于經(jīng)過兩個時鐘觸發(fā),
//key_rst存儲的是當(dāng)前時刻key的值,
//key_rst_pre存儲的是前一個時鐘的key的值
end
end
assign key_edge = key_rst_pre & (~key_rst);//脈沖邊沿檢測。
//當(dāng)key檢測到下降沿時,
//key_edge產(chǎn)生一個時鐘周期的高電平
reg [17:0] cnt; //產(chǎn)生延時所用的計數(shù)器,系統(tǒng)時鐘12MHz,
//要延時20ms左右時間,至少需要18位計數(shù)器
//產(chǎn)生20ms延時,當(dāng)檢測到key_edge有效是計數(shù)器清零開始計數(shù)
always @(posedge clk or negedge rst)
begin
if(!rst)
cnt <= 18'h0;
else if(key_edge)
cnt <= 18'h0;
else
cnt <= cnt + 1'h1;
end
reg [N-1:0] key_sec_pre; //延時后檢測電平寄存器變量
reg [N-1:0] key_sec;
//延時后檢測key,如果按鍵狀態(tài)變低產(chǎn)生一個時鐘的高脈沖。如果按鍵狀態(tài)是高的話說明按鍵無效
always @(posedge clk or negedge rst)
begin
if (!rst)
key_sec <= {N{1'b1}};
else if (cnt==18'h3ffff)
key_sec <= key;
end
always @(posedge clk or negedge rst)
begin
if (!rst)
key_sec_pre <= {N{1'b1}};
else
key_sec_pre <= key_sec;
end
assign key_pulse = key_sec_pre & (~key_sec);
endmodule
二.管腳分配
三.實(shí)驗(yàn)效果
數(shù)碼管顯示24秒倒計時,倒計時結(jié)束后所有LED燈亮起。文章來源:http://www.zghlxwxcb.cn/news/detail-761400.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-761400.html
到了這里,關(guān)于北郵22級信通院數(shù)電:Verilog-FPGA(11)第十一周實(shí)驗(yàn)(2)設(shè)計一個24秒倒計時器的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!