FPGA数码管
文章目录
- 前言
- 一、工程介绍
- 1.1 LED显示原理
- 1.2 控制LED的发光强度
- 1.3 7段发光二极管显示
前言
本系列文章来源于FPGA学习开源网站fpga4fun,网站由浅入深的介绍了26个FPGA工程,通过工程的学习,可以了解什么是FPGA以及它是如何工作的。本人仅用于学习和记录,如有侵权,速删。
一、工程介绍
本工程使用FPGA驱动LED数码管。
1.1 LED显示原理
LED是一个发光二极管,当加正向电压,LED点亮,加反向电压,LED熄灭,在实际连接电路上,FPGA引脚通过一个电阻连接LED,电阻值一般在100Ω-1KΩ之间,实际连接电路如下所示:
1.2 控制LED的发光强度
首先,看一下如何通过verilog代码实现LED的开关,代码类似用verilog代码实现蜂鸣器,具体代码如下所示:
module LEDBlink(input clk_i, //时钟一般在10MHz-50MHzoutput LED_o
);reg [31:0] cnt;always@(posedge clk_i)begincnt <= cnt + 1;endassign LED_o = cnt[22]; //这里使用的是计数器23bit控制开关的频率,使用不同的计数器位数实现不同的开关频率endmodule
其次,看一下如何控制LED实现半亮这种状态,一般由两种解决方案:一是将与FPGA、LED串联的电阻的阻值提高一倍;二是让FPGA输出不停的翻转,使得LED点亮和熄灭的时间一样,这样可以看到半亮的状态,具体代码如下所示:
module LEDhalflit(input clk_i,output LED_o
);reg toggle;always@(posedge clk_i)begintoggle <= ~toggle; //在时钟的一半进行翻转endassign LED = toggle;endmodule
然后,看一下如何控制LED的强度,一般可以使用pwm的思想。下面是一个使用4bit输入控制LED在16个亮度级别之间进行选择的例子,具体代码如下所示:
module LED_PWM(input clk_i,input [3:0] pwm_i, //16个亮度级别output LED_o
);reg [4:0] pwm;always@(posedge clk_i)beginpwm <= pwm[3:0] + pwm_i;endassign LED = pwm[4];endmodule
最后,看一下如何使LED看起来会发光,一般是使用计数器结合pwm的思想,具体代码如下所示:
module LEDglow(input clk_i,output LED_o
);reg [23:0] cnt;reg [ 4:0] pwm;wire [3:0] intensity = cnt[23] ? cnt[22:19] : ~cnt[22:19] //亮度在亮暗切换always@(posedge clk_i)begincnt <= cnt + 1;endalways@(posedge clk_i)beginpwm <= pwm[3:0] + intensity;endassign LED = PWM[4];endmodule
1.3 7段发光二极管显示
数码管由8个发光二极管组成,8个二极管命名为‘A’到‘G’,还有一个DP(点)。这8个二极管并不是独立的,一般会将阴极或者阳极接到一起,实际物理器件最少有九个引脚,如下图所示:
FPGA驱动数码管,最简单的方案是使用8个IO引脚,如下图所示,以显示数字2为例,具体代码如下:
module LED_7seg(output segA_o,output segB_o,output segC_o,output segD_o,output segE_o,output segF_o,output segG_o,output segDP_o
);assign {segA_o,segB_o,segC_o,segD_o,segE_o,segF_o,segG_o,segDP_o} = 8'b11011010;endmodule
下面使用FPGA驱动数码管实现一个10进制计数器,具体代码如下所示:
module LED_7seg(input clk_i,output segA_o,output segB_o,output segC_o,output segD_o,output segE_o,output segF_o,output segG_o,output segDP_o
);reg [23:0] cnt; //使用24bit计数器always@(posedge clk_i)begincnt <= cnt + 24'h1;endwire cntovf = &cnt; //归约与,&cnt=cnt[0]&cnt[1]&....&cnt[23],每计满24位,cntovf值为1,如果时钟设置好,可以实现1s置1一次reg [3:0] BCD;always@(posedge clk_i)beginif(cntovf)beign //每一秒,计数器加1BCD <= (BCD==4'h9 ? 4'h0 : BCD+4'h1); //from 0 to 9endendreg [7:0] SevenSeg;always@(*)begincase(BCD)4'h0: SevenSeg = 8'b1111_1100;4'h1: SevenSeg = 8'b0110_0000;4'h2: SevenSeg = 8'b1101_1010;4'h3: SevenSeg = 8'b1111_0010;4'h4: SevenSeg = 8'b0110_0110;4'h5: SevenSeg = 8'b1011_0110;4'h6: SevenSeg = 8'b1011_1110;4'h7: SevenSeg = 8'b1110_0000;4'h8: SevenSeg = 8'b1111_1110;4'h9: SevenSeg = 8'b1111_0110;default: SevenSeg = 8'b0000_0000;endcaseendassign {segA_o,segB_o,segC_o,segD_o,segE_o,segF_o,segG_o,segDP_o} = SevenSeg;endmodule
下面使用FPGA驱动数码管实现一个10进制平滑计数器,效果实现淡入淡出,具体代码如下所示:
module LED_7seg(input clk_i,output segA_o,output segB_o,output segC_o,output segD_o,output segE_o,output segF_o,output segG_o,output segDP_o
);reg [23:0] cnt; //使用24bit计数器always@(posedge clk_i)begincnt <= cnt + 24'h1;endwire cntovf = &cnt; //归约与,&cnt=cnt[0]&cnt[1]&....&cnt[23],每计满24位,cntovf值为1,如果时钟设置好,可以实现1s置1一次reg [3:0] BCD_new;reg [3:0] BCD_old;always@(posedge clk_i)beginif(cntovf)beign //每一秒,计数器加1BCD_new <= (BCD_new==4'h9 ? 4'h0 : BCD_new+4'h1); //from 0 to 0endendalways@(posedge clk_i)beginif(cntovf)beign BCD_old <= BCD_new; //将计数器打一拍endendreg [4:0] pwm;wire [3:0] pwm_input = cnt[22:19];always@(posedge clk_i)beginpwm <= pwm[3:0] + pwm_input; //通过pwm控制实现淡入淡出效果endwire [3:0] BCD = (cnt[23] | pwm[4]) ? BCD_new : BCD_old;reg [7:0] SevenSeg;always@(*)begincase(BCD)4'h0: SevenSeg = 8'b1111_1100;4'h1: SevenSeg = 8'b0110_0000;4'h2: SevenSeg = 8'b1101_1010;4'h3: SevenSeg = 8'b1111_0010;4'h4: SevenSeg = 8'b0110_0110;4'h5: SevenSeg = 8'b1011_0110;4'h6: SevenSeg = 8'b1011_1110;4'h7: SevenSeg = 8'b1110_0000;4'h8: SevenSeg = 8'b1111_1110;4'h9: SevenSeg = 8'b1111_0110;default: SevenSeg = 8'b0000_0000;endcaseendassign {segA_o,segB_o,segC_o,segD_o,segE_o,segF_o,segG_o,segDP_o} = SevenSeg;endmodule
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
