1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > 【 FPGA 】控制数码管动态扫描显示的小实验

【 FPGA 】控制数码管动态扫描显示的小实验

时间:2020-04-02 15:06:59

相关推荐

【 FPGA 】控制数码管动态扫描显示的小实验

实验的功能很简单,就是让4个数码管每隔1s递增显示,使用动态扫描的方式来实现。

从这个功能的描述可以看出,我们首先要写一个计数器模块,来让计数值每隔1s增加1,暂时实现的是16进制的东西,从0到f,之后10到1f等等。

我们的实验平台的系统时钟是25MHz,不是25MHz的实验平台,可以通过PLL来分频或倍频得到25MHz的时钟。

其次,写一个模块来控制数码管的位选和段选。

实验平台的数码管是共阴极的,也就是片选端低电平有效。

还需要注意的一个问题是:

片选控制信号的刷新速度必须足够快才能避免闪烁感,但也不能太快,以免影响数码管的开关切换,最佳的工作频率为1000Hz左右。如果FPGA的时钟为50MHz,那么至少跑5*10^4个周期,也即50000个周期刷新一次才行,我们知道2^16=65536,2^15=32768。

当然,这里的时钟是25Mhz,所以我们需要计数大概25000个周期才能刷新一次。

上面的最佳工作频率是1000hz的说法是否权威呢?我不知道,但是实验证明能用。

先给出计数模块的Verilog描述:

///工程硬件平台: Xilinx Spartan 6 FPGA/module counter(input clk,//时钟信号,25MHzinput rst_n,//复位信号,低电平有效output reg[15:0] display_num//数码管显示数据,[15:12]--数码管千位,[11:8]--数码管百位,[7:4]--数码管十位,[3:0]--数码管个位);//-------------------------------------------------//1s定时产生逻辑reg[24:0] timer_cnt;//1s计数器,0-24999999//1s定时计数always @(posedge clk or negedge rst_n)if(!rst_n) timer_cnt <= 25'd0;else if(timer_cnt < 25'd24_999_999) timer_cnt <= timer_cnt+1'b1;else timer_cnt <= 25'd0;wire timer_1s_flag = (timer_cnt == 25'd24_999_999);//1s定时到标志位,高有效一个时钟周期//-------------------------------------------------//递增数据产生逻辑//显示数据每秒递增always @(posedge clk or negedge rst_n)if(!rst_n) display_num <= 16'd0;else if(timer_1s_flag) display_num <= display_num+1'b1;endmodule

再给出片选和段选控制的Verilog描述:

