基于FPGA的正弦脉宽调制波设计(一)

2020-02-17 19:43发布

本帖最后由 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,点击打开发现其代码如下:
  1. LIBRARY ieee;
  2. USE ieee.std_logic_1164.all;

  3. LIBRARY altera_mf;
  4. USE altera_mf.all;

  5. ENTITY sin_512 IS
  6.         PORT
  7.         (
  8.                 address                : IN STD_LOGIC_VECTOR (8 DOWNTO 0);
  9.                 clock                : IN STD_LOGIC  := '1';
  10.                 q                : OUT STD_LOGIC_VECTOR (6 DOWNTO 0)
  11.         );
  12. END sin_512;


  13. ARCHITECTURE SYN OF sin_512 IS

  14.         SIGNAL sub_wire0        : STD_LOGIC_VECTOR (6 DOWNTO 0);



  15.         COMPONENT altsyncram
  16.         GENERIC (
  17.                 clock_enable_input_a                : STRING;
  18.                 clock_enable_output_a                : STRING;
  19.                 init_file                : STRING;
  20.                 intended_device_family                : STRING;
  21.                 lpm_hint                : STRING;
  22.                 lpm_type                : STRING;
  23.                 numwords_a                : NATURAL;
  24.                 operation_mode                : STRING;
  25.                 outdata_aclr_a                : STRING;
  26.                 outdata_reg_a                : STRING;
  27.                 widthad_a                : NATURAL;
  28.                 width_a                : NATURAL;
  29.                 width_byteena_a                : NATURAL
  30.         );
  31.         PORT (
  32.                         address_a        : IN STD_LOGIC_VECTOR (8 DOWNTO 0);
  33.                         clock0        : IN STD_LOGIC ;
  34.                         q_a        : OUT STD_LOGIC_VECTOR (6 DOWNTO 0)
  35.         );
  36.         END COMPONENT;

  37. BEGIN
  38.         q    <= sub_wire0(6 DOWNTO 0);

  39.         altsyncram_component : altsyncram
  40.         GENERIC MAP (
  41.                 clock_enable_input_a => "BYPASS",
  42.                 clock_enable_output_a => "BYPASS",
  43.                 init_file => "sin_512.mif",
  44.                 intended_device_family => "Cyclone II",
  45.                 lpm_hint => "ENABLE_RUNTIME_MOD=NO",
  46.                 lpm_type => "altsyncram",
  47.                 numwords_a => 512,
  48.                 operation_mode => "ROM",
  49.                 outdata_aclr_a => "NONE",
  50.                 outdata_reg_a => "CLOCK0",
  51.                 widthad_a => 9,
  52.                 width_a => 7,
  53.                 width_byteena_a => 1
  54.         )
  55.         PORT MAP (
  56.                 address_a => address,
  57.                 clock0 => clock,
  58.                 q_a => sub_wire0
  59.         );



  60. 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单元定制已经完全完成,怎么调用来生成正弦波,我们将在下一贴再具体说明,大家有什么问题欢迎回帖提问,我会尽我最大能力回答大家,谢谢。
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。