EDA大作业-----打地鼠,模块记录以及分享

2023-12-30 07:20

本文主要是介绍EDA大作业-----打地鼠,模块记录以及分享,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

EDA大作业-----打地鼠,模块记录以及分享

源码及相关实用工具(这个工具我也没用过,不知道好不好用)

题目要求:

1.选择一个拨码开关作为游戏开始开关;
2.使用一排LED灯(8个,从左至右编号1到8),灯亮表示地鼠出现,要求地鼠随机出现;
3.使用8个脉冲开关,对应位置(从左至右编号1到8)开关可以打击对应地鼠(灯灭);
4.击中一个地鼠得一分,用数码管显示当前分数;
5.一局游戏时间是60秒,时间到游戏结束,选择另外一个led灯亮指示时间到,拨下开始开关指示灯灭,数码管得分显示消失,恢复初始状态。

模块

简述

对于这个作业的话,个人感觉还是比较简单的(实现的过程想打人,特别折磨人),因为它的模块很清晰,下面我就简单的说一下我需要实现的模块有哪些:show(用于数码管上显示),compareadd(按键的信号和随机数进行比较来实现计分),random(随机数模块,其实也是地鼠产生的模块),button(按键,来实现打地鼠),time_down(倒计时),new_clock(实现分频,产生新的时钟信号),嗯,没错,就是这几个模块,下面我简单的描述一下我的每个模块。

show

对于这个模块我就不过多的说明了,不能理解的看我前面的相关博客。这个show也就是简单的数码管的动态扫描,只不过其中加入了一些输入信号而已,读者可以看前面的blog自行理解

“show”的源码

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;entity show is
port(
time_g:in std_logic_vector(3 downto 0);
time_s:in std_logic_vector(3 downto 0);
grade_s,grade_g:in std_logic_vector(3 downto 0);
clk:in std_logic;
sel:out std_logic_vector(7 downto 0);
smg:out std_logic_vector(6 downto 0)
);
end;
architecture one of show is
begin
process(clk)
variable cnt:integer range 0 to 3:=0;
begin
if clk'event and clk='1' then  if cnt=0 then sel<="10111111";case grade_g iswhen "0000"=>smg<="1111110";when "0001"=>smg<="0110000";when "0010"=>smg<="1101101";when "0011"=>smg<="1111001";when "0100"=>smg<="0110011";when "0101"=>smg<="1011011";when "0110"=>smg<="1011111";when "0111"=>smg<="1110000";when "1000"=>smg<="1111111";when "1001"=>smg<="1111011";when others=>smg<="0000000";end case;cnt:=cnt+1;elsif cnt=1 then sel<="01111111";case grade_s iswhen "0000"=>smg<="1111110";when "0001"=>smg<="0110000";when "0010"=>smg<="1101101";when "0011"=>smg<="1111001";when "0100"=>smg<="0110011";when "0101"=>smg<="1011011";when "0110"=>smg<="1011111";when "0111"=>smg<="1110000";when "1000"=>smg<="1111111";when "1001"=>smg<="1111011";when others=>smg<="0000000";end case;cnt:=cnt+1;elsif cnt=2 then sel<="11111101";case time_s iswhen "0000"=>smg<="1111110";when "0001"=>smg<="0110000";when "0010"=>smg<="1101101";when "0011"=>smg<="1111001";when "0100"=>smg<="0110011";when "0101"=>smg<="1011011";when "0110"=>smg<="1011111";when "0111"=>smg<="1110000";when "1000"=>smg<="1111111";when "1001"=>smg<="1111011";when others=>smg<="0000000";end case;cnt:=cnt+1;elsif cnt=3 then sel<="11111110";case time_g iswhen "0000"=>smg<="1111110";when "0001"=>smg<="0110000";when "0010"=>smg<="1101101";when "0011"=>smg<="1111001";when "0100"=>smg<="0110011";when "0101"=>smg<="1011011";when "0110"=>smg<="1011111";when "0111"=>smg<="1110000";when "1000"=>smg<="1111111";when "1001"=>smg<="1111011";when others=>smg<="0000000";end case;cnt:=0;end if;
end if;
end process;
end;

代码就是这样,读者自行结合前面的内容理解。

button

