最近在做数电研究,题目为数字频率计,要求用FPGA板子设计,为了能使51黑电子论坛能发展的更好,我也贡献我的一份力量,希望能帮到各位。
原理:测量1s时间内待测脉冲个数从而得出待测信号的频率。
具体模块:
基准信号产生模块:把50MHz分频成1Hz
控制模块:产生计数使能信号;产生清零信号;
计数模块:通过从控制模块输入进来的使能信号和清零信号能从0000~1001计数(8421码),并能产生进位;
锁存模块:把计数结果锁存;使显示模块能稳定显示结果
显示模块:通过数码管显示,位选是用的外部电路138译码器,段选是一个四位二进制码(8421码)
待测信号:由于本人没有函数信号发生器所以就把50MHz分成900Hz作为待测信号来验证该系统能否正确测量,也可以把该模块删掉,把输出口接一个input,就可以测量外部信号了,
由于板子资源有限,而我的程序有点复杂,不是很简洁,所以只能显示四位结果,即量程为0~9999Hz。板子上有8位数码管,理论上可以显示8位结果,即量程为0~99999999Hz。另外我准备用modelsim仿真各个模块,在我仿真完控制模块后遇到了问题,其他几个模块仿真不出来,只有控制模块可以仿真,其他几个写了激励信号,而且都赋了初值,但是输出结果一直是高阻态(显示红线),希望各位朋友能教教我(本人不怎么会用modelsim)
源程序:
- //控制模块
- 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
复制代码 |