最近在做數電研究,題目為數字頻率計,要求用FPGA板子設計,為了能使51黑電子論壇能發展的更好,我也貢獻我的一份力量,希望能幫到各位。
原理:測量1s時間內待測脈沖個數從而得出待測信號的頻率。
具體模塊:
基準信號產生模塊:把50MHz分頻成1Hz
控制模塊:產生計數使能信號;產生清零信號;
計數模塊:通過從控制模塊輸入進來的使能信號和清零信號能從0000~1001計數(8421碼),并能產生進位;
鎖存模塊:把計數結果鎖存;使顯示模塊能穩定顯示結果
顯示模塊:通過數碼管顯示,位選是用的外部電路138譯碼器,段選是一個四位二進制碼(8421碼)
待測信號:由于本人沒有函數信號發生器所以就把50MHz分成900Hz作為待測信號來驗證該系統能否正確測量,也可以把該模塊刪掉,把輸出口接一個input,就可以測量外部信號了,
由于板子資源有限,而我的程序有點復雜,不是很簡潔,所以只能顯示四位結果,即量程為0~9999Hz。板子上有8位數碼管,理論上可以顯示8位結果,即量程為0~99999999Hz。另外我準備用modelsim仿真各個模塊,在我仿真完控制模塊后遇到了問題,其他幾個模塊仿真不出來,只有控制模塊可以仿真,其他幾個寫了激勵信號,而且都賦了初值,但是輸出結果一直是高阻態(顯示紅線),希望各位朋友能教教我(本人不怎么會用modelsim)
38]E7N6BZF22`N0)5Y%UD00.png (8.03 KB, 下載次數: 117)
下載附件
頂層
2019-6-25 19:04 上傳
源程序:
- //控制模塊
- module fre_ctrl(clk,rst,count_en,count_clr,load);
- input clk,rst;
- output count_en,count_clr,load;
- reg count_en=0;
- reg load=0;
- always@(posedge clk)
- begin if(rst)begin count_en<=0;load<=1;end
- else begin count_en<=~count_en;
- load<=count_en;
- end
- end
- assign count_clr=(~clk)&load;
- endmodule
- //計數模塊
- module count10(out,cout,en,clr,clk);
- input en,clr,clk;
- output[3:0] out;
- output cout;
- reg[3:0] out;
- always @(negedge clk or posedge clr)
- begin if(clr) out<=0;//計數清零
- else if(en)
- begin if(out==9)
- out=0;
- else out<=out+1;//計數
- end
- end
- assign cout=((out==9)&en)?1:0;
- endmodule
- //鎖存模塊
- module latch_16(qo,din,load);
- input load;
- input[15:0] din;
- output [15:0] qo;
- reg[15:0] qo;
- always @(posedge load)
- begin qo=din;end
- endmodule
- //1Hz基準信號產生模塊(該模塊是我在網上找的,可以把50MHz分成任意小于50M的頻率)
- module div_N(
- input CLK,// 基準時鐘
- output CLK_div_N// N分頻后得到的時鐘
- );
- wire[31:0]N=50000000;// N為分頻系數,N≥2即可,N的值為CLK除以CLK_div_N后取整(四舍五入)
- /******************** 產生備用時鐘1 ***************/
- reg[31:0]cnt1;
- reg CLK_div_N_1;
- always @ (posedge CLK)
- begin
- if(N%2==0)// 如果N為偶數
- begin
- if(N==2)// 如果N為2
- CLK_div_N_1 <= ~CLK_div_N_1;
- else
- begin
- if(cnt1==(N-2)/2)
- begin
- cnt1 <= 0;
- CLK_div_N_1 <= ~CLK_div_N_1;
- end
- else
- cnt1 <= cnt1+1;
- end
- end
- else// 如果N為奇數
- begin
- if(cnt1==N-1)
- cnt1 <= 0;
- else
- cnt1 <= cnt1+1;
- if((cnt1==N-1) || (cnt1==(N-1)/2))
- CLK_div_N_1 <= ~CLK_div_N_1;
- else ;
- end
- end
- /*********************** 產生備用時鐘2 *********************/
- wire CLK0=(N%2)? (~CLK):0;// 如果N為偶數,備用時鐘2(CLK_div_N_2)恒為0,即不需要用到此備用時鐘
- reg[31:0]cnt2;
- reg CLK_div_N_2;
- always @ (posedge CLK0)
- begin
- if(cnt2==N-1)
- cnt2 <= 0;
- else
- cnt2 <= cnt2+1;
- if((cnt2==N-1) || (cnt2==(N-1)/2))
- CLK_div_N_2 <= ~CLK_div_N_2;
- end
- /******************** 產生最終分頻時鐘************************/
- assign CLK_div_N = CLK_div_N_1 | CLK_div_N_2;
- endmodule
- //待測信號(本人設置的輸出900Hz)
- module square(nrst,clk_in,clk_out);
- input wire nrst;
- input wire clk_in;
- output reg clk_out;
- reg [18:0]r_cnt;
- always @(posedge clk_in)
- if(nrst)
- begin
- if(r_cnt < 19'd27776)
- r_cnt <= r_cnt+1'b1;
- else begin
- r_cnt <= 19'b0;
- clk_out <= ~clk_out;
- end
- end
- else begin
- r_cnt <= 19'b0;
- clk_out <= 1'b0;
- end
- endmodule
- //數碼管顯示模塊
- module SMG(qo,clk,rst,se,sel);
- input wire clk,rst;
- input[15:0]qo;
- output reg [7:0]se;
- output reg [2:0]sel;
- reg [3:0]ge;
- reg [3:0]shi;
- reg [3:0]bai;
- reg [3:0]qian;
- reg [7:0]b;
- reg c;
- reg [25:0]q;
- reg [3:0]a;
- always@(posedge clk or negedge rst)
- begin
- if(rst==0)
- begin
- q<=0;
- c<=0;
- end
- else if(q==139999)
- begin
- q<=0;
- c<=~c;
- end
- else
- q<=q+1;
- end
- always@(posedge c)
- begin
- if(a==3)
- a<=0;
- else
- a<=a+1;
- end
- always@(*)
- begin
- case(a)
- 0:begin
- sel=3'b011;
- qian={qo[15],qo[14],qo[13],qo[12]};b=ge;
- end
- 1:begin
- sel=3'b010;
- bai={qo[11],qo[10],qo[9],qo[8]};b=shi;
- end
- 2:begin
- sel=3'b001;
- shi={qo[7],qo[6],qo[5],qo[4]};b=bai;
- end
- 3:begin
- sel=3'b000;
- ge={qo[3],qo[2],qo[1],qo[0]};b=qian;
- end
- default sel=3'b011;
- endcase
- end
- always@(posedge clk)
- begin
- case(b)
- 4'b0000:se=8'b0011_1111;//0
- 4'b0001:se=8'b0000_0110;//1
- 4'b0010:se=8'b0101_1011;//2
- 4'b0011:se=8'b0100_1111;//3
- 4'b0100:se=8'b0110_0110;//4
- 4'b0101:se=8'b0110_1101;//5
- 4'b0110:se=8'b0111_1101;//6
- 4'b0111:se=8'b0000_0111;//7
- 4'b1000:se=8'b0111_1111;//8
- 4'b1001:se=8'b0110_1111;//9
- endcase
- end
- endmodule
復制代碼 |