FPGA|CPLD|ASIC论坛
直播中

uuyuanuu

9年用户 47经验值
擅长:可编程逻辑 EDA/IC设计
私信 关注
[资料]

【AC620试用贴】+数字密码锁

  在上一个试用贴中,测试了附赠的AC620中的矩阵按键,本试用贴以此为基础实现一款数字密码锁。用矩阵键盘输入密码,输入完成后进行密码比对,如密码输入正确则输出开门信号以及灯光指示,如密码输入错误则蜂鸣器进行报警以及灯光指示。综合以上要求可以看出此处系统框图如图1所示。源代码在附件中给出
1.png

                              图1 系统框图

其中各模块功能描述如表1所示。
  
模块名称
  
  
功能简述
  
  Key_Board
  
  矩阵按键输入控制
  
  Mima_detect
  
  密码检测
  
  HEX8
  
  数码管驱动显示
  
  HC595_Driver
  
  74HC595串行移位寄存器驱动模块
  
  contrl
  
  逻辑控制
  
表1 各模块功能描述
矩阵按键模块
现在分开介绍,矩阵按键输入控制模块的框图及其接口列表如下所示,详细内容可以参考芯航线关于矩阵按键的教程,此处不再详述。
2.1.png


图2 矩阵按键模块框图
  
信号名称
  
  
I/O
  
  
功能描述
  
  Clk
  
  I
  
  模块时钟,50MHz
  
  Rst_n
  
  I
  
  模块复位,低电平有效
  
  Key_Board_row_i
  
  I
  
  矩阵按键行输入信号
  
  Key_Flag
  
  O
  
  按键按下标志信号
  
  Key_Value
  
  O
  
  按键值
  
  Key_Board_col_o
  
  O
  
  矩阵按键输出列信号
  
表2 矩阵按键模块接口列表
密码比较模块:
现介绍密码检测模块,其主要功能即比较输入与预设的密码是否一致,
4.png

图2 密码检测模块框图
  信号名称
  
  I/O
  
  功能描述
  
  Clk
  
  I
  
  模块时钟,50MHz
  
  Rst_n
  
  I
  
  模块复位,低电平有效
  
  Key_falg
  
  I
  
  按键按下标志信号
  
  Key_value
  
  I
  
  按键值
  
  start_bj
  
  I
  
  开始比较
  
  error
  
  O
  
  密码错误
  
  Mima_r
  
  O
  
  实际输入的密码
  
  Right
  
  O
  
  密码正确
  
表2 密码检测模块列表
这里先将密码设置为4位十进制数1234,如下所示
  
parameter PASSWORD = 16'b0001_0010_0011_0100;
  
