假期著
先祝大家新春快乐,新的一年心想事成,万事如意,横财就手.
小班的大作业之一.
之前做这个是因为这个是国赛题,然后上网找了半天的资料都是等精度测量,然后我就,手撸了一个不太一样的…
常用的数字频率测量方法有三种
在给定的闸门时间(常见为1s)内测量被测信号的脉冲个数,进行换算得出被测信号的频率。
通过测量被测信号一个周期时间计时信号的脉冲个数,然后换算出被测信号的频率。
这两种测量法的精度都与被测信号有关,因而它们属于非等精度测量法。
设实际闸门时间为t,被测信号周期数为Nx,则它通过测量被测信号数个周期的时间,然后换算得出被测信号的频率,克服了测量精度对被测信号的依赖性。算法核心思想是通过闸门信号与被测信号同步,将闸门时间t控制为被测信号周期长度的整数倍。测量时,先打开预置闸门,当检测到被测闸门关闭时,标准信号并不立即停止计数,而是等检测到的被测信号脉冲到达是才停止,完成被测信号的整数个周期的测量。测量的实际闸门时间与预置闸门时间可能不完全相同,但最大差值不超过被测信号的一个周期。
由于是小班的作业讲解之一(甚者他们数电还是虚空基础),所以这里实现前两种方法.(第三种可以联系我拿源码参考.
顺便也写写我用来跑2015国赛F题的流程
就是将待测信号整形变成计数器可以识别到的脉冲信号(方波).里面有点讲究,很多人以为里面只需要实现一个高速比较器,但实际上为了测量各个幅值的信号,必须对信号进行限幅,AGC(自动增益控制),抬升再比较(听朱老师说是为了降低噪声).等各种操作啦,但是实际上硬件是由另一位小伙伴@渤儿来写的,所以没有太操心…好像也是有一块芯片就可以直接实现上面的处理了.
事先声明:
- 本设计用的串口模块从黑金大兄弟哪里改过来的…不是卖广告,就是声明一下…
- 放的代码版本是v0.1,可粗略实现但未优化未删调试信号版,优化会作为小班接下来的作业…
- 第一遍阅读不建议阅读源码
端口说明
写得有点冗余,主要是比外头的做多了两个操作:
module timer_1s(
clk,rst_n,en_sig,
gate_control //控制信号输出
);
input clk;
input rst_n;
input en_sig;
output gate_control;
reg [1:0] en_sig_edge;
reg [1:0] en_sig_edge_n;
reg start_up;
reg [31:0] count;
reg op_reg;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
en_sig_edge <= 2'b0;
end
else
begin
en_sig_edge <= en_sig_edge_n;
end
end
always @(*)
begin
if(!rst_n)
begin
en_sig_edge_n = 2'b0;
end
else
begin
en_sig_edge_n = {en_sig_edge[0],en_sig};
end
end
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
count <= 31'b0;
op_reg <= 1'b0;
end
else
begin
if(start_up && count!= 31'd49999999)
begin
count <= count + 1'b1;
op_reg <= 1'b1;
end
else
begin
count <= 31'b0;
op_reg <= 1'b0;
end
end
end
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
start_up <= 1'b0;
end
else if(count == 31'd49999999)
begin
start_up <= 1'b0;
end
else if(start_up == 1'b1)
begin
start_up <= start_up;
end
else if(count == 31'b0)
begin
start_up <= en_sig_edge[0]^en_sig_edge[1];
end
else
begin
start_up <= start_up;
end
end
assign gate_control = op_reg;
endmodule
先来看一个excel
直接测量法过于简单,就不说了,就是一个计数器…
用双边沿其实就是想让大家多体会体会双边沿移位寄存器的写法这样子,实际上算单边沿就够了.
可以看到其实我的测频模块和闸门信号是可以不相关的,但是由于题目有要求,我就不断输出这些周期数,再给stm32做数据处理了,因为这样测频会多出很多结果用于处理.
主要做的工作有:
module FRE_SINE_CHECK_MODULE(
clk,rst_n,gate,sig,
fre_count,duty_count
);
input clk;
input rst_n;
input gate;
input sig;
output [31:0] fre_count;
output [31:0] duty_count;
wire clk_200;
wire locked;
pll_200 pll_module(
.areset(!rst_n),
.inclk0(clk),
.pfdena(1'b1),
.c0(clk_200)
);
reg [31:0] counter; //32位计数器
always @(posedge clk_200 or negedge rst_n)
begin
if(!rst_n)
begin
counter <= 1'b0;
end
else
begin
if(gate == 1'b1)
begin
counter <= counter + 1'b1;
end
else
begin
counter <= 32'b0;
end
end
end
reg [1:0] en_sig_edge;
reg [1:0] en_sig_edge_n;
always @(posedge clk_200 or negedge rst_n)
begin
if(!rst_n)
begin
en_sig_edge <= 2'b0;
end
else
begin
en_sig_edge <= en_sig_edge_n;
end
end
always @(*)
begin
if(!rst_n)
begin
en_sig_edge_n = 2'b0;
end
else
begin
en_sig_edge_n = {en_sig_edge[0],sig};
end
end
wire edge_turn;
assign edge_turn = en_sig_edge[0] ^ en_sig_edge[1]; //检测双边沿
reg [31:0] time_record[3:0];
always @(posedge clk_200 or negedge rst_n)
begin
if(!rst_n)
begin
time_record[0] <= 32'b0;
time_record[1] <= 32'b0;
time_record[2] <= 32'b0;
time_record[3] <= 32'b0;
end
else if(gate == 1'b0 )
begin
time_record[0] <= 32'b0;
time_record[1] <= 32'b0;
time_record[2] <= 32'b0;
time_record[3] <= 32'b0;
end
else
begin
if(edge_turn)
begin
time_record[0] <= counter;
time_record[1] <= time_record[0];
time_record[2] <= time_record[1];
time_record[3] <= time_record[2];
end
else
begin
time_record[0] <= time_record[0];
time_record[1] <= time_record[1];
time_record[2] <= time_record[2];
time_record[3] <= time_record[3];
end
end
end
reg [31:0] pipe_add_1;
reg [31:0] pipe_add_2;
reg [31:0] pipe_result;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
pipe_add_1 <= 32'b0;
pipe_add_2 <= 32'b0;
end
else
begin
pipe_add_1 <= time_record[0] + time_record[1];
pipe_add_2 <= time_record[2] + time_record[3];
end
end
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
pipe_result <= 32'b0 ;
end
else
begin
pipe_result <= pipe_add_1 - pipe_add_2;
end
end
reg [31:0] duty_count_reg;
always @(posedge sig or negedge rst_n)
begin
if(!rst_n)
begin
duty_count_reg <= 32'b0 ;
end
else
begin
if(gate == 1'b1)
duty_count_reg <= time_record[0] - time_record[1];
else
duty_count_reg <= 32'b0;
end
end
assign duty_count = duty_count_reg;
assign fre_count = pipe_result;
endmodule
负责显示屏显示和将fpga输出的周期转换成频率,由于串口使用黑金的,stm32不是我负责的,所以这里就不详述了.
如您是不小心看了源码,然后心烦意燥滑到最后的,不妨不看源码再看看字和图…毕竟是初代的源码,没精简过(甚至人为设计了语法错误)
可以看到,其实他的原理极其简单,适合新手入门,和熟悉verilog语法,小班的同学和大三的老狗们好像都要开始学这门语言了,不妨结合夏宇闻教授的书来尝试一下
小班进阶作业:理解源码(已贴心地为您删掉小部分源码和大部分注释),删去冗余逻辑和错误部分
新年第一更,不过下年要考研,就可能要开始断更或者只发一些课外拓展咯.(无奈
再次强烈请求csdn的md编辑器能加上对verilog语言的支持…
赞赏通道