FPGA学习——FPGA利用状态机实现电子锁模拟

文章目录

  • 一、本次实验简介
  • 二、源码及分析
  • 三、总结

一、本次实验简介

本次是实验是为了利用状态机模拟电子锁,相关要求如下:

  • 顺序输入4位密码,密码为1234,用按键来键入密码
  • 用led灯指示键入第几位密码,(博主IDLE状态亮1个LED,输入第一位密码后亮2个,以此类推),若密码输入正确,让4个led闪烁(每间隔0.3s)
  • 用3个按键,按下key1,对应位的数值加1
  • 按下key2,对应位的数值减1
  • 按下按键key3,表示确认键入该数值

二、源码及分析

fsm_lock模块:

源码分析:

  • 博主为状态机设计了五个状态并采用独热码编码的方式(一般均建议状态机状态编码方式采用独热码):
    IDLE 空闲状态
    P1密码1输入正确状态
    P2 密码2输入正确状态
    P3密码3输入正确状态
    P4密码4输入正确后LED闪烁状态
  • 有题目可以看出,我们有四位的密码,博主的想法是设置四个密码寄存器,KEY1按下后计数值加1,KEY2按下时计数值减一,以此来存储键入密码值(当然每个密码寄存器的加1条件有些许不同,详细请看代码)。
  • 而除了最后一个状态,其他状态博主设置的跳转下一状态的条件均为状态机处于当前状态并且按下了KEY3(确认键)并且此时键入的值为密码值。
  • 对于最后一个状态,由于需要在P4闪烁LED灯,因此跳转状态设置为了LED闪烁结束。至于如何控制LED闪烁结束,博主设置了一个八位的次数寄存器,LED每完成一次闪烁,该计数器左移一位(初始值为8’d1),当闪烁完成时,该计数器的最高位为1,此时便可以将最高位作为跳转的控制条件。
