赞
踩
数码管是现在电子产品上常用的显示器件,它有驱动简单、显示清晰、价格低廉等优势。数码管的实物图:
数码管的内部结构图如下所示:
从图中可以看出,它由八个段组成,即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变量控制数码管段选信号的输出。这样就实现了动态的显示!
备注:数码管的段选信号就是数码管A B C D E F G等七个段的控制信号,数码管位选信号就是公共端的控制信号。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。