首先放置效果图:
本次试验中采用的是等精度测频率,等精度测频的原理是产生一个1s的高电平,在高电平中对被测方波进行计数,所测得数字即该波形频率。具体等精度测量原理请参考:http://www.elecfans.com/d/591858.html
注意点:在1s高电平上升沿时,被测信号也需要是上升沿,才能进行准确计数,代码相对简单
本次实验功能,对信号测频,将测得频率以二进制32位通过uart发送给pc,对于pc发送得数据,将复制返回。下面将主要代码贴上:
顶层文件:Fre_measure.v
module Fre_measure(
input clk,
input rst_n,
input clk_measure,
input uart_rx,
output uart_tx
);
wire[31:0] fre_cnt;
Time_1s time_1s(
.clk (clk ),
.rst_n (rst_n ),
.flag_1s (flag_1s )
);
dff1 dff_1(
.clk_measure (clk_measure ),
.flag_1s (flag_1s ),
.clk_match (clk_match )
);
Fre_cnt fre_cnt1(
.clk_measure (clk_measure ),
.rst_n (rst_n ),
.clk_match (clk_match ),
.fre_cnt (fre_cnt )
);
uart_test uart_test1(
.clk (clk ),
.rst_n (rst_n ),
.uart_rx (uart_rx ),
.fre_cnt (fre_cnt ),
.uart_tx (uart_tx )
);
endmodule
匹配模块,将1s延时和被测信号匹配:dff.v
module dff1(
input flag_1s,
input clk_measure,
output reg clk_match
);
always@(posedge clk_measure)
begin
clk_match <= flag_1s;
end
endmodule
频率计数模块:Fre_cnt.v
module Fre_cnt(
input clk_measure,
input rst_n,
input clk_match,
output[31:0] fre_cnt
);
reg [31:0] fre_cnt_r1 = 32'b0;
reg [31:0] fre_cnt_r2 = 32'b0;
always@(negedge clk_match)
begin
fre_cnt_r2 <= fre_cnt_r1;
end
always@(posedge clk_measure or negedge rst_n)
begin
if(!rst_n)
fre_cnt_r1 <= 32'b0;
else if(clk_match)
fre_cnt_r1 <= fre_cnt_r1 + 32'b1;
else
fre_cnt_r1 <= 32'b0;
end
assign fre_cnt = fre_cnt_r2;
endmodule
0.5Hz方波产生(1s)高电平产生:Time_1s.v
module Time_1s(
input clk,
input rst_n,
output reg flag_1s=1'd0
);
reg [27:0] timer;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
timer <= 28'd0;
else if(timer == 28'd49_999_999)
begin
flag_1s <= ~flag_1s;
timer <= 28'd0;
end
else
timer <= timer + 28'd1;
end
endmodul
uart通信模块:uart_test.v
module uart_test(
input clk,
input rst_n,
input uart_rx,
input[31:0] fre_cnt,
output uart_tx
);
parameter CLK_FRE = 50;
localparam IDLE = 0;
localparam SEND = 1;
localparam WAIT = 2;
reg[7:0] tx_data;
reg[7:0] tx_str;
reg tx_data_valid;
wire tx_data_ready;
reg[7:0] tx_cnt;
wire[7:0] rx_data;
wire rx_data_valid;
wire rx_data_ready;
reg[31:0] wait_cnt;
reg[3:0] state;
assign rx_data_ready = 1'b1;
always@(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
wait_cnt <= 32'd0;
tx_data <= 8'd0;
state <= IDLE;
tx_cnt <= 8'd0;
tx_data_valid <= 1'b0;
end
else
case(state)
IDLE:
state <= SEND;
SEND:
begin
wait_cnt <= 32'd0;
tx_data <= tx_str;
if(tx_data_valid == 1'b1 && tx_data_ready == 1'b1 && tx_cnt < 8'd36)
begin
tx_cnt <= tx_cnt + 8'd1;
end
else if(tx_data_valid && tx_data_ready)
begin
tx_cnt <= 8'd0;
tx_data_valid <= 1'b0;
state <= WAIT;
end
else if(~tx_data_valid)
begin
tx_data_valid <= 1'b1;
end
end
WAIT:
begin
wait_cnt <= wait_cnt + 32'd1;
if(rx_data_valid == 1'b1)
begin
tx_data_valid <= 1'b1;
tx_data <= rx_data;
end
else if(tx_data_valid && tx_data_ready)
begin
tx_data_valid <= 1'b0;
end
else if(wait_cnt >= CLK_FRE * 1000000)
state <= SEND;
end
default:
state <= IDLE;
endcase
end
//combinational logic
//Send "HELLO ALINX\r\n"
always@(*)
begin
case(tx_cnt)
8'd0: tx_str <= fre_cnt[31]+8'd48;
8'd1: tx_str <= fre_cnt[30]+8'd48;
8'd2: tx_str <= fre_cnt[29]+8'd48;
8'd3: tx_str <= fre_cnt[28]+8'd48;
8'd4: tx_str <= fre_cnt[27]+8'd48;
8'd5: tx_str <= fre_cnt[26]+8'd48;
8'd6: tx_str <= fre_cnt[25]+8'd48;
8'd7: tx_str <= fre_cnt[24]+8'd48;
8'd8: tx_str <= fre_cnt[23]+8'd48;
8'd9: tx_str <= fre_cnt[22]+8'd48;
8'd10: tx_str <= fre_cnt[21]+8'd48;
8'd11: tx_str <= fre_cnt[20]+8'd48;
8'd12: tx_str <= fre_cnt[19]+8'd48;
8'd13: tx_str <= fre_cnt[18]+8'd48;
8'd14: tx_str <= fre_cnt[17]+8'd48;
8'd15: tx_str <= fre_cnt[16]+8'd48;
8'd16: tx_str <= fre_cnt[15]+8'd48;
8'd17: tx_str <= fre_cnt[14]+8'd48;
8'd18: tx_str <= fre_cnt[13]+8'd48;
8'd19: tx_str <= fre_cnt[12]+8'd48;
8'd20: tx_str <= fre_cnt[11]+8'd48;
8'd21: tx_str <= fre_cnt[10]+8'd48;
8'd22: tx_str <= fre_cnt[9]+8'd48;
8'd23: tx_str <= fre_cnt[8]+8'd48;
8'd24: tx_str <= fre_cnt[7]+8'd48;
8'd25: tx_str <= fre_cnt[6]+8'd48;
8'd26: tx_str <= fre_cnt[5]+8'd48;
8'd27: tx_str <= fre_cnt[4]+8'd48;
8'd28: tx_str <= fre_cnt[3]+8'd48;
8'd29: tx_str <= fre_cnt[2]+8'd48;
8'd30: tx_str <= fre_cnt[1]+8'd48;
8'd31: tx_str <= fre_cnt[0]+8'd48;
8'd32: tx_str <= " ";
8'd33: tx_str <= " ";
8'd34: tx_str <= " ";
8'd35: tx_str <= "\r";
8'd36: tx_str <= "\n";
default:tx_str <= 8'd0;
endcase
end
uart_rx#
(
.CLK_FRE(CLK_FRE),
.BAUD_RATE(115200)
) uart_rx_inst
(
.clk (clk ),
.rst_n (rst_n ),
.rx_data (rx_data ),
.rx_data_valid (rx_data_valid ),
.rx_data_ready (rx_data_ready ),
.rx_pin (uart_rx )
);
uart_tx#
(
.CLK_FRE(CLK_FRE),
.BAUD_RATE(115200)
) uart_tx_inst
(
.clk (clk ),
.rst_n (rst_n ),
.tx_data (tx_data ),
.tx_data_valid (tx_data_valid ),
.tx_data_ready (tx_data_ready ),
.tx_pin (uart_tx )
);
endmodule
串口通信设置:波特率115200,8位数据位,1位停止位,无校验,下面是串口通信截图,系统时钟为50M,下图为测量数据,输出信号数据为49999950,误差50hz,误差精度为0.000001,理论测量最大应该可达到200M左右,但由于实验条件有限无法测试。10M以下几乎没误差,而且板子时钟频率越高则越精准。
以上就是本次实战的主要内容,上述有误还请指出,如果需要原工程可留言,大家一起进步,一起实践~
要工程的同学比较多,在这把下载链接贴上