/****
状态机模拟电子锁- 顺序输入4位密码,密码为1234,用按键来键入密码
- 用led灯指示键入第几位密码,(博主IDLE状态亮1个LED,输入第一位密码后亮2个,以此类推),若密码输入正确,让4个led闪烁(每间隔0.3s)
- 用3个按键,按下key1,对应位的数值加1
- 按下key2,对应位的数值减1
- 按下按键key3,表示确认键入该数值****/
module fsm_lock (input       wire                clk     ,input       wire                rst_n   ,input       wire    [2:0]       key_in  , //按键输入信号output      reg     [3:0]       led       //输出led
);//参数定义
parameter MAX = 15_000_000  ;//300ms计数器
parameter IDLE = 5'b00001   ,//空闲状态P1   = 5'b00010   ,//密码1输入正确状态 P2   = 5'b00100   ,//密码2输入正确状态P3   = 5'b01000   ,//密码3输入正确状态P4   = 5'b10000   ;//密码4输入正确LED闪烁状态//状态转移条件定义
wire            idle2p1     ;
wire            p12p2       ;
wire            p22p3       ;
wire            p32p4       ;
wire            p42idle     ;//内部信号定义
reg     [23:0]  cnt      ;//300ms计数寄存器
reg     [7:0]   cnt_8    ;//解锁成功后让LED闪烁4次reg     [4:0]   cstate   ;//现态
reg     [4:0]   nstate   ;//次态reg     [3:0]   cnt_key1 ;//密码计数器 计数当前按下的密码值
reg     [3:0]   cnt_key2 ;
reg     [3:0]   cnt_key3 ;
reg     [3:0]   cnt_key4 ;reg             led_light;//三段式状态机
//第一段时序逻辑,描述状态转移
always@(posedge clk or negedge rst_n)beginif(!rst_n)begincstate <= IDLE;endelse begincstate <= nstate;end
end//第二段组合逻辑,描述状态转移规律及状态转移条件
always@(*)begincase(cstate)IDLE    :   beginif(idle2p1)beginnstate = P1;endelse beginnstate = cstate;endendP1      :   beginif(p12p2)beginnstate = P2;endelse beginnstate = cstate;endendP2      :   beginif(p22p3)beginnstate = P3;endelse beginnstate = cstate;endendP3      :   beginif(p32p4)beginnstate = P4;endelse beginnstate = cstate;endendP4      :   beginif(p42idle)beginnstate = IDLE;endelse beginnstate = cstate;endenddefault :   nstate = IDLE;endcase
endassign idle2p1 = (cstate == IDLE) && (key_in[2]) && (cnt_key1 == 4'd1);
assign p12p2   = (cstate == P1  ) && (key_in[2]) && (cnt_key2 == 4'd2);
assign p22p3   = (cstate == P2  ) && (key_in[2]) && (cnt_key3 == 4'd3);
assign p32p4   = (cstate == P3  ) && (key_in[2]) && (cnt_key4 == 4'd4);
assign p42idle = (cstate == P4  ) && (cnt_8[7]);//led闪烁完成后跳转//第三段,时序逻辑,描述不同状态下的输出
always@(posedge clk or negedge rst_n)beginif(!rst_n)beginled <= 4'b0000;endelse begincase(cstate)IDLE    :   led <= 4'b0001      ;P1      :   led <= 4'b0011      ;P2      :   led <= 4'b0111      ;P3      :   led <= 4'b1111      ;P4      :   led <= led_light    ;default :   led <= 4'b0000      ;endcaseend
end//密码计数器1
always@(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_key1 <= 1'b0;endelse if(key_in[0] && cstate == IDLE)begincnt_key1 <= cnt_key1 + 1'b1;endelse if(key_in[1] && (cnt_key1 != 1'b0))begincnt_key1 <= cnt_key1 - 1'b1;endelse if(cnt_8[7])begincnt_key1 <= 1'b0;endelse begincnt_key1 <= cnt_key1;end
end//密码计数器2
always@(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_key2 <= 1'b0;endelse if(key_in[0] && cstate == P1)begincnt_key2 <= cnt_key2 + 1'b1;endelse if(key_in[1] && (cnt_key2 != 1'b0))begincnt_key2 <= cnt_key2 - 1'b1;endelse if(cnt_8[7])begincnt_key2 <= 1'b0;endelse begincnt_key2 <= cnt_key2;end
end//密码计数器3
always@(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_key3 <= 1'b0;endelse if(key_in[0] && cstate == P2)begincnt_key3 <= cnt_key3 + 1'b1;endelse if(key_in[1] && (cnt_key3 != 1'b0))begincnt_key3 <= cnt_key3 - 1'b1;endelse if(cnt_8[7])begincnt_key3 <= 1'b0;endelse begincnt_key3 <= cnt_key3;end
end//密码计数器4
always@(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_key4 <= 1'b0;endelse if(key_in[0] && cstate == P3)begincnt_key4 <= cnt_key4 + 1'b1;endelse if(key_in[1] && (cnt_key4 != 1'b0))begincnt_key4 <= cnt_key4 - 1'b1;endelse if(cnt_8[7])begincnt_key4 <= 1'b0;endelse begincnt_key4 <= cnt_key4;end
end//300ms计数器
always @(posedge clk or negedge rst_n)beginif(!rst_n)begincnt <= 1'b0;endelse if(cnt == MAX - 1'b1)begincnt <= 1'b0;endelse if(cstate == P4)begincnt <= cnt + 1'b1;endelse begincnt <= 1'b0;end
end//闪烁次数寄存器
always @(posedge clk or negedge rst_n) beginif(!rst_n)begincnt_8 <= 8'b00000001;end    else if(cnt == MAX -1'd1)begincnt_8 <= {cnt_8[6:0],cnt_8[7]};endelse if(cstate == IDLE)begincnt_8 <= 8'b00000001;endelse begincnt_8 <= cnt_8;end
end//led闪烁
always@(posedge clk or negedge rst_n)beginif(!rst_n)beginled_light <= 4'b1111;endelse if(cstate == P4 && cnt == MAX - 1'b1)beginled_light <= ~led_light;endelse beginled_light <= led_light;end
endendmodule

fsm_key模块(按键消抖模块):

如果有读者不了解按键消抖原理与代码细节的可以查看博主此篇博文,博主在此就不再赘述了

module fsm_key#(parameter WIDTH = 3) (input       wire                    clk     ,input       wire                    rst_n   ,input       wire   [WIDTH - 1:0]    key_in  ,//按键信号输入output      reg    [WIDTH - 1:0]    key_out  //消抖后稳定的脉冲信号输出
);//参数定义
parameter       IDLE        = 4'b0001;//空闲状态
parameter       FILTER_DOWN = 4'b0010;//按键按下抖动状态
parameter       HOLD_DOWN   = 4'b0100;//按键稳定状态
parameter       FILTER_UP   = 4'b1000;//按键释放抖动状态parameter MAX = 20'd1_000_000 ;//延时20ms采样//内部信号定义
reg         [19:0]               cnt_20ms    ;//20ms计数寄存器
reg         [WIDTH - 1:0]        key_r0      ;//同步
reg         [WIDTH - 1:0]        key_r1      ;//打一拍
reg         [WIDTH - 1:0]        key_r2      ;//打两拍reg         [3:0]                cstate      ;//现态寄存器
reg         [3:0]                nstate      ;//次态寄存器//状态转移条件定义
wire                             idle2down   ;
wire                             down2hold   ;
wire                             hold2up     ;
wire                             up2idle     ;  //计数器信号定义
wire                             add_cnt_20ms;//开始计时的标志
wire                             end_cnt_20ms;//结束计时的标志wire        [WIDTH - 1:0]        nedge       ;//下降沿寄存器
wire        [WIDTH - 1:0]        pedge       ;//上升沿寄存器//同步打拍
always @(posedge clk or negedge rst_n) beginif(!rst_n)beginkey_r0 <= {WIDTH{1'b1}};key_r1 <= {WIDTH{1'b1}};key_r2 <= {WIDTH{1'b1}};endelse beginkey_r0 <= key_in;key_r1 <= key_r0;key_r2 <= key_r1;end
end//20ms计数器
always@(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_20ms <= 1'b0;endelse if(add_cnt_20ms)beginif(end_cnt_20ms)begincnt_20ms <= 1'b0;endelse begincnt_20ms <= cnt_20ms + 1'b1;endendelse begincnt_20ms <= 1'b0;end
endassign add_cnt_20ms = cstate == FILTER_DOWN || cstate == FILTER_UP;
assign end_cnt_20ms = add_cnt_20ms && cnt_20ms == MAX - 1'b1;//下降沿 上升沿检测
assign nedge = ~key_r1 & key_r2;
assign pedge = key_r1 & ~key_r2;//三段式状态机//第一段,时序逻辑,描述状态转移
always@(posedge clk or negedge rst_n)beginif(!rst_n)begincstate <= IDLE;endelse begincstate <= nstate;end
end//第二段,组合逻辑,状态转移规律及状态转移条件
always @(*)begincase (cstate)IDLE         : beginif(idle2down)beginnstate <= FILTER_DOWN;endelse beginnstate <= cstate;endendFILTER_DOWN  : beginif(down2hold)beginnstate <= HOLD_DOWN;endelse beginnstate <= cstate;endendHOLD_DOWN    : beginif(hold2up)beginnstate <= FILTER_UP;endelse beginnstate <= cstate;endendFILTER_UP    : beginif(up2idle)beginnstate <= IDLE;endelse beginnstate <= cstate;endenddefault     : nstate <= IDLE;endcase
endassign idle2down   = cstate == IDLE         && nedge        ;
assign down2hold   = cstate == FILTER_DOWN  && end_cnt_20ms ;
assign hold2up     = cstate == HOLD_DOWN    && pedge        ;
assign up2idle     = cstate == FILTER_UP    && end_cnt_20ms ;//第三段 时序逻辑或组合逻辑 描述输出
always@(posedge clk or negedge rst_n)beginif(!rst_n)beginkey_out <= {WIDTH{1'b0}};endelse if(down2hold)beginkey_out <= ~key_in;endelse beginkey_out <= {WIDTH{1'b0}};end
endendmodule

顶层模块:

module top_lock(input   wire            clk     ,input   wire            rst_n   ,input   wire    [2:0]   key_in  ,output  wire    [3:0]   led
);wire   [2:0]     key_out;fsm_lock u_fsm_lock(.clk   (clk    )  ,.rst_n (rst_n  )  ,.key_in(key_out)  ,.led   (led)   
);fsm_key u_fsm_key(.clk    (clk    ) ,.rst_n  (rst_n  ) ,.key_in (key_in ) ,.key_out(key_out)  
);endmodule

三、总结

本次实验较为简单,博主没有编写仿真文件跑仿真(其实是因为懒毕竟我觉得TB文件写起来真的很麻烦),功能实现也较为简单,感兴趣的读者可以自主添加其他功能,如:输入错误蜂鸣器鸣叫并自动跳转回到IDLE状态,或者利用数码管显示正在输入的密码位数与密码值等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/14928.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++模拟实现反向迭代器

1.代码实现 1.有了解正向迭代器的应该知道&#xff0c;比如list的正向迭代器其实本质是一个类&#xff0c;而有些人想模拟实现反向迭代器&#xff0c;依旧想再创建一个类&#xff0c;但是库里面想要的是&#xff0c;你给我一个迭代器&#xff0c;我就能给你反馈一个反向迭代器…

word显示书签并给书签添加颜色

CTRg 定位书签 在 Word 的用户界面中&#xff0c;没有直接的选项可以批量为所有书签设置颜色。但你可以使用 VBA 宏或者编写自定义的功能来实现这个需求。这里给出一个简单的 VBA 宏&#xff0c;它可以设置当前文档中所有书签内文本的颜色&#xff1a;vba Sub ColorAllBookmark…

Gromacs-plumed元动力学

标准的meta动力学模拟需要设定如下标准参数 metad: ARG__FILL__ PACE__FILL__ HEIGHT__FILL__ BIASFACTOR__FILL__ SIGMA__FILL__ FILE__FILL__ GRID_MIN__FILL__ GRID_MAX__FILL__ GRID_BIN__FILL__ TEMP__FILL__ARG: 需要添加高斯偏置势的集合变量CV (e.g. distance, angle,…

MySQL基于复制线程实现MTS并行恢复binlog

文章目录 一、MySQL备份恢复流程二、并行恢复binlog原理三、操作步骤四、总结 一、MySQL备份恢复流程 MySQL数据恢复通常分为两个步骤&#xff1a; 恢复全备数据&#xff0c;MySQL有多种备份工具&#xff0c;分为物理备份和逻辑备份&#xff1b;具体可以参看下面这篇文章 MySQL…

零代码编程:PDF文件名和Excel数据进行比对找不同

F盘“北交所招股说明书”文件夹下有150个文件&#xff1b; F盘”北证A股20230703.xlsx”表格中证券名称有200多个&#xff1b; 现在想找出文件夹下的哪些证券名称不在表格里面。 在ChatGPT中输入提示词&#xff1a; 写一段Python程序&#xff1a; F盘“北交所招股说明书”文…

ElementUI Select选择器如何根据value值显示对应的label

修改前效果如图所示&#xff0c;数据值状态应显示为可用&#xff0c;但实际上仅显示了状态码1&#xff0c;并没有显示其对应的状态信息。在排查了数据类型对应关系问题后&#xff0c;并没有产生实质性影响&#xff0c;只好对代码进行了如下修改。 修改前代码&#xff1a; <…

Python自动化测试----生成测试报告

如何才能让用例自动运行完之后&#xff0c;生成一张直观可看易懂的测试报告呢&#xff1f; 对于自动化测试有兴趣的朋友可以观看这个视频&#xff1a; 【整整200集】超超超详细的Python接口自动化测试进阶教程&#xff0c;真实模拟企业项目实战&#xff01;&#xff01; 小编使…

【暑期每日一练】 day9

目录 选择题 &#xff08;1&#xff09; 解析&#xff1a; &#xff08;2&#xff09; 解析&#xff1a; &#xff08;3&#xff09; 解析&#xff1a; &#xff08;4&#xff09; 解析&#xff1a; &#xff08;5&#xff09; 解析&#xff1a; 编程题 题一 …

python学习之【浅拷贝】

前言 上一篇文章&#xff0c;python学习之【继承、封装、多态】主要学习了面向对象的三大特征。这篇文章记录下对python的浅拷贝的学习&#xff0c;下一篇文章接着学习深拷贝。 简单了解 浅拷贝&#xff1a;python拷贝一般都是浅拷贝&#xff0c;拷贝时&#xff0c;对象包含的…

ARM基础(6):内存屏障指令之DMB、DSB和ISB详解

内存屏障是一个通用术语&#xff0c;用于指代一条或多条指令&#xff0c;它们强制处理器在执行加载(load)或存储(store)指令时进行同步事件。ARMv7-M 和 ARMv6-M架构都提供了三个内存屏障指令来支持内存顺序模型。这三个内存屏障指令分别是&#xff1a;DMB、DSB和ISB。 文章目录…

零信任安全解决方案

什么是零信任 零信任网络架构 &#xff08;ZTNA&#xff09; 或零信任安全是一种新的组织网络安全方法。它旨在修复传统基于边界的安全性中的缺陷并简化网络设计。 它以“永不信任&#xff0c;始终验证”的原则运作。这意味着&#xff0c;无论用户或设备位于何处&#xff0c;…

位运算 剑指offer15 二进制中1的个数 搜索算法:55-II 平衡二叉树 数值的整数次方 39数组中出现次数超过一半的数字

可能会引起死循环的解法&#xff1a; 看最右边一位是不是1&#xff0c;然后将输入的整数右移一位&#xff0c;再判断最右边一位&#xff08;即倒数第二位&#xff09;是否为1&#xff0c;接着再右移&#xff0c;知道整数移动到0为止 这个解法&#xff0c;把整数右移一位和把整数…

TCP网络通信编程之字符流

【案例1】 【题目描述】 【 注意事项】 (3条消息) 节点流和处理流 字符处理流BufferedReader、BufferedWriter&#xff0c;字节处理流-BufferedInputStream和BufferedOutputStream (代码均正确且可运行_Studying~的博客-CSDN博客 1。这里需要使用字符处理流&#xff0c;来将…

wxwidgets Ribbon构建多个page与按钮响应

新建一个控制台应用程序&#xff0c;添加好头文件的依赖与lib库文件的依赖&#xff0c;修改属性&#xff1a; 将进入ribbon界面的文件与主界面的类分开&#xff1a; 1、RibbonSample.cpp #include "stdafx.h" #include "MyFrame.h" class MyApp : public…

集成测试,单元测试隔离 maven-surefire-plugin

详见 集成测试,单元测试隔离 maven-surefire-plugin maven的goal生命周期 Maven生存周期 - 含 integration-test Maven本身支持的命令&#xff08;Goals&#xff09;是有顺序的&#xff0c;越后面执行的命令&#xff0c;会将其前面的命令和其本身按顺序执行一遍&#xff0c;…

AD从原理图到PCB超详细教程

AD超详细教程 前言一、建立一个工程模板二、原理图1.设计原理图。2.使用AD自带库和网上开源原理图库3.画原理图库4.编译原理图 三、PCB1.确定元器件尺寸大小2.绘制PCB Library①使用元器件向导绘制元件库②原理图与PCB的映射 3.绘制PCB①更新PCB②调整元件位置③布线④漏线检查…

c++函数式编程:统计文件字符串,文件流

头文件 #include <iostream> #include <fstream> #include <string> #include <sstream> #include <algorithm> #include <vector>统计方法 int count_lines(const std::string &filename) {std::ifstream in{filename};return std:…

100% RNN language model ChatRWKV 相关开源项目

RWKV(读作RwaKuv)借鉴了RNN的移动平均模型&#xff08;MA&#xff09;&#xff0c;将transformer的 O ( T 2 d ) O(T^2d) O(T2d)复杂度降低到 O ( T d ) O(Td) O(Td)&#xff0c;同时保持较好的结果表现。RWKV也是一个开源模型&#xff0c;甚至其介绍主页的html代码都有开源。以…

AI面试官:Asp.Net 中使用Log4Net (二)

AI面试官:Asp.Net 中使用Log4Net (二) 当面试涉及到使用log4net日志记录框架的相关问题时,通常会聚焦在如何在.NET或.NET Core应用程序中集成和使用log4net。以下是一些关于log4net的面试题目,以及相应的解答、案例和代码: 文章目录 AI面试官:Asp.Net 中使用Log4Net (二)…

【COlor传感器】通过扰动调制光传感实现智能光传输的占用分布估计研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…