从计数器到可控线性序列机——verilog学习5

1.设计一个led灯,亮0.5s暗0.5s循环亮暗。

0.5s是0.5s/20ns=25M    1s就是50M

module counter_led_0(
    clk,
    rst,
    led
    );
    input clk,rst;
    output reg led;
    
    reg [25:0]counter;
    parameter MCNT=50000000;
//这里面定义了参数MCNT,在仿真的时候修改参数,防止仿真时间太长不方便观察
    
    always@(posedge clk,negedge rst)
    begin
        if (!rst)
            counter<=0;
        else if (counter==MCNT-1)
            counter<=0;
        else 
            counter<=counter+1;
    end
    
    always@(posedge clk,negedge rst)
    begin
        if (!rst)
            led<=0;
        else if (counter==MCNT/2-1)
            led<=1;                    //这里代表0.5秒后由暗变亮
        else if (counter==MCNT-1)
            led<=0;                       //亮0.5秒后变暗
        else led<=led;
    end
    
endmodule
`timescale 1ns / 1ns
module counter_led_0_tb;

    reg clk,rst;
    wire led;
    
    counter_led_0 
    #(.MCNT(50000))
    counter_led_0(
    .clk(clk),     .rst(rst),     .led(led)
    );
    
    initial clk=1;
    always #10 clk=~clk;
    
    initial begin
    rst=0;
    #205;
    rst=1;
    #20000000;
    $stop;
    end
    
endmodule

2.设计一个led灯,亮0.25s暗0.75s循环亮暗。

仅需修改这部分代码 

    always@(posedge clk,negedge rst)
    begin
        if (!rst)
            led<=0;
        else if (counter==MCNT*3/4-1)
            led<=1;                    //这里代表0.75秒后由暗变亮
        else if (counter==MCNT-1)
            led<=0;                       //亮0.25秒后变暗
        else led<=led;
    end
    

3.设计一个led灯,亮0.25s暗0.5s,再亮0.75s随后暗1s循环亮暗。 

一个循环2.5s,也就是2.5s/20ns=125M

    reg [26:0]counter;
    parameter MCNT=125000000

 把led赋值那段代码改成下述形式

    always@(posedge clk,negedge rst)
    begin
        if (!rst)
            led<=0;
        else if (counter==(MCNT*2/5)-1)  //灭1s也就是2/5的总时间(2.5s)
            led<=1;
        else if (counter==MCNT/2-1)      //亮0.25s(1/10),1/10+2/5=1/2
            led<=0;
        else if (counter==MCNT*7/10-1)   //灭0.5s(1/5),1/5+1/2=7/10
            led<=1;
        else if (counter==MCNT-1)        //亮0.75s
            led<=0;
        else led<=led;    
    end

放大

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

2s为一个周期,那么也就是一个周期的频率为2s/20ns=100M

module counter_led_3(
    clk,
    rst,
    ctrl,
    led
    );
    input clk,rst;
    output reg led;
    input [7:0]ctrl;     //用户指定控制亮暗

    reg [26:0]counter;
    parameter MCNT=100000000;    //2s为一个循环周期
    
    always@(posedge clk,negedge rst)
    begin
        if (!rst)
            counter<=0;
        else if (counter==MCNT-1)
            counter<=0;
        else 
            counter<=counter+1;
    end
    
    always@(posedge clk,negedge rst)
    begin
        if (!rst)
            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/2-1)
            led<=ctrl[3];
        else if (counter==MCNT*5/8-1)
            led<=ctrl[4];
        else if (counter==MCNT*3/4-1)
            led<=ctrl[5];
        else if (counter==MCNT*7/8-1)
            led<=ctrl[6];
        else if (counter==MCNT-1)
            led<=ctrl[7];
        else led<=led;
    end
    
endmodule

        这里添加了应该指定的亮灭状态的输入端口input [7:0]ctrl;因为一共8个状态为一个变化周期。并注意对led赋值时的变化。

        在对led进行赋值的时候,我们使用的是if语句,但是由于这里语句分支太长了最好改为case语句,执行的功能是相同的。

    always@(posedge clk,negedge rst)
    begin
        if (!rst)
            led<=0;
        else 
            case (counter)
                MCNT/8-1:led<=ctrl[0];
                MCNT/4-1:led<=ctrl[1];
                MCNT*3/8-1:led<=ctrl[2];
                MCNT/2-1:led<=ctrl[3];
                MCNT*5/8-1:led<=ctrl[4];
                MCNT*3/4-1:led<=ctrl[5];
                MCNT*7/8-1:led<=ctrl[6];
                MCNT-1:led<=ctrl[7];
                default:led<=led;
            endcase
    end

//    always@(posedge clk,negedge rst)
//    begin
//        if (!rst)
//            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/2-1)
//            led<=ctrl[3];
//        else if (counter==MCNT*5/8-1)
//            led<=ctrl[4];
//        else if (counter==MCNT*3/4-1)
//            led<=ctrl[5];
//        else if (counter==MCNT*7/8-1)
//            led<=ctrl[6];
//        else if (counter==MCNT-1)
//            led<=ctrl[7];
//        else led<=led;
//    end

仿真验证代码

`timescale 1ns / 1ns
module counter_led_3_tb;

    reg clk,rst;
    reg [7:0]ctrl;
    wire led;
    
    counter_led_3  
    #(.MCNT(100000))
    counter_led_3(
    .clk(clk),     
    .rst(rst),     
    .led(led),   
    .ctrl(ctrl)
    );
    
    initial clk=1;
    always #10 clk=~clk;
    
    initial begin
    rst=0;
    ctrl=0;
    #205;
    rst=1;
    #2000;
    ctrl=8'b1000_0110;   //指定亮灭顺序是1000_0110
    #20000000;
    $stop;
    end
    
