09- 数码管

数码管

RTL代码

`timescale 1ns / 1ps

module hex8(
    clk,
    reset_n,
    disp_data,
    sel,
    led
    );
    
    input clk;
    input reset_n;
    input [32-1:0] disp_data;
    
	//选择8位数码管
    output reg [8-1:0] sel;
	//选择显示数字
    output reg [8-1:0] led;
    
    //分频计数1us,对应1kHz
    reg [16-1:0] div_cnt;
    always@(posedge clk or negedge reset_n)begin
        if(reset_n==0)
            div_cnt<=0;
        else if(div_cnt>=25000-1)
            div_cnt<=0;
        else 
            div_cnt<=div_cnt+1;
    end
	
    reg clk_1k;
    always@(posedge clk or negedge reset_n)begin
        if(reset_n==0)
            clk_1k<=0;
        else if(div_cnt==50000-1)
            clk_1k<=1;
        else 
            clk_1k<=0;
    end
    
	//用于选择数码管的计数
    reg [3-1:0] num_cnt;
    always@(posedge clk or negedge reset_n)begin
        if(reset_n==0)
            num_cnt<=0;
        else if(clk_1k)
            num_cnt<=num_cnt+1;
    end
    
    always@(posedge clk)
        case(num_cnt)
            0: sel<=8'b0000_0001;
            1: sel<=8'b0000_0010;
            2: sel<=8'b0000_0100;
            3: sel<=8'b0000_1000;
            4: sel<=8'b0001_0000;
            5: sel<=8'b0010_0000;
            6: sel<=8'b0100_0000;
            7: sel<=8'b1000_0000;
        endcase
        
	//从32位data中提取对应数码管位数上的显示数字
    //直接将data和数码管相连接
    reg [4-1:0] disp_temp;
    always@(posedge clk)begin
        case(num_cnt)
            7:disp_temp<=disp_data[3:0];
            6:disp_temp<=disp_data[7:4];
            5:disp_temp<=disp_data[11:8];
            4:disp_temp<=disp_data[15:12];
            3:disp_temp<=disp_data[19:16];
            2:disp_temp<=disp_data[23:20];
            1:disp_temp<=disp_data[27:24];
            0:disp_temp<=disp_data[31:28];
            default:;
        endcase
    end 
    
	//数码管显示数字和对应的编码的映射
    always@(posedge clk)
        case(disp_temp)
            0: led<=8'hc0;
            1: led<=8'hf9;
            2: led<=8'ha4;
            3: led<=8'hb0;
            4: led<=8'h99;
            5: led<=8'h92;
            6: led<=8'h82;
            7: led<=8'hf8;
            8: led<=8'h80;
            9: led<=8'h90;
           4'ha: led<=8'h88;
           4'hb: led<=8'h83;
           4'hc: led<=8'hc6;
           4'hd: led<=8'ha1;
           4'he: led<=8'h86;
           4'hf: led<=8'h8e;
           default:led<=8'h00;
        endcase
    
endmodule

代码解析

  • 在verilog实现中,这种case语句的使用很常见
  • 在从系统时钟进行分频操作中,直接使用always块生成的分频clk_1k基本不可用,时钟质量较差,这一部分要学习时钟相关内容

RTL代码,使用了74HC595芯片

`timescale 1ns / 1ps

