动态扫描数码管显示_总结

上一次写了驱动74HC595的驱动,并测试了他的可行性,但没有把整套电路综合起来测试,现在把三个电路连接起来进行了测试,并做一个总结。

目的:

    part1: 输入8个4位的数据(即8个0~f),共32位,使其可以在八个数码管上同时显示出来。

    注:前面提到,为了节省引脚,利用人眼的视觉暂留效果,所以设置了一个计数器,让每个数码管显示的刷新频率一定,达成同时显示的效果。为此,此模块的输出为: [7:0] 位选信号(选择8位中的某一位)  +    [7:0] 段选信号(选择显示哪一段,从而显示 0~f) ,多引脚的设计方案输出的信号为 2 * N ,而本模块输出的信号个数为 8+N 。当N> 8 时 ,用本模块更加节省引脚。

    这个模块输出的是16位并行信号([7:0] 位选信号(选择8位中的某一位) +  [7:0] 段选信号(选择显示哪一段,从而显示 0~f))。输入是32位信号(8个0~f),时分复用,逐个输出,动态显示

    本模块1是fpga的内部设计,开发板的数码管在外部,用74HC595控制,因此我们需要写一个驱动,驱动74HC595输出。

    part2:模块1输出并行数据,模块3接收串行数据,所以这个驱动用于并串转换。

    part3:74HC595模块,输入信号设计为3个:串行数据输入信号,时钟信号,锁存信号 。而模块1输出是并行数据,所以需要一个并串转换模块(利用计数器计时,逐个输出)。时钟信号频率需要一致,上一节已经解释了。

注:为什么要并转串,串转并这么麻烦呢?是因为开发板的设计导致的。开发板用的是74HC595来控制数码管,而不是fpga输出信号直接练到数码管,所以我们才需要多写一个驱动,让这几个模块的数据传输匹配,可以实现功能。

 电路图:

 

功能描述用上面三个模块讲完了,但是设计代码时会存在许多细节,需要调试。

①一开始没有设置一开send_en_pulse信号,提示有输入信号到来,这会导致后面的模块不知何时开始接收,接收完一个数据后什么时候再开始接收。

②第一个模块输出每一位的显示时间 t1,与第二个模块接收完这个显示的数据所花的时间 t2 是不一定相等的,t1>= t2  ,当 t1 > t2 时,模块2接收完一次数据之后,还会继续重复接收当前数据并输出,这会导致显示出错,因此需要设置send_dong信号,每输出一位数据,就发送结束标志信号,让模块2接收完这位数据后,输出0,并让内部计数器归零。这样就不会影响下一位的接收。

调试:先把电路图画出来,逻辑关系,引脚信号对应标记清楚,然后从头开始观察信号波形,把无关波形先删除,关键波形加入,分析功能,缺陷,适当引入标志信号,可以让功能实现更准确。

 

这个系统的代码最终版如下:

复制代码
module digital_tube(//八个数码管显示,并行输入,并行输出 part1
    clk,
    reset,
    send_en_pulse,
    disp_num_all,
    dg_tube,
    tube_part,
    send_done,
    send_sig
    );
    
    input clk ;
    input reset ;
    input send_en_pulse ;
    input [31:0]disp_num_all ;
    output [7:0]dg_tube ;
    output [7:0]tube_part ;
    output reg send_done ;
    output reg send_sig ;
    
    
    parameter one_dis_t = 25'd1_000_000 ;//每个晶体管显示时间(计数)
    
    reg [16:0]counter1 ;
    reg [2:0] counter2 ;
    reg send_en ;
    reg [31:0]dis_regist;
    
    always @ ( posedge clk or negedge reset )//分频
    begin
        if (! reset )
            send_en <= 1'd0 ;
        else if (send_en_pulse)
            send_en <= 1'd1 ;       
    end
    
    always @ ( posedge clk or negedge reset )//分频
    begin
        if (! reset )
            dis_regist <= 32'd0 ;
        else if (send_en_pulse)
            dis_regist <= disp_num_all ;
    end
    
    always @ ( posedge clk or negedge reset )//分频
    begin
        if (! reset )
        counter1 <= 17'd0 ;
        else if (send_en)
            begin
            if ( (one_dis_t-1) <= counter1 )
            counter1 <= 17'd0 ;
            else
            counter1 <= counter1 +1'b1 ;
            end
         else if ( send_en_pulse == 1 ) 
            counter1 <= 17'd0 ;
    end
    
    always @ ( posedge clk or negedge reset )//循环
    begin
        if (! reset )
            counter2 <= 3'd0 ;
        else if (( (one_dis_t-1) <= counter1 ) && ( send_en ) )
            counter2 <= counter2 +1'b1 ;
        else if ( send_en_pulse == 1 )
            counter2 <= 3'd0 ;
    end
    
    always @ ( posedge clk or negedge reset )//发送结束标志
    begin
        if (! reset )
        send_done <= 1'd0 ;
         else if (send_en)
            begin
            if ( (one_dis_t-1) <= counter1 )
            send_done <= 1 ;
            else if ( send_done == 1 ) 
            send_done <= 0 ;
            end
    end
    
    always @ ( posedge clk or negedge reset )//发送结束标志
    begin
        if (! reset )
            send_sig <= 1'd0 ;
        else if (send_en_pulse)
            send_sig <= 1'd1 ;
        else
            send_sig <= 1'd0 ;
    end
    
    wire [3:0]disp_num_one ;
    
    //3-8译码器 控制哪个数码管显示
    decoder_3_8 tube_select(//控制
               .a(counter2[2] ),
               .b(counter2[1]),
               .c(counter2[0]),
               .out(dg_tube)
        );
    
    //需要一个八选一选通器,对应哪个数码管显示什么内容
    mux8  tube_display(//选通
    .sel(counter2),
    .data(dis_regist),
    .out(disp_num_one)
    );
    
    //真值表对应显示数字
    LUT_truth translator(//控制
    .num(disp_num_one),
    .out(tube_part)
    );
