1,数码管介绍
一位数码管:
数码管等效电路(共阴极 和 共阳极)
数码管显示的值:
假设我们需要b,c亮,我们只需要给b,c接高电平,其他接低电平就可。
seg[7:0] = 8'b0000_0110
对于数码管显示的值,seg值如下图:
多位数码管----->如下图(以3位为例)
假设现在需要LED1亮,那么就让sel0为1,数码管0的LED0-LED7阳极都是高电平,然后再控制a为低电平,那么就实现了数码管0的LED0点亮。
如果是8个数码管呢
8个sel信号
2,位选输出
这个规律就是3-8译码器 我们要按顺序点亮每一位,就需要1个3位的计数器(控制位切换信号):
利用人眼视觉暂留效应,得到多个数码管同时点亮的效果
每个数码管20ms带点亮一次,我们有8个数码管,那么数码管的切换时间就是20/8=2.5ms,保险一点改为1ms切换一个数码管。
1ms计时就设计一个1ms的计数器(预留位宽大一点30位)
设计一个比较器,当技术达到指定要求就输出1,当作cnt_sel的时钟使能信号以及自己本身计数的清0信号。
现在就可以实现8位数码管位选输出了。
3,段选输出
使用查找表形式在实现所要显示的字符。
所谓查找表就是,我预先设定好一个表,在每个表项里面存放需要输出的具体值。把每个字符输出的段码存放在表里面,然后把每个字符的显示内容作为查找表的索引号,只要给出索引号,就能查出对应的值。
16个索引号 4位数据表示temp_data[3:0]
根据当前动态扫描,正在扫描在哪个数码管,就将这个数码管需要显示的内容送到查找表的输入端口去,将需要显示的字符内容作为查找表的索引号输入进去。
8个数码管用一个8选1的多路选择器,利用段选中的cnt_sel作为选通通道--就能实现在扫描对应数码管的时候让段选就是这个数码管。
如果要显示更多字符:
这里 是8个通道,每个通道4位,那么把这8个通道合成一个32位数据data[31:0]
4,代码编写
整体设计符号图:
根据以上描述,编写代码:
module digitial_tube_0(
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;
parameter MCNT_1MS = 1000000/20 -1;
parameter MCNT_SEL = 8-1;
reg [15:0]cnt_1ms;
reg [2:0]cnt_sel;
reg [7:0]encode_sel;
reg [7:0]LUT_seg;
reg [3:0]data_temp;
//1ms计数器
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
cnt_1ms <= 0;
else if(cnt_1ms == MCNT_1MS)
cnt_1ms <= 0;
else
cnt_1ms <= cnt_1ms + 1'b1;
//位选计数器
always@(posedge Clk or Reset_n)
if(!Reset_n)
cnt_sel <= 0;
else if(cnt_1ms == MCNT_1MS) begin
if(cnt_sel == MCNT_SEL)
cnt_sel <= 0;
else
cnt_sel <= cnt_sel + 1'b1;
end
else
cnt_sel <= cnt_sel;
//3_8译码器
always@(*)
case(cnt_sel)
3'b000:encode_sel = 8'b0000_0001;
3'b001:encode_sel = 8'b0000_0010;
3'b010:encode_sel = 8'b0000_0100;
3'b011:encode_sel = 8'b0000_1000;
3'b100:encode_sel = 8'b0001_0000;
3'b101:encode_sel = 8'b0010_0000;
3'b110:encode_sel = 8'b0100_0000;
3'b111:encode_sel = 8'b1000_0000;
endcase
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
SEL <= 0;
else
SEL <= encode_sel;
//段选
always@(*)
case(cnt_sel)
3'b000:data_temp = Disp_Data[3:0];
3'b001:data_temp = Disp_Data[7:4];
3'b010:data_temp = Disp_Data[11:8];
3'b011:data_temp = Disp_Data[15:12];
3'b100:data_temp = Disp_Data[19:16];
3'b101:data_temp = Disp_Data[23:20];
3'b110:data_temp = Disp_Data[27:24];
3'b111:data_temp = Disp_Data[31:28];
endcase
always@(*)
case(data_temp)
0 : LUT_seg = 8'hc0;
1 : LUT_seg = 8'hf9;
2 : LUT_seg = 8'ha4;
3 : LUT_seg = 8'hb0;
4 : LUT_seg = 8'h99;
5 : LUT_seg = 8'h92;
6 : LUT_seg = 8'h82;
7 : LUT_seg = 8'hf8;
8 : LUT_seg = 8'h80;
9 : LUT_seg = 8'h90;
4'ha :LUT_seg = 8'h88;
4'hb :LUT_seg = 8'h83;
4'hc :LUT_seg = 8'hc6;
4'hd :LUT_seg = 8'ha1;
4'he :LUT_seg = 8'h86;
4'hf :LUT_seg = 8'h8e;
endcase
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
SEG <= 0;
else
SEG <= LUT_seg;
endmodule
编写testbench,测试代码:
`timescale 1ns / 1ps
module digitial_tubr_1_tb();
reg Clk;
reg Reset_n;
reg [31:0]Disp_Data;
wire [7:0]SEL;
wire [7:0]SEG;
digitial_tube_0 digitial_tube_0(
.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'h00000000;
#201
Reset_n = 1;
#200;
Disp_Data = 32'h12345678;
#10000000
Disp_Data = 32'h9abcdef0;
#10000000
$stop;
end
endmodule
仿真波形如下:
文章来源:https://www.toymoban.com/news/detail-818747.html
至此,数码管驱动逻辑编写完毕,但是在实际应用此输出占用的管脚过多,所以为了节省FPGA的管脚,需要将输出信号并转串后(FPGA只需要输出3个管脚),再利用串转并芯片(比如74HC595)连接数码管去显示需要输出的字符。文章来源地址https://www.toymoban.com/news/detail-818747.html
到了这里,关于FPGA_数码管显示的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!