搜索
bottom↓
回复: 2

4x4键盘翻转扫描带消抖,4位数码管显示Verilog实现

[复制链接]

出0入0汤圆

发表于 2013-5-2 21:20:45 | 显示全部楼层 |阅读模式
本帖最后由 skyxjh 于 2013-5-2 21:32 编辑

刚学FPGA,基于红色飓风II开发板实现了4x4键盘翻转法扫描带消抖,4位数码管动态扫描显示,模块化设计,方便移植。

module ledbeepkeypad ( //顶层模块
        input clk, //时钟50MHz
        input rst, //复位信号,低电平复位
        inout [7:0] keypad, //4x4键盘行线[7:4]列线[3:0]
        output [7:0] ledd, //数码管段码数据接口
        output [3:0] ledc, //数码管位控制接口
        output beep, //蜂鸣器,高电平响,低电平停
        );
       
        reg [4:0] keycode = 5'h10; //当前按键编码,5'h0d表示编号为h0d的按键按下,5'h1x表示没有按键按下或非法按键组合
        reg [15:0] lednum = 16'h1234; //4位数码管显示数据BCD码
        reg [3:0] dotpoint = 4'b0000; //小数点,1表示对应位小数点显示
        reg [18:0] cnt = 19'd0; //19位记数器,用于时序控制
       
        always @ (posedge clk)         cnt = cnt + 1'b1; //记数器向上记数
        keypad4x4scan keypad1(.clk(cnt[18]),.keyp(keypad[7:0]),.keycode(keycode));  //4x4键盘扫描,时钟50M/(2^19)=95Hz
        keylogic keylogic1(.rst(rst),.clk(cnt[18]),.keycode(keycode),.beep(beep),.lednum(lednum),.dotpoint(dotpoint)); //按键处理逻辑
        led4disp disp1(.clk(cnt[16]),.lednum(lednum),.dotpoint(dotpoint),.ledd(ledd),.ledc(ledc));        //4位数码管显示,时钟50M/(2^17)=381Hz
       
endmodule

//////////////////////////////////////////////////////////////////
//keyp7        7                8                9                A      //
//keyp6        4                5                6                B      //
//keyp5        1                2                3                C      //
//keyp4        0                F                E                D      //
//                keyp3        keyp2        keyp1        keyp0    //
/////////////////////////////////////////////////////////////////
module keypad4x4scan ( //键盘扫描子模块
        input wire clk, //时钟>50Hz
        inout wire [7:0] keyp, //键盘行(外接上拉电阻)列输入
        output reg [4:0] keycode //按键编码
        );
       
        reg [7:0] keyc = 8'd0; //按键编码
        reg swap = 1'b0; //行列翻转扫描标志
       
        assign keyp = swap ? 8'h0z : 8'hz0; //swap为1时keyp[7:4]输出低电平,keyp[3:0]上拉输入;
                                                                                                        //swap为0时keyp[7:4]上拉输入,keyp[3:0]输出低电平;
        always @ (posedge clk)        begin
                case (swap)
                        1'b1: keyc[3:0] = keyp[3:0]; //swap为1时读取keyp[3:0]电平值
                        default: keyc[7:4] = keyp[7:4]; //swap为0时读取keyp[7:4]电平值
                endcase
                swap <= ~swap; //行列翻转
        end
       
        always @ (keyc) begin
                case (keyc) //按键编码
                        8'b1110_0111: keycode = 5'h0;
                        8'b1101_0111: keycode = 5'h1;
                        8'b1011_0111: keycode = 5'h4;
                        8'b0111_0111: keycode = 5'h7;
                        8'b1110_1011: keycode = 5'hf;
                        8'b1101_1011: keycode = 5'h2;
                        8'b1011_1011: keycode = 5'h5;
                        8'b0111_1011: keycode = 5'h8;
                        8'b1110_1101: keycode = 5'he;
                        8'b1101_1101: keycode = 5'h3;
                        8'b1011_1101: keycode = 5'h6;
                        8'b0111_1101: keycode = 5'h9;
                        8'b1110_1110: keycode = 5'hd;
                        8'b1101_1110: keycode = 5'hc;
                        8'b1011_1110: keycode = 5'hb;
                        8'b0111_1110: keycode = 5'ha;
                        default: keycode = 5'h10; //无按键按下或无效按键组合
                endcase
        end
       
endmodule


