打印
[FPGA]

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

[复制链接]
1554|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
IT举人|  楼主 | 2015-5-16 19:00 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 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-3
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,即可大功告成。
图3-1   
图3-2   
                                                                                                             图3-3                                                                                                           
             图3-4


至此,ROM单元定制已经完全完成,怎么调用来生成正弦波,我们将在下一贴再具体说明,大家有什么问题欢迎回帖提问,我会尽我最大能力回答大家,谢谢。

Guagle_wave.zip

234.02 KB

相关帖子

沙发
505091994| | 2015-5-16 19:28 | 只看该作者
哇塞!楼主威武啊!!!感谢!:)

使用特权

评论回复
板凳
lzayoi| | 2015-5-16 19:37 | 只看该作者
wenjugege,威武威武,求教如何比较三角波和正弦波,具体怎么设置时钟

使用特权

评论回复
地板
IT举人|  楼主 | 2015-5-16 20:45 | 只看该作者
lzayoi 发表于 2015-5-16 19:37
wenjugege,威武威武,求教如何比较三角波和正弦波,具体怎么设置时钟

等等

使用特权

评论回复
5
IT举人|  楼主 | 2015-5-16 23:01 | 只看该作者
505091994 发表于 2015-5-16 19:28
哇塞!楼主威武啊!!!感谢!

谢谢

使用特权

评论回复
6
xlhtracy| | 2015-5-19 09:52 | 只看该作者
图片都没有呢?

使用特权

评论回复
7
shaoyuan02| | 2015-5-20 14:38 | 只看该作者
学习了,能不能给个学习视频啊?我见明德扬,至芯都有,

使用特权

评论回复
8
chunzhengcibei| | 2015-10-4 17:08 | 只看该作者
mark

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

4

主题

11

帖子

3

粉丝