本帖最后由 IT举人 于 2015-5-16 19:00 编辑
由于最近比较多的同学们问的怎么用FPGA设计spwm和正弦函数输出,所以的干脆写个帖子来教大家,这样可以系统和详细一点。由于本人也是初学FPGA,所以难免会有差错,望大家多多指出。好吧,我们先来看看题目要求:
基本功能: (1 )实现单相正弦波脉宽调制信号(SPWM)输出。 (2)调制波(正弦波)的频率至少有三档可调,且频率显示在数码管上; (3)按钮开关输入须消抖处理。 (4)同时输出调制波(正弦波),使得可以将正弦波和SPWM同时显示在示波器上。 注:由于实验板上无数模转换(D/A)芯片,因此需设计一PWM发生器。正弦波数据输入PWM发生器,产生PWM信号,PWM信号经过RC低通滤波器输出模拟电压。 在完成基本功能的基础上,可发挥增加一些实用的功能。
即是题目要求我们输出两路,一是SPWM,另是调制波(正弦波)。其实无论是spwm还是调制波,归根到底都是正弦波的问题,所以本题的难点和重点都在于正弦波。下面我们就先说说怎么输出正弦波。 一、正弦信号输出 正弦波输出有多种方法,其中最常用的就是查表法。查表法即是在事先把正弦函数的数据点存进FPGA的ROM,然后再根据ROM中的数据生成相应的PWM,再经过低通滤波后输出就是正弦信号了。 1、正弦信号数据ROM的定制 利用quarterii是可以自由的定制ROM数据(.mif文件)并且生成元件(.vhd文件)的。步奏如下: 1.1、建立.mif 格式文件。首先选择 ROM 数据文件编辑窗,即在 File 菜单中选择“New” ,并在 New 窗中选择“Memory Initialization File” (图 1-1~1-3) ,点击 OK 后产生 ROM 数据文件大小选择窗。这里采用 512 点 8位数据的情况,可选 ROM 的数据数 Number 为 512,数据宽 Word size 取 8 位。点击“OK” ,将出现如图 3-12 的空的 mif数据表格,表格中的数据为 10 进制表达方式,任一数据(如第1行的 12)对应的地址为左列与顶行数之和) 。将波形数据填入此表中,完成后在 File 菜单中点击“Save as” ,保存此数据文件,在这里不妨取名为.sin_512.mif。
1.2 根据.mif文件生成元件。利用建立好的.mif文件是可以自动生成元件代码的,这一点非常好用,勉去了我们手动添加代码麻烦。
设置 MegaWizard Plug-In Manager 初始对话框。在 Tools 菜单中选择“MegaWizard Plug-In Manager” ,产生图①的界面,选择“Create a new custom…”项,即定制一个新的模块。点击“Next”后,产生图 ② 对话框,在左栏选择“Memory Compiler”项下的 ROM 1port,再选“Cyclone”器件和 VHDL 语言方式,最后键入 ROM 文件存放的路径和文件名:,点击“Next” 。选择 ROM 控制线和地址、数据线。在图③所示的对话框中选择地址与数据的位宽分别为 8 和 512,选择地址所存控制信号 inclock 。接着倒入在1.1中建好的mif文件,如图⑤,之后一直保持默认。最后完成 ROM 文件sin_512.vhd的生成。
在工程文件下可以看到生成的ROM文件sin_512.vhd,点击打开发现其代码如下: LIBRARY ieee;
USE ieee.std_logic_1164.all;
LIBRARY altera_mf;
USE altera_mf.all;
ENTITY sin_512 IS
PORT
(
address : IN STD_LOGIC_VECTOR (8 DOWNTO 0);
clock : IN STD_LOGIC := '1';
q : OUT STD_LOGIC_VECTOR (6 DOWNTO 0)
);
END sin_512;
ARCHITECTURE SYN OF sin_512 IS
SIGNAL sub_wire0 : STD_LOGIC_VECTOR (6 DOWNTO 0);
COMPONENT altsyncram
GENERIC (
clock_enable_input_a : STRING;
clock_enable_output_a : STRING;
init_file : STRING;
intended_device_family : STRING;
lpm_hint : STRING;
lpm_type : STRING;
numwords_a : NATURAL;
operation_mode : STRING;
outdata_aclr_a : STRING;
outdata_reg_a : STRING;
widthad_a : NATURAL;
width_a : NATURAL;
width_byteena_a : NATURAL
);
PORT (
address_a : IN STD_LOGIC_VECTOR (8 DOWNTO 0);
clock0 : IN STD_LOGIC ;
q_a : OUT STD_LOGIC_VECTOR (6 DOWNTO 0)
);
END COMPONENT;
BEGIN
q <= sub_wire0(6 DOWNTO 0);
altsyncram_component : altsyncram
GENERIC MAP (
clock_enable_input_a => "BYPASS",
clock_enable_output_a => "BYPASS",
init_file => "sin_512.mif",
intended_device_family => "Cyclone II",
lpm_hint => "ENABLE_RUNTIME_MOD=NO",
lpm_type => "altsyncram",
numwords_a => 512,
operation_mode => "ROM",
outdata_aclr_a => "NONE",
outdata_reg_a => "CLOCK0",
widthad_a => 9,
width_a => 7,
width_byteena_a => 1
)
PORT MAP (
address_a => address,
clock0 => clock,
q_a => sub_wire0
);
END SYN;
代码中的结构体部分我们不用理会,只需关注其实体定义即可。实体就三个参数: address : IN STD_LOGIC_VECTOR (8 DOWNTO 0);
clock : IN STD_LOGIC := '1';
q : OUT STD_LOGIC_VECTOR (6 DOWNTO 0) 从参数可以看出,我们只要传进ROM的地址address(即是mif表格中的左列数addr+行数之和,类似数组的下标)和给个工作时钟clock ,它即输出了此地址对应的数据q;
注意,在1.1中我们手动生成mif只要是为了让大家更好地理解好ROM储存的结构,其实有一款非常好用的软件Guagle_wave(附录一)可以直接生成我们想要的各种波形的mif文件,然后再按照1.2的步骤生成元件即可(如果有同学已完全手动生成的ROM数据,会会被打死呢:funk::funk:) 打开软件,如图3-1。接着在查看—>全局参数,设置参数,如图3-2。设置完参数好,在设定波形菜单下选择正弦波,即可生成相应参数的正弦波数据点,图3-3。最后点击另存为,把mif文件保存你的工程目录下,图3-4,即可大功告成。
至此,ROM单元定制已经完全完成,怎么调用来生成正弦波,我们将在下一贴再具体说明, 大家有什么问题欢迎回帖提问,我会尽我最大能力回答大家,谢谢。
|