黑金AX301开发板--数码管动态显示

本文主要讲解如何实现如何在AX301开发板上实现数码管的动态显示,不再叙述数码管动态显示的原理,网上也有相当多的帖子讲述原理。

一.AX301开发板的数码管开发手册

手册链接:下载地址
AX301 数码管
AX301数码管采用的六个8段共阳数码管,当某一字段对应的引脚为低电平时,相应字段就点亮,当某一字段对应的引脚为高电平时,相应字段就不亮。总共14个引脚,位选引脚6个,段选8个。
数码管引脚

二.设计

设计目的: 让数码管循环显示0-999
设计思路:

  • 计数模块 :生成二进制数据;
  • BCD转换模块:将生成的二进制数据转换成BCD码;
  • 译码模块:将输入数据转换成数码管段码;
  • 顶层模块:扫描数码管,输出段码。

下面是各个模块的介绍

2.1 计数模块(数据生成模块)

在这里插入图片描述

信号位宽类型功能描述
sys_clk1bitinput系统时钟50MHZ
sys_rst_n1bitinput复位信号
counter_cnt12bitoutput计数值

模块代码
带有标志位的计数模块,每隔0.1s数值加一,系统时钟50MHZ,周期就是0.00000002s,计5000000个数就是0.1s。计数到999清零。这里的数据输出位宽为12位,因为十进制999对应的二进制是0011 1110 0111,好像可以定义成10位,还没试过。

module counter
#(
    parameter CNT_MAX = 23'd4_999_999,
    parameter DATA_MAX = 20'd999
)
(
    input wire sys_clk,
    input wire sys_rst_n,
    output reg [11:0] counter_cnt
);

reg [22:0] cnt;
reg cnt_flag;

always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
    cnt <= 23'b0;
else if(cnt == CNT_MAX)
    cnt <= 23'b0;
else    
    cnt <= cnt + 1'b1;
end

always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
    cnt_flag <= 1'b0;
