FPGA 设计基础篇
FPGA 设计基础篇
基于FPGA 的脉宽测量著: 开源达人
时间:2016年12月14日
目录
1. 脉宽测量 ............................................................................................................................... 3
1.1简介 ............................................................................................................................ 3
1.2 代码解析.......................................................................................................................... 3
1. 脉宽测量
1.1简介
脉宽测量:测量出PWM 波高电平或低电平的宽度。
主要应用:脉宽调制的解调 占空比测量 频率测量
1.2 代码解析
脉宽测量案例1:VHDL 案例工程在如下文件夹中
(1_Foundation_course_of_FPGA_Design\example\Chapter7\Pulse_width_measure_VHDL)该案例采用的是 1M 采样频率,案例采用------------------------------------------------------
--design name :Pulse_width_measure
--use :脉宽测量 (脉宽调制的解调 占空比测量 频率测量) --build time :2016/12/14
--version :V0.1
--change note :
--V0.1 首次建立 2016年12月14日
-----------------------------------------------------
library IEEE;
port
(
:in std_logic;--系统时钟输入
:in std_logic;--系统复位输入
pulse_in :in std_logic;--脉冲输入
pulse_h_reg :out s td_logic_vector(15 downto 0);--脉冲高电平脉宽寄存器
pulse_l_reg :out s td_logic_vector(15 downto 0) --脉冲低电平脉宽寄存器
);
end Pulse_width_measure;
architecture Behavioral of Pulse_width_measure is
signal pulse_in_d1 :std_logic;--脉冲输入第1级D 触发器
signal pulse_in_d2 :std_logic;--脉冲输入第2级D 触发器
signal pulse_posedge :std_logic;--上升沿标志位
signal pulse_negedge :std_logic;--下降沿标志位
signal pulse_h_counter :std_logic_vector(15 downto 0);--高电平脉宽计数器 signal pulse_l_counter :std_logic_vector(15 downto 0);--低电平脉宽计数器
signal pulse_h_cache :std_logic_vector(15 downto 0);--高电平脉宽缓存寄存器 signal pulse_l_cache :std_logic_vector(15 downto 0);--低电平脉宽缓存寄存器
signal sampling :std_logic;--采样频率使能信号
signal sampling_counter :integer range 0 to 59;--1M 采样频率配置(此参数可配置成不同的采样速度)采样速度在1Mhz 时,推荐输入脉冲频率在20HZ~10Khz之间
signal reg_en :std_logic;--寄存器输出使能信号
--脉冲个数监测计数器,脉冲输入一个完整周期后再输出计数器的值,防止起始占空比计算值抖动
begin
---------------------脉冲输入第1级D 触发器代码---------------------
process(clk,rst)
begin
----------------------------------------------------------------
---------------------脉冲输入第2级D 触发器代码---------------------
process(clk,rst)
begin
if(rst = '1')then
pulse_in_d2
elsif(clk'event and clk = '1')then
pulse_in_d2
end if;
end process;
----------------------------------------------------------------
----------------------上升沿下降沿标志位代码-----------------------
process(clk,rst)
begin
if(rst = '1')then
pulse_posedge
pulse_negedge
elsif(clk'event and clk = '1')then
if(pulse_in_d2 = '0' and pulse_in_d1 = '1')then--上升沿
pulse_posedge
pulse_negedge
end if;
--下降沿 pulse_posedge
pulse_negedge
end if;
end if;
end process;
----------------------------------------------------------------
--------------------------采样频率配置代码------------------------
process(clk,rst)
begin
--配置成1M
sampling_counter
sampling
end if;
end if;
end process;
----------------------------------------------------------------
----------------------高电平脉宽计数器代码-------------------------
process(clk,rst)
begin
if(rst = '1')then
pulse_h_counter
elsif(clk'event and clk = '1')then
if(sampling = '1')then
if(pulse_posedge = '1')then
if(pulse_h_counter = x"ffff")then --脉宽限定,不要超出寄存器范围
pulse_h_counter
else
pulse_h_counter
end if;
else
pulse_h_counter
end if;
end if;
end if;
end process;
----------------------------------------------------------------
----------------------低电平脉宽计数器代码------------------------
process(clk,rst)
begin
if(rst = '1')then
--脉宽限定,不要超出寄存器范围
pulse_l_counter
end if;
else
pulse_l_counter
end if;
end if;
end if;
end process;
----------------------------------------------------------------
----------------------脉宽寄存器寄存代码--------------------------
process(clk,rst)
begin
if(rst = '1')then
pulse_h_cache
pulse_l_cache
elsif(clk'event and clk = '1')then
if(pulse_in_d2 = '0' and pulse_in_d1 = '1')then--上升沿时寄存低电平脉宽
pulse_l_cache
end if;
if(pulse_in_d2 = '1' and pulse_in_d1 = '0')then--下降沿时寄存高电平脉宽
pulse_h_cache
end if;
end process;
--------------------------------------------------------------
----------------------脉宽寄存器输出代码--------------------------
process(clk,rst)
begin
if(rst = '1')then
pulse_h_reg
pulse_l_reg
)then
下降沿输出, 防止占空比计算值抖动
--超过寄存器限制后占空比为0
该案例仿真主时钟为60M, 采样频率1M 对一个20K 的方波进行脉宽测量,一个周期后可见高地电平脉宽均为25,仿真结果正确。起始低电平脉宽为满值是为了避免占空比计算时出现0除以0的情况。
脉宽测量案例2:VERILOG 案例工程在如下文件夹中
(1_Foundation_course_of_FPGA_Design\example\Chapter7\Pulse_width_measure_Verilog)案例采用RTL 描述
/****************************************************
design name :Pulse_width_measure
use :脉宽调制的解调 占空比测量 频率测量
build time :2016/11/29
version :V0.1
change note :
V0.1 首次建立 2016年11月29日
*****************************************************/
module Pulse_width_measure
(
input clk, //时钟输入
input rst, //复位输入
input pulse_in, //脉冲信号输入
output reg [31:0] pulse_high_reg, //高电平宽度寄存器
output reg [31:0] pulse_low_reg //低电平宽度寄存器
);
reg pulse_in_q1,pulse_in_q2;//脉冲输入两级D 触发器
//输入脉冲上升沿标志触发器 //输入脉冲下降沿标志触发器
//脉冲高电平计数器 //脉冲低电平计数器
//高电平宽度寄存器D 端
//低电平宽度寄存器D 端
/****************输入两级D 触发器级联*******************/
begin
if(rst == 1'b0)
pulse_in_q1
else
pulse_in_q1
end
always@(posedge clk , negedge rst)
begin
if(rst == 1'b0)
pulse_in_q2
else
pulse_in_q2
end
/***************************************************/
/***************输入脉冲上升沿标志采集*****************/
always@(posedge clk , negedge rst)
begin
if(rst == 1'b0)
pulse_in_posedge_q
else
pulse_in_posedge_q
end
always@(*)
begin
//上升沿时标志触发器置1 pulse_in_posedge_d = 1'b1;
//下降沿时触发器清零 pulse_in_posedge_d = 1'b0;
else
end
/***************************************************/
/***************输入脉冲下升沿标志采集*****************/
begin
end
always@(*)
begin
if(pulse_in_q1 == 1'b0 && pulse_in_q2 == 1'b1)//下降沿时标志触发器置1 pulse_in_negedge_d = 1'b1;
else if(pulse_in_q1 == 1'b1 && pulse_in_q2 == 1'b0)//上升沿时标志触发器清零
pulse_in_negedge_d = 1'b0;
else
pulse_in_negedge_d = pulse_in_negedge_q;
end
/***************************************************/
/***************输入脉冲高电平计数器******************/ always@(posedge clk , negedge rst)
begin
if(rst == 1'b0)
pulse_high_counter_q
else
pulse_high_counter_q
always@(*)
begin
if(pulse_in_negedge_q == 1'b1)
pulse_high_counter_d = 1'b0;
else if(pulse_in_posedge_q == 1'b1)
else
end
/***************************************************/
/***************输入脉冲低电平计数器******************/ begin
if(rst == 1'b0)
else
end
pulse_low_counter_d = 1'b0;
else if(pulse_in_negedge_q == 1'b1)
pulse_low_counter_d = pulse_low_counter_q + 1'b1; else
pulse_low_counter_d = pulse_low_counter_q; end
/***************************************************/
/***************高电平宽度寄存器输出******************/
always@(posedge clk , negedge rst)
begin
if(rst == 1'b0)
pulse_high_reg
else
pulse_high_reg
end
always@(*)
begin
if(pulse_in_q1 == 1'b0 && pulse_in_q2 == 1'b1)//下降沿时输出高电平脉宽 pulse_high_reg_d = pulse_high_counter_q + 1'b1;//补齐偏差值 else
pulse_high_reg_d = pulse_high_reg;
end
/***************************************************/
/***************低电平宽度寄存器输出******************/
always@(posedge clk , negedge rst)
begin
if(rst == 1'b0)
pulse_low_reg
else
end
always@(*)
begin
//上升沿时输出高电平脉宽 //补齐偏差值
else
/***************************************************/
仿真分析:
该案例知识单纯输出脉宽,没有输出保护措施,若要使用该模块进行占空比和频率的测量,需要像上一案例一样进行输出保护措施。以上仿真为50M 采样
250K
方波的仿真,结果正确。
FPGA 设计基础篇
FPGA 设计基础篇
基于FPGA 的脉宽测量著: 开源达人
时间:2016年12月14日
目录
1. 脉宽测量 ............................................................................................................................... 3
1.1简介 ............................................................................................................................ 3
1.2 代码解析.......................................................................................................................... 3
1. 脉宽测量
1.1简介
脉宽测量:测量出PWM 波高电平或低电平的宽度。
主要应用:脉宽调制的解调 占空比测量 频率测量
1.2 代码解析
脉宽测量案例1:VHDL 案例工程在如下文件夹中
(1_Foundation_course_of_FPGA_Design\example\Chapter7\Pulse_width_measure_VHDL)该案例采用的是 1M 采样频率,案例采用------------------------------------------------------
--design name :Pulse_width_measure
--use :脉宽测量 (脉宽调制的解调 占空比测量 频率测量) --build time :2016/12/14
--version :V0.1
--change note :
--V0.1 首次建立 2016年12月14日
-----------------------------------------------------
library IEEE;
port
(
:in std_logic;--系统时钟输入
:in std_logic;--系统复位输入
pulse_in :in std_logic;--脉冲输入
pulse_h_reg :out s td_logic_vector(15 downto 0);--脉冲高电平脉宽寄存器
pulse_l_reg :out s td_logic_vector(15 downto 0) --脉冲低电平脉宽寄存器
);
end Pulse_width_measure;
architecture Behavioral of Pulse_width_measure is
signal pulse_in_d1 :std_logic;--脉冲输入第1级D 触发器
signal pulse_in_d2 :std_logic;--脉冲输入第2级D 触发器
signal pulse_posedge :std_logic;--上升沿标志位
signal pulse_negedge :std_logic;--下降沿标志位
signal pulse_h_counter :std_logic_vector(15 downto 0);--高电平脉宽计数器 signal pulse_l_counter :std_logic_vector(15 downto 0);--低电平脉宽计数器
signal pulse_h_cache :std_logic_vector(15 downto 0);--高电平脉宽缓存寄存器 signal pulse_l_cache :std_logic_vector(15 downto 0);--低电平脉宽缓存寄存器
signal sampling :std_logic;--采样频率使能信号
signal sampling_counter :integer range 0 to 59;--1M 采样频率配置(此参数可配置成不同的采样速度)采样速度在1Mhz 时,推荐输入脉冲频率在20HZ~10Khz之间
signal reg_en :std_logic;--寄存器输出使能信号
--脉冲个数监测计数器,脉冲输入一个完整周期后再输出计数器的值,防止起始占空比计算值抖动
begin
---------------------脉冲输入第1级D 触发器代码---------------------
process(clk,rst)
begin
----------------------------------------------------------------
---------------------脉冲输入第2级D 触发器代码---------------------
process(clk,rst)
begin
if(rst = '1')then
pulse_in_d2
elsif(clk'event and clk = '1')then
pulse_in_d2
end if;
end process;
----------------------------------------------------------------
----------------------上升沿下降沿标志位代码-----------------------
process(clk,rst)
begin
if(rst = '1')then
pulse_posedge
pulse_negedge
elsif(clk'event and clk = '1')then
if(pulse_in_d2 = '0' and pulse_in_d1 = '1')then--上升沿
pulse_posedge
pulse_negedge
end if;
--下降沿 pulse_posedge
pulse_negedge
end if;
end if;
end process;
----------------------------------------------------------------
--------------------------采样频率配置代码------------------------
process(clk,rst)
begin
--配置成1M
sampling_counter
sampling
end if;
end if;
end process;
----------------------------------------------------------------
----------------------高电平脉宽计数器代码-------------------------
process(clk,rst)
begin
if(rst = '1')then
pulse_h_counter
elsif(clk'event and clk = '1')then
if(sampling = '1')then
if(pulse_posedge = '1')then
if(pulse_h_counter = x"ffff")then --脉宽限定,不要超出寄存器范围
pulse_h_counter
else
pulse_h_counter
end if;
else
pulse_h_counter
end if;
end if;
end if;
end process;
----------------------------------------------------------------
----------------------低电平脉宽计数器代码------------------------
process(clk,rst)
begin
if(rst = '1')then
--脉宽限定,不要超出寄存器范围
pulse_l_counter
end if;
else
pulse_l_counter
end if;
end if;
end if;
end process;
----------------------------------------------------------------
----------------------脉宽寄存器寄存代码--------------------------
process(clk,rst)
begin
if(rst = '1')then
pulse_h_cache
pulse_l_cache
elsif(clk'event and clk = '1')then
if(pulse_in_d2 = '0' and pulse_in_d1 = '1')then--上升沿时寄存低电平脉宽
pulse_l_cache
end if;
if(pulse_in_d2 = '1' and pulse_in_d1 = '0')then--下降沿时寄存高电平脉宽
pulse_h_cache
end if;
end process;
--------------------------------------------------------------
----------------------脉宽寄存器输出代码--------------------------
process(clk,rst)
begin
if(rst = '1')then
pulse_h_reg
pulse_l_reg
)then
下降沿输出, 防止占空比计算值抖动
--超过寄存器限制后占空比为0
该案例仿真主时钟为60M, 采样频率1M 对一个20K 的方波进行脉宽测量,一个周期后可见高地电平脉宽均为25,仿真结果正确。起始低电平脉宽为满值是为了避免占空比计算时出现0除以0的情况。
脉宽测量案例2:VERILOG 案例工程在如下文件夹中
(1_Foundation_course_of_FPGA_Design\example\Chapter7\Pulse_width_measure_Verilog)案例采用RTL 描述
/****************************************************
design name :Pulse_width_measure
use :脉宽调制的解调 占空比测量 频率测量
build time :2016/11/29
version :V0.1
change note :
V0.1 首次建立 2016年11月29日
*****************************************************/
module Pulse_width_measure
(
input clk, //时钟输入
input rst, //复位输入
input pulse_in, //脉冲信号输入
output reg [31:0] pulse_high_reg, //高电平宽度寄存器
output reg [31:0] pulse_low_reg //低电平宽度寄存器
);
reg pulse_in_q1,pulse_in_q2;//脉冲输入两级D 触发器
//输入脉冲上升沿标志触发器 //输入脉冲下降沿标志触发器
//脉冲高电平计数器 //脉冲低电平计数器
//高电平宽度寄存器D 端
//低电平宽度寄存器D 端
/****************输入两级D 触发器级联*******************/
begin
if(rst == 1'b0)
pulse_in_q1
else
pulse_in_q1
end
always@(posedge clk , negedge rst)
begin
if(rst == 1'b0)
pulse_in_q2
else
pulse_in_q2
end
/***************************************************/
/***************输入脉冲上升沿标志采集*****************/
always@(posedge clk , negedge rst)
begin
if(rst == 1'b0)
pulse_in_posedge_q
else
pulse_in_posedge_q
end
always@(*)
begin
//上升沿时标志触发器置1 pulse_in_posedge_d = 1'b1;
//下降沿时触发器清零 pulse_in_posedge_d = 1'b0;
else
end
/***************************************************/
/***************输入脉冲下升沿标志采集*****************/
begin
end
always@(*)
begin
if(pulse_in_q1 == 1'b0 && pulse_in_q2 == 1'b1)//下降沿时标志触发器置1 pulse_in_negedge_d = 1'b1;
else if(pulse_in_q1 == 1'b1 && pulse_in_q2 == 1'b0)//上升沿时标志触发器清零
pulse_in_negedge_d = 1'b0;
else
pulse_in_negedge_d = pulse_in_negedge_q;
end
/***************************************************/
/***************输入脉冲高电平计数器******************/ always@(posedge clk , negedge rst)
begin
if(rst == 1'b0)
pulse_high_counter_q
else
pulse_high_counter_q
always@(*)
begin
if(pulse_in_negedge_q == 1'b1)
pulse_high_counter_d = 1'b0;
else if(pulse_in_posedge_q == 1'b1)
else
end
/***************************************************/
/***************输入脉冲低电平计数器******************/ begin
if(rst == 1'b0)
else
end
pulse_low_counter_d = 1'b0;
else if(pulse_in_negedge_q == 1'b1)
pulse_low_counter_d = pulse_low_counter_q + 1'b1; else
pulse_low_counter_d = pulse_low_counter_q; end
/***************************************************/
/***************高电平宽度寄存器输出******************/
always@(posedge clk , negedge rst)
begin
if(rst == 1'b0)
pulse_high_reg
else
pulse_high_reg
end
always@(*)
begin
if(pulse_in_q1 == 1'b0 && pulse_in_q2 == 1'b1)//下降沿时输出高电平脉宽 pulse_high_reg_d = pulse_high_counter_q + 1'b1;//补齐偏差值 else
pulse_high_reg_d = pulse_high_reg;
end
/***************************************************/
/***************低电平宽度寄存器输出******************/
always@(posedge clk , negedge rst)
begin
if(rst == 1'b0)
pulse_low_reg
else
end
always@(*)
begin
//上升沿时输出高电平脉宽 //补齐偏差值
else
/***************************************************/
仿真分析:
该案例知识单纯输出脉宽,没有输出保护措施,若要使用该模块进行占空比和频率的测量,需要像上一案例一样进行输出保护措施。以上仿真为50M 采样
250K
方波的仿真,结果正确。