对于这个东西是我最头疼的部分,为啥呢?这个鬼玩意要实现消抖。因为不消抖的话,就会出现很大的偏差。然后消抖一开始我只会单个按键的消抖,这里我推荐一篇文章是有关于消抖的,但是是单个按键的.(vhdl按键消抖程序)。然后在捣鼓一段时间后我就发现这个多个按键的消抖是和单个按键的没什么区别的(主要是对这些底层的东西不是很理解),也是通过时钟脉冲来实现的,一开始是不知道如何下笔,后来理解了就很好写了。

代码呈上:

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;entity button is
port(
clk:in std_logic;
reset_in:in std_logic_vector(7 downto 0);
com:out std_logic_vector(7 downto 0):="00000000"--com为按键后输出的值,用来和random产生数进行比较
);
end;
architecture one of button is
begin
process(clk,reset_in(7),reset_in(6),reset_in(5),reset_in(4),reset_in(3),reset_in(2),reset_in(1),reset_in(0))
variable cnt:integer range 0 to 20:=0;--计数器,来实现消抖的关键,因为一般的按键的延时是在20ms左右,这里频率是1000hz
begin--本质上和单个按键消抖没什么区别,读者可以参考那片消抖的文章,自行领悟。当然我也会简单的说一下
if reset_in(7)='0' then if clk='1'and cnt<20 then cnt:=cnt+1;elsif cnt=20 then com<="10000000";cnt:=0;end if;
elsif reset_in(6)='0' then if clk='1'and cnt<20 then cnt:=cnt+1;elsif cnt=20 then com<="01000000";cnt:=0;end if;
elsif reset_in(5)='0' then if clk='1'and cnt<20 then cnt:=cnt+1;elsif cnt=20 then com<="00100000";cnt:=0;end if;
elsif reset_in(4)='0' then if clk='1'and cnt<20 then cnt:=cnt+1;elsif cnt=20 then com<="00010000";cnt:=0;end if;
elsif reset_in(3)='0' then if clk='1'and cnt<20 then cnt:=cnt+1;elsif cnt=20 then com<="00001000";cnt:=0;end if;
elsif reset_in(2)='0' then if clk='1'and cnt<20 then cnt:=cnt+1;elsif cnt=20 then com<="00000100";cnt:=0;end if;
elsif reset_in(1)='0' then if clk='1'and cnt<20 then cnt:=cnt+1;elsif cnt=20 then com<="00000010";cnt:=0;end if;
elsif reset_in(0)='0' then if clk='1'and cnt<20 then cnt:=cnt+1;elsif cnt=20 then com<="00000001";cnt:=0;end if;
else com<="00000000";end if;
end process;
end;

ps:我还是简单的说一下按键消抖,这个其实比较简单,因为按键在按下去的一瞬间,会因为一些其他的原因而产生一些反应,这个好像就被称为抖动,具体的细节还请参考百度(读者自己查证)。而对于一般的抖动而言就只有20ms左右,那么就很好解决了嘛。没错就是通过时钟来实现,然后再设置一个变量来实现等待的时间,至于给多少自己按照选定的频率来看。然后当达到这个variable的时候,就执行相关的操作,这个就是所谓的消抖,知道了这个上面的代码应该很好实现吧

random

首先对于random,在vhdl上是没有随机数算法,然后就自己实现随机数的。然后对于随机数的实现,我这里采用m序列来实现随机数。

对于这个m序列其实就是首先定义几个变量,然后通过循环进行赋值,譬如说:x1->out,x2->x1…Xn->Xn-1;然后Xn被赋值为之前的Xn和之前的X1的异或。如此循环往复,就可以实现一个伪随机的数字序列。对于这个m序列运用似乎也是挺广的,详细请参考文档m序列。

知道了原理,那么就很好实现了,那么代码呈上:

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;entity random is
port(
clk :in std_logic;
finish:in std_logic;
random_out:out std_logic_vector(7 downto 0)
);
end;
architecture one of random is
signal rd:std_logic_vector(4 downto 0):="10000";
signal mid:std_logic;
signal put:std_logic_vector(2 downto 0);
begin
process(clk)
begin
if clk'event and clk='1' then 
if finish='1' then mid<=rd(0);rd(0)<=rd(1);rd(1)<=rd(2);rd(2)<=rd(3);rd(3)<=rd(4);rd(4)<=rd(4) xor mid;put<=rd(4 downto 2); --因为要产生8只地鼠,那么直接取m序列的高三位即可,然后映射为八位二进制数(只含一个1表示地鼠的位置)if put="000" then random_out<="00000001";elsif put="001" then random_out<="00000010";elsif put="010" then random_out<="00000100";elsif put="011" then random_out<="00001000";elsif put="100" then random_out<="00010000";elsif put="101" then random_out<="00100000";elsif put="110" then random_out<="01000000";else random_out<="10000000";end if;
end if;
end if;
end process;
end;

