动态数码管

 

 

 

 

module    Segment_scan
(
input            clk,
input             rst_n,
input    [3:0]    dat_1,        //SEG1 显示的数据输入,左边第一个数码管
input    [3:0]    dat_2,
input    [3:0]    dat_3,
input    [3:0]    dat_4,
input    [3:0]    dat_5,
input    [3:0]    dat_6,
input    [3:0]    dat_7,
input    [3:0]    dat_8,        //SEG8 显示的数据输入,最右边的数码管
input    [7:0]    dat_en,        //数码管数据位显示使能,[MSB~LSB]=[SEG1~SEG8],高有效
input    [7:0]    dot_en,        //数码管小数点位显示使能,[MSB~LSB]=[SEG1~SEG8],高有效

output    reg        seg_rck,        
output    reg        seg_sck,
output    reg        seg_din//595发送数据是在sck的作用下一位一位的移位A-B-C-D-E-F-G-H,RCK的作用下并行输出
);

localparam    CNT_40KHz = 300;
//1ms 一个数码管刷新一次,8个数码管8ms刷新一次,1s刷新125次,,视觉暂留。
//1ms/16=62.5us,一个周期刷新小于62.5us,取50us,敏感变量的周期就应该是25us,频率就是40k

localparam    IDLE  = 3'd0;
localparam    MAIN  = 3'd1;
localparam    WRITE = 3'd2;
localparam    LOW      = 1'b0;
localparam    HIGH  = 1'b1;

//创建数码管的字库,字库数据依段码顺序有关
//这里字库数据[MSB~LSB]={G,F,E,D,C,B,A}
reg[6:0] seg [15:0]; //共阴极
always @(negedge rst_n) begin
    seg[0]    =    7'h3f;   // 0
    seg[1]    =    7'h06;   // 1
    seg[2]    =    7'h5b;   // 2
    seg[3]    =    7'h4f;   // 3
    seg[4]    =    7'h66;   // 4
    seg[5]    =    7'h6d;   // 5
    seg[6]    =    7'h7d;   // 6
    seg[7]    =    7'h07;   // 7
    seg[8]    =    7'h7f;   // 8
    seg[9]    =    7'h6f;   // 9
    seg[10]    =    7'h77;   // A
    seg[11]    =    7'h7c;   // b
    seg[12]    =    7'h39;   // C
    seg[13]    =    7'h5e;   // d
    seg[14]    =    7'h79;   // E
    seg[15]    =    7'h71;   // F
end 

