***********大学
课程设计报告
设计名称: 3位数字频率设计
姓 名: 学 号:
专业班级:
院(系): 物电学院
设计时间: 2012年12月5日至10日
设计地点:
目录
题目 :3位数字频率计 1页
一、数字频率计的功能…………………………………………………… 1页
二、数字频率计的设计思路……………………………………………… 1页
三、硬件资源概述………………………………………………………… 1~5页
四、各模块的VHDL语言描述与实现…………………………………… 5~13页
五、仿真模拟图…………………………………………………………… 13~15页
六、软件硬件结合实现……………………………………………… 15~17页
六、仿真及调试心得………………………………………………………… 17页
七、总结…………………………………………………………………… 17页
3位数字频率计设计
一、数字频率计的功能
我设计的是3位数字频率计,用3个十进制数字显示式频率,其频率范围为1MHz。有五个档位,并能自动换档。五个档的具体功能是:
1、计数溢出档,当频率计数超过量程时,自动显示溢出标--"-1.-1.-1";
2、1MHz档,显示000到999,默认单位为1KHz;
3、100KHz档,显示00.0到99.9,默认单位为1KHz;
4、10KHz档,显示0.00到9.99,默认单位为1KHz;
5、测周档,当所测频率小于0.99KHz时,显示数值变为周期,以毫秒为默认单位。
二、数字频率计的设计思路
1、时基的设计
在测频时,输入信号的频率大于频率计提供的基准频率,所以这时以频率计提供的基准频率信号为时基,输入信号为时钟信号,在频率计提供的基准信号周期里,计算输入信号的周期数,再乘以频率计的基准频率,就是输入信号的频率值。测周时,输入信号的频率小于频率计提供的基准频率信号,所以要以频率计提供的基准频率信号为时钟信号,以输入信号为时基信号,在输入信号周期内,计算频率计提供的基准信号的周期数,再乘以基准频率的周期值,就是输入信号的周期值。
输入信号是未知的,所以要求其自动调档,当测频为10KHz档时,提供时基应该是0.01KHz的脉冲。当测频为100KHz档时,提供的时基为0.1KHz的脉冲。当测频为1MKHz时,提供的时基为1KHz。用一分频器对50MHz的晶振进行分频得到1KHz的脉冲。然后用一个有100个状态状态机实现持续1ms、10ms、100ms的高电平即不同档位的闸门信号,状态机用1KHz的脉冲信号触发,产生1ms的高电平,只需在状态99的时候产生高电平,状态100时回到高电平;产生10ms的高电平,只需在状态90的时候产生高电平,在状态100的时候回到低电平。产生100ms的高电平,则需在状态为1前的一个状态产生高电平,直到状态100的时候回到低电平。在100个状态中,有很多状态的功能是相同的,可以将它们合并。
2、计数器的设计
各个档位之间的转换应遵循设计要求,要根据在时基有效时间内的计数值进行判断。计数器可以定义成一个整形信号,这样计数器加1就非常方便,要显示计数的数值,直接用三位数码管动态扫描实现显示个位、十位、百位。这样显示就要求计数器遵循加法逢十进一的规则。然后在不同的档位,小数点的位置不同,所以小数点的显示要以所在档位为判断条件。
3、模块划分
可以将计数器跟七段译码器设计成单独的模块,这样更省资源,利用率更高。
三、硬件资源概述
A、EP1C12核心板
EP1C12核心板为基于Altera Cyclone器件的嵌入式系统开发提供了一个很好的硬件台,
它可以为开发人员提供以下资源:
1、 主芯片采用Altera Cyclone器件EP1C12F324C8
2 、EPCS4I8配置芯片
3 、4个用户自定义按键
4 、4个用户自定义LED
5 、1个七段码LED
6 、标准AS编程接口和JTAG调试接口
7 、50MHz高精度时钟源
8 、三个高密度扩展接口
9 、系统上电复位电路
10 、支持+5V直接输入,板上电源管理模块
系统主芯片采用324引脚、BGA封装的E1C12 FPGA,它拥有12060个LE,52个M4K
片上RAM(共计239616bits),2个高性能PLL以及多达249个用户自定义IO。
B、FPGA开发板
FPGA开发平台提供了丰富的资源供学生或开发人员学习使用,资源包括接口通信、 控 制、存储、数据转换以及人机交互显示等几大模块,接口通信模块包括SPI接口、IIC接口、VGA接口、RS232接口、USB接口、PS2键盘/鼠标接口、1-Wire接口等;存储模块包括EEPROM存储器模块等;数据转换模块包括串行ADC、 DAC以及音频CODE等;人机交互显示模块包括8个按键、16个LED发光二极管显示、1602字符型点阵LCD、8位动态7段码管、实时时钟、SD卡等。上述的这些资源模块既可以满足初学者入门的要求,也可以满足开发人员进行二次开发的要求。
EDA/SOPC实验开发平台提供的资源有:
1、 标准配置核心板为EP1C12核心板(核心芯片为EP1C12F324C8)。可更换EP2C20F484C8等其它核心板。
2、 1602字符型液晶点阵。
3、 RTC,提供系统实时时钟。
4、 1个256色VGA接口。
5、1个标准串行接口。
6、 1个USB设备接口,利用PDIUSBD12芯片实现USB协议转换。
7、 基于SPI或IIC接口的音频CODEC模块。
8、 1个蜂鸣器输出模块。
9、 2个PS2键盘/鼠标接口。
10、 串行ADC和串行DAC模块。
11、 IIC接口的EEPROM存储器模块。
12、 基于1-Wire接口的数字温度传感器。
13、 8位动态七段码管LED显示。
14、 16个用户自定义LED显示,8个用户自定义按键输出。
15、 一个SD卡接口模块。
16、 扩展接口,供用户高速稳定的自由扩展。
开发板的系统平台功能图如下:
图1-2 FPGA系统平台功能框图
EP1C12 与开发平台硬件资源I/O接口对照表
四、各模块的VHDL语言描述及实现
1、计数器模块
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity frequency is
port(treset:in std_logic;
tclk:in std_logic;
tsig:in std_logic;
tkeep1:out std_logic_vector(3 downto 0);
tkeep2:out std_logic_vector(3 downto 0);
tkeep3:out std_logic_vector(3 downto 0));
end entity frequency;
architecture one of frequency is
signal tcou1:std_logic_vector(3 downto 0);
signal tcou2:std_logic_vector(3 downto 0);
signal tcou3:std_logic_vector(3 downto 0);
begin
ctrcou:process(treset,tclk)
begin
if treset='0' then
tcou1<="0000";tcou2<="0000";tcou3<="0000";
else
if tclk'event and tclk='1' then
if tsig='1' then
if tcou3="1010" then
tcou3<="1010";
else
if tcou1="1001" and tcou2="1001" and tcou3="1001" then
tcou1<="0000";tcou2<="0000";tcou3<="1010";
elsif tcou1="1001" and tcou2="1001" then
tcou1<="0000";tcou2<="0000";tcou3<=tcou3+1;
elsif tcou1="1001" then
tcou1<="0000";tcou2<=tcou2+1;
else tcou1<=tcou1+1;
end if;
end if;
else
tcou1<="0000";tcou2<="0000";tcou3<="0000";
end if;
end if;
end if;
end process ctrcou;
oputctr:process(treset,tsig)
begin
if treset='0' then
tkeep1<="0000";tkeep2<="0000";tkeep3<="0000";
else
if tsig'event and tsig='0' then
tkeep1<=tcou1;
tkeep2<=tcou2;
tkeep3<=tcou3;
end if;
end if;
end process oputctr;
end one;
2、7段译码器模块
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity display1 is
port (data_in:in std_logic_vector(3 downto 0);
clk1k:in std_logic;
del:out std_logic_vector(1 downto 0);
data_out:out std_logic_vector(6 downto 0));
end entity display1;
architecture one of display1 is
signal indata:std_logic_vector(3 downto 0);
begin
process(clk1K) --数码管动态扫描
variable dount : std_logic_vector(1 downto 0);
begin
if clk1k'event and clk1k='1' then--检测时钟上升沿
if dount="10" then dount:="00";
else
dount:=dount+1;--计数器dount累加
end if;
end if;
del<=dount;
end process;
process(data_in)
begin
indata<=data_in;
case indata is
when"0000"=>data_out<="1111110";
when"0001"=>data_out<="0110000";
when"0010"=>data_out<="1101101";
when"0011"=>data_out<="1111001";
when"0100"=>data_out<="0110011";
when"0101"=>data_out<="1011011";
when"0110"=>data_out<="1011111";
when"0111"=>data_out<="1110000";
when"1000"=>data_out<="1111111";
when"1001"=>data_out<="1111011";
when others=>data_out<="0110001";
end case;
end process;
end one;
3、频率计综合设计
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity dfre is
port(reset:in std_logic;
clk:in std_logic;
-- testsignal:in std_logic;
display:out std_logic_vector(6 downto 0);
del1:out std_logic_vector(1 downto 0);
unit:out std_logic;
d:out std_logic);
end entity dfre;
architecture one of dfre is
type state is
(start,judge,count1,count2to89,count90,count91to98,count99,count100);
signal myfre:state;
signal frecou:integer range 0 to 100;
signal clklk:std_logic;
signal clkl0k:std_logic;
signal coulk:integer range 0 to 9999;
signal enfre:std_logic;
signal flag:std_logic_vector(2 downto 0);
signal keepcou1:std_logic_vector(3 downto 0);
signal keepcou2:std_logic_vector(3 downto 0);
signal keepcou3:std_logic_vector(3 downto 0);
signal ttclk:std_logic;
signal ttsig:std_logic;
signal s:std_logic_vector(1 downto 0);
signal jishu:std_logic_vector(3 downto 0);
signal dot: std_logic_vector(2 downto 0);
signal testsignal:std_logic;
component display1 is
port(data_in:in std_logic_vector(3 downto 0);
clk1k:in std_logic;
del:out std_logic_vector(1 downto 0);
data_out:out std_logic_vector(6 downto 0));
end component;
component frequency is
port (treset:in std_logic;
tclk,tsig:in std_logic;
tkeep1:out std_logic_vector(3 downto 0);
tkeep2:out std_logic_vector(3 downto 0);
tkeep3:out std_logic_vector(3 downto 0));
end component;
begin
PROCESS(clk) --产生1Khz信号
variable cnt1 : INTEGER RANGE 0 TO 49999;
BEGIN
IF clk='1' AND clk'event THEN
IF cnt1=49999 THEN cnt1:=0;
ELSE
IF cnt1<25000 THEN clklk<='1';
ELSE clklk<='0';
END IF;
cnt1:=cnt1+1;
END IF;
END IF;
end process;
PROCESS(clk) --产生被测信号
variable cnt10 : INTEGER RANGE 0 TO 3999999;
BEGIN
IF clk='1' AND clk'event THEN
IF cnt10=3999999 THEN cnt10:=0;
ELSE
IF cnt10<2000000 THEN clkl0k<='1';
ELSE clkl0k<='0';
END IF;
cnt10:=cnt10+1;
END IF;
END IF;
testsignal<=clkl0k;
end process;
ctrdot:process(flag)--控制小数点显示进程
begin
case flag is
when"000"=>dot<="000";
when"001"=>dot<="100";
when"010"=>dot<="010";
when"011"=>dot<="001";
when others=>dot<="111";
end case;
end process ctrdot;
ctrfre:process(reset,clklk)--用于产生时基的状态机
begin
if reset='0' then
frecou<=0;enfre<='0';flag<="000";myfre<=start;
else
if clklk'event and clklk='1' then
case myfre is
when start=>frecou<=0;enfre<='0';flag<="011";myfre<=judge;
when judge=>
if flag="000" then --标志位0
if keepcou3="0000" and keepcou2="0000" and keepcou1="0000" then
flag<="001";enfre<='1';
else flag<="000";
end if;
elsif flag="100" then --标志为4
if keepcou3="1010" then
flag<="100";
else flag<="011";
end if;
elsif flag="010" then --标志为2
if keepcou3<"0001" then
flag<=flag-1;
enfre<='1';
elsif keepcou3="1010" then
flag<=flag+1;
else flag<=flag;
end if;
elsif flag="001" then --标志为1
if keepcou3<"0001" then
flag<=flag-1;
elsif keepcou3="1010" then
flag<=flag+1;
else flag<=flag;
enfre<='1';
end if;
else --标志为3
if keepcou3<"0001" then
flag<=flag-1;
elsif keepcou3="1010" then
flag<=flag+1;
else flag<=flag;
end if;
end if;
myfre<=count1;
when count1=> --处于计数状态1
if flag="001" or flag="000" then
enfre<='1';
else enfre<=enfre;
end if;
frecou<=1;
myfre<=count2to89;
when count2to89=> --处于计数状态2-89
if frecou=88 then
frecou<=89;
myfre<=count90;
else frecou<=frecou+1;
myfre<=count2to89;
end if;
when count90=> --处于计数状态90
if flag="010" then
enfre<='1';
else enfre<=enfre;
end if;
frecou<=90;
myfre<=count91to98;
when count91to98=> --处于计数状态91-98
if frecou=97 then
frecou<=98;
myfre<=count99;
else frecou<=frecou+1;
myfre<=count91to98;
end if;
when count99=> --处于计数状态99
if flag="011" or flag="100" then
enfre<='1';
else enfre<=enfre;
end if;
frecou<=99;
myfre<=count100;
when count100=> --处于计数状态100
frecou<=99;
enfre<='0';
myfre<=judge;
when others=>null;
end case;
end if;
end if;
end process ctrfre;
ctrtt:process(reset,flag)
begin
if reset='0' then
ttclk<='0';ttsig<='0';unit<='0';
else
if flag=0 then ttclk<=clklk; ttsig<=testsignal;unit<='1';
else ttclk<=testsignal;ttsig<=enfre; unit<='0';
end if;
end if;
end process ctrtt;
process (clklk)
begin
if (clklk'event and clklk='1')then
if (s="10") then
s<="00";
else s<=s+1;
end if;
end if;
end process;
process (s)
begin
case s is
when "00"=>jishu<=keepcou1;d<=dot(0);
when "01"=>jishu<=keepcou2;d<=dot(1);
when "10"=>jishu<=keepcou3;d<=dot(2);
when others=>null;
end case;
end process;
c1: frequency port map(reset,ttclk,ttsig,keepcou1,keepcou2,keepcou3);
dis:display1 port map(jishu,clklk,del1,display);
end one;
五、仿真截图
将dfre.vhd文件中的clk改成clk1k,并修改相应的位置,让dfre.vhd文件编译通过后,直接给clk1k输入1kHz信号,然后在程序中修改相应的输入测试信号,得到五个档位的相应仿真波形如下:
1、测试信号频率为250KHZ,周期为4us时仿真稳定后的图像如下:
2、测试信号频率为25KHz,周期为40us时,稳定后仿真波形图如下:
3、测试信号频率为5KHz,周期为200us时,波形仿真图如下:
4、测试信号周期为6ms,波形仿真图如下:
5、测试信号为2MHz时,波形仿真如下:
仿真结果与实验预期结果一致,软件实现了其相关功能。
六、软件硬件结合实现
1、打开QUARTUSII软件,新建一个工程。
2、建完工程之后,再新建一个VHDL File,打开VHDL编辑器对话框。
3、按照实验原理和自己的想法,在VHDL编辑窗口编写上面的VHDL程序,。其具体的功能如下表23-2:
4、将自己编辑好的的程序进行编译仿真,并对程序的错误进行修改,最终通过编译。
5、编译仿真无误后,依照所用模块与FPGA的管脚连接表或参照用户手册附表进行管脚分配。分配完成后,再进行全编译一次,以使管脚分配生效。
管脚分配图如下:
6、用下载电缆通过JTAG口将对应的sof文件加载到FPGA中。观察实验结果是否与
自己的编程思想一致。
7、观察发现实验结果与开始时实现功能一致,实验成功。当在软件程序里改变测试信
号的值,如后在硬件上实现,得到在误差范围内允许的正确读数。我想在程序部分
添加一锁存器实验结果会更好。
七、仿真及调试心得
仿真时把clk改成clk1k,并将相应部分修改,输入1KHz的时钟信号,这样比输入1MHz时钟信号要节省资源与时间。仿真时会出现各种情况与预期不一致,这时要认真读程序,然后修改程序,让仿真达到实验预期。有时,由于我们不太了解软件仿真的原理过程,可能在硬件上能实现其正确功能,但是在软件仿真时有个别地方错误,这样的情况下应该不是程序原理性错误,而是某个小地方不够完善,要改正这样的地方需要耐心与机遇。做学问就应该有一份持久的耐心。
八、总结
通过这次EDA课程设计我了解了测频的方法和原理;掌握了如何在FPGA内部设计多种功能模块,并通过综合设计实现其功能,并加深了对FPGA开发板的了解;掌握VHDL在测量模块设计方面的一些技巧,了解到了划分模块的一些经验,更提高了我VHDL语言的编程能力及阅读VHDL语言程序的能力,也更加了解了状态机的使用,及动态扫描显示译码的使用。