0%

中科院实习—— 参数化设计实现模块的重用与可控线性序列机

FPGA开发。包括让8个LED分别以不同的频率闪烁、从计数器到可控线性序列机(让LED灯按照亮0.25秒,灭0.75秒的状态循环亮灭等多个任务).

让8个LED分别以不同的频率闪烁

module led_flash(
Clk,
Reset_n,
Led
);

input Clk;
input Reset_n;
output reg Led;
parameter MCNT = 24999999;

reg [24:0]counter;

always@(posedge Clk or negedge Reset_n)begin
if (!Resnet)
    counter <= 0;
else if (counter == MCNT)
    counter <= 0;
else 
    counter <= counter + 1'd1;
end

always@(posedge Clk or negedge Reset_n)begin
if (!Resnet)
    Led <= 1;
else if (counter == MCNT)
    Led <= !Led;
end

endmodule

================================================================

module Led_run3_test(
    Clk;
    Reset_n;
    Led
);  

//例化
input Clk;
input Reset_n;
output [3:0]Led;


Led_flash Led_flash_inst0(
    
    .Clk(Clk);
    .Reset_n(Reset_n);
    .Led(Led[0])
    );
defparam Led_flash_inst0.MCNT = 499999;

Led_flash Led_flash_int1(
    
    .Clk(Clk);
    .Reset_n(Reset_n);
    .Led(Led[0])
    );
defparam Led_flash_inst1.MCNT = 2499999;

Led_flash Led_flash_int2(
    
    .Clk(Clk);
    .Reset_n(Reset_n);
    .Led(Led[0])
    );
defparam Led_flash_inst2.MCNT = 7499999;

Led_flash Led_flash_int3(
    
    .Clk(Clk);
    .Reset_n(Reset_n);
    .Led(Led[0])
    );
defparam Led_flash_inst3.MCNT = 1499999;

endmodule

在开发时,可能会遇到之前的项目具有相同的输入输出,那么此时我们就不必重复定义端口了:
1.一般在项目名\led_run.srcs\constrs_1\new\文件名;
2.打开复制;
3.image.png
4.复制内容到该文件中;
5.image.png
设置为target。

从计数器到可控线性序列机

1.让LED灯按照亮0.25秒,灭0.75秒的状态循环亮灭;
2.让LED灯按照亮0.25秒,灭0.5秒,亮0.75秒,灭1秒的状态循环亮灭;
3.让LED灯按照指定的亮灭模式亮灭,亮灭模式未知,由用户随机指定。以0.25秒为一个变化周期,8个变化状态为1个循环;
4.让LED灯按照指定的亮灭模式亮灭,亮灭模式未知,由用户随机指定。8个变化状态为一个循环,每个变化状态的时间值可以根据不同的应用场景选择;
5.让多个LED灯按照设置的模式各自在一个变化循环内独立亮灭变化;
6.每隔10ms,让LED灯的一个8状态循环执行一次(每个状态的变化时间值小一点,方便测试,比如设置为10us)。

让LED灯按照亮0.25秒,灭0.75秒的状态循环亮灭

module led_flash_0(
    Clk,
    Reset_n,
    Led
    );
    
    input Clk;
    input Reset_n;
    output reg Led;
    
    reg [25:0]counter;
    
    parameter MCNT = 50000000;
    
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
    counter <= 0;
else if(counter == MCNT - 1)
    counter <= 0;
else 
    counter <= counter + 1'b1;
    
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
    Led <= 0;
else if(counter == MCNT/2 - 1)
    Led <= 1;
else if(counter == MCNT - 1)
    Led <= 0;
    
endmodule

=============================================================================

