ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

基于FPGA的按键计数(通过按键实现对FPGA板子的数码管显示数进行控制)

2021-09-22 17:01:12  阅读:287  来源: 互联网

标签:FPGA clk bcd 数码管 add key 按键 rst data


​1.项目要求:数码管显示范围为0~999 999,当数码管显示999 999,若此时按下加的按键,则数码管显示数清零,若数码管显示为0 ,若按下减的按键时,数码管为999 999

2.编写分频计数模块,用1KHz(系统时钟为5Mhz)作为驱动时钟。将分频出来的时钟输出给key_jitter模块

点击此处添加图片说明文字

代码如下:(仿真时可以把T设小一点,不然跑不完)

module freq(         //系统时钟是50M,产生一个1KHZ的慢时钟
    input clk,
    input rst_n,
    output reg clk_1KHz
);
parameter T = 50000;   //50000 仿真时要选一个小一点的值
reg [19:0] counter;

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        begin
            counter <= 0;
            clk_1KHz <= 1;
        end 
    else
        begin
            if(counter < (T/2-1))
                counter <= counter+1;
            else
                begin
                    counter <= 0;
                    clk_1KHz <= ~clk_1KHz;
                end
        end
    
end
endmodule
//系统时钟是50M,产生一个1KHZ的慢时钟

3.按键消抖模块,并将加/减的信号传输给数据处理模块

点击此处添加图片说明文字

点击此处添加图片说明文字

点击此处添加图片说明文字

代码如下


module key_jitter(      //按键消抖
    input clk,
    input rst_n,
    input key_add,     //表示加的按键
    input key_sub,     //表示减的按键
    
    output reg pos_add_flag,       //当加的按键按下之后,该标志位为1
    output reg pos_sub_flag        //当减的按键按下之后,该标志位为1
    
 //   output reg [3:0] flag_sub,       //记录减按键按下的次数
 //   output reg [3:0] flag_add        //记录加按键按下的次数
);
reg [10:0] counter1;       //加按下计数寄存器
reg [10:0] counter2;       //减按下计数寄存器
//reg pos_add_flag;         //按键按下成功标志位
//reg pos_sub_flag;         //按键按下成功标志位


reg [3:0] sum_sub;       //记录减按键按下的次数
reg [3:0] sum_add;  
  
  
reg state1;             //状态寄存器
reg state2;     
always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)          //复位时,参数置0
        begin
            counter1 <= 11'b0;
            counter2 <= 11'b0;
            pos_add_flag <= 0;
            pos_sub_flag <= 0;
            sum_sub <= 0;
            sum_add <= 0;
            state1 <= 0;
            state2 <= 0;
        end
    else
        begin
            case(state1)
            0:begin         //当为起始状态时 先判断按键按下的状态计数是否超过10
                if(counter1<10)
                    begin
                        if(!key_add)
                            counter1 <= counter1 + 1;
                        else
                            counter1 <= 11'b0;  //如果按键没有按下,则清零  
                    end
                else
                    begin        //当按键按下的状态计数超过10,说明按键已经按下
                        pos_add_flag <= 1;  //尖峰脉冲到达
                        sum_add <= sum_add + 1;
                        counter1 <= 11'b0; 
                        state1 <= 1;
                    end
               end 
            1: begin
                 pos_add_flag <= 0;
                 if(key_add)
                    state1 <= 0;
               end
            default: state1 <= 0;
            endcase
            
            
            case(state2)
            0:begin         //当为起始状态时 先判断按键按下的状态计数是否超过10
                if(counter2<10)
                    begin
                        if(!key_sub)
                            counter2 <= counter2 + 1;
                        else
                            counter2 <= 11'b0;  //如果按键没有按下,则清零  
                    end
                else
                    begin        //当按键按下的状态计数超过10,说明按键已经按下
                        pos_sub_flag <= 1;  //尖峰脉冲到达
                        sum_sub <= sum_sub + 1;
                        counter2 <= 11'b0; 
                        state2 <= 1;
                    end
               end 
            1: begin
                 pos_sub_flag <= 0;
                 if(key_sub)
                    state2 <= 0;
               end
            default: state2 <= 0;
            endcase
        end 
    
end
endmodule

