本帖最后由 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-1
图1-2
图1-31.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,即可大功告成。
图3-1 图3-2 图3-3 图3-4
至此,ROM单元定制已经完全完成,怎么调用来生成正弦波,我们将在下一贴再具体说明,
大家有什么问题欢迎回帖提问,我会尽我最大能力回答大家,谢谢。
一周热门 更多>