目录
1.实现1
2.实现2
2.1方法1
2.2方法2
3.实现3
3.1实验现象
4.实现4
4.1分析
4.2实现过程
4.2.1 counter的计数
4.2.2 en_counter2的判断
4.2.3 en_counter0的判断
4.2.4 对case语句加判断条件
4.3仿真结果
编辑
4.4实验现象
1.实现1
1.实现以下图示功能,直接计到1s时,counter清零,在0~0.25s之间高电平,0.25s~1s之间低电平。

2.仿真波形

3.问题,像C那样写却不行,只能在某个时刻点亮才行。

计数器相当于时间的一把尺子,用计数器的每一个计数值当作一个刻度,能够得到各个需要的时刻,在指定的时刻,执行需要的操作。
2.实现2
实现下图方式的方波:

2.1方法1
跟第一种方式一样,找出每个高低信号跳变的位置。要减小仿真时间,多个参数下如何设定最简便的参数,按照之前的思路需要加4个参数。这里直接用他们都共有的倍数来进行,仿真时间缩小1000倍。
parameter MCNT = 1000;
    
    always@(posedge clk or negedge reset)
    if(!reset)
    counter<=1'b0;
    else if (counter == 125_000*MCNT-1)
    counter<=1'b0;
    else
    counter<=counter+1'd1;
    
    always@(posedge clk or negedge reset)
    if(!reset)
    led<=1'b0;
    else if(counter == 0)
        led<=1'd1;
    else if(counter == 125_00*MCNT)
        led<=1'd0;
    else if(counter == 375_00*MCNT)
        led<=1'd1;
    else if(counter == 75_000*MCNT)
        led<=1'd0;仿真波形:

2.2方法2
把划分成几个区间,取每个时间间隔的最大公约数,分成几段。用一个计数器记到该最大公约数,再用一个计数器记到9,每次对应不同的高低电平。

源文件代码,中间有段if else 没用begin...end为什么也没问题。
module led_light1(
    reset,
    clk,
    led
    );
    
    input reset;
    input clk;
    output reg led;
    reg [26:0]counter;
    parameter MCNT = 12500_000-1;
    
    always@(posedge clk or negedge reset)
    if(!reset)
        counter <= 1'd0;
    else if (counter == MCNT)
        counter <= 1'd0;
    else
        counter <= counter+1'd1;
    
    reg [3:0]counter1;
    always@(posedge clk or negedge reset)
    if(!reset)
        counter1 <= 1'd0;
    else if(counter == MCNT)
        if(counter1 == 9)
            counter1 <= 1'd0;
        else
            counter1 <= counter1+1'd1;   
    else
        counter1=counter1;
    
    always@(posedge clk or negedge reset)
    if(!reset)
        led<=1'd0;
    else begin
        case(counter1)
        0:led <= 1'd1;
        1:led <= 1'd0;
        2:led <= 1'd0;
        3:led <= 1'd1;
        4:led <= 1'd1;
        5:led <= 1'd1;
        6:led <= 1'd0;
        7:led <= 1'd0;
        8:led <= 1'd0;
        9:led <= 1'd0;
        default:led <= led;
        endcase
    end  
endmodule仿真结果:

3.实现3

即直接新建立一个数值,让counter1依次计数,每次计数后,切换到对应的SW状态。
源文件:
module led_light2(
    reset,
    clk,
    led,
    SW
    );
    
    input reset;
    input clk;
    input [7:0]SW;
    output reg led;
    reg [26:0]counter;
    parameter MCNT = 12500_000-1;
    
    always@(posedge clk or negedge reset)
    if(!reset)
        counter <= 1'd0;
    else if (counter == MCNT)
        counter <= 1'd0;
    else
        counter <= counter+1'd1;
    
    reg [2:0]counter1;
    always@(posedge clk or negedge reset)
    if(!reset)
        counter1 <= 1'd0;
    else
        counter1 <= counter1+1'd1;   
    
    always@(posedge clk or negedge reset)
    if(!reset)
        led<=1'd0;
    else begin
        case(counter1)
        0:led <= SW[0];
        1:led <= SW[1];
        2:led <= SW[2];
        3:led <= SW[3];
        4:led <= SW[4];
        5:led <= SW[5];
        6:led <= SW[6];
        7:led <= SW[7];
        default:led <= led;
        endcase
    end  
