数码管是现在电子产品上常用的显示器件,它有驱动简单、显示清晰、价格低廉等优势。数码管的实物图:
数码管的内部结构图如下所示:
从图中可以看出,它由八个段组成,即A B C D E F G DP(小数点),只要将这八个段按规律组合点亮,就能显示出一定的数字。例如,对于数字1,只需要将B C两段点亮,其他全部熄灭,那么就可以在数码管上显示出数字1.数码管还有一个公共端,用于接电源或地。
数码管又分为两种,一种是共阴极数码管,一种是共阳极数码管。对于共阴极数码管而言,它的各个段是高电平点亮,公共端接地。对于共阳极数码管,它的各个段是低电平点亮,公共端接电源。现在给出两种数码管的0-9这十个数字的段码表:
共阴极(兼有共阳极):
共阳极:
至此,对于如何在数码管上显示出数字,我们就有了思路。本次我用的是共阳极数码管,不需要显示小数点,所以对我而言,我只需要控制数码管的七个段即可。用FPGA控制数码管静态显示是很容易的,直接给七个段分配七个管脚,然后再输出对应的电平,就能静态显示出数字。如果要显示数字1,只要输出电平 1111001即可。难点在于如何动态显示。下面讲解FPGA驱动四位数码管动态显示的思路:
本次使用的四位数码管按如下方式排列:
每个数码管都有一个位选端,通过位选端的控制,就可以一次只点亮一个数码管,然后快速切换到另一个数码管,只要频率够快,就能达到动态显示的效果。本次我使用的4位数码管的位选端是低电平有效,那么当位选信号为1110时,标号为4的数码管被点亮,可以显示相应的数字。要使得标号为3的数码管也被点亮显示数字时,只需要将位选信号赋值为1101即可。只要以足够快的频率,依次给位选信号赋值为1110 ,1101 , 1011 , 0111,就可以同时点亮四个数码管。
下面给出FPGA驱动数码管动态显示的代码,并对代码进行具体的分析、解释。
module seg(
input sys_clk,sys_rest,
input [15:0] data,
output reg [3:0] sel,
output reg [6:0] seg_led
);
parameter CLK_NUM=4'd10;
parameter MSNUM=14'd5000;
reg [3:0] CNT_NUM;
reg CLK;
reg [12:0] MSCNT;
reg MS_flag;
reg [3:0] num_display;
reg [15:0] num;
reg [2:0] sel_num; //选择哪一位数码管被点亮
//wire define
wire [3:0] data0 ; // 个位数
wire [3:0] data1 ; // 十位数
wire [3:0] data2 ; // 百位数
wire [3:0] data3 ; // 千位数
//提取显示数值所对应的十进制数的各个位
assign data0 = data[3:0]; // 个位数
assign data1 = data[7:4]; // 十位数
assign data2 = data[11:8]; // 百位数
assign data3 = data[15:12]; // 千位数
always @(posedge sys_clk or negedge sys_rest) begin
if(!sys_rest)
begin
CNT_NUM<=4'd0;
CLK<=1'd1;
end
else if(CNT_NUM<=CLK_NUM/2-1'b1)
begin
CLK<=~CLK;
CNT_NUM<=4'd0;
end
else
begin
CNT_NUM<=CNT_NUM+1;
CLK<=CLK;
end
end
always @(posedge CLK or negedge sys_rest) begin
if(!sys_rest)
num<=16'd0;
else
begin
num[15:12] <= data3; //则依次给4位数码管赋值
num[11:8] <= data2;
num[ 7:4] <= data1;
num[ 3:0] <= data0;
end
end
always @(posedge CLK or negedge sys_rest) begin //产生1ms脉冲
if(!sys_rest)
begin
MSCNT<=13'd0;
MS_flag<=1'b0;
end
else if(MSCNT==MSNUM-1)
begin
MSCNT<=13'd0;
MS_flag<=1'b1;
end
else
begin
MSCNT<=MSCNT+1;
MS_flag<=1'b0;
end
end
always @(posedge CLK or negedge sys_rest) begin
if(!sys_rest)
sel_num<=0;
else if(MS_flag)
begin
if(sel_num<3'd3)
sel_num<=sel_num+1;
else
sel_num<=0;
end
else
sel_num<=sel_num;
end
always @(posedge CLK or negedge sys_rest) begin
if(!sys_rest)
sel<=4'b1111;
else
begin
case(sel_num)
3'd0: begin
sel<= 4'b1110; //显示数码管最低位
num_display<=num[3:0];
end
3'd1: begin
sel<= 4'b1101; //显示数码管第1位
num_display<=num[7:4];
end
3'd2: begin
sel<= 4'b1011; //显示数码管第2位
num_display<=num[11:8];
end
3'd3: begin
sel<= 4'b0111; //显示数码管第3位
num_display<=num[15:12];
end
default sel<= 4'b1111;
endcase
end
end
always @(posedge CLK or negedge sys_rest) begin
if(!sys_rest)
seg_led<=7'b100000;
else
begin
case(num_display)
4'h0 : seg_led <= 7'b1000000;
4'h1 : seg_led <= 7'b1111001;
4'h2 : seg_led <= 7'b0100100;
4'h3 : seg_led <= 7'b0110000;
4'h4 : seg_led <= 7'b0011001;
4'h5 : seg_led <= 7'b0010010;
4'h6 : seg_led <= 7'b0000010;
4'h7 : seg_led <= 7'b1111000;
4'h8 : seg_led <= 7'b0000000;
4'h9 : seg_led <= 7'b0010000;
4'd10: seg_led <= 7'b1111111; //不显示任何字符
default : seg_led <= 7'b1000000;
endcase
end
end
endmodule
首先显示的数据是以BCD码的格式传入的,例如我要显示数据1234,那么就要传入0001_0010_0011_0100给该模块,所以输入数据data的位宽为16。然后定义4个内部变量,data0到data3,用于保存个位 ,十位, 百位 ,千位上的数字,方便后面的显示。随后又分频,产生了5M的时钟CLK和1K的时钟MS_flag。位选信号的变化就是在MS_flag信号的驱动下变换的,也就是说,数码管以1KHZ的频率切换显示,人眼是分辨不出来的,所以看起来就是同时显示了四个数字。最后,根据位选信号,将对应位(个位/十位/百位/千位)的数字传给num_display,再由num_display变量控制数码管段选信号的输出。这样就实现了动态的显示!文章来源:https://www.toymoban.com/news/detail-516118.html
备注:数码管的段选信号就是数码管A B C D E F G等七个段的控制信号,数码管位选信号就是公共端的控制信号。文章来源地址https://www.toymoban.com/news/detail-516118.html
到了这里,关于FPGA项目(5)--FPGA控制数码管动态显示的原理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!