endmodule

 ctrl=8'b1000_0110;   //指定亮灭顺序是1000_0110

        这里再看led的波形图的时候应该是反过来看(01100001)而不是1000_0110.因为是从低往高位看的。

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

        每个状态的时间长短位置,所以在输入端引入一个时间值input [31:0]T; 这里为了让每个状态的时间够长,所以特意设置为32位。

        

module counter_led_4(
    clk,
    rst,
    ctrl,
    T,
    led
    );
    input clk,rst;
    input [31:0]T;   //T代表的是单个状态的时间T
    output reg led;
    input [7:0]ctrl;

    reg [31:0]counter;  //第一个计数器的位数要和T的位数相同,防止不够算
    
    always@(posedge clk,negedge rst)
    begin
        if (!rst)
            counter<=0;
        else if (counter==T-1)  //当计数到T时,置0
            counter<=0;
        else 
            counter<=counter+1;   
    end
    
    reg [2:0]counter2;    //这里引入第二个计数器,来计算什么时候切换下一个状态
    
    always@(posedge clk,negedge rst)
    begin
        if (!rst)
            counter2<=0;
        else if(counter==T-1)
            counter2<=counter2+1'b1;  //如果计数到T时间,切换下一个状态
        else
            counter2<=counter2;
    end
    
    
    always@(posedge clk,negedge rst)
    begin
        if (!rst)
            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
    end
    
    
endmodule

        这里一共引入了两个计数器,和一个输入端T。T的含义是:每个状态的时间长短(由用户来定义)。第一个计数器的目的是,当技术时间达到T时,就切换下一个状态(共八个状态)。

仿真验证代码

`timescale 1ns / 1ns
module counter_led_4_tb;

    reg clk,rst;
    reg [7:0]ctrl;
    reg [31:0]T;
    wire led;
    
    counter_led_4  counter_led_4(
    .clk(clk),     
    .rst(rst),     
    .led(led),   
    .ctrl(ctrl),
    .T(T)
    );
    
    initial clk=1;
    always #10 clk=~clk;
    
    initial begin
    rst=0;
    ctrl=0;
    T=0;
    #205;
    rst=1;
    #2000;
    T=2500;
    ctrl=8'b1010_0110;
    #20000000;
    $stop;
    end
    
endmodule

        这里为了仿真波形方便观察,并没有给T设置一个很大的指4,只设置了2500.给八个状态的控制端ctrl设置为10100_110。

在运行仿真前,现将刚刚的tb文件设置为顶层,在观察。不然观察到的波形就是原来顶层文件的波形。

 

        仿真波形与理论相符。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值