endmodule仿真文件:
改变SW的值,进行延时后,再进行改变。
`timescale 1ns / 1ns
module led_light_tb();
reg clk;
reg reset;
wire led;
reg [7:0]SW;
led_light2 led_light2(
    .reset(reset),
    .clk(clk),
    .led(led),
    .SW(SW)
);
initial clk=1;
always #10 clk=~clk;
initial begin
    reset =0;
    SW=8'b10101010;
    #201;
    reset=1;
    #2000_000_000;
    SW=8'b00000001;
    #2000_000_000;
    $stop;
end
endmodule前半段符合10101010

2s后变为00000001,仿真图如下:

代码中counter1的值等每次计数来一次才加一次,不然就不是按照设定的值增加。 将间隔时间设为1s。

3.1实验现象
开关设置为10101010时,LED灯每间隔1s闪烁。多上拉几个,就多亮会儿。
4.实现4
4.1分析
实现下图所示的动态变化,1s时间是可变的,只是这里指代为1s。学习计数器不是一定要不停的计数,而是要有静有动,中途可暂停。

需要用到三个计数器,counter1~3。
counter0:用于SW切换的间隔时间0.25s
1.计数最大值:计数的最大值为0.25*10^9/20-1=12500_000-1。
2.计数的条件为前面1s的空闲时间到,8个状态马上开始或已经开始。
3.清零条件:计数到最大值,或还在前1s的空闲状态中。
counter1:计数当前第几个LED的状态计数器
1.计数最大值:7
2.计数条件:counter0计满1次加1
3.清零条件:计数到最大值
counter2:1s的空闲状态计数器
1.计数最大值:1*10^9/20-1=5000_0000-1。
2.计数条件:8个LED状态切换完毕,counter1计满。
3.清零条件:计数至最大值
4.2实现过程
4.2.1 counter的计数
对于counter0来说,需要一会儿计数一会儿停,所以加入一个变量en_counter,当en_counter=1时,开始计数,否则就停下。
always@(posedge clk or negedge reset)
begin
    if(!reset)
        counter0 <= 1'd0;
    else if (en_counter0)
    begin
        if(counter0 == MCNT)
            counter0 <= 1'd0;
        else
            counter0 <= counter0+1'd1;
    end
end对于counter1,直接counter0计满一次加1,满8次清0。
always@(posedge clk or negedge reset)
    if(!reset)
        counter1 <= 1'd0;
    else if (counter0 == 7)
        counter1 <= 1'd0;   
    else if (counter0 == MCNT)
        counter1 <= counter1+1'd1;   
    else
        counter1 <= counter1;对于counter2,空闲段计数,8个0.25s内不计数。
always@(posedge clk or negedge reset)
begin
    if(!reset)
        counter2 <= 1'd0;
    else if(en_counter2)
    begin
        if(counter2 == MCNT2)
            counter2 <= 1'd0;
        else
            counter2 <= counter2+1'd1;
    end
end4.2.2 en_counter2的判断
counter2保持计数的条件有:
(1)从复位到正常运行,需要立即开始计数。
(2)每次LED8个状态切换完,重新开始计数。
counter2停止计数的条件有:
(1)计数满1s
总结:
(1)复位时,让en_counter2置1。
(2)counter1==7 时,让en_counter2置1。
(3)counter2计满时,让en_counter2置0。
关于第(2)个条件,我认为不附加sw计数也能满足,因为counter1==7已经都记录了8个状态了。
always@(posedge clk or negedge reset)
begin
    if(!reset)
        en_counter2 <= 1'd1;
    else if(counter1 ==7)
        en_counter2 <= 1'd1;
    else if(counter2 <= MCNT2)
        en_counter2 <=1'd0;
    else
        en_counter2 <= en_counter2;
end4.2.3 en_counter0的判断
counter0保持计数的条件:
(1)counter2计数计满的时候
counter0停止计数的条件;
(1)程序复位,counter0需要停止。
(2)LED的8个状态完成,counter停止。
总结:
(1)复位时,en_counter0置0;
(2)counter1==7时,en_counter0置0;
(3)counter2计满最大值时,en_counter0置1;
always@(posedge clk or negedge reset)
begin
    if(!reset)
        en_counter0 <= 1'd0;
    else if(counter1 ==7)
        en_counter0 <= 1'd0;
    else if(counter2 <= MCNT2)
        en_counter0 <=1'd1;
    else
        en_counter0 <= en_counter0;
end4.2.4 对case语句加判断条件
led在空闲状态置0,所以要么en_counter1==0,要么en_counter2==1。
always@(posedge clk or negedge reset)
begin
if(!reset)
    led <= 1'd0;
else if(en_counter2 ==1)
    led <= 1'd0;
else begin
    case(counter1)
    0:led <= SW[0];
    1:led <= SW[1];
    2:led <= SW[2];
    3:led <= SW[3];
    4:led <= SW[4];
    5:led <= SW[5];
    6:led <= SW[6];
    7:led <= SW[7];
    default:led <= led;
    endcase
end
end  4.3仿真结果
出现问题,并未按预期波形出现。

在en_counter处加入了附加的判断条件,else if((counter1 ==7) && (counter0 == MCNT)),仿真波形还是不对。
 错误1,将这里的判断用了非阻塞符号,修改后,仿真波形仍不对。
 错误1,将这里的判断用了非阻塞符号,修改后,仿真波形仍不对。

 
 
en_counter0的错误也是如此。仿真波形在第二段开始出现错误,counter2计数一直为0。

问题在于:程序中counter1计数到7时就要清0,而此时在counter1计数到6完成时,counter0就已经记到0.25s了,在下一个时钟脉冲来临时,counter1被清0,所以后面的en_counter2永远不会置1。
 
 
最后仿真结果相对应,led显示的波形与SW相反的原因是,在工程文件的case语句,从左到右是对应从低到高。
4.4实验现象
SW全部拉低,LED灯不亮;SW全部拉低,LED灯熄1s,亮2s。SW一高一低,LED熄灭一s,闪烁2s。





![[Linux#67][IP] 报头详解 | 网络划分 | CIDR无类别 | DHCP动态分配 | NAT转发 | 路由器](https://img-blog.csdnimg.cn/img_convert/32eb110884f0d038d790c84104eb0ffe.jpeg)




![[枚举坤坤]二进制枚举基础](https://i-blog.csdnimg.cn/direct/e3b056fea3ad4a4aa7ec6bef68c4565a.jpeg)