//计数器对系统时钟信号进行计数
reg    [9:0]    cnt = 1'b0;
always@(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            cnt <= 1'b0;
        else if(cnt >=CNT_40KHz-1)
            cnt <= 1'b0;
        else
            cnt <= cnt + 1'b1;
    end
//根据计数器计数的周期产生分频的脉冲信号
reg clk_40khz = 1'b0;
always@(posedge clk or negedge rst_n)
    if(!rst_n)
        clk_40khz <= 1'b0;
    else if(cnt < (CNT_40KHz>>1))
        clk_40khz <= 1'b0;
    else
        clk_40khz <= 1'b1;

//使用状态机完成数码管的扫描和74HC595时序的实现
reg    [15:0]    data;
reg    [2:0]    cnt_main;
reg    [5:0]    cnt_write;
reg    [2:0]    state = IDLE;

always@(posedge clk_40khz or negedge rst_n)
    begin
        if(!rst_n)
            begin
                state <= IDLE;
                cnt_main <= 3'd0; cnt_write <= 6'd0;
                seg_din <= 1'b0; seg_sck <= LOW; seg_rck <= LOW;
            end
        else
            begin
                case(state)
                    IDLE:begin//IDLE作为第一个状态,相当于软件复位
                            state <= MAIN;
                            cnt_main <= 3'd0;cnt_write <= 6'd0;
                            seg_din <= 1'b0; seg_sck <= LOW; seg_rck <= LOW;
                         end
                    MAIN:begin
                            cnt_main <= cnt_main + 1'b1;
                            state <= WRITE;    //在配置完发给74HC595的数据同时跳转至WRITE状态,完成串行时序
                            case(cnt_main)
                                //对8位数码管逐位扫描
                                3'd0: data <= {{dot_en[7],seg[dat_1]},dat_en[7]?8'hfe:8'hff};//发送数据高位开始,所以A连接左边第一位数码管,也就是SEG1
                                3'd1: data <= {{dot_en[6],seg[dat_2]},dat_en[6]?8'hfd:8'hff};
                                3'd2: data <= {{dot_en[5],seg[dat_3]},dat_en[5]?8'hfb:8'hff};
                                3'd3: data <= {{dot_en[4],seg[dat_4]},dat_en[4]?8'hf7:8'hff};
                                3'd4: data <= {{dot_en[3],seg[dat_5]},dat_en[3]?8'hef:8'hff};
                                3'd5: data <= {{dot_en[2],seg[dat_6]},dat_en[2]?8'hdf:8'hff};
                                3'd6: data <= {{dot_en[1],seg[dat_7]},dat_en[1]?8'hbf:8'hff};
                                3'd7: data <= {{dot_en[0],seg[dat_8]},dat_en[0]?8'h7f:8'hff};
                                default: data <= {8'h00,8'hff};
                            endcase
                         end
                    WRITE:begin
                            if(cnt_write >= 6'd33)
                                cnt_write <= 1'b0;
                            else
                                cnt_write <= cnt_write +1'b1;
                            case(cnt_write)
                                //74HC595是串行转并行的芯片,3路输入可产生8路输出,而且可以级联使用
                                //74HC595的时序实现,参考74HC595的芯片手册
                                6'd0: begin seg_sck <= LOW; seg_din <= data[15];end
                                6'd1: begin seg_sck <= HIGH; end
                                6'd2: begin seg_sck <= LOW; seg_din <= data[14];end
                                6'd3: begin seg_sck <= HIGH; end
                                6'd4: begin seg_sck <= LOW; seg_din <= data[13];end
                                6'd5: begin seg_sck <= HIGH; end
                                6'd6: begin seg_sck <= LOW; seg_din <= data[12];end
                                6'd7: begin seg_sck <= HIGH; end
                                6'd8: begin seg_sck <= LOW; seg_din <= data[11];end
                                6'd9: begin seg_sck <= HIGH; end
                                6'd10: begin seg_sck <= LOW; seg_din <= data[10];end
                                6'd11: begin seg_sck <= HIGH; end
                                6'd12: begin seg_sck <= LOW; seg_din <= data[9];end
                                6'd13: begin seg_sck <= HIGH; end
                                6'd14: begin seg_sck <= LOW; seg_din <= data[8];end
                                6'd15: begin seg_sck <= HIGH; end
                                6'd16: begin seg_sck <= LOW; seg_din <= data[7];end
                                6'd17: begin seg_sck <= HIGH; end
                                6'd18: begin seg_sck <= LOW; seg_din <= data[6];end
                                6'd19: begin seg_sck <= HIGH; end
                                6'd20: begin seg_sck <= LOW; seg_din <= data[5];end
                                6'd21: begin seg_sck <= HIGH; end
                                6'd22: begin seg_sck <= LOW; seg_din <= data[4];end
                                6'd23: begin seg_sck <= HIGH; end
                                6'd24: begin seg_sck <= LOW; seg_din <= data[3];end
                                6'd25: begin seg_sck <= HIGH; end
                                6'd26: begin seg_sck <= LOW; seg_din <= data[2];end
                                6'd27: begin seg_sck <= HIGH; end
                                6'd28: begin seg_sck <= LOW; seg_din <= data[1];end
                                6'd29: begin seg_sck <= HIGH; end
                                6'd30: begin seg_sck <= LOW; seg_din <= data[0];end
                                6'd31: begin seg_sck <= HIGH; end
                                6'd32: begin seg_rck <= HIGH; end
                                6'd33: begin seg_sck <= LOW; seg_rck <= LOW;end
                                    
                                default:;
                            endcase
                        end
                    default: state<= IDLE;
            endcase
        end
    end
endmodule

 

posted @ 2022-09-16 11:17  xiaoberber  阅读(139)  评论(0编辑  收藏  举报