基于FPGA的四位数码管显示按键计数器设计(verilog编程)

这篇具有很好参考价值的文章主要介绍了基于FPGA的四位数码管显示按键计数器设计(verilog编程)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

软件:Vivado 2022.2

硬件:BASYS 3

设计描述:通过开发板上的四个按键,按下一次记数加一,分别由四个数码管从左到右分别显示四个按键记数情况。

例:

1.初始值为0000,意为无记数

2.当按下第一个按键,记数加一,数码管显示1000

3.再次按下一第一个按键,记数加一,数码管显示2000

4.按下第二个按键9次,数码管显示2900,第二位记满

5.当再次按下第二个按键后,数码管显示2000

应用原理:

1.按键去抖动:

        通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时, 由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。因而在闭合及断开的瞬间均伴随有一连串的抖动 。抖动时间的长短由按键的机械特性决定,一般为5ms~20ms。这是一个 很重要的时间参数,在很多场合都要用到。按键稳定闭合时间的长短则是由操作人员的按键动作决定的,一般为零点几秒至数秒。键抖动会引起一次按键被误读多次。为确保对按键的一次闭合仅作一次处理,必须去除键抖动。        

基于FPGA的四位数码管显示按键计数器设计(verilog编程)

 

2.数码管显示:

        共阳极数码管 :

        共阳极数码管的8个发光二极管的阳极(二极管正端)连接在一起。通常,公共阳极接高电平(一般接电源),其它管脚接段驱动电路输出端。当某段驱动电路的输出端为低电平时,则该端所连接的字段导通并点亮。

        共阴极数码管:

        通常,公共阴极接低电平(一般接地),其它管脚接段驱动电路输出端。当某段驱动电路的输出端为高电平时,则该端所连接的字段导通并点亮。

基于FPGA的四位数码管显示按键计数器设计(verilog编程)

                                              

设计思路:

按键扫描消抖延时:

        BASYS 3开发板W5引脚的时钟为100MHZ,设计采用10ms的按键消抖,100MHz(0101_1111_0101_1110_0001_0000_0000)分频记数得100Hz(1111_0100_0010_0100_0000)

        即为10ms延时

数码管显示:

        BASYS 3 数码管的是共阳极,所以引脚输出为0时亮起。 按键记数每一位从0到9显示,记满9次归零。

                                               共阳极数码管显示(七位和八位)

共阳 七位(不包括小数点) 八位
0 1000000 11000000
1 1111001 11111001
2 0100100 10100100
3 0110000 10110000
4 0011001 10011001
5 0010010 10010010
6 0000010 10000010
7 1111000 11111000
8 0000000 10000000
9 0010000 10010000

代码示例:

按键消抖模块:

module delay(clk,key,key_delay);
   input clk;//100MHz
   input key;//按键输入
   output key_delay;//按键消抖判断输出
   reg key_delay;
   reg[19:0] cnt1;//10ms延时20位记数
    always@(posedge clk)//100Mhz