ps:这里的random_out需要和button的com的位数。在经过老师的验收之后,发现随机数的出现频率太快(地鼠),对用户体验感很差,但是修改很容易,加上一个分频即可,大家可以自行加入,我懒得搞了(即使很简单)。

new_clock

对于这个模块我也感觉没什么好说的,因为要实现1s来实现对计数器的计数,而已有的时钟频率是不能够实现,所以的话,我就创建一个新的时钟信号来实现即可,其实也就是分频。

原理:对于这个其实也很好实现了,也是和消抖的差不多。首先也是定义一个变量来实现什么时候对时钟信号进行改变,但是这个我采用的是翻转来实现的,所以对于分频的话,这个公式就得在原来的基础上除以2(公式可以在以前的文章中找到),至于原因嘛就是两次反转才是一个周期,所以这样就可以实现一个新的时钟信号了。

源码奉上:

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;entity new_clock is
port(
clk:in std_logic;
n_clk:buffer std_logic:='0'
);
end;architecture one of new_clock is
begin
process(clk)
variable cnt:integer range 0 to 50000:=0;--控制变量来实现分频,就是说当其有50000个时钟上升沿信号到后,新clk才会翻转
begin
if clk'event and clk='1' thenif cnt=50000 then cnt:=0;n_clk<=not n_clk;else cnt:=cnt+1;end if;
end if;
end process;
end;

对,这个模块就是这样

time_down&compareAdd

对于这两个模块是要放在一起来描述的,为啥?因为这两个模块相互影响,所以我把这两个模块放到一起来进行描述

首先你需要通过时钟信号来实现打地鼠的时长,然后再通过倒计时输出的信号来作用于compareAdd这个模块,拟实现对计分的控制。

当倒计时结束的时候,compareAdd模块就停止计分。当然可以通过clr信号来实现对倒计时和分数的重置,以及控制开始游戏,当然本质上是一样的。

对于控制停止计分这个我简要的说一下,这个实现其实很容易,就是通过finish这个变量来进行控制。当然这其中还用一丝丝小细节,大家可以参考代码。(就是这个部分实现的我都想吐了,后来在time_down中加入了一个varialbe就很轻松解决了)。

