FPGA 花式流光、数码管显示?

问题描述 投票:0回答:1

问题是:

输入时钟是板载50MHz晶振产生的时钟,经过分频器后得到1Hz时钟。流光灯由8个LED灯组成,按照以下8种图案顺序循环显示:

模式1-向右依次亮起:10000000->11000000->11100000...->11111110->11111111;

模式2-依次向左关闭:11111110->11111100->11111000->... -> 10000000->100000000;

模式 3- 向左依次亮起:000000 1->000000 11->00000 111->... -> 01111111->11111111;

模式 4-依次向右输出:01111111->00111111->00011111->... -> 000000 1->000000 0;

图案5-从两侧向中心点亮:10000001->11000011->11100111->11111111;

图案6-从中间向两侧熄灭:11100111->11000011->10000001->10000000;

图案7-从中间向两侧点亮:00011000->00111100->01111110->11111111;

图案8-从两侧向中间熄灭:011111110->00111100->00011000->000000。

在8个LED灯上显示流光图案时,要求在1个数码管上同步显示图案号1->8。即用数码管显示当前运行的模式号。

这是我的代码: 水 LED.v

module water_led(
    input wire clk ,
    input wire rst ,
    input wire [3:0] num,
    output reg [7:0] led,
    output reg [7:0] seg
    );

    parameter CNT_MAX = 29'd50_000_000;
    parameter S1 = 3'b000;
    parameter S2 = 3'b001;
    parameter S3 = 3'b010;
    parameter S4 = 3'b011;
    parameter S5 = 3'b100;
    parameter S6 = 3'b101;
    parameter S7 = 3'b110;
    parameter S8 = 3'b111;          //八种闪烁方式
    
    reg [2:0]   current_state;
    reg [2:0]   next_state;
    reg [2:0]   mode;
    reg [28:0]  cnt_1s;      //1s clk : 50MHz 20s   29bit
    reg [3:0]   data;
    reg         cnt_flag;


always@(posedge clk or negedge rst)begin
    if(~rst)begin       //rst == 1'b0
        cnt_1s <= 29'd0;
    end
    else begin
        if(cnt_1s == CNT_MAX - 1)begin
            cnt_1s <= 29'd0;
        end
    else begin
            cnt_1s <= cnt_1s + 29'd1;
            end
        end
    end