通过计数矩阵按键按下标志信号,依次将数据暂存到寄存器mima_r中。
  
     always@(posedge Clk or negedge Rst_n) begin
  
     if(!Rst_n)
  
         key_cnt <= 2'b0;
  
     else if(key_flag) begin
  
         if(key_cnt == 2'd3)
  
            key_cnt <= 2'b0;
  
         else
  
            key_cnt <= key_cnt + 1'b1;
  
     end
  
     else
  
         key_cnt <= key_cnt;
  
     end
  
  
     always@(posedge Clk or negedge Rst_n) begin
  
     if(!Rst_n)
  
         mima_r <= 16'b0;
  
     else if(key_flag)
  
         case(key_cnt)
  
            2'd0: mima_r[15:12] <= key_value[3:0];
  
            2'd1: mima_r[11:8]  <= key_value[3:0];
  
            2'd2: mima_r[7:4]    <= key_value[3:0];
  
            2'd3:    mima_r[3:0]    <= key_value[3:0];     
  
            default: mima_r <= 0;   
  
         endcase
  
     else
  
         mima_r <= mima_r;   
  
     end
  

这里通过一个独立按键来控制比较信号,用到了按键消抖模块,详细内容可以参考芯航线有关章节。
  
     wire key_startbj_flag;wire key_startbj_state;
  
  
     key_filter key_filter_start(
  
         .Clk(Clk),
  
         .Rst_n(Rst_n),
  
         .key_in(start_bj),
  
         .key_flag(key_startbj_flag),
  
         .key_state(key_startbj_state)
  
         );
  

当开始比较后,根据实际情况判断后输出正确与否。
  
     always@(posedge Clk or negedge Rst_n)begin
  
         if(!Rst_n) begin
  
            error <= 1'b0;
  
            right   <= 1'b0;
  
         end
  
         else if(key_startbj_flag && !key_startbj_state)begin  
  
            if(mima_r == PASSWORD) begin
  
                right <= 1'b1;
  
                error <= 1'b0;
  
            end
  
            else begin  
  
                right   <= 1'b0;
  
                error <= 1'b1;
  
            end
  
         end
  
         else begin
  
            error <= 1'b0;
  
            right   <= 1'b0;
  
         end
  
     end
  

控制模块:
现在介绍模块的控制单元。本模块主要功能是根据密码检测模块的输出确定,开关门信号以及声光信号。其模块接口列表及功能描述如下所示。
5.png


图3 控制模块框图
  
信号名称
  
  
I/O
  
  
功能描述
  
  Clk
  
  I
  
  模块时钟,50MHz
  
  Rst_n
  
  I
  
  模块复位,低电平有效
  
  Error
  
  I
  
  密码错误输入信号
  
  Right
  
  I
  
  密码正确输入信号
  
  Door_open
  
  O
  
  开门信号
  
  Led_right
  
  O
  
  密码正确灯光信号
  
  Beep_alarm
  
  O
  
  密码错误报警信号
  
  Led_alarm
  
  O
  
  密码错误灯光信号
  
表3 控制模块接口列表

在这里使用三段式状态机进行描述。
  
     parameter    IDLE  = 3'b001,
  
                    PASS  = 3'b010,
  
                    ALARM = 3'b100;
  

第一个always块:
  
     always@(posedge Clk or negedge Rst_n) begin
  
         if(!Rst_n)
  
            current_state <= IDLE;
  
         else
  
            current_state <= next_state;
  
     end
  
  
第二个always块:
  
     always@(current_state or error or right or cnt_2s) begin
  
         case(current_state)            
  
            IDLE: begin
  
                if(right)
  
                    next_state = PASS;
  
                else if(error)
  
                    next_state = ALARM;
  
                else
  
                    next_state = IDLE;      
  
            end            
  
            PASS: begin            
  
                if(cnt_2s) //door_close
  
                    next_state = IDLE;
  
                else
  
                    next_state = PASS;      
  
            end
  
            ALARM: begin
  
                if(cnt_2s)  
  
                    next_state = IDLE;
  
                else
  
                    next_state = ALARM;
  
            end            
  
            default: next_state = IDLE;            
  
         endcase
  
     end
  

第三个always块:
  
     always@(posedge Clk or negedge Rst_n) begin
  
         if(!Rst_n) begin
  
            door_open_r  <= 1'b0;   led_alarm_r  <= 1'b0;
  
            led_right_r  <= 1'b0;   beep_En <= 1'b0;            
  
         end
  
         else begin
  
            case(next_state)
  
                IDLE: begin
  
                    door_open_r  <= 1'b0; led_alarm_r  <= 1'b0;
  
                    led_right_r  <= 1'b0; beep_En <= 1'b0;                    
  
                end
  
                PASS: begin
  
                    if(cnt_2s)begin
  
                        door_open_r  <= 1'b0; led_alarm_r  <= 1'b0;
  
                        beep_En <= 1'b0;      led_right_r  <= 1'b0;
  
                    end
  
                    else begin           
  
                        door_open_r = 1'b1;led_right_r = 1'b1;
  
                    end
  
                end
  
                ALARM: begin
  
                    if(cnt_2s) begin
  
                        led_alarm_r = 1'b0; beep_En = 1'b0;
  
                    end
  
                    else begin
  
                        led_alarm_r = 1'b1;   beep_En = 1'b1;
  
                    end
  
                end
  
                default:     begin           
  
                    door_open_r  <= door_open_r;                     led_alarm_r  <= led_alarm_r;
  
                    beep_En <= beep_En;
  
                    led_right_r  <= led_right_r;
  
                end
  
            endcase
  
         end
  
     end
  

数码管显示模块:
Hex8为数码管显示模块,其框图以及其接口列表如下所示,具体功能介绍可参见芯航线相关内容。
6.png


图4 数码管显示模块框图
  
信号名称
  
  
功能描述
  
  
Clk
  
  
50M时钟
  
  
Rst_n
  
  
复位信号
  
  
En
  
  
数码管使能信号1使能,0关闭
  
  
disp_data[31:0]
  
  
8个数码管待显示数据,每四位组成一个BCD码
  
  
sel[7:0]
  
  
数码管位选,选择当前要显示的数码管
  
  
seg[6:0]
  
  
数码管段选,当前要显示的内容
  
表4 数码管显示模块接口列表
74HC595串行移位寄存器驱动模块:
74HC595串行移位寄存器驱动模块主要实现将数码管的段选和位选数据转换为串行数据并移入74HC595芯片中,然后由74HC595转化为并行数据,用以驱动7端8位数码管。该部分内容在《FPGA自学笔记——设计与验证》一书第3章3.9小节有介绍,本文不再赘述。
顶层设计:
最后在顶层例化各模块即可,分配引脚后全编译无误后即可下载到AC620开发板中,按照文中所述的功能按键依次输入,即可观测到对应现象,如本文开篇所示图。下图为本工程经过Quartus II软件综合后得到的顶层RTL视图。
7.png


图5 顶层文件RTLViewer

  • 3.png
  • 3.png
  • 4.png

回帖(2)

gslscyh

2017-11-16 18:15:04
hao!!!!!!!!!!!!!!!!!!!!!!!!!!
举报

张天宇

2018-3-12 11:26:53
终于找到一个可以参考的?
举报

更多回帖

发帖
×
20
完善资料,
赚取积分