4. data_ctrl用于实现数据处理功能,当加按下时,显示的数字加一,当减时,显示的数字减一

点击此处添加图片说明文字

module data_ctrl(      //用于实现数据处理功能,当加按下时,显示的数字加一,当减时,显示的数字减一
    input clk,
    input rst_n,
//    input flag_add,
 //   input flag_sub,
    input pos_add_flag,
    input pos_sub_flag,
    output reg[19:0] data
 //   input  data_en   //数据使能信号
    
);

reg [19:0] data_temp;   //数据暂存器
always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        begin
            data_temp <= 19'd0;
            data <= 19'd0;
           
        end
    else
        begin
          //  if (data_en)
           //     begin
                    if(pos_add_flag)        //当加按键按下时
                        begin
                            if(data_temp == 19'd999999)   //如果加按键按下后,但之前的数据已经是999999了,就要清零
                                data_temp <= 0;
                            else
                                data_temp <= data_temp + 1;  //否则就加一
                              //  data <= data_temp;
                        end
                    if(pos_sub_flag)
                        begin
                            if(data_temp == 0)  //如果减按键按下后,但之前的数据已经是0了,就要变为999999
                                data_temp <= 999999;
                            else       
                                data_temp <= data_temp - 1;  //否则就减一
                        end
                    data <= data_temp;
            //    end
        end
    
end

endmodule

5.实现二进制转化为BCD码的功能

点击此处添加图片说明文字

点击此处添加图片说明文字

代码如下

module bin_bcd(      //实现二进制转化为BCD码的功能
    input clk,
    input rst_n,
    input  [19:0] data,   //因为数码管能显示的数最大为999999,故该为20位
 //   output reg data_en,   //数据使能信号
    output reg [23:0] bcd_out      //6位数的bcd输出(因为最大的十进制数为6位,每一位需要4位表示bcd,所以需要24位)
);

reg [43:0] bcd_out_r;   //bcd转换码移位寄存器
reg [1:0] state3;   //状态寄存器
reg [5:0] shift_cnt;  //移位计数器 
//reg  data1 =1;

//assign data_en = data1;

/*always @(*)
begin
    data1 <= data;
end*/
always @(posedge clk or negedge rst_n)
begin
   
    if(!rst_n)
        begin
            bcd_out_r <= 0;
            state3 <= 0;
            shift_cnt <= 0;
            bcd_out <= 0;
         //   data_en = 1;
         //   data_en = data1;
        end
    else
        begin
            case(state3)
                2'd0:begin   //刚开始时,将数据赋值给bcd码的移位寄存器
                         bcd_out_r <= {24'b0,data};
                         state3 <= state3 + 1;
                         shift_cnt <= 0;
                     //    data_en = 0;
                     end 
                2'd1:begin   //移位
                         if(shift_cnt < 20)  //如果移位次数小于数据长度的话,就将bcd码进行移位
                            begin
                                bcd_out_r <= bcd_out_r << 1;
                                shift_cnt <= shift_cnt + 1;
                                state3 <= state3 + 1;
                            end
                         else
                            begin
                                state3 <= 0;
                                shift_cnt <= 0;
                            end
                     end 
          /*      2'd2:begin
                        bcd_out_r <= {bcd_out_r[],data[19:0],1'b0};
                     end */
                     2'd2:begin      //移位之后就进行大四加   *****是对BCD码进行大四加三,不能所有进行大四加三
                         if(bcd_out_r[43:40] > 4)
                            bcd_out_r[43:40] <= bcd_out_r[43:40] + 3;
                         if(bcd_out_r[39:36] > 4)
                            bcd_out_r[39:36] <= bcd_out_r[39:36] + 3;
                         if(bcd_out_r[35:32] > 4)
                            bcd_out_r[35:32] <= bcd_out_r[35:32] + 3;
                         if(bcd_out_r[31:28] > 4)
                            bcd_out_r[31:28] <= bcd_out_r[31:28] + 3;
                         if(bcd_out_r[27:24] > 4)
                            bcd_out_r[27:24] <= bcd_out_r[27:24] + 3;
                         if(bcd_out_r[23:20] > 4)
                            bcd_out_r[23:20] <= bcd_out_r[23:20] + 3;
                       /*  if(bcd_out_r[19:16] > 4)
                            bcd_out_r[19:16] <= bcd_out_r[19:16] + 3;
                         if(bcd_out_r[15:12] > 4)
                            bcd_out_r[15:12] <= bcd_out_r[15:12] + 3;
                         if(bcd_out_r[11:8] > 4)
                            bcd_out_r[11:8] <= bcd_out_r[11:8] + 3; 
                         if(bcd_out_r[7:4] > 4)
                            bcd_out_r[7:4] <= bcd_out_r[7:4] + 3; 
                         if(bcd_out_r[3:0] > 4)
                            bcd_out_r[3:0] <= bcd_out_r[3:0] + 3;*/
                         
                        
                         state3 <= 3;    
                     end
                2'd3:begin
                        state3 <= 1;    //继续进行移位,直到把数据全部移位
                     end 
                default : state3 <= 0;
            endcase
            bcd_out = (state3 == 3) && (shift_cnt == 20) ? bcd_out_r[43:20] : bcd_out; //如果移位和比较都完成之后就把值给输出
         //   data_en = (state3 == 3) && (shift_cnt == 20) ? 1 : 0;
      end 
end 
endmodule

6.实现数码管的译码

点击此处添加图片说明文字

点击此处添加图片说明文字

代码如下:

module seg_driver(  //实现数码管的译码
    input clk,
    input rst_n,
    input [23:0] bcd_out,         //输入的数据
    output reg[7:0] seg,     //数码管段选信号
    output reg[5:0] sel     //数码管位选信号
);
reg [3:0] data_temp;          //数码管显示的数值,因为一个数码管显示的最大数为9,就需要4位
reg [2:0] state4;         //状态寄存器

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        begin
            sel <= 0;
            data_temp <= 0;
            state4 <= 0;
      //      data <= 24'h234567;
        end
    else
    begin
        case (state4)
            0:begin
                sel <= 0;     //将最高位显示在第一个数码管上
                data_temp <= bcd_out[23:20];
                state4 <= 1;
              end
            1:begin
                sel <= 1;     //将最高位显示在第二个数码管上
                data_temp <= bcd_out[19:16];
                state4 <= 2;
              end
            2:begin
                sel <= 2;     //将最高位显示在第3个数码管上
                data_temp <= bcd_out[15:12];
                state4 <= 3;
              end
            3:begin
                sel <= 3;     //将最高位显示在第4个数码管上
                data_temp <= bcd_out[11:8];
                state4 <= 4;
              end
            4:begin
                sel <= 4;     //将最高位显示在第5个数码管上
                data_temp <= bcd_out[7:4];
                state4 <= 5;
              end
            5:begin
                sel <= 5;     //将最高位显示在第6个数码管上
                data_temp <= bcd_out[3:0];
                state4 <= 0;
              end
            default : state4 <= 0;
        endcase
    end 
end 

always @(*)
begin
    if(!rst_n)
        begin
            seg = 8'b0000_0000;  //复位时数码管熄灭
        end
    else
        begin
            case(data_temp)
                0:seg =8'b1100_0000;    //数码管显示0
                1:seg =8'b1111_1001;
                2:seg =8'b1010_0100;
                3:seg =8'b1011_0000;
                4:seg =8'b1001_1001;
                5:seg =8'b1001_0010;
                6:seg =8'b1000_0010;
                7:seg =8'b1111_1000;
                8:seg =8'b1000_0000;
                9:seg =8'b1001_0000;
                10:seg =8'b1000_1000;
                11:seg =8'b1000_0011;
                12:seg =8'b1100_0110;
                13:seg =8'b1010_0001;
                14:seg =8'b1000_1110;
                15:seg =8'b1000_1110;   数码管显示F
            
                default : seg = 8'b1111_1111; 
            endcase
        end
    
end

endmodule

7.顶层模块

点击此处添加图片说明文字

代码如下:

module key_seg(   //顶层模块
    input clk,
    input rst_n,
    input key_add,     //表示加的按键
    input key_sub, 
  //  input [23:0] data,
    output [7:0] seg,     //数码管段选信号
    output [5:0] sel 
);


wire clk_1KHz;
wire [19:0] data;
wire [23:0] bcd_out;

freq freq(
    .clk(clk),
    .rst_n(rst_n),
    .clk_1KHz(clk_1KHz)
);
key_jitter key_jitter(
    .clk(clk_1KHz),
    .rst_n(rst_n),
    .key_add(key_add),
    .key_sub(key_sub),
    .pos_sub_flag(pos_sub_flag),
    .pos_add_flag(pos_add_flag)
);

data_ctrl data_ctrl(
    .clk(clk_1KHz),
    .rst_n(rst_n),
    .data(data),
    .pos_sub_flag(pos_sub_flag),
   // .data_en(data_en),
    .pos_add_flag(pos_add_flag)
);


bin_bcd bin_bcd(
    .clk(clk_1KHz),
    .rst_n(rst_n),
    .data(data),
 //   .data_en(data_en),
    .bcd_out(bcd_out)
);


seg_driver seg_driver(
    .clk(clk_1KHz),
    .rst_n(rst_n),
    .bcd_out(bcd_out),
    .seg(seg),
    .sel(sel)
);



endmodule

7.测试文件及仿真图:

点击此处添加图片说明文字

代码如下:

`timescale 1 ns/ 1 ns
module key_seg_tb();
parameter T = 20;
/********************系统输入**********************/
reg clk;
reg rst_n;                                           
reg   key_add;
reg   key_sub;
/*********************系统输出*****************/
wire [7:0]  seg;
wire [5:0]  sel;

wire [19:0] data;                    
wire [23:0] bcd_out;
wire data_en;
initial 
begin                                                  
    clk = 1'b1;
	rst_n = 1'b0;  
    key_add = 1;
    key_sub = 1;
	#1000 rst_n = 1'b1;
    #10000000 key_add = 0;
    #10000000 key_add = 1;
 /*   #100000000000000 key_add = 0;
    #100000000000000 key_add = 1;
    #100000000000000 key_sub = 0;
    #100000000000000 key_sub = 1;
    #10000000 key_add = 0;
    #10000000 key_add = 1;
    #10000000 key_add = 0;
    #10000000 key_add = 1;
    #10000000 key_add = 0;
    #10000000 key_add = 1;*/
    $stop;  	                 
end                                                                                                 
always #(T/2)  clk = ~clk;     
freq freq(
    .clk(clk),
    .rst_n(rst_n),
    .clk_1KHz(clk_1KHz)
);
key_jitter key_jitter(
    .clk(clk_1KHz),
    .rst_n(rst_n),
    .key_add(key_add),
    .key_sub(key_sub),
    .pos_sub_flag(pos_sub_flag),
    .pos_add_flag(pos_add_flag)
);

data_ctrl data_ctrl(
    .clk(clk_1KHz),
    .rst_n(rst_n),
    .data(data),
    .pos_sub_flag(pos_sub_flag),
 //   .data_en(data_en),
    .pos_add_flag(pos_add_flag)
);


bin_bcd bin_bcd(
    .clk(clk_1KHz),
    .rst_n(rst_n),
    .data(data),
 //   .data_en(data_en),
    .bcd_out(bcd_out)
);


seg_driver seg_driver(
    .clk(clk_1KHz),
    .rst_n(rst_n),
    .bcd_out(bcd_out),
    .seg(seg),
    .sel(sel)
);
key_seg key_seg(

	.rst_n(rst_n),
    .clk(clk),
    .key_add(key_add),
    .seg(seg),
    .sel(sel),
    .key_sub(key_sub)
);                              
endmodule


仿真图:

点击此处添加图片说明文字

ps:

1)各个模块之间的连线一定要在顶层文件和testbench文件定义申明wire类型,因为input默认是wire类型,而大多数output是reg类型,连接的起来相当于是一根线,即要定义为wire类型,还要标明宽度,因为默认好像是2,如果不定义就不能接受宽度大的数据了。比如:我这里就是data_ctrol可以输出data,但是bin_bcd 里面就接收不了,如下图:

点击此处添加图片说明文字

2)在转化为bcd码时,本来想的是在移位完成和比较完成之后就可以把值给输出,但是看程序可以看出,在当移位完成之后,还没有比较完成时就已经把值给输出了,所以会出错。

点击此处添加图片说明文字

标签:FPGA,clk,bcd,数码管,add,key,按键,rst,data
来源: https://blog.csdn.net/qq_43811597/article/details/120418032

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有