一、数码管的原理
数码管的示意图。左边为共阴极,右边为共阳极。
使用时要注意到底是共阴极还是共阳极,
数码管的控制信号的示意图。
用一个二进制数seg[7:0]的不同的位,来实现不同的控制。
1.数码管的对应值
数码管对应的具体值的体现。
具体值的对应如图。
2.数码管的控制
让sel的控制信号改变,同时改变seg[7:0]的值。例如sel1为高电平,上面的通路打开,b对应的seg[1]为低电平对应的就是数码管1的LED1点亮。
这样的话控制的就是11个信号,sel0,sel1,sel2加上seg[7:0],一共11个信号就实现了数码管的控制。
二、数码管扫描的逻辑建模
将38译码器的位选输出作为数码管的控制信号
有两个计数器一个是29位用来计时1ms,一个是3位用来切换3个控制信号。
LUT的含义是查找表,就是你预先设置一个值,在这个表中对这个值进行一个查询。
可以将需要的字符替换所需要的查找表的对应位置。将需要输出的内容对应的编号输入进去,这样前面就需要加入一个对应的多路选择器。
如何显示更多的字符呢?
1.可以扩大通道数据的位宽
2.扩大查找表的容量
加入了多路数据选择器可以被拆分扩展为32位的。
所设计的数码管模块接口示意
三、具体代码实现
1.引入库
module hex8(
Clk,
Reset_n,
Disp_Data,
SEL,
SEG
);
input Clk;
input Reset_n;
input [31:0]Disp_Data;
output reg[7:0]SEL;
output reg[7:0]SEG;
reg [29:0]div_cnt;
parameter CLOCK_FREQ = 50_000_000; //定义接入的时钟信号的频率
parameter TURN_FREQ = 1000; //数码管切换的速率
parameter MCNT = CLOCK_FREQ / TURN_FREQ - 1; //写在后面,先定义再使用。分频计数器
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
div_cnt <= 0;
else if(div_cnt ==MCNT)
div_cnt <= 0;
else
div_cnt <= div_cnt + 1'd1;
reg [2:0]cnt_sel;
always@(posedge Clk or negedge Reset_n) //位选择计数器
if(!Reset_n)
cnt_sel <= 0;
else if(div_cnt ==MCNT)
cnt_sel <= cnt_sel +1'd1;
reg [3:0]data_temp;
always@(posedge Clk )
case(cnt_sel)
0:SEL <= 8'b0000_0001; //0
1:SEL <= 8'b0000_0010; //1
2:SEL <= 8'b0000_0100; //2
3:SEL <= 8'b0000_1000; //3
4:SEL <= 8'b0001_0000; //4
5:SEL <= 8'b0010_0000; //5
6:SEL <= 8'b0100_0000; //6
7:SEL <= 8'b1000_0000; //7
endcase
always@(posedge Clk ) //对应查找表
case(data_temp)
0:SEG <= 8'b1100_0000; //0
1:SEG <= 8'b1111_1001; //1
2:SEG <= 8'b1010_0100; //2
3:SEG <= 8'b1011_0000; //3
4:SEG <= 8'b1001_1001; //4
5:SEG <= 8'b1001_0010; //5
6:SEG <= 8'b1000_0010; //6
7:SEG <= 8'b1111_1000; //7
8:SEG <= 8'b1000_0000; //8
9:SEG <= 8'b1001_0000; //9
10:SEG <= 8'b1000_1000; //A
11:SEG <= 8'b1000_0011; //B
12:SEG <= 8'b1100_0110; //C
13:SEG <= 8'b1010_1001; //D
14:SEG <= 8'b1000_0110; //E
15:SEG <= 8'b1000_1110; //F
endcase
always@(*) //8路选择器
case(cnt_sel)
0:data_temp <= Disp_Data[3:0]; //0
1:data_temp <= Disp_Data[7:4]; //1
2:data_temp <= Disp_Data[11:8]; //2
3:data_temp <= Disp_Data[15:12]; //3
4:data_temp <= Disp_Data[19:16]; //4
5:data_temp <= Disp_Data[23:20]; //5
6:data_temp <= Disp_Data[27:24]; //6
7:data_temp <= Disp_Data[31:28]; //7
endcase
endmodule
2.激励文件
`timescale 1ns / 1ps
module hex8_tb;
reg Clk;
reg Reset_n;
reg [31:0]Disp_Data;
wire [7:0]SEL;
wire [7:0]SEG;
hex8 hex8(
.Clk(Clk),
.Reset_n(Reset_n),
.Disp_Data(Disp_Data),
.SEL(SEL),
.SEG(SEG)
);
initial Clk = 1;
always #10 Clk=~Clk; //时钟生成
initial begin
Reset_n = 0;
Disp_Data = 32'h12345678;
#201;
Reset_n = 1;
#20_000_000; //延时20ms
Disp_Data = 32'h9abcdef0;
#20_000_000; //延时20ms
$stop;
end
endmodule
3.仿真验证
仿真波形图如上
总结
对数码管扫描的实现在vivado做了仿真验证