endmodule
复制代码
复制代码
module drive_digital_tube(//并行输入,串行输出 part2
    clk,
    reset,
    data,
    s_signal,
    s_signal1,
    DIO,
    sclk,
    rclk,
    s_done
    );
    input clk;//50MHz
    input reset;
    input [15:0]data;
    input  s_signal;
    input  s_signal1;
    output reg DIO;
    output reg sclk;
    output reg rclk;
    output reg s_done;
    
    reg [15:0]dats_regist ;
    always@( posedge clk or negedge reset)//使能端
    begin
        if (!reset)
            dats_regist <= 16'd0 ;
        else if  ((s_signal1) || (s_signal))
            dats_regist <= data ;
        else if (s_done == 1'd1 )
            dats_regist <= 16'd0 ;
    end
    
    reg s_en ;
    
    reg [1:0]div_cnt;// 分频计数器,频率为25MHz
    always@( posedge clk or negedge reset)
    begin
        if (!reset)
            div_cnt <= 2'd0 ;
        else if(div_cnt == 1)
            div_cnt <= 2'd0 ;
        else
            div_cnt <= div_cnt + 1'd1 ; 
    end
    
    wire pulse25M; //频率为25MHz的取样脉冲
    assign pulse25M = ( div_cnt == 2'd1 ) ? 1 : 0 ;
    
    reg [5:0]cnt;//计数33个状态
    always@(posedge clk or negedge reset)
    begin
        if(!reset)
            cnt <= 6'd0 ;
        else if (s_en)
        begin
            if (pulse25M)
                begin
                    if(cnt == 6'd32)
                        cnt <= 6'd0 ; 
                    else 
                        cnt <= cnt + 1 ;
                end
        end
        else
            cnt <= 6'd0 ;
    end
    
    always@(posedge clk or negedge reset)
    begin
        if(!reset)
        begin
            DIO <= 0 ;
            sclk <= 0 ;
            rclk <= 0 ;
            s_done = 0 ;
            s_en <= 1'd0 ;
        end
        else if(s_en)           
        begin
                if (pulse25M)
                case(cnt)//sclk为12.5MHz信号,rclk为输出使能(所有数据取完后),在sclk的低电平时取值,可以稳定,在sclk上升沿到来时可稳定输出
                    0:begin DIO <= dats_regist[15] ;sclk <= 0 ;s_done = 0 ;end
                    1: begin sclk <= 1 ; end
                    2:begin DIO <= dats_regist[14];sclk <= 0 ; rclk <= 0 ;end
                    3:sclk <= 1 ;
                    4:begin DIO <= dats_regist[13] ;sclk <= 0 ; end
                    5:sclk <= 1 ;
                    6:begin DIO <=dats_regist[12] ;sclk <= 0 ; end
                    7:sclk <= 1 ;
                    8:begin DIO <=dats_regist[11] ;sclk <= 0 ; end
                    9:sclk <= 1 ;
                    10:begin DIO <=dats_regist[10] ;sclk <= 0 ; end
                    11:sclk <= 1 ;
                    12:begin DIO <=dats_regist[9] ;sclk <= 0 ; end
                    13:sclk <= 1 ;
                    14:begin DIO <=dats_regist[8] ;sclk <= 0 ; end
                    15:sclk <= 1 ;
                    16:begin DIO <=dats_regist[7] ;sclk <= 0 ; end
                    17:sclk <= 1 ;
                    18:begin DIO <=dats_regist[6] ;sclk <= 0 ; end
                    19:sclk <= 1 ;
                    20:begin DIO <=dats_regist[5] ;sclk <= 0 ; end
                    21:sclk <= 1 ;
                    22:begin DIO <=dats_regist[4] ;sclk <= 0 ; end
                    23:sclk <= 1 ;
                    24:begin DIO <=dats_regist[3] ;sclk <= 0 ; end
                    25:sclk <= 1 ;
                    26:begin DIO <=dats_regist[2] ;sclk <= 0 ; end
                    27:sclk <= 1 ;
                    28:begin DIO <=dats_regist[1] ;sclk <= 0 ; end
                    29:sclk <= 1 ;
                    30:begin DIO <=dats_regist[0] ;sclk <= 0 ; end
                    31:begin sclk <= 1 ;    end
                    32:begin s_done = 1 ;  rclk <= 1 ;s_en = 0;  end
                    
                    default ;           
                endcase
        end
        else if((s_signal1) || (s_signal))
            s_en <= 1'd1 ;
        else
        begin
            DIO <= 0 ;
            sclk <= 0 ;
            rclk <= 0 ;
            s_done = 0 ;
        end
    end    
    
endmodule
复制代码
复制代码
module my_74HC595(//串转并 part3
    clk,
    lock_en,
    series_data,
    reset,
    parallel_data    
    );
    
    input clk ;
    input lock_en ;
    input series_data ;
    input reset ;
    output reg [15:0]parallel_data ;
    
    reg [15:0]regist_data ;
    always@( posedge clk or negedge reset )
    begin   
        if ( !reset )
            regist_data <= 8'd0 ;
        else if ( lock_en )
            regist_data <= 8'd0 ;
        else 
            regist_data <= { regist_data[14:0], series_data} ;            
    end
    
    always@(*)
    begin
        case(lock_en)
            0:;
            1: parallel_data <= regist_data ;            
        endcase
    end
endmodule
复制代码
复制代码
module digital_tube_3ctrl( 顶层连线部分
    clk,
    reset,
    send_en,
    data_input,
    display_num
    );
    input clk ;
    input reset; 
    input send_en ;
    input  [31:0]data_input ;
    output [15:0]display_num ;
    
    wire [15:0]byte_part ;
    wire en_1 ;
    wire en_2 ;
    wire sig_free ;
    digital_tube  
    #(.one_dis_t(100))
    part_1(//八个数码管显示,并行输入,并行输出
    .clk(clk),
    .reset(reset),
    .send_en_pulse(send_en),
    .disp_num_all(data_input),
    .dg_tube(byte_part[15:8]),
    .tube_part(byte_part[7:0]),
    .send_done(en_2),
    .send_sig(en_1)    
    );
    
    wire uart_data1 ;
    wire s_clk ;
    wire r_clk ;
    wire s_done1 ;
    drive_digital_tube part_2(//并行输入,串行输出
    .clk(clk),
    .reset(reset),
    .data(byte_part),
    .s_signal(en_1),
    .s_signal1(en_2),
    .DIO(uart_data1),
    .sclk(s_clk),
    .rclk(r_clk),
    .s_done(s_done1)
    );
    
    my_74HC595 part_3(//串转并
    .clk(s_clk),
    .lock_en(r_clk),
    .series_data(uart_data1),
    .reset(reset),
    .parallel_data(display_num)    
    );
endmodule
复制代码
复制代码
`timescale 1ns / 1ns
module digital_tube_3ctrl_tb( 测试激励代码
    );

    reg clk ;
    reg reset ;
    reg send_en ;
    reg [31:0]data_input ;
    wire [15:0]display_num ;
    
    digital_tube_3ctrl digital_tube_3ctrl_sim(
    clk,
    reset,
    send_en,
    data_input,
    display_num
    );

    initial clk = 1 ;
    always #10 clk = ! clk ;
    initial
    begin
        reset = 0 ;
        send_en = 0 ;
        data_input = 32'd0 ;
        #201 ;
        reset = 1 ;
        #200 ;
        data_input = 32'habb02525 ;
        send_en = 1 ;
        #20 ;
        send_en = 0 ;
        #20000;
        data_input = 32'h52520bba ;
        send_en = 1 ;
        #20 ;
        send_en = 0 ;
        #30000;        
        $stop;
    end
    
endmodule
复制代码

 

posted @   little_breeze  阅读(419)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示