FPGA学习笔记——简易的DDS信号发生器

目录

一、任务

二、分析

[三、ROM IP核配置](#三、ROM IP核配置)

四、Visio图

五、代码

(1).v代码

(2)仿真代码

六、仿真

七、实验现象



一、任务

用串口模块,用上位机发送指令,FPGA接收,然后输出对应的波形;其中指令用FE+波形+类型+频率+相位+幅度+EE。

波形:选择哪个波形

类型:频率缩小还是放大


二、分析

首先要有串口模块rx和tx,还要有四个单端口ROM模块,分别存储四种不同的波形,然后还要对指令处理的模块,将处理后的指令给各个模块使用。


三、ROM IP核配置


四、Visio图

这里我就用RTL Viewer代替了。


五、代码

(1).v代码

top.v

cpp 复制代码
module top (
input       wire            clk             ,
input       wire            rst_n           ,
input       wire            rx              ,
input       wire            key             ,
output      wire            led             ,
output      wire            tx              
);
//key
wire    key_out;
//tx
wire    [7:0]   data_tx;
wire            start  ;
wire            done_tx;
//rx
wire    [7:0]   data_rx;
wire            done_rx;
//ctrl_rom1
wire      [7:0]   data_wave1;
wire              done_wave1;

//ctrl_rom2
wire      [7:0]   data_wave2;
wire              done_wave2;

//ctrl_rom3
wire      [7:0]   data_wave3;
wire              done_wave3;

//ctrl_rom4
wire      [7:0]   data_wave4;
wire              done_wave4;

//cmd
wire     [7:0]   wave    ;
wire     [1:0]   mode    ;
wire     [7:0]   freq    ;
wire     [7:0]   phas    ;
wire     [7:0]   ampl    ;
wire             done_cmd;
//select_wave
wire     [7:0]   data_wave;
wire             done_wave;


cmd cmd_u(
.    clk      (clk     )   ,
.    rst_n    (rst_n   )   ,
.    key_out  (  key_out     )   ,
.    data_rx  (data_rx )   ,//并行数据 ,其它模块用
.    done_rx  (done_rx )   ,
.    led      (led     )   ,
.    wave     (wave    )   ,//波形
.    mode     (mode    )   ,//01:除法;10:乘法
.    freq     (freq    )   ,//频率
.    phas     (phas    )   ,//相位
.    ampl     (ampl    )   ,//赋值
.    done_cmd (done_cmd)    //命令解析完成
);

rx rx_u(
.   clk      (clk    )  ,
.   rst_n    (rst_n  )  ,
.   rx       (rx     )  ,//数据接收信号线
.   data_rx  (data_rx)  ,//并行数据 ,其它模块用
.   done_rx  (done_rx)   //握手信号 ,接收结束信号 , 结束成功信号  
);

tx tx_u(
.   clk     (clk      )  ,
.   rst_n   (rst_n    )  ,
.   data_tx (data_wave)  ,//并行输入 --- 变化
.   start   (done_wave)  ,//数据有效信号
.   tx      (tx       )  ,  //串行输出
.   done_tx (done_tx  )    //字节传输完成
);

ctrl_rom1 ctrl_rom1_u(
.    clk        (clk       ) ,
.    rst_n      (rst_n     ) ,
.    wave       (wave      ) ,//波形
.    mode       (mode      ) ,//01:除法(  );10:乘法(  )
.    freq       (freq      ) ,//频率
.    done_tx    (done_tx   ) ,
.    phas       (phas      ) ,//相位
.    ampl       (ampl      ) ,//幅值
.    done_cmd   (done_cmd  ) ,//命令解析完成
.    data_wave1 (data_wave1) ,
.    done_wave1 (done_wave1)  
);

ctrl_rom2 ctrl_rom2_u(
.    clk        (clk       ) ,
.    rst_n      (rst_n     ) ,
.    wave       (wave      ) ,//波形
.    mode       (mode      ) ,//01:除法(  );10:乘法(  )
.    freq       (freq      ) ,//频率
.    done_tx    (done_tx   ) ,
.    phas       (phas      ) ,//相位
.    ampl       (ampl      ) ,//幅值
.    done_cmd   (done_cmd  ) ,//命令解析完成
.    data_wave2 (data_wave2) ,
.    done_wave2 (done_wave2)  
);

ctrl_rom3 ctrl_rom3_u(
.    clk        (clk       ) ,
.    rst_n      (rst_n     ) ,
.    wave       (wave      ) ,//波形
.    mode       (mode      ) ,//01:除法(  );10:乘法(  )
.    freq       (freq      ) ,//频率
.    done_tx    (done_tx   ) ,
.    phas       (phas      ) ,//相位
.    ampl       (ampl      ) ,//幅值
.    done_cmd   (done_cmd  ) ,//命令解析完成
.    data_wave3 (data_wave3) ,
.    done_wave3 (done_wave3)  
);

ctrl_rom4 ctrl_rom4_u(
.    clk        (clk       ) ,
.    rst_n      (rst_n     ) ,
.    wave       (wave      ) ,//波形
.    mode       (mode      ) ,//01:除法(  );10:乘法(  )
.    freq       (freq      ) ,//频率
.    done_tx    (done_tx   ) ,
.    phas       (phas      ) ,//相位
.    ampl       (ampl      ) ,//幅值
.    done_cmd   (done_cmd  ) ,//命令解析完成
.    data_wave4 (data_wave4) ,
.    done_wave4 (done_wave4)  
);

select_wave select_wave_u(
.      clk        (clk       ) ,
.      rst_n      (rst_n     ) ,
.      done_cmd   (done_cmd  ) ,//命令解析完成
.      wave       (wave      ) ,//波形
.      data_wave1 (data_wave1) ,
.      done_wave1 (done_wave1) ,
.      data_wave2 (data_wave2) ,
.      done_wave2 (done_wave2) ,
.      data_wave3 (data_wave3) ,
.      done_wave3 (done_wave3) ,
.      data_wave4 (data_wave4) ,
.      done_wave4 (done_wave4) ,
.      data_wave  (data_wave ) ,
.      done_wave  (done_wave ) 
);

key key_u(
.     clk       (clk    ) ,
.     rst_n     (rst_n  ) ,
.     key       (key    ) ,
.     key_out   (key_out)
);

endmodule

cmd.v

cpp 复制代码
module cmd (
input       wire            clk         ,
input       wire            rst_n       ,
input       wire            key_out     ,
input       wire    [7:0]   data_rx     ,//并行数据 ,其它模块用
input       wire            done_rx     ,
output      reg             led         ,
output      reg     [7:0]   wave        ,//波形
output      reg     [1:0]   mode        ,//01:除法;10:乘法
output      reg     [7:0]   freq        ,//频率
output      reg     [7:0]   phas        ,//相位
output      reg     [7:0]   ampl        ,//幅值
output      reg             done_cmd     //命令解析完成
);
//指令处理

localparam  IDLE  = 8'b0000_0001,
            START = 8'b0000_0010,
            WAVE  = 8'b0000_0100, 
            MODE  = 8'b0000_1000, 
            FREQ  = 8'b0001_0000,
            PHAS  = 8'b0010_0000,
            AMPL  = 8'b0100_0000,
            STOP  = 8'b1000_0000;
reg    [7:0]    cur_state ,next_state ;

always @(posedge clk) begin
    if(!rst_n)
        cur_state <= IDLE;
    else
        cur_state <= next_state;
end

always @(*) begin
    if(!rst_n)
        next_state = IDLE;
    else
        case (cur_state)
            IDLE :begin
                if(key_out)
                    next_state = START;
                else
                    next_state = cur_state;
            end
            START:begin   //包头
                if( data_rx == 8'hFE && done_rx )
                    next_state = WAVE;
                else if( data_rx != 8'hFE && done_rx )
                    next_state = IDLE;
                else
                    next_state = cur_state;
            end
            WAVE :begin  //波形
                if( done_rx )
                    next_state = MODE;
                else
                    next_state = cur_state;
            end
            MODE :begin  //
                if( done_rx )
                    next_state = FREQ;
                else
                    next_state = cur_state;
            end
            FREQ :begin  //
                if( done_rx )
                    next_state = PHAS;
                else
                    next_state = cur_state;
            end
            PHAS :begin  //
                if( done_rx )
                    next_state = AMPL;
                else
                    next_state = cur_state;
            end
            AMPL :begin  //
                if( done_rx )
                    next_state = STOP;
                else
                    next_state = cur_state;
            end
            STOP : begin  //包尾
                if( done_rx && data_rx == 8'hEE)
                    next_state = START;
                else if(done_rx && data_rx != 8'hEE)
                    next_state = IDLE;
                else
                    next_state = cur_state;
            end
            default: next_state = IDLE;
        endcase
end


always @(posedge clk) begin
   if(!rst_n) begin
        led      <= 0;
        wave     <= 0;
        mode     <= 0;
        freq     <= 0;
        phas     <= 0;
        ampl     <= 0;
        done_cmd <= 0;
   end 
   else
        case (cur_state)
            IDLE :begin
            led      <= 1;
            wave     <= 0;
            mode     <= 0;
            freq     <= 0;
            phas     <= 0;
            ampl     <= 0;
            done_cmd <= 0;
        end 
            START:begin
            led      <= 0;
            wave     <= wave    ;
            mode     <= mode    ;
            freq     <= freq    ;
            phas     <= phas    ;
            ampl     <= ampl    ;
            done_cmd <= 0;
        end 
            WAVE :begin
                if(done_rx)
                    wave <= data_rx; 
            end
            MODE :begin
                if(done_rx)
                    mode <= data_rx; 
            end
            FREQ :begin
                if(done_rx)
                    freq <= data_rx; 
            end
            PHAS :begin
                if(done_rx)
                    phas <= data_rx; 
            end
            AMPL :begin
                if(done_rx)
                    ampl <= data_rx; 
            end
            STOP : begin
                if(done_rx && data_rx == 8'hEE)
                    done_cmd <= 1; 
                else
                    done_cmd <= 0; 
            end
            default: begin
        led      <= 0;
        wave     <= 0;
        mode     <= 0;
        freq     <= 0;
        phas     <= 0;
        ampl     <= 0;
        done_cmd <= 0;
   end 
        endcase
end

endmodule

ctrl_rom1.v

cpp 复制代码
module ctrl_rom1 (
input       wire             clk         ,
input       wire             rst_n       ,
input       wire     [7:0]   wave        ,//波形
input       wire     [1:0]   mode        ,//01:除法(  );10:乘法(  )
input       wire     [7:0]   freq        ,//频率
input       wire             done_tx     ,
input       wire     [7:0]   phas        ,//相位
input       wire     [7:0]   ampl        ,//幅值
input       wire             done_cmd    ,//命令解析完成
output      reg      [7:0]   data_wave1  ,
output      reg              done_wave1   
);
//rom1
wire    [7:0]   q;
reg     [7:0]   address;
reg     [7:0]   q_reg ;//幅度计算寄存器

//------------信号寄存---------//
reg    done_cmd_reg;
reg    [7:0]   wave_reg;
reg    [1:0]   mode_reg;
reg    [7:0]   freq_reg;
reg    [7:0]   phas_reg;
reg    [7:0]   ampl_reg;

always @(posedge clk) begin
    if(!rst_n) begin
        wave_reg <= 0;
        mode_reg <= 0;
        freq_reg <= 0;
        phas_reg <= 0;
        ampl_reg <= 0;
        done_cmd_reg <= 0;
    end
    else if ( done_cmd ) begin
        wave_reg <= wave;
        mode_reg <= mode;
        freq_reg <= freq;
        phas_reg <= phas;
        ampl_reg <= ampl;
        done_cmd_reg <=done_cmd;
    end
    else
        done_cmd_reg <= 0;
end

//状态机--------------------//
localparam  IDLE = 7'b0000001,   //等待key_out
            WAVE = 7'b0000010,   //波形判断
            PHAS = 7'b0000100,   //相位:rom地址起始值
            FREQ = 7'b0001000,   //频率:01:隔n个地址取一次数据,10:同一个地址数据取n次
            AMPL = 7'b0010000,   //计算幅值
            DATA = 7'b0100000,   //输出波形 + done
            STOP = 7'b1000000;   //等待done_tx 构成循环
reg    [6:0]   cur_state , next_state;
reg    [3:0]    cnt;



//
always @(posedge clk) begin
    if(!rst_n)
        cur_state <= IDLE;
    else
        cur_state <= next_state;
end

always @(*) begin
    if(!rst_n) begin
        next_state = IDLE;
    end
    else
        case (cur_state)
            IDLE: begin
                if(done_cmd_reg)
                    next_state = WAVE;
                else
                    next_state = cur_state;
            end
            WAVE: begin
                if(wave_reg == 8'h01)
                    next_state = PHAS;
                else if (wave_reg != 8'h01)
                    next_state = IDLE;
                else
                    next_state = cur_state;
            end
            PHAS:begin
                if(done_cmd_reg)
                    next_state = WAVE;
                else
                    next_state = FREQ;
            end
            FREQ:begin
                if(done_cmd_reg)
                    next_state = WAVE;
                else if( cnt == freq_reg - 1 && mode_reg == 2'b01 )
                    next_state = AMPL;
                else if( mode_reg == 2'b10 )
                    next_state = AMPL;
                else
                    next_state = cur_state;
            end
            AMPL:begin
                if(done_cmd_reg)
                    next_state = WAVE;
                else
                    next_state = DATA;
            end
            DATA:begin
                if(done_cmd_reg)
                    next_state = WAVE;
                else
                    next_state = STOP;
            end
            STOP: begin
                if(done_cmd_reg)
                    next_state = WAVE;
                else if( done_tx )
                    next_state = FREQ;
                else
                    next_state = cur_state;
            end
            default: next_state = IDLE;
        endcase
end
                                                                                   
always @(posedge clk) begin
    if(!rst_n) begin
        data_wave1 <= 0;
        done_wave1 <= 0;
        address    <= 0;
        cnt        <= 0;
        q_reg      <= 0;
    end
    else
        case (cur_state)
            IDLE:begin
                data_wave1 <= 0;
                done_wave1 <= 0;
                address    <= 0;
                cnt        <= 0;
                q_reg      <= 0;
            end
            WAVE:begin
                data_wave1 <= 0;
                done_wave1 <= 0;
                address    <= 0;
                cnt        <= 0;
                q_reg      <= 0;
            end
            PHAS:begin//rom起始地址
                address    <= phas_reg;
            end
            FREQ:begin
                case (mode) //频率:01:隔n个地址取一次数据,10:同一个地址数据取n次
                    2'b01:begin
                        address <= address + 1;
                        if( cnt == freq_reg - 1 )
                            cnt <= 0;
                        else
                            cnt <= cnt + 1;
                    end
                    2'b10: begin
                        if( cnt == freq_reg - 1 ) begin
                            cnt <= 0;
                            address <= address + 1;
                        end
                        else
                            cnt <= cnt + 1;
                    end
                    default: begin
                        address    <= 0;
                        cnt        <= 0;
                    end
                endcase
            end
            AMPL:begin
                q_reg      <= q/ampl_reg;
            end
            DATA:begin
                data_wave1 <= q_reg;
                done_wave1 <= 1; //短信号
            end
            STOP: begin
                data_wave1 <= 0;
                done_wave1 <= 0;
                q_reg      <= 0;
            end
            default: begin
                data_wave1 <= 0;
                done_wave1 <= 0;
                address    <= 0;
                cnt        <= 0;
                q_reg      <= 0;
            end
        endcase
end

//rom1
rom1	rom1_inst (
	.aclr     ( !rst_n     ),
	.address  ( address    ),
	.clock    ( clk        ),
	.q        ( q          )
	);


endmodule

ctrl_rom2.v

cpp 复制代码
module ctrl_rom2 (
input       wire             clk         ,
input       wire             rst_n       ,
input       wire     [7:0]   wave        ,//波形
input       wire     [1:0]   mode        ,//01:除法(  );10:乘法(  )
input       wire     [7:0]   freq        ,//频率
input       wire             done_tx     ,
input       wire     [7:0]   phas        ,//相位
input       wire     [7:0]   ampl        ,//幅值
input       wire             done_cmd    ,//命令解析完成
output      reg      [7:0]   data_wave2  ,
output      reg              done_wave2   
);
//rom1
wire    [7:0]   q;
reg     [7:0]   address;
reg     [7:0]   q_reg ;//幅度计算寄存器

//------------信号寄存---------//
reg    done_cmd_reg;
reg    [7:0]   wave_reg;
reg    [1:0]   mode_reg;
reg    [7:0]   freq_reg;
reg    [7:0]   phas_reg;
reg    [7:0]   ampl_reg;

always @(posedge clk) begin
    if(!rst_n) begin
        wave_reg <= 0;
        mode_reg <= 0;
        freq_reg <= 0;
        phas_reg <= 0;
        ampl_reg <= 0;
        done_cmd_reg <= 0;
    end
    else if ( done_cmd ) begin
        wave_reg <= wave;
        mode_reg <= mode;
        freq_reg <= freq;
        phas_reg <= phas;
        ampl_reg <= ampl;
        done_cmd_reg <=done_cmd;
    end
    else
        done_cmd_reg <= 0;
end

//状态机--------------------//
localparam  IDLE = 7'b0000001,   //等待key_out
            WAVE = 7'b0000010,   //波形判断
            PHAS = 7'b0000100,   //相位:rom地址起始值
            FREQ = 7'b0001000,   //频率:01:隔n个地址取一次数据,10:同一个地址数据取n次
            AMPL = 7'b0010000,   //计算幅值
            DATA = 7'b0100000,   //输出波形 + done
            STOP = 7'b1000000;   //等待done_tx 构成循环
reg    [6:0]   cur_state , next_state;
reg    [3:0]    cnt;



//
always @(posedge clk) begin
    if(!rst_n)
        cur_state <= IDLE;
    else
        cur_state <= next_state;
end

always @(*) begin
    if(!rst_n) begin
        next_state = IDLE;
    end
    else
        case (cur_state)
            IDLE: begin
                if(done_cmd_reg)
                    next_state = WAVE;
                else
                    next_state = cur_state;
            end
            WAVE: begin
                if(wave_reg == 8'h02)
                    next_state = PHAS;
                else if (wave_reg != 8'h02)
                    next_state = IDLE;
                else
                    next_state = cur_state;
            end
            PHAS:begin
                if(done_cmd_reg)
                    next_state = WAVE;
                else
                    next_state = FREQ;
            end
            FREQ:begin
                if(done_cmd_reg)
                    next_state = WAVE;
                else if( cnt == freq_reg - 1 && mode_reg == 2'b01 )
                    next_state = AMPL;
                else if( mode_reg == 2'b10 )
                    next_state = AMPL;
                else
                    next_state = cur_state;
            end
            AMPL:begin
                if(done_cmd_reg)
                    next_state = WAVE;
                else
                    next_state = DATA;
            end
            DATA:begin
                if(done_cmd_reg)
                    next_state = WAVE;
                else
                    next_state = STOP;
            end
            STOP: begin
                if(done_cmd_reg)
                    next_state = WAVE;
                else if( done_tx )
                    next_state = FREQ;
                else
                    next_state = cur_state;
            end
            default: next_state = IDLE;
        endcase
end
                                                                                   
always @(posedge clk) begin
    if(!rst_n) begin
        data_wave2 <= 0;
        done_wave2 <= 0;
        address    <= 0;
        cnt        <= 0;
        q_reg      <= 0;
    end
    else
        case (cur_state)
            IDLE:begin
                data_wave2 <= 0;
                done_wave2 <= 0;
                address    <= 0;
                cnt        <= 0;
                q_reg      <= 0;
            end
            WAVE:begin
                data_wave2 <= 0;
                done_wave2 <= 0;
                address    <= 0;
                cnt        <= 0;
                q_reg      <= 0;
            end
            PHAS:begin//rom起始地址
                address    <= phas_reg;
            end
            FREQ:begin
                case (mode) //频率:01:隔n个地址取一次数据,10:同一个地址数据取n次
                    2'b01:begin
                        address <= address + 1;
                        if( cnt == freq_reg - 1 )
                            cnt <= 0;
                        else
                            cnt <= cnt + 1;
                    end
                    2'b10: begin
                        if( cnt == freq_reg - 1 ) begin
                            cnt <= 0;
                            address <= address + 1;
                        end
                        else
                            cnt <= cnt + 1;
                    end
                    default: begin
                        address    <= 0;
                        cnt        <= 0;
                    end
                endcase
            end
            AMPL:begin
                q_reg      <= q/ampl_reg;
            end
            DATA:begin
                data_wave2 <= q_reg;
                done_wave2 <= 1; //短信号
            end
            STOP: begin
                data_wave2 <= 0;
                done_wave2 <= 0;
                q_reg      <= 0;
            end
            default: begin
                data_wave2 <= 0;
                done_wave2 <= 0;
                address    <= 0;
                cnt        <= 0;
                q_reg      <= 0;
            end
        endcase
end


//rom2
rom2	rom2_inst (
	.aclr     ( !rst_n     ),
	.address  ( address    ),
	.clock    ( clk        ),
	.q        ( q          )
	);


endmodule

ctrl_rom3.v

cpp 复制代码
module ctrl_rom3 (
input       wire             clk         ,
input       wire             rst_n       ,
input       wire     [7:0]   wave        ,//波形
input       wire     [1:0]   mode        ,//01:除法(  );10:乘法(  )
input       wire     [7:0]   freq        ,//频率
input       wire             done_tx     ,
input       wire     [7:0]   phas        ,//相位
input       wire     [7:0]   ampl        ,//幅值
input       wire             done_cmd    ,//命令解析完成
output      reg      [7:0]   data_wave3  ,
output      reg              done_wave3   
);
//rom1
wire    [7:0]   q;
reg     [7:0]   address;
reg     [7:0]   q_reg ;//幅度计算寄存器

//------------信号寄存---------//
reg    done_cmd_reg;
reg    [7:0]   wave_reg;
reg    [1:0]   mode_reg;
reg    [7:0]   freq_reg;
reg    [7:0]   phas_reg;
reg    [7:0]   ampl_reg;

always @(posedge clk) begin
    if(!rst_n) begin
        wave_reg <= 0;
        mode_reg <= 0;
        freq_reg <= 0;
        phas_reg <= 0;
        ampl_reg <= 0;
        done_cmd_reg <= 0;
    end
    else if ( done_cmd ) begin
        wave_reg <= wave;
        mode_reg <= mode;
        freq_reg <= freq;
        phas_reg <= phas;
        ampl_reg <= ampl;
        done_cmd_reg <=done_cmd;
    end
    else
        done_cmd_reg <= 0;
end

//状态机--------------------//
localparam  IDLE = 7'b0000001,   //等待key_out
            WAVE = 7'b0000010,   //波形判断
            PHAS = 7'b0000100,   //相位:rom地址起始值
            FREQ = 7'b0001000,   //频率:01:隔n个地址取一次数据,10:同一个地址数据取n次
            AMPL = 7'b0010000,   //计算幅值
            DATA = 7'b0100000,   //输出波形 + done
            STOP = 7'b1000000;   //等待done_tx 构成循环
reg    [6:0]   cur_state , next_state;
reg    [3:0]    cnt;



//
always @(posedge clk) begin
    if(!rst_n)
        cur_state <= IDLE;
    else
        cur_state <= next_state;
end

always @(*) begin
    if(!rst_n) begin
        next_state = IDLE;
    end
    else
        case (cur_state)
            IDLE: begin
                if(done_cmd_reg)
                    next_state = WAVE;
                else
                    next_state = cur_state;
            end
            WAVE: begin
                if(wave_reg == 8'h03)
                    next_state = PHAS;
                else if (wave_reg != 8'h03)
                    next_state = IDLE;
                else
                    next_state = cur_state;
            end
            PHAS:begin
                if(done_cmd_reg)
                    next_state = WAVE;
                else
                    next_state = FREQ;
            end
            FREQ:begin
                if(done_cmd_reg)
                    next_state = WAVE;
                else if( cnt == freq_reg - 1 && mode_reg == 2'b01 )
                    next_state = AMPL;
                else if( mode_reg == 2'b10 )
                    next_state = AMPL;
                else
                    next_state = cur_state;
            end
            AMPL:begin
                if(done_cmd_reg)
                    next_state = WAVE;
                else
                    next_state = DATA;
            end
            DATA:begin
                if(done_cmd_reg)
                    next_state = WAVE;
                else
                    next_state = STOP;
            end
            STOP: begin
                if(done_cmd_reg)
                    next_state = WAVE;
                else if( done_tx )
                    next_state = FREQ;
                else
                    next_state = cur_state;
            end
            default: next_state = IDLE;
        endcase
end
                                                                                   
always @(posedge clk) begin
    if(!rst_n) begin
        data_wave3 <= 0;
        done_wave3 <= 0;
        address    <= 0;
        cnt        <= 0;
        q_reg      <= 0;
    end
    else
        case (cur_state)
            IDLE:begin
                data_wave3 <= 0;
                done_wave3 <= 0;
                address    <= 0;
                cnt        <= 0;
                q_reg      <= 0;
            end
            WAVE:begin
                data_wave3 <= 0;
                done_wave3 <= 0;
                address    <= 0;
                cnt        <= 0;
                q_reg      <= 0;
            end
            PHAS:begin//rom起始地址
                address    <= phas_reg;
            end
            FREQ:begin
                case (mode) //频率:01:隔n个地址取一次数据,10:同一个地址数据取n次
                    2'b01:begin
                        address <= address + 1;
                        if( cnt == freq_reg - 1 )
                            cnt <= 0;
                        else
                            cnt <= cnt + 1;
                    end
                    2'b10: begin
                        if( cnt == freq_reg - 1 ) begin
                            cnt <= 0;
                            address <= address + 1;
                        end
                        else
                            cnt <= cnt + 1;
                    end
                    default: begin
                        address    <= 0;
                        cnt        <= 0;
                    end
                endcase
            end
            AMPL:begin
                q_reg      <= q/ampl_reg;
            end
            DATA:begin
                data_wave3 <= q_reg;
                done_wave3 <= 1; //短信号
            end
            STOP: begin
                data_wave3 <= 0;
                done_wave3 <= 0;
                q_reg      <= 0;
            end
            default: begin
                data_wave3 <= 0;
                done_wave3 <= 0;
                address    <= 0;
                cnt        <= 0;
                q_reg      <= 0;
            end
        endcase
end

//rom3
rom3	rom3_inst (
	.aclr     ( !rst_n     ),
	.address  ( address    ),
	.clock    ( clk        ),
	.q        ( q          )
	);


endmodule

ctrl_rom4.v

cpp 复制代码
module ctrl_rom4 (
input       wire             clk         ,
input       wire             rst_n       ,
input       wire     [7:0]   wave        ,//波形
input       wire     [1:0]   mode        ,//01:除法(  );10:乘法(  )
input       wire     [7:0]   freq        ,//频率
input       wire             done_tx     ,
input       wire     [7:0]   phas        ,//相位
input       wire     [7:0]   ampl        ,//幅值
input       wire             done_cmd    ,//命令解析完成
output      reg      [7:0]   data_wave4  ,
output      reg              done_wave4   
);
//rom1
wire    [7:0]   q;
reg     [7:0]   address;
reg     [7:0]   q_reg ;//幅度计算寄存器

//------------信号寄存---------//
reg    done_cmd_reg;
reg    [7:0]   wave_reg;
reg    [1:0]   mode_reg;
reg    [7:0]   freq_reg;
reg    [7:0]   phas_reg;
reg    [7:0]   ampl_reg;

always @(posedge clk) begin
    if(!rst_n) begin
        wave_reg <= 0;
        mode_reg <= 0;
        freq_reg <= 0;
        phas_reg <= 0;
        ampl_reg <= 0;
        done_cmd_reg <= 0;
    end
    else if ( done_cmd ) begin
        wave_reg <= wave;
        mode_reg <= mode;
        freq_reg <= freq;
        phas_reg <= phas;
        ampl_reg <= ampl;
        done_cmd_reg <=done_cmd;
    end
    else
        done_cmd_reg <= 0;
end

//状态机--------------------//
localparam  IDLE = 7'b0000001,   //等待key_out
            WAVE = 7'b0000010,   //波形判断
            PHAS = 7'b0000100,   //相位:rom地址起始值
            FREQ = 7'b0001000,   //频率:01:隔n个地址取一次数据,10:同一个地址数据取n次
            AMPL = 7'b0010000,   //计算幅值
            DATA = 7'b0100000,   //输出波形 + done
            STOP = 7'b1000000;   //等待done_tx 构成循环
reg    [6:0]   cur_state , next_state;
reg    [3:0]    cnt;



//
always @(posedge clk) begin
    if(!rst_n)
        cur_state <= IDLE;
    else
        cur_state <= next_state;
end

always @(*) begin
    if(!rst_n) begin
        next_state = IDLE;
    end
    else
        case (cur_state)
            IDLE: begin
                if(done_cmd_reg)
                    next_state = WAVE;
                else
                    next_state = cur_state;
            end
            WAVE: begin
                if(wave_reg == 8'h04)
                    next_state = PHAS;
                else if (wave_reg != 8'h04)
                    next_state = IDLE;
                else
                    next_state = cur_state;
            end
            PHAS:begin
                if(done_cmd_reg)
                    next_state = WAVE;
                else
                    next_state = FREQ;
            end
            FREQ:begin
                if(done_cmd_reg)
                    next_state = WAVE;
                else if( cnt == freq_reg - 1 && mode_reg == 2'b01 )
                    next_state = AMPL;
                else if( mode_reg == 2'b10 )
                    next_state = AMPL;
                else
                    next_state = cur_state;
            end
            AMPL:begin
                if(done_cmd_reg)
                    next_state = WAVE;
                else
                    next_state = DATA;
            end
            DATA:begin
                if(done_cmd_reg)
                    next_state = WAVE;
                else
                    next_state = STOP;
            end
            STOP: begin
                if(done_cmd_reg)
                    next_state = WAVE;
                else if( done_tx )
                    next_state = FREQ;
                else
                    next_state = cur_state;
            end
            default: next_state = IDLE;
        endcase
end
                                                                                   
always @(posedge clk) begin
    if(!rst_n) begin
        data_wave4 <= 0;
        done_wave4 <= 0;
        address    <= 0;
        cnt        <= 0;
        q_reg      <= 0;
    end
    else
        case (cur_state)
            IDLE:begin
                data_wave4 <= 0;
                done_wave4 <= 0;
                address    <= 0;
                cnt        <= 0;
                q_reg      <= 0;
            end
            WAVE:begin
                data_wave4 <= 0;
                done_wave4 <= 0;
                address    <= 0;
                cnt        <= 0;
                q_reg      <= 0;
            end
            PHAS:begin//rom起始地址
                address    <= phas_reg;
            end
            FREQ:begin
                case (mode) //频率:01:隔n个地址取一次数据,10:同一个地址数据取n次
                    2'b01:begin
                        address <= address + 1;
                        if( cnt == freq_reg - 1 )
                            cnt <= 0;
                        else
                            cnt <= cnt + 1;
                    end
                    2'b10: begin
                        if( cnt == freq_reg - 1 ) begin
                            cnt <= 0;
                            address <= address + 1;
                        end
                        else
                            cnt <= cnt + 1;
                    end
                    default: begin
                        address    <= 0;
                        cnt        <= 0;
                    end
                endcase
            end
            AMPL:begin
                q_reg      <= q/ampl_reg;
            end
            DATA:begin
                data_wave4 <= q_reg;
                done_wave4 <= 1; //短信号
            end
            STOP: begin
                data_wave4 <= 0;
                done_wave4 <= 0;
                q_reg      <= 0;
            end
            default: begin
                data_wave4 <= 0;
                done_wave4 <= 0;
                address    <= 0;
                cnt        <= 0;
                q_reg      <= 0;
            end
        endcase
end

//rom4
rom4	rom4_inst (
	.aclr     ( !rst_n     ),
	.address  ( address    ),
	.clock    ( clk        ),
	.q        ( q          )
	);


endmodule

select_wave.v

cpp 复制代码
module select_wave (
input       wire             clk         ,
input       wire             rst_n       ,
input       wire             done_cmd    ,//命令解析完成
input       wire     [7:0]   wave        ,//波形
input       wire     [7:0]   data_wave1  ,
input       wire             done_wave1  ,
input       wire     [7:0]   data_wave2  ,
input       wire             done_wave2  ,
input       wire     [7:0]   data_wave3  ,
input       wire             done_wave3  ,
input       wire     [7:0]   data_wave4  ,
input       wire             done_wave4  ,
output      reg      [7:0]   data_wave   ,
output      reg              done_wave   
);
reg [7:0]  wave_reg;

always @(posedge clk) begin
    if(!rst_n)
        wave_reg <= 0;
    else
        wave_reg <= wave;
end


always @(*) begin
    if(!rst_n) begin
        data_wave = 0;
        done_wave = 0;
    end
    else
        case (wave_reg )
            8'h01:begin
                if( done_wave1 ) begin
                    data_wave = data_wave1;
                    done_wave = done_wave1;
                end
                else
                    begin
                    data_wave = 0;
                    done_wave = 0;
                end
            end
            8'h02: begin
                if( done_wave2 ) begin
                    data_wave = data_wave2;
                    done_wave = done_wave2;
                end
                else begin
                    data_wave = 0;
                    done_wave = 0;
                end
            end
            8'h03: begin
                if( done_wave3 ) begin
                    data_wave = data_wave3;
                    done_wave = done_wave3;
                end
                else begin
                    data_wave = 0;
                    done_wave = 0;
                end
            end
            8'h04: begin
                if( done_wave4 ) begin
                    data_wave = data_wave4;
                    done_wave = done_wave4;
                end
                else begin
                    data_wave = 0;
                    done_wave = 0;
                end
            end
            default: begin
                data_wave = 0;
                done_wave = 0;
            end
        endcase
end

endmodule

串口发送模块和按键模块可以去我的其它学习笔记找,这里就不发了。

(2)仿真代码

tb文件

cpp 复制代码
`timescale 1ns/1ns
module tb();
parameter   sysclk = 50_000_000  ,//系统时钟下:1s
            bps    = 115200      , //波特率
            delay  = sysclk / bps * 20;//1bit工作周期

reg             clk    ;
reg             rst_n  ;
reg             rx     ;
reg             key    ;
wire    [7:0]   data_rx;
wire            done_rx;
wire            key_out;

always #10 clk = ~clk;

initial begin
    clk = 0;
    rst_n = 0;
    rx = 1;
    key   = 1;
    #100
    rst_n = 1;
    key   = 0;
    #200
    key   = 1;
    send_data(8'hFE);

    #200
    send_data(8'h01);

    #200
    send_data(8'h01);

    #200
    send_data(8'h01);

    #200
    send_data(8'h01);

    #200
    send_data(8'h01);

    #200
    send_data(8'hee);
end

task send_data ;

input [7:0] data ;
begin
    rx = 1;
    #100 //空闲

    rx = 0; #delay //起始位

    rx = data[0]; #delay //数据位 
    rx = data[1]; #delay //数据位
    rx = data[2]; #delay //数据位
    rx = data[3]; #delay //数据位
    rx = data[4]; #delay //数据位
    rx = data[5]; #delay //数据位
    rx = data[6]; #delay //数据位
    rx = data[7]; #delay //数据位

    rx = 1; #delay; //停止位
end


endtask

rx rx_u(
.   clk      (clk    )   ,
.   rst_n    (rst_n  )   ,
.   rx       (rx     )   ,//数据接收信号线
.   data_rx  (data_rx)   ,//并行数据 ,其它模块用
.   done_rx  (done_rx)    //握手信号 ,接收结束信号 , 结束成功信号  
);

top top_u(
.      clk    (clk  )         ,
.      rst_n  (rst_n)         ,
.      rx     (rx   )         ,
.      key    (key  )         ,
.      led    (led  )          
);

key key_u(
.     clk       (clk    ) ,
.     rst_n     (rst_n  ) ,
.     key       (key    ) ,
.     key_out   (key_out)
);

endmodule

六、仿真

这里就列举波形一的,其它的,可以自己尝试尝试。


七、实验现象

波形一

波形二

波形三

波形四


以上就是简易DDS信号发生器。