热度 28
2013-12-2 10:21
5887 次阅读|
7 个评论
利用FPGA+DAC0832制作的信号源 制作信号源有多种方法,但是由于接口数量以及手头资源的因素,我选择了用FPGA来产生一个信号源,算是自己正式开始了FPGA逻辑设计吧。本文介绍的就是我自己利用cyclone系列的FPGA制作的信号源,信号源的设计包括以下几个部分: 1、整个设计框架 2、各个小模块的实现(可调分频模块,三角波产生模块(含rom的定制,需先生成.mif文件),正弦波产生(同上)模块,方波产生模块,锯齿波产生模块,具体生成方法同上,4选1多路选择器模块,4路输入及输出均为8位,DAC0832控制器) 3、外围电路的设计(包括频率控制,加 减 设置功能,以及直接设置多少频率,显示模块(待设计),DAC0832模块) 4、仿真结果 在每一个设计开始的时候,首先要进行的是整体框架的划分,即系统有哪些部分组成,模块与模块之间应该怎样互联,明确这些之后才是具体的底层实现。 一、整体设计的框架图 系统时钟是FPGA正常工作所需的时钟(选取的是50MHz),时钟分频模块用于将系统时钟分频,它决定了信号波形的周期,通过控制它可以调整信号发生器产生的信号的周期(这里先介绍含有两个固定分频系数的分频器,如何产生可调周期的信号等下次详述)。接着是四个波形发生器,它们都需要先定制rom的初始化数据,然后再利用初始化的存储数据产生rom,利用QUARTUS Ⅱ产生各模块。4选1多路选择器,用于选择输出的波形,DAC0832控制器用于产生外部硬件的控制信号。接下来的是DAC0832的外部电路,用于产生最终输出的模拟信号。 在以上各模块中,难点是如何产生波形发生器,以及如何进行调频和调幅。(在本设计中只是用到了两个固定的周期,而且没有涉及到调幅,这些都将在下一篇中进行详述介绍)。 二、各小模块的具体实现 1、时钟分频模块 本部分设计的周期是6.25MHz和12.5MHz,对系统时钟进行8分频和4分频即可,分频系数分别为8和4。 具体实现电路原理图如下,rst信号用于复位,k4用于选择频率选择,当K4为高电平时输出频率为6.25MHz,为低电平时是12.5MHz。clkin是系统时钟为50MHz。 图1、分频模块 具体的FPGA实现代码如下: library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; use ieee.std_logic_arith.all; entity divide_8 is port( rst : in std_logic; clkin: in std_logic; k4: in std_logic; clkout: out std_logic ); end entity; architecture divide of divide_8 is signal n :integer range 0 to 7; signal clk: std_logic; begin devide:process(clkin,rst) begin if rst='0' then --reset configration clkout='0'; n=0; clk='0'; elsif rising_edge(clkin) then if k4='1' then if n=7 then --6.25MHz n=0; clk= not clk; else n=n+1; end if; else if n=3 then --12.5MHz n=0; clk=not clk; else n=n+1; end if; end if; end if; clkout=clk; end process; end architecture; 2、波形发生模块 本模块分为正弦波发生器模块,三角波发生器模块,方波发生器模块,锯齿波发生模块,分别用于产生对应的波形数据。 产生流程如下:1、建立存储器初始化数据表(用于存储波形数据)。2、利用新建立的初始化数据表.mif文件定制对应的rom,生成对应的波形发生器。 具体步骤如下: 2.1新建一个.mif文件。File→new→memory initialization file→ok 填入的字数为128,字节位数为8(字),这用于确定建立的数据表的大小。 图2、新建的.mif文件 在里面填入波形初始化数据即可,由于采用的是8位的数模转换器,转换精度为8位,最大值为255,对应的如果参考电压为5V的话,精度即为19.6mV。 定制rom过程如下: 利用megawizard plug-in manager定制正弦信号数据ROM宏功能块,并将上面的波形数据加载于此ROM中。 选择菜单tools—megawizard plug-in manager命令,在出现的对话框中选择create a new custom,单击next,产生图3所示对话框,如图设置 图3. LPM宏功能模块设定 在左栏选择memory compiler项下的ROM:1-PORT,再选择器件和VHDL语言方式,输入ROM文件存放的路径和文件名。单击next出现图4对话框,按图中设置 图4. 选择控制线、地址线和数据线 注意需要将上面设置框中的64改选为128,产生7位地址线,单击next,按图5所示设置 图5. 选择地址锁存信号inclock 单击next,按图6所示设置 图6. 调入ROM初始化数据文件并选择在系统读写功能 在上面的窗口中,点击browse选择工程下面的之前建立的sinwave.mif初始化数据文件,单击finish按钮完成ROM定制。将生成的sinwave.vhd文件加入工程中。 library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; entity rom_out is port(clk:in std_logic; dout:out std_logic_vector(7 downto 0)); end rom_out; architecture dacc of rom_out is component sinwave port(address:in std_logic_vector(6 downto 0); clock:in std_logic; q:out std_logic_vector(7 downto 0)); end component; signal q1:std_logic_vector(6 downto 0); --generate --address signal,address rise by 1 along with clk's rising_edge begin process(clk) begin if clk'event and clk='1' then q1=q1+1; end if; end process; u1:sinwave port map(address=q1,q=dout,clock=clk); --call --sinwave.mif file end dacc; 生成原理图文件:file- Create/Update-create symbol files for current file即可生成。如图7所示: 图7、正弦波发生器 其余三种波形发生器的生成方法与正弦波类似,这里就不再赘述,下面只将三角波、方波、锯齿波的初始化数据表和波形发生器顶层设计列出。 2.2三角波生成器 数据表如图8所示(这些数据都是可以自己计算的,方法是在对应的函数图形上取点,只取纵坐标上的点,并将其存入数据表即可), 图8、三角波数据 三角波发生器顶层设计 library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; entity tri_angle_out is port( clk: in std_logic; dout: out std_logic_vector(7 downto 0) ); end entity; architecture transmit of tri_angle_out is component tri_angle --tri_angle rom claim port( address: in std_logic_vector(6 downto 0); clock: in std_logic; q: out std_logic_vector(7 downto 0) ); end component; signal q1 : std_logic_vector(6 downto 0); begin process(clk) begin if(rising_edge(clk)) then q1=q1+1; end if; end process; u1: tri_angle port map(clock=clk,address=q1,q=dout); --call tri_angle.vhd file end architecture; 生成原理图文件,如图9所示 图9、三角波发生器原理图 2.3锯齿波发生器 波形数据如图10所示:此处只选取了64个数据,(这在数据rom定制中可以修改) 图10、锯齿波发生器数据 锯齿波发生器的顶层设计 library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; entity sawtooth_out is port( clk: in std_logic; dout: out std_logic_vector(7 downto 0) ); end entity; architecture transmit of sawtooth_out is component sawtooth port( address: in std_logic_vector(5 downto 0); clock: in std_logic; q: out std_logic_vector(7 downto 0) ); end component; signal q1 : std_logic_vector(5 downto 0);--由于是64个数据,所以此--处只有5位地址线 begin process(clk) begin if(rising_edge(clk)) then q1=q1+1; end if; end process; u1: sawtooth port map(clock=clk,address=q1,q=dout); end architecture; 原理图符号生成如图11所示: 图11锯齿波发生器原理图符号 2.4方波发生器模块 数据表如图12所示: 图12、方波发生器数据 方波发生器顶层设计: library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; entity fangbo_out is port( clk: in std_logic; dout: out std_logic_vector(7 downto 0) ); end entity; architecture transmit of fangbo_out is component fangbo port( address: in std_logic_vector(6 downto 0); clock: in std_logic; q: out std_logic_vector(7 downto 0) ); end component; signal q1 : std_logic_vector(6 downto 0); begin process(clk) begin if(rising_edge(clk)) then q1=q1+1; end if; end process; u1: fangbo port map(clock=clk,address=q1,q=dout); end architecture; 方波发生器的原理图13所示: 图13、方波发生器原理图 注:在以上的顶层设计中,只是相对于定制的rom模块来说是顶层设计,并不是整个设计的顶层设计,每一个发生器的顶层设计中均需要调用已生成的IP核,即rom模块,这就需要先进行被调用模块的声明,然后还需要对其进行例化才能正确调用。 三、4选1多路选择器的设计 4选1多路选择器由4路8输入端及两条选择线控制,输出为1路8输出信号。当选择输入信号sel与输出的对应关系见具体设计。 具体实现如下所示: library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; entity mux4_1 is port( rst: in std_logic; din4,din3,din2,din1: in std_logic_vector(7 downto 0); sel: in std_logic_vector(1 downto 0); q: out std_logic_vector(7 downto 0) ); end entity; architecture sel of mux4_1 is begin process(sel,din4,din3,din2,din1,rst) begin if rst='0' then q="00000000"; --复位 else case sel is --输入选择控制 when "00"= q=din1; when "01"= q=din2; when "10"= q=din3; when "11"= q=din4; when others= q=din1; end case; end if; end process; end architecture; 生成的原理图文件如图14所示: 图14、 4选1多路选择器 四、DAC0832外部电路的设计:如图15所示:DAC0832的具体使用介绍网上已有很多资料介绍,本设计不再单独列出,可参照网上。本设计的DAC0832的引脚图如下所示: 图15、DAC0832的引脚图 DI0~DI7:数据输入线,TLL电平。 ILE:数据锁存允许控制信号输入线,高电平有效。 CS:片选信号输入线,低电平有效。 WR1:为输入寄存器的写选通信号。 XFER:数据传送控制信号输入线,低电平有效。 WR2:为DAC寄存器写选通输入线。 Iout1:电流输出线。当输入全为1时Iout1最大。 Iout2: 电流输出线。其值与Iout1之和为一常数。 Rfb:反馈信号输入线,芯片内部有反馈电阻. Vcc:电源输入线 (+5v~+15v) 。 Vref:基准电压输入线 (-10v~+10v) 。 AGND:模拟地,摸拟信号和基准电源的参考地.。 DGND:数字地,两种地线在基准电源处共地比较好。 D/A转换结果采用电流形式输出。若需要相应的模拟电压信号,可通过一个高输入阻抗的线性运算放大器实现。运放的反馈电阻可通过RFB端引用片内固有电阻,也可外接。 控制时序如图16所示: 图16、DAC0832的控制时序图 具体设计如下所示: library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; use ieee.std_logic_arith.all; entity DAC0832 is port(din :in std_logic_vector(7 downto 0); --data input rst :in std_logic; cs :out std_logic; --控制信号cs wr1 :out std_logic; --控制信号wr1 dout:out std_logic_vector(7 downto 0) --波形数据输出 ); end DAC0832; architecture behav of DAC0832 is begin process(rst) begin if rst='0' then cs='1'; wr1='1'; dout="00000000"; else cs='0'; wr1='0'; dout=din; --cs、wr1赋值;波形数据输出; end if; end process; end behav; 注:以上设计中没有涉及到的控制引脚信号,已利用外部硬件对应的连到地或电源线上了。 具体生成的原理图符号如图16所示: 图16、DAC0832控制模块原理图文件 将以上所生成的各部分按对应关系连接在顶层文件中,即构成了整个设计,具体如下(图17)可放大 六、仿真结果如下所示: 6.25MHz的正弦波 12.5 MHz的正弦波 6.25 MHz的方波 12.5 MHz的方波 6.25 MHz的三角波 12.5 MHz的三角波 6.25 MHz的锯齿波 12.5 MHz的锯齿波