///工程硬件平台: Xilinx Spartan 6 FPGA/module seg7(input clk,//时钟信号,25MHzinput rst_n,//复位信号,低电平有效input[15:0] display_num,//数码管显示数据,[15:12]--数码管千位,[11:8]--数码管百位,[7:4]--数码管十位,[3:0]--数码管个位output reg[3:0] dtube_cs_n,//7段数码管位选信号output reg[7:0] dtube_data//7段数码管段选信号(包括小数点为8段));//-------------------------------------------------//参数定义//数码管显示 0~F 对应段选输出parameter NUM0 = 8'h3f,//c0,NUM1 = 8'h06,//f9,NUM2 = 8'h5b,//a4,NUM3 = 8'h4f,//b0,NUM4 = 8'h66,//99,NUM5 = 8'h6d,//92,NUM6 = 8'h7d,//82,NUM7 = 8'h07,//F8,NUM8 = 8'h7f,//80,NUM9 = 8'h6f,//90,NUMA = 8'h77,//88,NUMB = 8'h7c,//83,NUMC = 8'h39,//c6,NUMD = 8'h5e,//a1,NUME = 8'h79,//86,NUMF = 8'h71,//8e;NDOT= 8'h80;//小数点显示//数码管位选 0~3 对应输出parameterCSN= 4'b1111,CS0= 4'b1110,CS1= 4'b1101,CS2= 4'b1011,CS3= 4'b0111;parameter N = 17;//高两位控制片选,其他位用于分频//-------------------------------------------------//分时显示数据控制单元reg[3:0] current_display_num;//当前显示数据reg[N-1:0] div_cnt;//分时计数器//分时计数器always @(posedge clk or negedge rst_n)if(!rst_n) div_cnt <= 0;else div_cnt <= div_cnt+1'b1;//显示数据always @(posedge clk or negedge rst_n)if(!rst_n) current_display_num <= 4'h0;else begincase(div_cnt[N-1:N-2])2'b00: current_display_num <= display_num[3:0];2'b01: current_display_num <= display_num[7:4];2'b10: current_display_num <= display_num[11:8];2'b11: current_display_num <= display_num[15:12];default: ;endcaseend//段选数据译码always @(posedge clk or negedge rst_n)if(!rst_n) dtube_data <= NUM0;else begincase(current_display_num) 4'h0: dtube_data <= NUM0;4'h1: dtube_data <= NUM1;4'h2: dtube_data <= NUM2;4'h3: dtube_data <= NUM3;4'h4: dtube_data <= NUM4;4'h5: dtube_data <= NUM5;4'h6: dtube_data <= NUM6;4'h7: dtube_data <= NUM7;4'h8: dtube_data <= NUM8;4'h9: dtube_data <= NUM9;4'ha: dtube_data <= NUMA;4'hb: dtube_data <= NUMB;4'hc: dtube_data <= NUMC;4'hd: dtube_data <= NUMD;4'he: dtube_data <= NUME;4'hf: dtube_data <= NUMF;default: ;endcaseend//位选译码always @(posedge clk or negedge rst_n)if(!rst_n) dtube_cs_n <= CSN;else begincase(div_cnt[N-1:N-2])2'b00: dtube_cs_n <= CS0;2'b01: dtube_cs_n <= CS1;2'b10: dtube_cs_n <= CS2;2'b11: dtube_cs_n <= CS3;default: dtube_cs_n <= CSN;endcaseendendmodule

最后给出主模块,调用上述两个模块:

///工程硬件平台: Xilinx Spartan 6 FPGA///产生一个每秒递增的16bit数据以16进制方式显示在4位数码管上module sp6(input ext_clk_25m,//外部输入25MHz时钟信号input ext_rst_n,//外部输入复位信号,低电平有效output[3:0] dtube_cs_n,//7段数码管位选信号output[7:0] dtube_data//7段数码管段选信号(包括小数点为8段));//-------------------------------------//PLL例化wire clk_12m5;//PLL输出12.5MHz时钟wire clk_25m;//PLL输出25MHz时钟wire clk_50m;//PLL输出50MHz时钟wire clk_100m;//PLL输出100MHz时钟wire sys_rst_n;//PLL输出的locked信号,作为FPGA内部的复位信号,低电平复位,高电平正常工作pll_controller uut_pll_controller(// Clock in ports.CLK_IN1(ext_clk_25m),// IN// Clock out ports.CLK_OUT1(clk_12m5),// OUT.CLK_OUT2(clk_25m),// OUT.CLK_OUT3(clk_50m),// OUT.CLK_OUT4(clk_100m),// OUT// Status and control signals.RESET(~ext_rst_n),// IN.LOCKED(sys_rst_n));// OUT//-------------------------------------//25MHz时钟进行分频,产生每秒递增的16位数据wire[15:0] display_num;//数码管显示数据,[15:12]--数码管千位,[11:8]--数码管百位,[7:4]--数码管十位,[3:0]--数码管个位counteruut_counter(.clk(clk_25m),//时钟信号.rst_n(sys_rst_n),//复位信号,低电平有效.display_num(display_num)//LED指示灯接口);//-------------------------------------//4位数码管显示驱动seg7uut_seg7(.clk(clk_25m),//时钟信号.rst_n(sys_rst_n),//复位信号,低电平有效.display_num(display_num),//LED指示灯接口.dtube_cs_n(dtube_cs_n),//7段数码管位选信号.dtube_data(dtube_data)//7段数码管段选信号(包括小数点为8段));endmodule

里面用到了一个PLL的IP核,这里只是一个示例,由于本设计的实验平台的时钟频率本身就是25MHz,所以不用也行。

实验结果证明,很完美。

关于数码管,以前也写过两篇博文:

数码管显示实验(一)(初步明白片选、段选)

四位16进制的数码管动态显示设计

8段数码管译码表

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。