DDS信号发生器加强版(双通道,发送波形的频率可控,相位可控,种类可控)

该博客介绍了一个双通道直接数字频率合成器(DDS)的设计,每个通道具有独立的频率、相位和波形选择。通过使用四个ROM分别存储正弦、三角、锯齿和方波,实现了波形种类的切换。频率通过计数器和频率控制按钮实现,相位同样通过计数器和相位控制按钮调整。文章还详细解释了输出波形周期与频率控制字的关系,并提供了Verilog代码实现。通过按键消抖模块提高系统稳定性,最后进行了功能验证。
摘要由CSDN通过智能技术生成

目的:设计一个DDS,可以输出两个波形,输出的波形的周期可以修改,相位可以修改,种类也可以修改

输入:clk,reset,一个控制T的按键,一个控制相位的按键,一个控制波形种类的按键。

思路:双通道——需要两个DDS。

     波形种类可控——每个DDS需要四个ROM分别存放正弦波,三角波,锯齿波,方波。

   频率可控——一个频率控制按钮,按一下切换一次频率,可供选择的频率是固定的,用计数器来设计。

      相位可控——一个相位控制按钮,按一下切换一次相位,可供选择的相位是固定的,用计数器来设计。

      有按钮——引入按键消抖模块,提高准确性。

   可控——计数器+查找表 可以实现简单切换。(其他,如矩阵键盘等,后续)

建模:

     

细节:输出波形的周期与频率控制的关系

  ROM存储一个波形,而相位累加器的内存存储一个波形的离散点。一般来说相位累加器内存大于ROM。而取点间隔就是频率控制字。

  比如ROM是十位【9:0】,而相位累加器是【15:0】,那么取点时相位累加器应该取高10位来ROM中取幅度,即【15:6】,这样子输出的波形的周期会随着频率控制字(即取点步长)的大小而改变。如果频率比较小(如2),那么取ROM中一个点要停留很多个系统时钟周期,且ROM中每个点都会被取到,输出的波形周期就长,如果频率比较大(如128),那么取ROM中一个点只停留一个系统时钟周期,且会跳过ROM中的某些点,输出的波形周期就短。

验证结果:

第一行:频率可控

第二行:波形可控

 

 

代码:

module DDS_advanced(
    clk,
    reset,
    f_change_A,
    f_change_B,
    p_change_A,
    p_change_B,
    wave_change_A,
    wave_change_B,
    dout_A,
    dout_B
    );
    input clk ;
    input reset ;
    input f_change_A ;
    input f_change_B ;
    input p_change_A ;
    input p_change_B ;
    input wave_change_A ;
    input wave_change_B ;
    output wire[9:0]dout_A ;
    output wire[9:0]dout_B ;
    
    
    reg [1:0]f_cnt_A ;//设置A通道的频率选择按钮的消抖,计数
    wire tx_fA ;
    wire f_change_A_sign ;
    buttopn_debounde 
    #(
    .delay(1000)
    )
    buttopn_debounde_fA (//消抖,取释放符号为+1信号
    .clk(clk),
    .tx(f_change_A),
    .reset(reset),
    .bd_tx(tx_fA),
    .release_sign(f_change_A_sign)
    );
    always@(posedge clk or negedge reset)//计数
    if (!reset)
        f_cnt_A <= 2'd0 ;
    else if(f_change_A_sign)    
        f_cnt_A <= f_cnt_A + 1'd1 ;
    else 
        f_cnt_A <= f_cnt_A ;
        
    reg [1:0]p_cnt_A ;//设置A通道的相位选择按钮的消抖,计数
    wire tx_pA ;
    wire p_change_A_sign ;
    buttopn_debounde 
    #(
    .delay(1000)
    )
    buttopn_debounde_pA (//消抖,取释放符号为+1信号
    .clk(clk),
    .tx(p_change_A),
    .reset(reset),
    .bd_tx(tx_pA),
    .release_sign(p_change_A_sign)
    );
    always@(posedge clk or negedge reset)//计数
    if (!reset)
        p_cnt_A <= 2'd0 ;
    else if(p_change_A_sign)    
        p_cnt_A <= p_cnt_A + 1'd1 ;
    else 
        p_cnt_A <= p_cnt_A ;    
    
    reg [1:0]wave_change_cnt_A ;//设置A通道的波形选择按钮的消抖,计数
    wire tx_wavea ;
    wire wave_change_A_debounde_sign ;
    buttopn_debounde 
    #(
    .delay(1000)
    )
    buttopn_debounde_waveA (//消抖,取释放符号为+1信号
    .clk(clk),
    .tx(wave_change_A),
    .reset(reset),
    .bd_tx(tx_wavea),
    .release_sign(wave_change_A_debounde_sign)
    );
    always@(posedge clk or negedge reset)//计数
    if (!reset)
        wave_change_cnt_A <= 2'd0 ;
    else if(wave_change_A_debounde_sign)    
        wave_change_cnt_A <= wave_change_cnt_A + 1'd1 ;
    else 
        wave_change_cnt_A <= wave_change_cnt_A ;
    
    
    
    
    
    reg [1:0]f_cnt_B ;//设置B通道的频率选择按钮的消抖,计数
    wire tx_fB ;
    wire f_change_B_sign ;
    buttopn_debounde 
    #(
    .delay(1000)
    )
    buttopn_debounde_fB (//消抖,取释放符号为+1信号
    .clk(clk),
    .tx(f_change_B),
    .reset(reset),
    .bd_tx(tx_fB),
    .release_sign(f_change_B_sign)
    );
    always@(posedge clk or negedge reset)//计数
    if (!reset)
        f_cnt_B <= 2'd0 ;
    else if(f_change_B_sign)    
        f_cnt_B <= f_cnt_B + 1'd1 ;
    else 
        f_cnt_B <= f_cnt_B ;
        
    reg [1:0]p_cnt_B ;//设置B通道的相位选择按钮的消抖,计数
    wire tx_pB ;
    wire p_change_B_sign ;
    buttopn_debounde 
    #(
    .delay(1000)
    )
    buttopn_debounde_pB (//消抖,取释放符号为+1信号
    .clk(clk),
    .tx(p_change_B),
    .reset(reset),
    .bd_tx(tx_pB),
    .release_sign(p_change_B_sign)
    );
    always@(posedge clk or negedge reset)//计数
    if (!reset)
        p_cnt_B <= 2'd0 ;
    else if(p_change_B_sign)    
        p_cnt_B <= p_cnt_B + 1'd1 ;
    else 
        p_cnt_B <= p_cnt_B ;   
        
    reg [1:0]wave_change_cnt_B ;//设置B通道的波形选择按钮的消抖,计数
    wire tx_waveb ;
    wire wave_change_B_debounde_sign ;
    buttopn_debounde 
    #(
    .delay(1000)
    )
    buttopn_debounde_waveB (//消抖,取释放符号为+1信号
    .clk(clk),
    .tx(wave_change_B),
    .reset(reset),
    .bd_tx(tx_waveb),
    .release_sign(wave_change_B_debounde_sign)
    );
    always@(posedge clk or negedge reset)//计数
    if (!reset)
        wave_change_cnt_B <= 2'd0 ;
    else if(wave_change_B_debounde_sign)    
        wave_change_cnt_B <= wave_change_cnt_B + 1'd1 ;
    else 
        wave_change_cnt_B <= wave_change_cnt_B ;
   
   DDS_Module channel_A(//A通道连线
    .clk(clk) ,
    .reset(reset) ,
    .f_ctrl(f_cnt_A) ,
    .p_ctrl(p_cnt_A) ,
    .wave_ctrl(wave_change_cnt_A) ,
    .dout(dout_A)
    );
    
    DDS_Module channel_B(//B通道连线
    .clk(clk) ,
    .reset(reset) ,
    .f_ctrl(f_cnt_B) ,
    .p_ctrl(p_cnt_B) ,
    .wave_ctrl(wave_change_cnt_B) ,
    .dout(dout_B)
    );
     
endmodule

