【verilog】动态数码管显示(带符号和定点小数,FPGA)

该博客详细介绍了动态数码管显示的电路设计和程序实现过程。通过分频产生5Mhz时钟,根据输入数值进行位拆分,并判断显示内容所占数码管数量。采用动态扫描方式切换数码管,结合译码电路将数据转换为段选信号,实现数值、符号和小数点的显示。程序中还包括了对输入数值的符号判断和动态数码管的1ms计数器。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

电路设计

在这里插入图片描述

程序设计

顶层模块

测试显示内容 “-432.10”

module signed_seg_top(clk,rst_n,seg_sel,seg_led);

    input clk;
    input rst_n;
    
    output [5:0] seg_sel;
    output [7:0] seg_led;

signed_seg f0 (
               .clk(clk)    ,       
               .rst_n(rst_n)  ,      

               .data(20'd43210)   ,       
               .point_position(6'b000100)  ,       
               .en(1'b1) ,       
               .sign(1'b1)   ,        
                
               //seg pin
               .seg_sel(seg_sel),        
               .seg_led(seg_led)         
    );
    
endmodule

主模块

//数码管-带符号位以及小数点程序
/*
接口:
signed_seg f0 (
               .clk(clk)    ,        // 时钟信号
               .rst_n(rst_n)  ,      // 复位信号
 
               .data()   ,          //显示的数值支持20'd0~20'd999999
               .point_position(),   //小数点具体显示的位置6bit独热码形式
               .en(1'b1) ,          //数码管使能
               .sign()   ,          //符号(-),1有效
                
               //seg pin
               .seg_sel(seg_sel),   // 数码管pin位选
               .seg_led(seg_led)    // 数码管pin段选
    );

*/
module signed_seg(
    input                   clk    ,        
    input                   rst_n  ,       

    input         [19:0]    data   ,       
    input         [5:0]     point_position  ,
    input                   en     ,        
    input                   sign   ,      

    //seg pin
    output   reg  [5:0]     seg_sel,       
    output   reg  [7:0]     seg_led 
    );



/******对50Mhz时钟进行:计数-译码,得到5Mhz的分频时钟dri_clk******/
reg    [ 3:0]             clk_cnt  ; 
reg                       dri_clk  ;        
always @(posedge clk or negedge rst_n) begin
   if(!rst_n) begin
       clk_cnt <= 4'd0;
   end
   else if(clk_cnt == 3'd4) begin
       clk_cnt <= 4'd0;
   end
   else begin
       clk_cnt <= clk_cnt + 1'b1;
   end
end

always @(posedge clk or negedge rst_n) begin
   if(!rst_n) begin
       dri_clk <= 1'b1;
   end
   else if(clk_cnt == 3'd4) begin
       dri_clk <= ~dri_clk;
   end
   else begin
       dri_clk <= dri_clk;
   end
end




/******对输入进来的data(范围:0~999999)进行位拆分******/
wire   [3:0]              data0    ;        //个位
wire   [3:0]              data1    ;        //十位
wire   [3:0]              data2    ;        //百位
wire   [3:0]              data3    ;        //千位
wire   [3:0]              data4    ;        //万位
wire   [3:0]              data5    ;        //十万位
assign  data0 = data % 4'd10;               
assign  data1 = data / 4'd10 % 4'd10   ;    
assign  data2 = data / 7'd100 % 4'd10  ;    
assign  data3 = data / 10'd1000 % 4'd10 ;  
assign  data4 = data / 14'd10000 % 4'd10;   
assign  data5 = data / 17'd100000;      


/******判断待显示内容占几个数码管******/
wire  six;
wire  five;
wire  four;
wire  three;
wire  two;
wire  one;
assign  six =   data5 || point_position[5]; //若第六个数码管不为0 或 第六个数码管上存在小数点,则内容占6个数码管
assign  five =  data4 || point_position[4]; //...
assign  four =  data3 || point_position[3];
assign  three = data2 || point_position[2];
assign  two =   data1 || point_position[1];
assign  one =   data0 || point_position[0];


/******根据上述的判断,为中间寄存器赋值******/

reg    [23:0]    num; //中间寄存器,寄存6个数码管每一个的显示内容
                      //    6          5           4         3         2        1
                      //num[23:20] num[19:16] num[15:12] num[11:8] num[7:4] num[3:0]

    always @(posedge dri_clk or negedge rst_n) begin
            if (!rst_n)
                num <= 24'b0;
                
            else if(six) //开始判断待显示内容占几个数码管,注意逐级判断.  
            begin         
                num[23:0] <= {data5,data4,data3,data2,data1,data0};
            end
            
            else if(!six && five)
            begin                         
                num[19:0] <= {data4,data3,data2,data1,data0};
                if(sign)                    
                    num[23:20] <= 4'd11; 
                else
                    num[23:20] <= 4'd10; 
            end
            
            else if(!six && !five && four)
            begin   
                num[15:0] <= {data3,data2,data1,data0};
                num[23:20] <= 4'd10;    //第六个数码管多余,则将其关闭。
                if(sign)             
                    num[19:16] <= 4'd11;//如果需要显示负号,则第五个数码管显示负号
                else                    //不需要显示负号时,则第五个数码管关闭
                    num[19:16] <= 4'd10;
            end
            
            else if(!six && !five && !four && three)
            begin
                num[11: 0] <= {data2,data1,data0};
                num[23:16] <= {2{4'd10}};
                if(sign)        
                    num[15:12] <= 4'd11;
                else            
                    num[15:12] <= 4'd10;
            end
            
            else if(!six && !five && !four && !three && two) 
            begin  
                 num[ 7: 0] <= {data1,data0};
                 num[23:12] <= {3{4'd10}};
                 if(sign)     
                    num[11:8]  <= 4'd11;
                 else         
                    num[11:8] <=  4'd10;
            end
            
            else if(!six && !five && !four && !three && !two && one) 
            begin   
                num[3:0] <= data0;
                num[23:8] <= {4{4'd10}};
                if(sign)    
                    num[7:4] <= 4'd11;
                else        
                    num[7:4] <= 4'd10;
            end
end


/******计数1ms,输出一个flag******/
reg    [12:0]  cnt0;
reg            flag; 
always @ (posedge dri_clk or negedge rst_n) begin
    if (rst_n == 1'b0) begin
        cnt0 <= 13'b0;
        flag <= 1'b0;
     end
    else if (cnt0 < 13'd5000 - 1'b1) begin
        cnt0 <= cnt0 + 1'b1;
        flag <= 1'b0;
     end
    else begin
        cnt0 <= 13'b0;
        flag <= 1'b1;
     end
end

/******动态数码管显示核心部分******/
/*根据计数器,快速动态轮流切换数码管,那么总有一个数码管可以被称为"当前数码管"*/
reg    [2:0] cnt_sel  ; 
reg    [3:0] num_disp ; // 当前数码管显示的数据是什么
reg          dtdpe;     // dtdpe = Does the decimal point exist,当前数码管存在小数点吗       
always @ (posedge dri_clk or negedge rst_n) begin
    if (rst_n == 1'b0)
        cnt_sel <= 3'b0;
    else if(flag) begin
        if(cnt_sel < 3'd5)
            cnt_sel <= cnt_sel + 1'b1;
        else
            cnt_sel <= 3'b0;
    end
    else
        cnt_sel <= cnt_sel;
end


always @ (posedge dri_clk or negedge rst_n) begin
    if(!rst_n) begin
        seg_sel  <= 6'b111111;              //位选信号低电平有效
        num_disp <= 4'b0;           
        dtdpe <= 1'b1;                   //共阳极数码管,低电平导通
    end
    else begin
        if(en) begin
            case (cnt_sel)
                3'd0 :begin
                    seg_sel  <= 6'b111110;      //当前数码管是哪个数码管
                    num_disp <= num[3:0] ;      //当前数码管显示什么值
                    dtdpe <= ~point_position[0];//当前数码管是否有小数点
                end
                3'd1 :begin
                    seg_sel  <= 6'b111101;  
                    num_disp <= num[7:4] ;
                    dtdpe <= ~point_position[1];
                end
                3'd2 :begin
                    seg_sel  <= 6'b111011;  
                    num_disp <= num[11:8];
                    dtdpe <= ~point_position[2];
                end
                3'd3 :begin
                    seg_sel  <= 6'b110111;  
                    num_disp <= num[15:12];
                    dtdpe <= ~point_position[3];
                end
                3'd4 :begi           n
                    seg_sel  <= 6'b101111;  
                    num_disp <= num[19:16];
                    dtdpe <= ~point_position[4];
                end
                3'd5 :begin
                    seg_sel  <= 6'b011111;  
                    num_disp <= num[23:20];
                    dtdpe <= ~point_position[5];
                end
                default :begin
                    seg_sel  <= 6'b111111;
                    num_disp <= 4'b0;
                    dtdpe <= 1'b1;
                end
            endcase
        end
        else begin
            seg_sel  <= 6'b111111; //使能信号为0时,所有数码管disable
            num_disp <= 4'b0;
            dtdpe <= 1'b1;
        end
    end
end


/******译码:将数字、符号、小数点,翻译成数码管专用段选信号******/
always @ (posedge dri_clk or negedge rst_n) begin
    if (!rst_n)
        seg_led <= 8'hc0;
    else begin
        case (num_disp)
            4'd0 : seg_led <= {dtdpe,7'b1000000}; //0
            4'd1 : seg_led <= {dtdpe,7'b1111001}; //1
            4'd2 : seg_led <= {dtdpe,7'b0100100}; //2
            4'd3 : seg_led <= {dtdpe,7'b0110000}; //3
            4'd4 : seg_led <= {dtdpe,7'b0011001}; //4
            4'd5 : seg_led <= {dtdpe,7'b0010010}; //5
            4'd6 : seg_led <= {dtdpe,7'b0000010}; //6
            4'd7 : seg_led <= {dtdpe,7'b1111000}; //7
            4'd8 : seg_led <= {dtdpe,7'b0000000}; //8
            4'd9 : seg_led <= {dtdpe,7'b0010000}; //9
            4'd10: seg_led <= 8'b11111111;        //空
            4'd11: seg_led <= 8'b10111111;        //-
            default: 
                   seg_led <= {dtdpe,7'b1000000};
        endcase
    end
end

endmodule 

结果

在这里插入图片描述

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

搞IC的那些年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值