always@(posedge clk or negedge rst)begin
    if(~rst)begin
        data <= 4'b0000;
    end
    else begin
        if(cnt_1s == CNT_MAX - 1 && data == 4'b1111)begin
            data <= 4'b0000;
        end
    else if(cnt_1s == CNT_MAX - 1)begin
        data <= data + 1'b1;
    end
    else begin
        data <= data;
    end
  end
end

//数码管段码选择
always@(posedge clk or negedge rst)
     if(~rst)begin
     seg <= 8'hff;
     end
     else case(data)
            4'd1: seg <= 8'hf9;
            4'd2: seg <= 8'ha4;
            4'd3: seg <= 8'hb0;
            4'd4: seg <= 8'h99;
            4'd5: seg <= 8'h92;
            4'd6: seg <= 8'h82;
            4'd7: seg <= 8'hf8;
            4'd8: seg <= 8'h80;
            default:seg <= 8'hf9;
endcase

//输出
always@(posedge clk or negedge rst)begin
    if(~rst)begin
        seg <= 8'hf9;
    end
    else begin
        if(seg == 8'h80)begin
            seg <= 8'hf9;
        end
    else if(seg<8'h80)
    begin
    seg <= seg +1'd1;
    end
    else begin
        seg <= seg;
    end
  end
end

//每种闪烁方式下的8种状态
always@(posedge clk or negedge rst)begin
    if(~rst)begin
        mode <= 3'b000;
    end
    else begin
        if(cnt_1s == CNT_MAX - 1 && mode == 3'b111)begin    
            mode <= 3'b000;
        end
     else if(cnt_1s == CNT_MAX - 1)begin
        mode <= mode + 1'b1;
        end
        else begin
            mode <= mode;
        end
    end
end



//次状态 给到 现状态        
always@(posedge clk or negedge rst)begin        //延后一个时钟周期 a <= a;
    if(~rst)begin
        current_state <= S1;
    end
    else begin
        current_state <= next_state;
    end
end

//状态转换
always@(*)begin
    case(current_state)
        S1 : begin
            case(num)
                4'b0001:next_state = S1;
                4'b0010:next_state = S2;
                4'b0011:next_state = S3;
                4'b0100:next_state = S4;
                4'b0101:next_state = S5;
                4'b0110:next_state = S6;
                4'b0111:next_state = S7;
                4'b1000:next_state = S8;
                default:next_state = S1;
            endcase
        end

        S2 : begin
                case(num)
                4'b0001:next_state = S1;
                4'b0010:next_state = S2;
                4'b0011:next_state = S3;
                4'b0100:next_state = S4;
                4'b0101:next_state = S5;
                4'b0110:next_state = S6;
                4'b0111:next_state = S7;
                4'b1000:next_state = S8;
                default:next_state = S1;
            endcase
        end
        
        S3 : begin
                case(num)
                4'b0001:next_state = S1;
                4'b0010:next_state = S2;
                4'b0011:next_state = S3;
                4'b0100:next_state = S4;
                4'b0101:next_state = S5;
                4'b0110:next_state = S6;
                4'b0111:next_state = S7;
                4'b1000:next_state = S8;
                default:next_state = S1;
            endcase
        end
        
        S4 : begin
                case(num)
                4'b0001:next_state = S1;
                4'b0010:next_state = S2;
                4'b0011:next_state = S3;
                4'b0100:next_state = S4;
                4'b0101:next_state = S5;
                4'b0110:next_state = S6;
                4'b0111:next_state = S7;
                4'b1000:next_state = S8;
                default:next_state = S1;
            endcase
        end
        
        S5 : begin
                case(num)
                4'b0001:next_state = S1;
                4'b0010:next_state = S2;
                4'b0011:next_state = S3;
                4'b0100:next_state = S4;
                4'b0101:next_state = S5;
                4'b0110:next_state = S6;
                4'b0111:next_state = S7;
                4'b1000:next_state = S8;
                default:next_state = S1;
            endcase
        end
        
        S6 : begin
                case(num)
                4'b0001:next_state = S1;
                4'b0010:next_state = S2;
                4'b0011:next_state = S3;
                4'b0100:next_state = S4;
                4'b0101:next_state = S5;
                4'b0110:next_state = S6;
                4'b0111:next_state = S7;
                4'b1000:next_state = S8;
                default:next_state = S1;
            endcase
        end
        
        S7 : begin
                case(num)
                4'b0001:next_state = S1;
                4'b0010:next_state = S2;
                4'b0011:next_state = S3;
                4'b0100:next_state = S4;
                4'b0101:next_state = S5;
                4'b0110:next_state = S6;
                4'b0111:next_state = S7;
                4'b1000:next_state = S8;
                default:next_state = S1;
            endcase
        end
        
        S8 : begin
                case(num)
                4'b0001:next_state = S1;
                4'b0010:next_state = S2;
                4'b0011:next_state = S3;
                4'b0100:next_state = S4;
                4'b0101:next_state = S5;
                4'b0110:next_state = S6;
                4'b0111:next_state = S7;
                4'b1000:next_state = S8;
                default:next_state = S1;
            endcase
        end
        default:next_state = S1;
    endcase
end

//输出
always@(posedge clk or negedge rst)begin
    if(~rst)begin
        led <= 8'b00000000;
    end
    else begin
        case(current_state)
            S1 : begin              //向右依次点亮
                case(mode)
                3'b000: led <= 8'b10000000;
                3'b001: led <= 8'b11000000;
                3'b010: led <= 8'b11100000;
                3'b011: led <= 8'b11110000;
                3'b100: led <= 8'b11111000;
                3'b101: led <= 8'b11111100;
                3'b110: led <= 8'b11111110;
                3'b111: led <= 8'b11111111;
                default:led <= 8'b10000000;
                endcase
            end                    
            S2 : begin              //向左依次熄灭
                case(mode)
                3'b000: led <= 8'b11111110;
                3'b001: led <= 8'b11111100;
                3'b010: led <= 8'b11111000;
                3'b011: led <= 8'b11110000;
                3'b100: led <= 8'b11100000;
                3'b101: led <= 8'b11000000;
                3'b110: led <= 8'b10000000;
                3'b111: led <= 8'b00000000;
                default:led <= 8'b11111110;
                endcase
            end                    
            S3 : begin          //向左依次点亮
                case(mode)
                3'b000: led <= 8'b00000001;
                3'b001: led <= 8'b00000011;
                3'b010: led <= 8'b00000111;
                3'b011: led <= 8'b00001111;
                3'b100: led <= 8'b00011111;
                3'b101: led <= 8'b00111111;
                3'b110: led <= 8'b01111111;
                3'b111: led <= 8'b1111111;
                default:led <= 8'b00000001;
                endcase
            end                
            S4 : begin          //向右依次熄灭
                case(mode)
                3'b000: led <= 8'b01111111;
                3'b001: led <= 8'b00111111;
                3'b010: led <= 8'b00011111;
                3'b011: led <= 8'b00001111;
                3'b100: led <= 8'b00000111;
                3'b101: led <= 8'b00000011;
                3'b110: led <= 8'b00000001;
                3'b111: led <= 8'b00000000;
                default:led <= 8'b01111111;
                endcase
            end                 
            S5 : begin          //两边向中间点亮
                case(mode)
                3'b000: led <= 8'b10000001;
                3'b001: led <= 8'b11000011;
                3'b010: led <= 8'b11100111;
                3'b011: led <= 8'b11111111;
                default:led <= 8'b10000001;
                endcase
            end                 
            S6 : begin          //中间向两边熄灭
                case(mode)
                3'b000: led <= 8'b11100111;
                3'b001: led <= 8'b11000011;
                3'b010: led <= 8'b10000001;
                3'b011: led <= 8'b00000000;
                default:led <= 8'b11100111;
                endcase
            end                 
            S7 : begin          //中间向两边点亮
                case(mode)
                3'b000: led <= 8'b00011000;
                3'b001: led <= 8'b00111100;
                3'b010: led <= 8'b01111110;
                3'b011: led <= 8'b11111111;
                default:led <= 8'b00011000;
                endcase
            end
            S8 : begin         //两边向中间熄灭
                case(mode)
                3'b000: led <= 8'b01111110;
                3'b001: led <= 8'b00111100;
                3'b010: led <= 8'b00011000;
                3'b011: led <= 8'b00000000;
                default:led <= 8'b01111110;
                endcase
            end
        endcase    
    end
end
endmodule     

tb_water_led.v

`timescale 1ns/1ns     //#10

module tb_water_led();
reg         clk;
reg         rst;
reg   [3:0] num;
wire  [7:0] led;  
wire  [3:0] seg;

//例化
water_led         u_led(
        .clk        (clk),
        .rst        (rst),
        .num        (num),
        .seg        (seg),
        .led        (led)
);

initial begin
    clk = 0;
    rst = 0;
    #25
    rst = 1;      //正常运行
end

initial begin
    num = 4'b0000;
    #100
    num = 4'b0001;      //1
    #2500
    num = 4'b0010;      //2
    #2500
    num = 4'b0011;      //3
    #2500
    num = 4'b0100;      //4
    #2500
    num = 4'b0101;      //5
    #2500
    num = 4'b0110;      //6
    #2500
    num = 4'b0111;      //7
    #2500
    num = 4'b1000;      //8
    $stop;              //系统函数
end

always#10 clk = ~clk;   //20ns

endmodule

感觉数码管的显示逻辑有问题。原理图显示数码管没有连接,不符合题目要求。我不知道该怎么办

verilog fpga vivado
1个回答
0
投票

RTL 代码在

seg
输出上有多个驱动程序。
这两个过程都会驱动 seg 输出。
这在 RTL 编码中是不允许的。

RTL 编码推断硬件,因此从多个进程驱动相同的信号就像将两个硬件输出连接在一起。硬件工程师明白这是短路,会损坏硬件。

// drives the seg output
always@(posedge clk or negedge rst)
     if(~rst)begin
     seg <= 8'hff;
     end
     else case(data)
            4'd1: seg <= 8'hf9;
            4'd2: seg <= 8'ha4;
            4'd3: seg <= 8'hb0;
            4'd4: seg <= 8'h99;
            4'd5: seg <= 8'h92;
            4'd6: seg <= 8'h82;
            4'd7: seg <= 8'hf8;
            4'd8: seg <= 8'h80;
            default:seg <= 8'hf9;
endcase

// also drives the seg output
always@(posedge clk or negedge rst)begin
    if(~rst)begin
        seg <= 8'hf9;
    end
    else begin
        if(seg == 8'h80)begin
            seg <= 8'hf9;
        end
    else if(seg<8'h80)
    begin
    seg <= seg +1'd1;
    end
    else begin
        seg <= seg;
    end
  end
end

您需要组合这些过程以获得您想要的 seg 输出行为。其中一个过程是计数器,另一个过程是使用基于变量

case
data
语句进行编码。如果您有时需要编码器,有时需要 case 语句,则需要将它们复用在一起,这提供了某种控制告诉逻辑要使用哪个。

如果您查看 Vivado 日志文件,您可能会看到关于 seg 变量的多个驱动程序的警告。

© www.soinside.com 2019 - 2024. All rights reserved.