`timescale 1ns / 1ns


module led_flash_tb(

    );
    
    reg Clk;
    reg Reset_n;
    wire Led;
    
    led_flash_0 
    #(
        .MCNT(50000000)
      )
      led_flash_0(
    
        .Clk(Clk),
        .Reset_n(Reset_n),
        .Led(Led)
    );
    
    initial Clk = 1;
    always #10 Clk = !Clk;
    
    initial begin
       Reset_n = 0;
       #201;
       Reset_n = 1;
       #2000000000;
       $stop;
    end


endmodule

这是实现0.5s亮,0.5s灭的程序,如果想要0.75s亮,0.25s灭直接修改MCNT处就行。

让LED灯按照亮0.25秒,灭0.5秒,亮0.75秒,灭1秒的状态循环亮灭

module led_flash_1(
    Clk,
    Reset_n,
    Led
    );
    
    input Clk;
    input Reset_n;
    output reg Led;
    
    reg [26:0]counter;
    
    parameter MCNT = 125000000;
    
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
    counter <= 0;
else if(counter == MCNT - 1)
    counter <= 0;
else 
    counter <= counter + 1'b1;
    
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
    Led <= 1;
else if(counter == MCNT/10 - 1)
    Led <= 0;
else if(counter == MCNT*3/10- 1)
    Led <= 1;
else if(counter == MCNT*6/10- 1)
    Led <= 0;
else if(counter == MCNT - 1)
    Led <= 1;

endmodule

让LED灯按照指定的亮灭模式亮灭,亮灭模式未知,由用户随机指定。以0.25秒为一个变化周期,8个变化状态为1个循环

2秒为一个循环周期,有一个指定的端口由用户指定亮灭模式

module led_flash_2(
    Clk,
    Reset_n,
    Ctrl,
    Led
    );
    
    input Clk;
    input Reset_n;
    input [7:0] Ctrl;
    output reg Led;
    
    reg [26:0]counter;
    
    parameter MCNT = 50000000;
    
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
    counter <= 0;
else if(counter == MCNT - 1)
    counter <= 0;
else 
    counter <= counter + 1'b1;
    
//always@(posedge Clk or negedge Reset_n)
//if(!Reset_n)
//	Led <= 0;
//else if(counter == MCNT/8 - 1)
//	Led <= Ctrl[0];
//else if(counter == MCNT/4 - 1)
//	Led <= Ctrl[1];
//else if(counter == MCNT*3/8 - 1)
//	Led <= Ctrl[2];
//else if(counter == MCNT*4/8 - 1)
//	Led <= Ctrl[3];
//else if(counter == MCNT*5/8 - 1)
//	Led <= Ctrl[4];
//else if(counter == MCNT*6/8 - 1)
//	Led <= Ctrl[5];
//else if(counter == MCNT*7/8 - 1)
//	Led <= Ctrl[6];
//else if(counter == MCNT - 1)
//	Led <= Ctrl[7];	

always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
    Led <= 0;
else case(counter)
    MCNT/8 - 1:Led <= Ctrl[0];
    MCNT*2/8 - 1:Led <= Ctrl[1];
    MCNT*3/8 - 1:Led <= Ctrl[2];
    MCNT*4/8 - 1:Led <= Ctrl[3];
    MCNT*5/8 - 1:Led <= Ctrl[4];
    MCNT*6/8 - 1:Led <= Ctrl[5];
    MCNT*7/8 - 1:Led <= Ctrl[6];
    MCNT - 1:Led <= Ctrl[7];
    default:Led <= Led;
endcase
    
endmodule

=============================================================================

`timescale 1ns / 1ns


module led_flash_tb(

    );
    
    reg Clk;
    reg Reset_n;
    reg [7:0]Ctrl;
    wire Led;
    
    led_flash_2 
    #(
        .MCNT(100000000)
      )
      led_flash_0(
    
        .Clk(Clk),
        .Reset_n(Reset_n),
        .Ctrl(Ctrl)
        .Led(Led)
    );
    
    initial Clk = 1;
    always #10 Clk = !Clk;
    
    initial begin
       Reset_n = 0;
       #201;
       Reset_n = 1;
       Ctrl = 8'b1000_0111;
       #2000000000;
       $stop;
    end


endmodule

让LED灯按照指定的亮灭模式亮灭,亮灭模式未知,由用户随机指定。8个变化状态为一个循环,每个变化状态的时间值可以根据不同的应用场景选择

思路:设置一个计数器用于每个状态的计时(这个计时由用户自己定义),设置另一个3位计数器用于一个循环,该计数器在另一个计数器计数达到用户设定的时间时自加1。这个3位计数器不需要清零,在加到111时,会自己清零。