module DDS_Module(
    clk ,
    reset ,
    f_ctrl ,
    p_ctrl ,
    wave_ctrl ,
    dout
    );
    input clk ;
    input reset ;
    input [1:0]wave_ctrl ;
    input [1:0]f_ctrl ;//(频率选择按钮)
    input [1:0]p_ctrl ;
    output reg [9:0]dout ;
    
    reg [4:0]frequen;
    always@(*)
        case(f_ctrl)
        0:frequen = 5'd2 ;//输出周期:(65536/2 )* 20ns = 655360ns
        1:frequen = 5'd4 ;//输出周期:(2^16/4 )* 20ns = 327680ns
        2:frequen = 5'd8 ;//输出周期:(2^16/8 )* 20ns = 163840ns
        3:frequen = 5'd16 ;//输出周期:(2^16/4 )* 20ns = 81920ns
        endcase
 
    //频率控制字寄存器(频率)(大于1的时候,后面相位累加器输出到实时相位时要砍掉它的位宽)
    reg [4:0]f_regist ;//(取值限制为2的倍数)
    always @ (posedge clk)
        f_regist <= frequen ;
    
    //相位累加器  (f * t)  
    reg [15:0]p_add ;
    always@(posedge clk or negedge reset )
        if(!reset )
            p_add <= 0 ;
        else
            p_add <= p_add + f_regist ;
    
    reg [9:0]phase_cv;
    always@(*)
        case(p_ctrl)
        0:phase_cv = 10'd128 ;//45°
        1:phase_cv = 10'd256 ;//90°
        2:phase_cv = 10'd512 ;//135°
        3:phase_cv = 10'd640 ;//180°
        endcase
    //相位控制字寄存器(初始相位)(相位偏移量)
    reg [9:0]p_regist ;
    always @ (posedge clk)
        p_regist <= phase_cv ;
    
    //实时相位
    reg [9:0]p_now ;
    always@(posedge clk or negedge reset )
        if(!reset )
            p_now <= 0 ;
        else
            p_now <= p_add[15:6] + p_regist ; //取相位累加器的前10位
     
     
     wire [9:0]wave_sin ;
     wire [9:0]wave_square ;
     wire [9:0]wave_triangular;
     wire [9:0]wave_sawtooth;
     always@(*)//波形选择
        case(wave_ctrl)
            0: dout = wave_sin ;
            1: dout = wave_triangular ;
            2: dout = wave_square ;
            3: dout = wave_sawtooth ;
        endcase
        
     rom_sin rom_sin(//正弦波
      .clka(clk),
      .addra(p_now),
      .douta(wave_sin)
     ); 
     
     rom_triangular rom_triangular(//三角波
      .clka(clk),
      .addra(p_now),
      .douta(wave_triangular)
     );  
     
     rom_square rom_square(//方波
      .clka(clk),
      .addra(p_now),
      .douta(wave_square)
     );  
     
     rom_sawtooth rom_sawtooth(//锯齿波
      .clka(clk),
      .addra(p_now),
      .douta(wave_sawtooth)
     );  
        
