本文主要讲解如何实现如何在AX301开发板上实现数码管的动态显示,不再叙述数码管动态显示的原理,网上也有相当多的帖子讲述原理。
一.AX301开发板的数码管开发手册
手册链接:下载地址

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

二.设计
设计目的: 让数码管循环显示0-999
设计思路:
- 计数模块 :生成二进制数据;
- BCD转换模块:将生成的二进制数据转换成BCD码;
- 译码模块:将输入数据转换成数码管段码;
- 顶层模块:扫描数码管,输出段码。
下面是各个模块的介绍
2.1 计数模块(数据生成模块)

| 信号 | 位宽 | 类型 | 功能描述 |
|---|---|---|---|
| sys_clk | 1bit | input | 系统时钟50MHZ |
| sys_rst_n | 1bit | input | 复位信号 |
| counter_cnt | 12bit | output | 计数值 |
模块代码
带有标志位的计数模块,每隔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_clk | 1bit | input | 系统时钟50MHZ |
| sys_rst_n | 1bit | input | 复位信号 |
| counter_cnt | 12bit | input | 计数值 |
| da_0 | 4bit | output | 个位 |
| da_1 | 4bit | output | 十位 |
| da_2 | 4bit | output | 百位 |
模块代码
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] | 1bit | input | 输入的BCD码 |
| seg_data[7:0] | 1bit | output | 输出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 整体框架

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

1064

被折叠的 条评论
为什么被折叠?