对于数码的计数,计分;这个可以分别利用两个逻辑序列来进行实现,就很容易的在show这个模块来进行相关的操作。(一开始我才用的一个variable来搞的,然后通过取余等一系列操作来搞的,结果导致超出了板载资源,我直接炸裂!!!!!!!!!!!!!

那么说完了原理,读者看代码自行理解吧:

time_down
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;entity time_down is
port(
clk:in std_logic;
clr:in std_logic;
finish:out std_logic;
time_s,time_g:out std_logic_vector(3 downto 0)
);
end;architecture one of time_down is
signal g:std_logic_vector(3 downto 0):="0000";
signal s:std_logic_vector(3 downto 0):="0000";
begin
process(clk)
variable cnt:integer range 0 to 60:=0;
begin
if clr='0' then time_s<="0000";time_g<="0000";
s<="0000";g<="0000";finish<='0';cnt:=0;
elsif clk'event and clk='1' thenif cnt<60 or cnt=60 then time_s<=s;time_g<=g;if g="1001" then if s="0101" then s<="0000";else s<=s+1;finish<='1';end if;g<="0000";else g<=g+1;finish<='1';end if;cnt:=cnt+1;else finish<='0';end if;
end if;
end process;
end;
compareAdd
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;entity CompareAdd is
port(
clk,clr:in std_logic;
com,random_out:in std_logic_vector(7 downto 0);
finish:in std_logic;
grade_s,grade_g:out std_logic_vector(3 downto 0)
);
end;
architecture one of CompareAdd is
signal s,g:std_logic_vector(3 downto 0):="0000";
begin
process(clk)
begin
if clk'event and clk='1' then if clr<='0' then grade_s<="0000";grade_g<="0000";s<="0000";g<="0000";elsif com=random_out and finish='1'  thenif g="1001" then g<="0000";if s="1001" then s<="0000";g<="0000";else s<=s+1;end if;else g<=g+1;end if;grade_s<=s;grade_g<=g;end if;
end if;
end process;
end;

这其中不好理解的,我个人认为就是finish的这个部分,其他的都应该很好实现,我也就懒得写注释了(一个不好的习惯)

顶层文件

这个部分就是通过编译器的生成元器件来实现。个人认为连线比较容易(至少这个比较简单

如下图:(连线很好理解,我也就不多说了)

vhdl-打地鼠顶层文件图.png · zmc-x/图库 - 码云 - 开源中国 (gitee.com)

那么,好了这也就是EDA的大作业的全部内容了,真的很累。要是有啥问题私信我

这篇关于EDA大作业-----打地鼠,模块记录以及分享的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/552104

相关文章

SpringBoot请求参数接收控制指南分享

《SpringBoot请求参数接收控制指南分享》:本文主要介绍SpringBoot请求参数接收控制指南,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Spring Boot 请求参数接收控制指南1. 概述2. 有注解时参数接收方式对比3. 无注解时接收参数默认位置

Python的time模块一些常用功能(各种与时间相关的函数)

《Python的time模块一些常用功能(各种与时间相关的函数)》Python的time模块提供了各种与时间相关的函数,包括获取当前时间、处理时间间隔、执行时间测量等,:本文主要介绍Python的... 目录1. 获取当前时间2. 时间格式化3. 延时执行4. 时间戳运算5. 计算代码执行时间6. 转换为指

Python正则表达式语法及re模块中的常用函数详解

《Python正则表达式语法及re模块中的常用函数详解》这篇文章主要给大家介绍了关于Python正则表达式语法及re模块中常用函数的相关资料,正则表达式是一种强大的字符串处理工具,可以用于匹配、切分、... 目录概念、作用和步骤语法re模块中的常用函数总结 概念、作用和步骤概念: 本身也是一个字符串,其中

Python中的getopt模块用法小结

《Python中的getopt模块用法小结》getopt.getopt()函数是Python中用于解析命令行参数的标准库函数,该函数可以从命令行中提取选项和参数,并对它们进行处理,本文详细介绍了Pyt... 目录getopt模块介绍getopt.getopt函数的介绍getopt模块的常用用法getopt模

Java使用SLF4J记录不同级别日志的示例详解

《Java使用SLF4J记录不同级别日志的示例详解》SLF4J是一个简单的日志门面,它允许在运行时选择不同的日志实现,这篇文章主要为大家详细介绍了如何使用SLF4J记录不同级别日志,感兴趣的可以了解下... 目录一、SLF4J简介二、添加依赖三、配置Logback四、记录不同级别的日志五、总结一、SLF4J

在Spring Boot中浅尝内存泄漏的实战记录

《在SpringBoot中浅尝内存泄漏的实战记录》本文给大家分享在SpringBoot中浅尝内存泄漏的实战记录,结合实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧... 目录使用静态集合持有对象引用,阻止GC回收关键点:可执行代码:验证:1,运行程序(启动时添加JVM参数限制堆大小):2,访问 htt

python logging模块详解及其日志定时清理方式

《pythonlogging模块详解及其日志定时清理方式》:本文主要介绍pythonlogging模块详解及其日志定时清理方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录python logging模块及日志定时清理1.创建logger对象2.logging.basicCo

MySQL 中查询 VARCHAR 类型 JSON 数据的问题记录

《MySQL中查询VARCHAR类型JSON数据的问题记录》在数据库设计中,有时我们会将JSON数据存储在VARCHAR或TEXT类型字段中,本文将详细介绍如何在MySQL中有效查询存储为V... 目录一、问题背景二、mysql jsON 函数2.1 常用 JSON 函数三、查询示例3.1 基本查询3.2

Qt spdlog日志模块的使用详解

《Qtspdlog日志模块的使用详解》在Qt应用程序开发中,良好的日志系统至关重要,本文将介绍如何使用spdlog1.5.0创建满足以下要求的日志系统,感兴趣的朋友一起看看吧... 目录版本摘要例子logmanager.cpp文件main.cpp文件版本spdlog版本:1.5.0采用1.5.0版本主要

Python通过模块化开发优化代码的技巧分享

《Python通过模块化开发优化代码的技巧分享》模块化开发就是把代码拆成一个个“零件”,该封装封装,该拆分拆分,下面小编就来和大家简单聊聊python如何用模块化开发进行代码优化吧... 目录什么是模块化开发如何拆分代码改进版:拆分成模块让模块更强大:使用 __init__.py你一定会遇到的问题模www.