begin
if(key)   //假如按键按下,按键按下为高电平
begin
   if( cnt1==20'b1111_0100_0010_0100_0000 && key) //10ms
    key_delay<=1;   //延时后,如果key仍然为1,则key_delay输出1,确认按键按下
   else begin
   cnt1<= cnt1+1;key_delay<=0; //  否则输出0,
        end
end
else begin 
    cnt1<= 0 ; key_delay<= 0 ;  //当key不为1 时,计数器清零,输出0
     end
end
   
endmodule

记数模块:

module cnt_delay(key_delay,cnt);
    input key_delay;
    output reg [3:0]cnt;
    
    always@(posedge  key_delay )    //以按键作为时钟信号,实现计数
begin
    if(cnt==4'b1001)
         cnt<=0;
    else
         cnt<=cnt+1;
end
endmodule

主模块:

module but_delay_cnt_4(clk,key1,key2,key3,key4,dig,seg);
input clk;   //clk是Basys3板上时钟100 MHz
input  key1,key2,key3,key4;//按钮1,2,3,4
output dig;
output seg;
reg[3:0] dig;//位选数码管
reg[6:0] seg;//段选数码管
wire key4_delay,key1_delay,key2_delay,key3_delay;//按钮消抖按下输出
reg [19:0] cnt;//延时计数器,100MHz/3KHz,
reg [15:0] seg_count;//按键扫描计数器
reg clk_ttt;//数码管位选动态扫描频率,3KHz
reg [1:0]selcnt;//数码管位选标志位,0,1,2,3
reg [1:0]ain;//位选0123对应的段选标志位
wire [3:0]cnt1,cnt2,cnt3,cnt4;//段选转换标志位,0-9

//按键消抖,判断按键按下
delay U1(.clk(clk),.key(key1),.key_delay(key1_delay));    
delay U2(.clk(clk),.key(key2),.key_delay(key2_delay));      
delay U3(.clk(clk),.key(key3),.key_delay(key3_delay));
delay U4(.clk(clk),.key(key4),.key_delay(key4_delay));     


//判断按键上调变,即为按键按下,记数加一
cnt_delay K1(.key_delay(key1_delay),.cnt(cnt1));
cnt_delay K2(.key_delay(key2_delay),.cnt(cnt2));
cnt_delay K3(.key_delay(key3_delay),.cnt(cnt3));
cnt_delay K4(.key_delay(key4_delay),.cnt(cnt4));


 always @(posedge clk)  //100MHz
       begin
            seg_count <= seg_count + 1;
           if(seg_count==16'b1000_0010_0011_0101)//100MHz/33333Hz
           begin
                  seg_count <=0;//清零
              clk_ttt <= ~clk_ttt;//3KHz的动态扫描频率
           end
       end

always @(posedge clk_ttt)//位选标志位随3KHz频率从0-3轮换
 begin
   selcnt <= selcnt + 1;//标志位+1,11记满后加一回到00
 end

always @(selcnt)      //位选信号控制
begin
 case (selcnt)
  2'b00: begin dig <= 4'b0111;ain <= 2'b00;end //1号数码管显示ain对应的段码
  2'b01: begin dig <= 4'b1011;ain <= 2'b01;end
  2'b10: begin dig <= 4'b1101;ain <= 2'b10;end
  2'b11: begin dig <= 4'b1110;ain <= 2'b11;end
  default:   dig<=4'b1111;
 endcase
 end


always @(ain or cnt1 or cnt2 or cnt3 or cnt4)
begin
if (ain==2'b00)begin //1号数码管
  case({ain,cnt1})
    6'b000000:seg <= 7'b1000000;
    6'b000001:seg <= 7'b1111001;
    6'b000010:seg <= 7'b0100100;
    6'b000011:seg <= 7'b0110000;
    
    6'b000100:seg <= 7'b0011001;
    6'b000101:seg <= 7'b0010010;
    6'b000110:seg <= 7'b0000010;
    6'b000111:seg <= 7'b1111000;
    
    6'b001000:seg <= 7'b0000000;
    6'b001001:seg <= 7'b0010000;
   default :seg <= 7'b1100000;
  endcase 
  end
  
 if (ain==2'b01)begin  //2号数码管
  case({ain,cnt2})
    6'b010000:seg <= 7'b1000000;
    6'b010001:seg <= 7'b1111001;
    6'b010010:seg <= 7'b0100100;
    6'b010011:seg <= 7'b0110000;
    
    6'b010100:seg <= 7'b0011001;
    6'b010101:seg <= 7'b0010010;
    6'b010110:seg <= 7'b0000010;
    6'b010111:seg <= 7'b1111000;
    
    6'b011000:seg <= 7'b0000000;
    6'b011001:seg <= 7'b0010000;
   default :seg <= 7'b1010000;
  endcase 
 end
 
 if (ain==2'b10)begin //3号数码管
  case({ain,cnt3})
    6'b100000:seg <= 7'b1000000;
    6'b100001:seg <= 7'b1111001;
    6'b100010:seg <= 7'b0100100;
    6'b100011:seg <= 7'b0110000;
    
    6'b100100:seg <= 7'b0011001;
    6'b100101:seg <= 7'b0010010;
    6'b100110:seg <= 7'b0000010;
    6'b100111:seg <= 7'b1111000;
    
    6'b101000:seg <= 7'b0000000;
    6'b101001:seg <= 7'b0010000;
   default :seg <= 7'b1001000;
  endcase 
  end 
  
  if (ain==2'b11)begin //4号数码管
  case({ain,cnt4})
    6'b110000:seg <= 7'b1000000;
    6'b110001:seg <= 7'b1111001;
    6'b110010:seg <= 7'b0100100;
    6'b110011:seg <= 7'b0110000;
    
    6'b110100:seg <= 7'b0011001;
    6'b110101:seg <= 7'b0010010;
    6'b110110:seg <= 7'b0000010;
    6'b110111:seg <= 7'b1111000;
    
    6'b111000:seg <= 7'b0000000;
    6'b111001:seg <= 7'b0010000;
    default :seg <= 7'b1000000;
  endcase 
end
end

endmodule

创建工程:

调用四个按键消抖模块和四个记数模块

基于FPGA的四位数码管显示按键计数器设计(verilog编程)

 引脚定义:

 数码管位选

基于FPGA的四位数码管显示按键计数器设计(verilog编程)

数码管段选

基于FPGA的四位数码管显示按键计数器设计(verilog编程)

 100MHz输入,四个按键

基于FPGA的四位数码管显示按键计数器设计(verilog编程)

 

综合出的电路:基于FPGA的四位数码管显示按键计数器设计(verilog编程)

         可以看到八个我们调用的模块

设计障碍以及解决方法:

错误代码示例:

        这里与主模块的代码做一个比较,这个always模块下的思路是ain位选到数码管,然后通过cntx选择对应的段选,以为真正记数的时候是0-9,

        但cntx记数是0-15(1111),为了避cntx跳到10-15(1010-1111)非法范围,所以在case语句中加如default语句,使其归零

        但此处就会遇到一个综合问题,因为{ain,cntx}中的ain值在同一时间只有一种情况,但是cntx有cnt1,cnt2,cnt3,cnt4,不论四个一位计数器是否跳变,seg就会被四个case语句赋值,并由于“<="且是同时赋值。这里就会产生竞争。

always @(ain or cnt1 or cnt2 or cnt3 or cnt4)
begin
 //1号数码管
  case({ain,cnt1})
    6'b000000:seg <= 7'b1000000;
    6'b000001:seg <= 7'b1111001;
    6'b000010:seg <= 7'b0100100;
    6'b000011:seg <= 7'b0110000;
    
    6'b000100:seg <= 7'b0011001;
    6'b000101:seg <= 7'b0010010;
    6'b000110:seg <= 7'b0000010;
    6'b000111:seg <= 7'b1111000;
    
    6'b001000:seg <= 7'b0000000;
    6'b001001:seg <= 7'b0010000;
   default :seg <= 7'b1000000;
  endcase 

 //2号数码管
  case({ain,cnt2})
    6'b010000:seg <= 7'b1000000;
    6'b010001:seg <= 7'b1111001;
    6'b010010:seg <= 7'b0100100;
    6'b010011:seg <= 7'b0110000;
    
    6'b010100:seg <= 7'b0011001;
    6'b010101:seg <= 7'b0010010;
    6'b010110:seg <= 7'b0000010;
    6'b010111:seg <= 7'b1111000;
    
    6'b011000:seg <= 7'b0000000;
    6'b011001:seg <= 7'b0010000;
   default :seg <= 7'b1000000;
  endcase 

 
 //3号数码管
  case({ain,cnt3})
    6'b100000:seg <= 7'b1000000;
    6'b100001:seg <= 7'b1111001;
    6'b100010:seg <= 7'b0100100;
    6'b100011:seg <= 7'b0110000;
    
    6'b100100:seg <= 7'b0011001;
    6'b100101:seg <= 7'b0010010;
    6'b100110:seg <= 7'b0000010;
    6'b100111:seg <= 7'b1111000;
    
    6'b101000:seg <= 7'b0000000;
    6'b101001:seg <= 7'b0010000;
   default :seg <= 7'b1000000;
  endcase 

  
 //4号数码管
  case({ain,cnt4})
    6'b110000:seg <= 7'b1000000;
    6'b110001:seg <= 7'b1111001;
    6'b110010:seg <= 7'b0100100;
    6'b110011:seg <= 7'b0110000;
    
    6'b110100:seg <= 7'b0011001;
    6'b110101:seg <= 7'b0010010;
    6'b110110:seg <= 7'b0000010;
    6'b110111:seg <= 7'b1111000;
    
    6'b111000:seg <= 7'b0000000;
    6'b111001:seg <= 7'b0010000;
    default :seg <= 7'b1000000;
  endcase 
end

硬件综合故障演示:

基于FPGA的四位数码管显示按键计数器设计(verilog编程)

         可以看到,四个位数,只能综合处一个按键记数,另外三个key1,key2,key3,没有连接。

解决方法:

        所以我们需要判断,ain的情况,在同一时间,seg只由一个{ain,cntx}六位组合值case语句赋值。

故这里加了四个if判断ain约束进入哪个case语句。

always @(ain or cnt1 or cnt2 or cnt3 or cnt4)
begin
if (ain==2'b00)begin //1号数码管
  case({ain,cnt1})
    6'b000000:seg <= 7'b1000000;
    6'b000001:seg <= 7'b1111001;
    6'b000010:seg <= 7'b0100100;
    6'b000011:seg <= 7'b0110000;
    
    6'b000100:seg <= 7'b0011001;
    6'b000101:seg <= 7'b0010010;
    6'b000110:seg <= 7'b0000010;
    6'b000111:seg <= 7'b1111000;
    
    6'b001000:seg <= 7'b0000000;
    6'b001001:seg <= 7'b0010000;
   default :seg <= 7'b1000000;
  endcase 
  end
  
 if (ain==2'b01)begin  //2号数码管
  case({ain,cnt2})
    6'b010000:seg <= 7'b1000000;
    6'b010001:seg <= 7'b1111001;
    6'b010010:seg <= 7'b0100100;
    6'b010011:seg <= 7'b0110000;
    
    6'b010100:seg <= 7'b0011001;
    6'b010101:seg <= 7'b0010010;
    6'b010110:seg <= 7'b0000010;
    6'b010111:seg <= 7'b1111000;
    
    6'b011000:seg <= 7'b0000000;
    6'b011001:seg <= 7'b0010000;
   default :seg <= 7'b1000000;
  endcase 
 end
 
 if (ain==2'b10)begin //3号数码管
  case({ain,cnt3})
    6'b100000:seg <= 7'b1000000;
    6'b100001:seg <= 7'b1111001;
    6'b100010:seg <= 7'b0100100;
    6'b100011:seg <= 7'b0110000;
    
    6'b100100:seg <= 7'b0011001;
    6'b100101:seg <= 7'b0010010;
    6'b100110:seg <= 7'b0000010;
    6'b100111:seg <= 7'b1111000;
    
    6'b101000:seg <= 7'b0000000;
    6'b101001:seg <= 7'b0010000;
   default :seg <= 7'b1000000;
  endcase 
  end 
  
  if (ain==2'b11)begin //4号数码管
  case({ain,cnt4})
    6'b110000:seg <= 7'b1000000;
    6'b110001:seg <= 7'b1111001;
    6'b110010:seg <= 7'b0100100;
    6'b110011:seg <= 7'b0110000;
    
    6'b110100:seg <= 7'b0011001;
    6'b110101:seg <= 7'b0010010;
    6'b110110:seg <= 7'b0000010;
    6'b110111:seg <= 7'b1111000;
    
    6'b111000:seg <= 7'b0000000;
    6'b111001:seg <= 7'b0010000;
    default :seg <= 7'b1000000;
  endcase 
end
end

设计总结:

        BASYS 3开发板设计的四位记数器可以实现从0到9999的数字计数功能。这种设计可以在许多数字电路应用中使用,例如测量仪器、时钟和闹钟等。

        这里只采用了四个一位记数,后期可以改成多位记数,但是掌握了一位记数,就可以

        通过设计这个计数器,我获得了以下收获:

  1. 深入了解数字电路的工作原理和设计方法。
  2. 掌握计数器的原理和实现方式,以及如何将其集成到更大的数字系统中。
  3. 学习如何使用Verilog硬件描述语言来编写数字电路设计。
  4. 加强了对硬件设计工具(Vivado)的运用能力。

        总之,BASYS 3开发板设计的四位记数器是一项有意义的项目,它帮助我进一步深化对数字电路设计的理解,并提高我的技能水平。文章来源地址https://www.toymoban.com/news/detail-476923.html

到了这里,关于基于FPGA的四位数码管显示按键计数器设计(verilog编程)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Arduino UNO驱动TM1637四位时钟数码管显示时间

    TM1637 是一种带键盘扫描接口的LED(发光二极管显示器)驱动控制专用电路,内部集成有MCU 数字接口、数据锁存器、LED 高压驱动、键盘扫描等电路。  显示模式(8 段×6 位),支持共阳数码管输出  键扫描(8×2bit),增强型抗干扰按键识别电路  辉度调节电路(占空比

    2024年02月12日
    浏览(42)
  • 基于FPGA的超声波测距——数码管显示

    环境: 1、Quartus18.1 2、vscode 3、板子型号:EP4CE6F17C8N 4、超声波模块:HC_SR04 要求: 使用 EP4CE6F17C8开发板驱动 超声波检测模块(HC_SR04 ),并将所测得数据显示到开发板上的数码管上 HC-SR04超声波测距模块可提供2cm-400cm的非接触式距离感测功能,测距精度可达高到3mm;模块包括超

    2024年02月06日
    浏览(37)
  • Arduino:实现四位LED共阴极数码管显示——从认识、连接、程序到实现功能

    (1)一位八段共阴极数码管        在认识四位共阴极数码管之前我先介绍一下一位八段共阴极数码管。如左图所示为以为数码管的实物图,其中它共有10个引脚,且上下各五个。 小数点位于右下时为数码管正面 ,在四位共阴极数码管中也是如此,在连接组装时尤为重要。

    2024年02月02日
    浏览(48)
  • 【51单片机】矩阵按键实现数码管显示

    闲的没事看一看玩一玩········· 矩阵按键 数码管是一种导体发光器件,其基本单元是发光二极管。按发光二极管单元连接方式可分为共阳极数码管和共阴极数码管 共阴极数码管是指将所有发光二极管的阴极接到一起形成共阴极的数码管,共阴极的数码管在应用时将公共

    2024年02月02日
    浏览(57)
  • 51单片机按键控制数码管显示0-9

    实验题目:使用51单片机设计两个按键控制数码管显示0-9,当K1按下减1,当K2按下加1. 理解程序可参考我的另外两个文章; 51单片机数码管显示0-9_学习笔记吧的博客-CSDN博客 51单片机独立按键控制合集_学习笔记吧的博客-CSDN博客 两个文章一结合就是一个新的产物,所以51单片机

    2024年02月11日
    浏览(52)
  • 实验五 键盘按键与数码管显示(汇编与微机原理)

    实验目的: 熟悉星研集成开发环境,掌握微机接口程序编写调试的基本方法。 掌握矩阵式键盘的工作原理及识别键盘按键的方法。 掌握8段数码管显示数字或字符的工作原理和它的使用方法。 掌握用8255扫描键盘及用8255刷新数码管显示的方法。 实验:       在(2行*8列)小

    2024年02月04日
    浏览(46)
  • 【汇编语言与微机原理】实验五:键盘按键与数码管显示

    熟悉星研集成开发环境,掌握微机接口程序编写调试的基本方法。 掌握矩阵式键盘工作原理及识别按键的方法。 掌握8段数码管显示数字或字符的工作原理和它的使用方法。 掌握用8255扫描键盘及用8255刷新数码管的显示方法。 在2*8(看 着像4*4,实际上是2*8 )的小键盘上按下

    2024年02月16日
    浏览(41)
  • 51单片机“独立按键”控制静态数码管———显示数字0-9

    (1).独立按键模块电路图可以清楚的看到,所有从引脚JP1出来的电流都会接到GND,且当所有按键按下时被执行链接GND。所以,当JP1引脚各端口----识别----到“电流为低电平为0时”,说明按键被按下,否则为高电平按键没有被按下。 ( 2).按键的原理其是需要我们单片机有检

    2024年02月11日
    浏览(45)
  • 单片机学习-使用矩阵按键来显示数码管0-F

    1、行列扫码 //数码管字摸 u8 gsmg_code[17] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,                         0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};      //共阴 显示0-F 2、线翻转扫描

    2024年02月04日
    浏览(61)
  • FPGA_数码管显示

    一位数码管: 数码管等效电路(共阴极 和 共阳极) 数码管显示的值: 假设我们需要b,c亮,我们只需要给b,c接高电平,其他接低电平就可。 seg[7:0]  = 8\\\'b0000_0110 对于数码管显示的值,seg值如下图: 多位数码管-----如下图(以3位为例) 假设现在需要LED1亮,那么就让sel0为1,

    2024年01月23日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包