module led_flash_3(
    Clk,
    Reset_n,
    Ctrl,
    Time,
    Led
    );
    
    input Clk;
    input Reset_n;
    input [7:0] Ctrl;
    input [31:0] Time;
    output reg Led;
    
    reg [31:0]counter;
    

    
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        counter <= 0;
    else if(counter == Time - 1)
        counter <= 0;
    else 
        counter <= counter + 1'b1;
        
    reg [2:0]counter2;
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        counter2 <= 0;
    else if(counter ==Time - 1)
        counter2 = counter2 + 1'b1;
    

    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        Led <= 0;
    else case(counter2)
        0:Led <= Ctrl[0];
        1:Led <= Ctrl[1];
        2:Led <= Ctrl[2];
        3:Led <= Ctrl[3];
        4:Led <= Ctrl[4];
        5:Led <= Ctrl[5];
        6:Led <= Ctrl[6];
        7:Led <= Ctrl[7];
        default:Led <= Led;
    endcase
    
endmodule  

让多个LED灯按照设置的模式各自在一个变化循环内独立亮灭变化;

module led_flash_4(
    Clk,
    Reset_n,
    CtrlA,
    CtrlB,
    Time,
    Led
    );
    
    
    input Clk;
    input Reset_n;
    input [7:0] Ctrl;
    input [31:0] Time;
    output reg [1:0]Led;
    
    reg [31:0]counter;
    

    
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        counter <= 0;
    else if(counter == Time - 1)
        counter <= 0;
    else 
        counter <= counter + 1'b1;
        
    reg [2:0]counter2;
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        counter2 <= 0;
    else if(counter ==Time - 1)
        counter2 = counter2 + 1'b1;
    

    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        Led <= 0;
    else case(counter2)
        0:begin Led <= CtrlA[0];Led[1] <= CtrlB[0];end
        1:Led <= Ctrl[1];
        2:Led <= Ctrl[2];
        3:Led <= Ctrl[3];
        4:Led <= Ctrl[4];
        5:Led <= Ctrl[5];
        6:Led <= Ctrl[6];
        7:Led <= Ctrl[7];
        default:Led <= Led;
    endcase
    
endmodule  

熟悉控制方法,可以控制多个信号

每隔10ms,让LED灯的一个8状态循环执行一次(每个状态的变化时间值小一点,方便测试,比如设置为10us)

EN = 1:counter计数
EN拉低的条件时8个翻转状态结束之时

module led_flash_3(
    Clk,
    Reset_n,
    Ctrl,
    Time,
    Led
    );
    
    input Clk;
    input Reset_n;
    input [7:0] Ctrl;
    input [31:0] Time;
    output reg Led;
    
    
    reg [31:0]counter;
    reg EN;
    
    reg [18:0]counter0;
    

    
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n) //10ms定时器
        counter0 <= 0;
    else if(counter0 == 500000 - 1)
        counter0 <= 0;
    else 
        counter0 <= counter0 + 1'b1;  
    
    
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n) //使能端:使开始计时
        EN <= 0;
    else if(counter == 0)
        EN <= 1;
    else if(counter2 == 7) && (counter == Time - 1))
        EN <= 0;  
    

    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        counter <= 0;
    else if(EN)begin
        if (counter == Time - 1)
            counter <= 0
        else
            counter = counter + 1'b1;
    end
    else
        counter <= 0 
    
    
    reg [2:0]counter2;
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        counter2 <= 0;
    else if(EN)begin
        if (counter == Time - 1)
            counter2 = counter2 + 1'b1;
    end
    else
        counter2 <= 0 
    

    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        Led <= 0;
    else case(counter2)
        0:Led <= Ctrl[0];
        1:Led <= Ctrl[1];
        2:Led <= Ctrl[2];
        3:Led <= Ctrl[3];
        4:Led <= Ctrl[4];
        5:Led <= Ctrl[5];
        6:Led <= Ctrl[6];
        7:Led <= Ctrl[7];
        default:Led <= Led;
    endcase
    
endmodule   
-------------本文结束感谢您的阅读-------------