endmodule
module buttopn_debounde(
    clk,
    tx,
    reset,
    bd_tx,
    release_sign
    );
    input tx ;
    input clk ;
    input reset ;
    output reg bd_tx ;
    output reg release_sign ;//按下释放信号
    
    reg [1:0]edge_detect_regist;
    always@(posedge clk or negedge reset)//输入信号的移位寄存器
    begin
        if (!reset)
            edge_detect_regist <= 2'd0 ;
        else 
            begin
            edge_detect_regist[0] <= tx ;
            edge_detect_regist[1] <= edge_detect_regist[0] ;
            //等效于 edge_detect_regist <={ edge_detect_regist[0] , tx }
            end            
    end
    
    wire neg_edge , pos_edge ;
    assign neg_edge = ( edge_detect_regist == 2'b10 ) ? 1 : 0 ;//下降沿
    assign pos_edge = ( edge_detect_regist == 2'b01 ) ? 1 : 0 ;//上升沿
    
    parameter delay = 20000000 / 20 ;//抖动20ms
    
    reg [3:0]state ;   
    reg [19:0]counter1 ;
    always@(posedge clk or negedge reset)
    begin
        if (!reset)
            state <= 4'd0 ;//空闲态
        else if ( ( neg_edge ) && ( state == 4'd0 ) )
            state <= 4'd1 ;//按下消抖态
        else if ( ( state == 4'd1 ) && (( delay - 1) > counter1 ) && ( pos_edge ) )   
             state <= 4'd0 ;//空闲态
        else if ( ( state == 4'd1 ) && (( delay - 1) <= counter1 ) )
            state <= 4'd2 ;//按下态
        else if ( ( pos_edge ) && ( state == 4'd2 ) )
            state <= 4'd3 ;//释放消抖态   
        else if ( ( state == 4'd3 ) && (( delay - 1) > counter1 ) && ( neg_edge ) ) 
            state <= 4'd2 ;//按下态
        else if ( ( state == 4'd3 ) && (( delay - 1) <= counter1 ) )
            state <= 4'd0 ;//空闲态                          
    end
    

    always@(posedge clk or negedge reset)
    begin
        if (!reset)
            counter1 <= 5'd0 ;
        else if ( ( neg_edge ) || ( pos_edge ) ) 
            counter1 <= 5'd0 ;
        else if ( ( state == 4'd1 ) && (! neg_edge ) && (! pos_edge ) )
            counter1 <= counter1 + 1'd1 ;
        else if ( ( state == 4'd3 ) && (! neg_edge ) && (! pos_edge ) )
            counter1 <= counter1 + 1'd1 ;              
    end
    
    always@(posedge clk or negedge reset)
    begin
        if (!reset)
            bd_tx <= 1'd1 ;//空闲态
        else 
            case(state)
            0:bd_tx <= 1'd1 ;
            1:bd_tx <= 1'd1 ;
            2:bd_tx <= 1'd0 ;
            3:bd_tx <= 1'd0 ;
           endcase           
    end    
    
    reg pre_sign ;
    always@(posedge clk or negedge reset)
    begin
        if (!reset)
            pre_sign <= 1'd1 ;//空闲态
        else if( ( state == 4'd1 ) && (( delay - 1) <= counter1 ) )
            pre_sign <= 1'd0 ;
        else if ( state == 4'd2 )      
            pre_sign <= 1'd1 ;
    end
    
    always@(posedge clk or negedge reset)
    begin
        if (!reset)
            release_sign <= 1'd0 ;//空闲态
        else if( ( state == 4'd3 ) && (( delay - 1) <= counter1 ) )
            release_sign <= 1'd1 ;
        else if ( state == 4'd0 )      
            release_sign <= 1'd0 ;
    end       
            
endmodule
`timescale 1ns / 1ps
module DDS_advanced_tb(    
    );
    reg clk ;
    reg reset ;
    reg f_change_A ;
    reg f_change_B ;
    reg p_change_A ;
    reg p_change_B ;
    reg wave_change_A ;
    reg wave_change_B ;
    wire [9:0]dout_A ;
    wire [9:0]dout_B ;
    DDS_advanced DDS_advanced_sim(
    clk,
    reset,
    f_change_A,
    f_change_B,
    p_change_A,
    p_change_B,
    wave_change_A,
    wave_change_B,
    dout_A,
    dout_B
    );
    
    initial clk = 1 ;
    always #10 clk = ! clk ;
    initial 
        begin
            reset = 0 ;
            f_change_A = 1 ;
            f_change_B = 1 ;
            p_change_A = 1 ;
            p_change_B = 1 ;
            wave_change_A = 1 ;
            wave_change_B = 1 ;
            #201 ;
            reset = 1 ;
            #90000 ;
            
            wave_change_A = 0 ;
            #910000 ;
            
            wave_change_A = 1 ;
            f_change_B = 0 ;
            #910000 ;
            
            f_change_B = 1 ;
            wave_change_A = 0 ;
            #910000 ;
            
            wave_change_A = 1 ;
            f_change_B = 0 ;
            #910000 ;
            
            f_change_B = 1 ;
            wave_change_A = 0 ;
            #910000 ;
            
            f_change_B = 0 ;
            wave_change_A = 1 ;
            #910000 ;           
             
            f_change_B = 1 ;
            wave_change_A = 0 ;
            #910000 ;
            
            f_change_B = 0 ;
            wave_change_A = 1 ;
            #910000 ;
            
            f_change_B = 1 ;
            #910000 ;//验证波形和频率控制
            
            reset = 0 ;//验证相位控制
            #201 ;
            reset = 1 ;
            p_change_B = 0 ;
            f_change_A = 0 ;
            f_change_B = 0 ;
            #200
            f_change_A = 1 ;
            f_change_B = 1 ;
            #910000 ;
            p_change_B = 1 ;
            #910000 ;
            
            p_change_B = 0 ;
            #910000 ;
            p_change_B = 1 ;
            #910000 ;
            
            p_change_B = 0 ;
            #910000 ;
            p_change_B = 1 ;
            #910000 ;
            
            p_change_B = 0 ;
            #910000 ;
            p_change_B = 1 ;
            #910000 ;
            

            $stop;
        end
endmodule

 

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值