module keylogic( //按键处理子模块
        input wire rst, //低电平复位信号
        input wire clk, //时钟>50Hz
        input wire [4:0] keycode, //按键编码,5'h1x表示无按键按下或无效按键组合,5'h0x表示编号为x的按键按下
        output reg [15:0] lednum, //4位数码管显示数据
        output reg [3:0] dotpoint, //小数点驱动,1表示对应位显示小数点
        output reg beep //蜂鸣器驱动
        );
       
        reg keypressdone = 1'b1; //按键已处理标志,1表示已处理,0表示未处理
        reg [4:0] keycode1 = 5'h10; //上一次检测到的按键值,用于消抖
       
        always @ (posedge clk) begin
                if(rst) begin
                        if (keycode1 == keycode) begin //连续2次检测到的按键值相同,稳定
                                if (keycode[4]) begin //确认按键弹起
                                        beep = 1'b0; //按键弹起时蜂鸣器停
                                        keypressdone = 1'b1; //置按键已处理标志,准备处理下一次按键
                                        end
                                else if (keypressdone) begin //有按键按下,按键处理,只处理1次
                                        lednum = lednum << 4; //数码管前3位显示前3次按键值
                                        lednum[3:0] = keycode1[3:0]; //数码管第4位显示当前按键值
                                        dotpoint = 4'b0100; //小数点后2位数字
                                        beep = 1'b1; //按键按下时蜂鸣器响
                                        keypressdone = 1'b0; //按键未弹起之前按键已处理标志清零
                                        end
                                else ; //按键已处理
                                end
                        else ; //连续2次检测到的按键值不同(抖动)
                        end
                else begin //复位
                        lednum = 16'd0; //显示清零
                        dotpoint = 2'd0; //不显示小数点
                        beep = 1'b0; //蜂鸣器停
                        end
                keycode1 = keycode; //保存当前按键值
        end
               
endmodule


module led4disp(  //4位数码管显示子模块
        input wire clk, //时钟>240Hz
        input wire [15:0] lednum, //4数码管显示数字BCD码
        input wire [3:0] dotpoint, //小数点,1表示对应位小数点显示
        output reg [7:0] ledd, //数码管段码数据接口
        output reg [3:0] ledc //数码管位选接口
        );
       
        reg [4:0] ledmsk = 5'h0; //数码管驱动位图索引
        reg [1:0] ledbit = 2'd0; //数码管位扫描
       
        always @ (posedge clk) begin //动态扫描4位数码管显示,刷新频率>60Hz
                ledbit = ledbit + 1'b1; //位扫描
        end
       
        always @ (ledbit,lednum) begin
                case (ledbit) //数码管当前位段码
                        2'd3:         ledmsk[3:0] = lednum[15:12]; //第1位
                        2'd2:         ledmsk[3:0] = lednum[11:8]; //第2位
                        2'd1:         ledmsk[3:0] = lednum[7:4]; //第3位
                        default: ledmsk[3:0] = lednum[3:0]; //第4位
                endcase
        end
       
        assign ledc = 4'b1 << ledbit; //数码管位选择,阴极加NPN三极管反向控制,高电平位选
        assign ledd[7] = (dotpoint[3:0] & ledc[3:0]) ? 1'b1 : 1'b0; //小数点驱动
       
        always @ (ledmsk) begin
                case (ledmsk) //共阴极数码管段码数据输出
                        5'h0: ledd[6:0] = 7'b011_1111; //显示数字0
                        5'h1: ledd[6:0] = 7'b000_0110; //显示数字1
                        5'h2: ledd[6:0] = 7'b101_1011; //显示数字2
                        5'h3: ledd[6:0] = 7'b100_1111; //显示数字3
                        5'h4: ledd[6:0] = 7'b110_0110; //显示数字4
                        5'h5: ledd[6:0] = 7'b110_1101; //显示数字5
                        5'h6: ledd[6:0] = 7'b111_1101; //显示数字6
                        5'h7: ledd[6:0] = 7'b000_0111; //显示数字7
                        5'h8: ledd[6:0] = 7'b111_1111; //显示数字8
                        5'h9: ledd[6:0] = 7'b110_1111; //显示数字9
                        5'hA: ledd[6:0] = 7'b111_0111; //显示数字A
                        5'hB: ledd[6:0] = 7'b111_1100; //显示数字B
                        5'hC: ledd[6:0] = 7'b011_1001; //显示数字C
                        5'hD: ledd[6:0] = 7'b101_1110; //显示数字D
                        5'hE: ledd[6:0] = 7'b111_1001; //显示数字E
                        5'hF: ledd[6:0] = 7'b111_0001; //显示数字F
                        default: ledd[6:0] = 7'b000_0000; //不显示
                endcase
        end
               
endmodule

编辑说明:排版调整

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

 楼主| 发表于 2013-5-2 21:27:41 | 显示全部楼层
FPAG引脚内部上拉设置方法:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2013-5-2 22:12:42 | 显示全部楼层
上传工程文件:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-24 07:14

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表