else if(cnt == CNT_MAX - 23'b1)
    cnt_flag <= 1'b1;
else
    cnt_flag <= 1'b0;
end

always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        counter_cnt <= 12'd0;
    else if(cnt_flag == 1'b1)
        counter_cnt <= counter_cnt + 1'b1;
    else if(counter_cnt == DATA_MAX && cnt_flag == 1'b1)
        counter_cnt <= 12'd0;
    else
        counter_cnt <= counter_cnt;
end
endmodule

2.2 BCD转换模块

这里需要用到二进制转BCD码,具体就是当我们要显示123这个数据时,二进制数据为
0111 1011,但是数码管没法显示啊,这就需要把123转换成BCD码,这里是8421BCD
BCD码:0001 0010 0011
1 = 0001
2 = 0010
3 = 0011
不懂得可以百度BCD码,这里推荐野火教程,阐述的很明白,这是链接
在这里插入图片描述

信号位宽类型功能描述
sys_clk1bitinput系统时钟50MHZ
sys_rst_n1bitinput复位信号
counter_cnt12bitinput计数值
da_04bitoutput个位
da_14bitoutput十位
da_24bitoutput百位

模块代码

module bcd8421 (
    input wire sys_clk,
    input wire sys_rst_n,
    input wire [11:0] counter_cnt,

    output reg [3:0] da_0,
    output reg [3:0] da_1,
    output reg [3:0] da_2
);

reg [3:0] cnt_shift;//移位12次
reg [11:0] bcd_code;//转换结果
reg [23:0] data_Shift;//移位寄存器
reg shift_flag;//移位标志

//cnt_shift 
always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        cnt_shift <= 4'd0;
    else if((cnt_shift == 4'd13) && (shift_flag == 1'b1)) 
        cnt_shift <= 4'd0;
    else if(shift_flag == 1'b1)
        cnt_shift <= cnt_shift + 1'b1;
    else 
        cnt_shift <= cnt_shift;
end

//data_Shift
always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        data_Shift <= 24'd0;
    else if(cnt_shift == 4'd0)
        data_Shift <= {12'b0,counter_cnt};
    else if((cnt_shift <= 12) && (shift_flag == 1'b0)) begin
        data_Shift[15:12] <= (data_Shift[15:12] > 4) ? (data_Shift[15:12] + 2'b11) : (data_Shift[15:12]);
        data_Shift[19:16] <= (data_Shift[19:16] > 4) ? (data_Shift[19:16] + 2'b11) : (data_Shift[19:16]);
        data_Shift[23:20] <= (data_Shift[23:20] > 4) ? (data_Shift[23:20] + 2'b11) : (data_Shift[23:20]);
    end
    else if((cnt_shift <= 4'd12) && (shift_flag == 1'b1))
        data_Shift <= data_Shift << 1;
    else
        data_Shift <= data_Shift;
end

always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        bcd_code <= 12'd0;
    else if((cnt_shift == 4'd13) && (shift_flag == 1'b1))
        bcd_code <= data_Shift[23:12];
    else
        bcd_code <= bcd_code;
end

//shift_flag
always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        shift_flag <= 1'b0;
    else
        shift_flag <= ~shift_flag;
end

//
always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) begin
        da_0 <= 4'b0;
        da_1 <= 4'b0;
        da_2 <= 4'b0;
end
    else if(cnt_shift == 4'd12) begin
        da_0 <= bcd_code[3:0];
        da_1 <= bcd_code[7:4];
        da_2 <= bcd_code[11:8];
    end
end              
endmodule

部分代码参考了野火教程,设计逻辑如下:
cnt_shift

  • 复位:0
  • shift_flag移位标志为1时:左移
  • shift_flag移位标志为1且cnt_shift计数次数到13时:清零

data_Shift

  • 复位:0
  • cnt_shift移位次数为0时:将bcd码和二进制数据连接
  • cnt_shift移位次数小于等于12,且shift_flag移位标志为0时,对数据进行判断
  • cnt_shift移位次数小于等于12,且shift_flag移位标志为1时,对数据进行移位

bcd_code

  • 复位:0
  • shift_flag移位标志为1且cnt_shift计数次数到13时:将转换结果赋值给bcd_code

shift_flag

  • 复位:0
  • 时钟变换:取反

2.3 译码模块

在这里插入图片描述

信号位宽类型功能描述
bin_data[3:0]1bitinput输入的BCD码
seg_data[7:0]1bitoutput输出8位段码
module seg_decoder (
    input wire [3:0] bin_data,
    output reg [7:0] seg_data
);


always @(*) begin
    case (bin_data)
        4'd0: 	seg_data = 8'b1100_0000;	// 0
        4'd1: 	seg_data = 8'b1111_1001;	// 1
        4'd2: 	seg_data = 8'b1010_0100;	// 2
        4'd3: 	seg_data = 8'b1011_0000;	// 3
        4'd4: 	seg_data = 8'b1001_1001;	// 4
        4'd5: 	seg_data = 8'b1001_0010;	// 5
        4'd6: 	seg_data = 8'b1000_0010;	// 6
        4'd7: 	seg_data = 8'b1111_1000;	// 7
        4'd8: 	seg_data = 8'b1000_0000;	// 8
        4'd9: 	seg_data = 8'b1001_0000;	// 9
        // 4'ha: 	seg_data = 8'b1000_1000;
        // 4'hb: 	seg_data = 8'b1000_0011;
        // 4'hc: 	seg_data = 8'b1100_0110;
        // 4'hd: 	seg_data = 8'b1010_0001;
        // 4'he: 	seg_data = 8'b1000_0110;
        // 4'hf: 	seg_data = 8'b1000_1110;
        default:    seg_data = 8'hff;		// 关闭
    endcase
end


endmodule

2.4 数码管扫描模块(顶层模块)

在这里插入图片描述

module seg_scan 
#(
    //parameter
    parameter SCAN_CNT = 16'd49_999
)
(
    input wire sys_clk,
    input wire sys_rst_n,
    
    output reg [2:0] seg_sel,
    output reg [7:0] seg_data
);

reg [15:0] time_cnt;
reg [3:0] scan_sel;  
reg [23:0] smg_disp;

wire [7:0] data_0;
wire [7:0] data_1;
wire [7:0] data_2;

//scan_sel
always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) begin
        time_cnt <= 15'd0;
        scan_sel <= 4'd0;
    end
    else if(time_cnt == SCAN_CNT ) begin
        time_cnt <= 15'd0;
        if(scan_sel == 4'd5) begin
            scan_sel <= 4'd0;
        end
        else begin
            scan_sel <= scan_sel + 4'd1;
        end
    end
    else begin
        time_cnt <= time_cnt + 16'd1;
    end
end


always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) 
        smg_disp <= 24'b0;
    else if(da_2)
        smg_disp <= {data_2,data_1,data_0};
    else if(da_1)
        smg_disp <= {8'hff,data_1,data_0};
    else if(da_0)
        smg_disp <= {8'hff,8'hff,data_0};
    else 
        smg_disp <= smg_disp;
end


//smg  display
always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) begin
        seg_sel <= 3'b111;
        seg_data <= 8'hff;
    end
    else begin
        case(scan_sel)
           3'd0: begin		
                seg_sel	    <= 3'b110;		
                seg_data	<= smg_disp[7:0];
            end
            3'd1: begin
                seg_sel	    <= 3'b101;		
                seg_data	<= smg_disp[15:8];
            end
            3'd2: begin
                seg_sel	    <= 3'b011;		
                seg_data	<= smg_disp[23:16];
            end
            default: begin
                seg_sel	    <= 3'b111;
                seg_data	<= 8'hff;
            end
        endcase
    end
end

wire [11:0] counter_cnt;
counter counter__inst
(
    .sys_clk(sys_clk),
    .sys_rst_n(sys_rst_n),

    .counter_cnt(counter_cnt)
);

wire [3:0] da_0;
wire [3:0] da_1;
wire [3:0] da_2;

bcd8421 bcd8421_inst
(
    .sys_clk(sys_clk),
    .sys_rst_n(sys_rst_n),
    .counter_cnt(counter_cnt),

    .da_0(da_0),
    .da_1(da_1),
    .da_2(da_2)
);

seg_decoder seg_decoder_inst0
(
    .bin_data(da_0),

    .seg_data(data_0)
);
seg_decoder seg_decoder_inst1
(
    .bin_data(da_1),

    .seg_data(data_1)
);
seg_decoder seg_decoder_inst2
(
    .bin_data(da_2),

    .seg_data(data_2)
);
endmodule


2.5 整体框架

在这里插入图片描述
下个实验在这个代码上改了一下,可能有些地方没改回来,工程就不放出来了。本次也只用到三个数码管,而且复用性不是很好,如果想用到六个数码管,就必须改位宽。大家参考一下吧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值