赞
踩
一位数码管:
数码管等效电路(共阴极 和 共阳极)
数码管显示的值:
假设我们需要b,c亮,我们只需要给b,c接高电平,其他接低电平就可。
seg[7:0] = 8'b0000_0110
对于数码管显示的值,seg值如下图:
多位数码管----->如下图(以3位为例)
假设现在需要LED1亮,那么就让sel0为1,数码管0的LED0-LED7阳极都是高电平,然后再控制a为低电平,那么就实现了数码管0的LED0点亮。
如果是8个数码管呢
8个sel信号
这个规律就是3-8译码器 我们要按顺序点亮每一位,就需要1个3位的计数器(控制位切换信号):
利用人眼视觉暂留效应,得到多个数码管同时点亮的效果
每个数码管20ms带点亮一次,我们有8个数码管,那么数码管的切换时间就是20/8=2.5ms,保险一点改为1ms切换一个数码管。
1ms计时就设计一个1ms的计数器(预留位宽大一点30位)
设计一个比较器,当技术达到指定要求就输出1,当作cnt_sel的时钟使能信号以及自己本身计数的清0信号。
现在就可以实现8位数码管位选输出了。
使用查找表形式在实现所要显示的字符。
所谓查找表就是,我预先设定好一个表,在每个表项里面存放需要输出的具体值。把每个字符输出的段码存放在表里面,然后把每个字符的显示内容作为查找表的索引号,只要给出索引号,就能查出对应的值。
16个索引号 4位数据表示temp_data[3:0]
根据当前动态扫描,正在扫描在哪个数码管,就将这个数码管需要显示的内容送到查找表的输入端口去,将需要显示的字符内容作为查找表的索引号输入进去。
8个数码管用一个8选1的多路选择器,利用段选中的cnt_sel作为选通通道--就能实现在扫描对应数码管的时候让段选就是这个数码管。
如果要显示更多字符:
这里 是8个通道,每个通道4位,那么把这8个通道合成一个32位数据data[31:0]
整体设计符号图:
根据以上描述,编写代码:
- 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
仿真波形如下:
至此,数码管驱动逻辑编写完毕,但是在实际应用此输出占用的管脚过多,所以为了节省FPGA的管脚,需要将输出信号并转串后(FPGA只需要输出3个管脚),再利用串转并芯片(比如74HC595)连接数码管去显示需要输出的字符。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。