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状态,或者利用数码管显示正在输入的密码位数与密码值等。
相关文章:
FPGA学习——FPGA利用状态机实现电子锁模拟
文章目录 一、本次实验简介二、源码及分析三、总结 一、本次实验简介 本次是实验是为了利用状态机模拟电子锁,相关要求如下: 顺序输入4位密码,密码为1234,用按键来键入密码用led灯指示键入第几位密码,(博…...
Bert经典变体学习
ALBert ALBERT就是为了解决模型参数量大以及训练时间过长的问题。ALBERT最小的参数只有十几M, 效果要比BERT低1-2个点,最大的xxlarge也就200多M。可以看到在模型参数量上减少的还是非常明显的,但是在速度上似乎没有那么明显。最大的问题就是这种方式其实…...
uniapp checkbox radio 样式修改
文章目录 通过查看代码,发现 before部分是设置样式的主要属性 我们要设置的话,就要设置checkbox::before的属性。 其中的content表示内容,比如内部的对勾 那么我们设置的时候,比如设置disabletrue的时候或者checkedtrue的时候&…...
电脑重启后VScode快捷方式失效,找不到Code.exe
问题描述 下班回家关了部分程序就直接关机了,回家后重启电脑发现vscode的快捷方式就失效了,提示Code.exe已被移动或删除。 解决方法 查看你的vscode安装目录,Microsoft VS Code目录下大概率会存在一个名为_的文件夹,然后会发现…...
C语言实现扫雷游戏
test.c源文件 - 扫雷游戏测试 game.h头文件 - 扫雷游戏函数的声明 game.c源文件 - 扫雷游戏函数的实现 1.布置雷 -- 存放雷的雷盘 9*9 数组设计成11*11 上下左右方各多一行,保证周围8的范围 雷 - 1 不是雷 - 0 2.排查雷 主题测试源文件代码 &…...
蓝图节点编辑器
打印字符串 第02章 蓝图结构 03 -注释和重新路由_哔哩哔哩_bilibili 第02章 蓝图结构 04 - 变量_哔哩哔哩_bilibili 第03章 蓝图简易门 01 - 箱子碰撞_哔哩哔哩_bilibili 第03章 蓝图简易门 02 - 静态Mesh和箭头_哔哩哔哩_bilibili 第03章 蓝图简易门 03 - 设置相对旋转节点_哔…...
MySql 知识大汇总
数据库索引 数据库索引是一种数据结构,用于提高数据库查询的速度和效率。索引可以看作是表中一列或多列的值的快速查找方式,类似于书籍的目录。通过创建索引,可以减少数据库的扫描量,加快数据的检索速度。 常见的索引类型 常见…...
深入浅出Pytorch函数——torch.sum
分类目录:《深入浅出Pytorch函数》总目录 相关文章: 深入浅出Pytorch函数——torch.Tensor 函数torch.sum有两种形式: torch.sum(input, *, dtypeNone):返回输入张量input所有元素的和。torch.sum(input, dim, keepdimFalse, *,…...
Git克隆文件不显示绿色勾、红色感叹号等图标
1、问题 Git和TorToiseGit安装后,Git克隆的文件不会显示绿色勾、红色感叹号等图标。 2、检查注册表 2.1、打开注册表 (1)WinR打开运行窗口,输入regedit,点击确定,打开注册表编辑器。 2.2、找如下路径 (1)找到路径 计算机\HKEY_…...
SOC FPGA之HPS模型设计(一)
目录 一、建立HPS硬件系统模型 1.1 GHRD 1.2 从0开始搭建HPS 1.2.1 FPGA Interfaces 1.2.1.1 General 1.2.1.2 AXI Bridge 1.2.1.3 FPGA-to-HPS SDRAM Interface 1.2.1.4 DMA Peripheral Request 1.2.1.5 Interrupts 1.2.1.6 EMAC ptp interface 1.2.2 Peripheral P…...
解决openstack重启swift服务后报错
swift重启报错 问题描述解决办法 问题描述 swift服务正常状态如下 [rootcontroller ~]# swift statAccount: AUTH_8bde12ff804e42498661b7454994c446Containers: 0Objects: 0Bytes: 0X-Put-Timestamp: 1690507907.67931X-Timestamp: 1690507907.67931X-Trans-Id: tx56d22fa13…...
[Linux]进程控制详解!!(创建、终止、等待、替换)
hello,大家好,这里是bang___bang_,在上两篇中我们讲解了进程的概念、状态和进程地址空间,本篇讲解进程的控制!!包含内容有进程创建、进程等待、进程替换、进程终止!! 附上前2篇文章…...
全面适配 | 走近openGauss数据库+鲲鹏欧拉操作系统
引入 全面适配 | openEuler操作系统 openGauss数据库 开篇 1、openEuler欧拉操作系统 百度百科:openEuler是覆盖全场景的创新平台,在引领内核创新,夯实云化基座的基础上,面向计算架构互联总线、存储介质发展新趋势,…...
2023Robocom CAIP省赛 第四题 相对论大师
原题链接: PTA | 程序设计类实验辅助教学平台 题面: 在某个直播间里,观众常常会发送类似这样的弹幕: 鱼越大,鱼刺越大;鱼刺越大,肉越少;肉越少,鱼越小;所以鱼…...
【TypeScript】TS入门级基础学习(一)
【TypeScript】TS入门级基础学习(一) 一、前言 TypeScript 是一种用于应用程序规模的 JavaScript 语言。 TypeScript 向 JavaScript 添加了可选类型,支持用于任何浏览器、任何主机、任何操作系统的大规模 JavaScript 应用程序的工具。 Type…...
jenkins执行jmeter时,报Begin size 1 is not equal to fixed size 5
jenkins执行jmeter脚本的时候一直提示如下错误: Tidying up ... Fri Jul 28 17:03:53 CST 2023 (1690535033178) Error generating the report: org.apache.jmeter.report.dashboard.GenerationException: Error while processing samples: Consumer failed wi…...
在 “小小容器” WasmEdge 里运行小小羊驼 llama 2
昨天,特斯拉前 AI 总监、OpenAI 联合创始人 Andrej Karpathy 开源了 llama2.c 。 只用 500 行纯 C 语言就能训练和推理 llama 2 模型的框架,没有任何繁杂的 python 依赖。这个项目一推出就受到大家的追捧,24 小时内 GitHub 收获 4000 颗星&am…...
【C#】async和await 续
前言 在文章《async和await》中,我们观察到了一下客观的规律,但是没有讲到本质,而且还遗留了一个问题: 这篇文章中,我们继续看看这个问题如何解决! 我们再看看之前写的代码: static public void TestWait2() {var t…...
【Matlab】基于粒子群优化算法优化BP神经网络的数据回归预测(Excel可直接替换数据)
【Matlab】基于粒子群优化算法优化 BP 神经网络的数据回归预测(Excel可直接替换数据) 1.模型原理2.数学公式3.文件结构4.Excel数据5.分块代码5.1 fun.m5.2 main.m6.完整代码6.1 fun.m6.2 main.m7.运行结果1.模型原理 基于粒子群优化算法(Particle Swarm Optimization, PSO)…...
QPainter绘制雷达界面
文章目录 功能实现定义的结构体定义的函数效果图gitee源码链接 功能实现 相较于上一版,这一版添加的功能有: 1、自适应窗口 2、扫描方式(圆周扫描、扇形扫描(指定起始角度和结束角度)) 3、扫描方向&#x…...
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...
vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...
python报错No module named ‘tensorflow.keras‘
是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...
AI病理诊断七剑下天山,医疗未来触手可及
一、病理诊断困局:刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断",医生需通过显微镜观察组织切片,在细胞迷宫中捕捉癌变信号。某省病理质控报告显示,基层医院误诊率达12%-15%,专家会诊…...
C++:多态机制详解
目录 一. 多态的概念 1.静态多态(编译时多态) 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1).协变 2).析构函数的重写 5.override 和 final关键字 1&#…...
QT3D学习笔记——圆台、圆锥
类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体(对象或容器)QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质(定义颜色、反光等)QFirstPersonC…...