//74HC595驱动模块,verilog语法不允许首位为数字
module HC595_driver(
    clk,
    reset_n,
    Data,
    S_EN,
    SH_CP,
    ST_CP,
    DS  
    );
    
    input clk;
    input reset_n;
    input [16-1:0] Data;
    input S_EN;
	
	//74HC595芯片手册定义的三个信号
    output reg SH_CP;
    output reg ST_CP;
    output reg DS;
    
    parameter CNT_MAX = 2;
    
	//数据寄存操作
	//防止在数据发送或接收过程中发生变化
    reg [16-1:0] r_Data;
    always@(posedge clk)
        if(S_EN)
            r_Data<=Data;
        
	//分频计数
	//对系统时钟进行二分频
	//具体()分频由CNT_MAX参数确定
    reg [8-1:0] divider_cnt;
    always@(posedge clk or negedge reset_n)begin
        if(reset_n==0)
            divider_cnt<=0;
        else if(divider_cnt==CNT_MAX-1'b1)
            divider_cnt<=0;
        else 
            divider_cnt<=divider_cnt+1;
    end
    
	//周期脉冲
	//每当分频计满,则脉冲一次
    wire sck_plus;
    assign sck_plus = (CNT_MAX-1'b1);
	
	//SH_CP的边缘计数,每一次周期计数一次
    reg [6-1:0] SHCP_EDGE_CNT;
    always@(posedge clk or negedge reset_n)begin
        if(reset_n==0)
            SHCP_EDGE_CNT<=0;
        else if(sck_plus)
            if(SHCP_EDGE_CNT==32)
                SHCP_EDGE_CNT<=0;
            else 
                SHCP_EDGE_CNT<=SHCP_EDGE_CNT+1'b1;
    end
        
	//直接对于32位波形定义
	//避免使用div_cnt产生的时钟信号质量过差的问题
    always@(posedge clk or negedge reset_n)begin
        if(reset_n==0)begin
            SH_CP<=0;
            ST_CP<=0;
            DS<=0;
        end
        else begin
            case(SHCP_EDGE_CNT)
                0: begin SH_CP<=0;ST_CP<=1'd0;DS<=r_Data[15]; end
                1: SH_CP<=1'd1;
				//下降沿的时候进行数据传输(为什么不是常见的上升沿?)
				//理解:fpga传输data,74HC595接收data
				//这里在写fpga代码,当在下降沿把data传输过去时
				//74HC595接收时就在上升沿!
                2: begin SH_CP<=0;DS<=r_Data[14]; end
                3: SH_CP<=1'd1;
                4: begin SH_CP<=0;DS<=r_Data[13]; end                
                5: SH_CP<=1'd1;
                6: begin SH_CP<=0;DS<=r_Data[12]; end
                7: SH_CP<=1'd1;
                8: begin SH_CP<=0;DS<=r_Data[11]; end
                9: SH_CP<=1'd1;
                10: begin SH_CP<=0;DS<=r_Data[10]; end
                11: SH_CP<=1'd1;
                12: begin SH_CP<=0;DS<=r_Data[9]; end
                13: SH_CP<=1'd1;
                14: begin SH_CP<=0;DS<=r_Data[8]; end
                15: SH_CP<=1'd1;
                16: begin SH_CP<=0;DS<=r_Data[7]; end
                17: SH_CP<=1'd1;
                18: begin SH_CP<=0;DS<=r_Data[6]; end
                19: SH_CP<=1'd1;
                20: begin SH_CP<=0;DS<=r_Data[5]; end
                21: SH_CP<=1'd1;
                22: begin SH_CP<=0;DS<=r_Data[4]; end
                23: SH_CP<=1'd1;
                24: begin SH_CP<=0;DS<=r_Data[3]; end
                25: SH_CP<=1'd1;
                26: begin SH_CP<=0;DS<=r_Data[2]; end
                27: SH_CP<=1'd1;     
                28: begin SH_CP<=0;DS<=r_Data[1]; end
                29: SH_CP<=1'd1;
                30: begin SH_CP<=0;DS<=r_Data[0]; end
                31: SH_CP<=1'd1;
                32: ST_CP<=1'd1;
                default: 
                    begin
                        SH_CP<=0;
                        ST_CP<=0;
                        DS<=0;
                    end
            endcase
        end
    end
endmodule

代码解析

  • 在使用芯片时,一定要通过芯片手册查询相关时序,从而才能实现相关的RTL代码
  • 对于74HC595芯片规定的波形,这里代码没有先分频,而是直接将每一bit都自行拟定赋值,从而规避时钟质量过差的问题

测试平台

`timescale 1ns / 1ps

module hex8_tb();

    reg clk;
    reg reset_n;
    reg [32-1:0] disp_data;
    
    wire [8-1:0] sel;
    wire [8-1:0] led;

    hex8 hex8(
        clk,
        reset_n,
        disp_data,
        sel,
        led
        );
                  
    initial begin
        clk = 1;
        forever #10 clk = ~clk;
    end
    
	
    initial begin
        reset_n=0;
        disp_data=32'h0000_0000;
        #201;
        reset_n=1;
        #2000;
        disp_data=32'h1234_abcd;
        #10_000_000;
        disp_data=32'h5678_4321;
        #10_000_000;
        $stop;
    end
    
endmodule
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值