【FPGA】电梯楼层显示(简易)

前言

        这是作者室友的项目,本来不管作者事儿的,但是后来听到说是室友去网上找人花了80块买了个劣质的,不仅是从CSDN上抄的,而且使用的板子还不符合室友的要求。可叹作者心软啊,顺便给室友做了。

        在代码实现部分会给出设计理念和分析,整体资源可以直接下载压缩包(手机端依然看不到,还是不知道为什么)。

题目需求及分析

需求

基于双向计数器设计一个电梯楼层显示电路

说明:
        设计多层电梯楼层显示电路。电梯每经过一层,“楼层信号”输入一个可逆计数脉冲电梯上升时“上升”为高电平,“下降”为低电平,下降时相反。

要求:
        1、电梯楼层数为2(至少2层)
        2、楼层数需使用7位译码器显示
        3、可逆计数功能需用双向计数器实现 其输入端包含上升和下降操作信号、楼层信号、校正
        4、上升下降状态过程中用小彩灯灯带变化体现

分析

1. sw1作为总开关,置0清零,置1工作

2. sw2作为楼层“上升”/“下降”控制开关:置0时呈下降状态,楼层信号发生后楼层数减一;置1时呈上升状态,楼层信号发生后楼层数加一

3. led流水灯作为上升下降的具象化表示:向上流水表示上升,向下流水表示下降

4. 辅助功能:显然对于按键,需要有按键消抖的功能;显示分数则需要数码管驱动模块;而关于时序电路中必不可少的分频器也是需要的

代码实现

由于CSDN编辑文章工具中没有VDL语言的设置,这里就用C++来显示代码了(纯黑实属难看)。

1. 楼层显示模块

(1) 中控:elevator.v

module elevator(input clk,input rst,					//重置键input floor_signal,		//楼层信号//功能选择端input sw1,					//sw1作为总开关,置0清零,置1工作input sw2,					//sw2作为楼层“上升”/“下降”控制开关:0下1上output [8:0] segment_led_1,segment_led_2,    	  //数码管输出output [7:0] led);reg 	[7:0] floor_level;	//内部信号:当前楼层数reg	[7:0] display;			//显示输出  //电梯显示模块
always@(posedge clk_500hz)begin//sw1=0,此时楼层数清零,显示FF,作为reset态if(sw1 == 1'b0)beginfloor_level[7:0] <= 8'h00; display[7:0] = 8'hff;end//sw1,2=10,此时表示下降else if(sw1 == 1'b1 && sw2 == 1'b0)begin//清零if(!rst)beginfloor_level[7:0] <= 8'h00;end//楼层下降else if(!floor_signal && key_done)beginif(floor_level[3:0] > 4'd0)beginfloor_level[3:0] <= floor_level[3:0]-2'd1;floor_level[7:4] <= floor_level[7:4];endelse if(floor_level[3:0] == 4'd0)beginfloor_level[3:0] <= 4'h9;floor_level[7:4] <= floor_level[7:4]-4'h1;endend//将当前楼层数赋值给显示display[7:0] = floor_level[7:0];end//sw1,2=11,此时表示上升else if(sw1 == 1'b1 && sw2 == 1'b1)begin//清零if(!rst)beginfloor_level[7:0] <= 8'h00;end//楼层上升else if(!floor_signal && key_done)beginif(floor_level[3:0] < 4'd9)beginfloor_level[3:0] <= floor_level[3:0]+2'd1;floor_level[7:4] <= floor_level[7:4];endelse if(floor_level[3:0] == 4'd9)beginfloor_level[3:0] <= 4'h0;floor_level[7:4] <= floor_level[7:4]+4'h1;endend//将当前楼层数赋值给显示display[7:0] = floor_level[7:0];end
end
//例化数码管显示模块
segment
(.seg_data_1		(display[7:4]),  		//seg_data input.seg_data_2		(display[3:0]),  		//seg_data input.seg_led_1		(segment_led_1),  	//MSB~LSB = SEG,DP,G,F,E,D,C,B,A.seg_led_2		(segment_led_2)   	//MSB~LSB = SEG,DP,G,F,E,D,C,B,A
);//例化消抖module 
wire key_done; //有按键按下
debounce  //消抖模块
(.clk       (clk),.rst_n     (rst),.key_in    (floor_signal),.clk_500hz (clk_500hz),.key_done  (key_done)
);//例化流水灯
flashled u1 (                                   .clk	(clk),  .rst	(rst),.led	(led),.sw	(sw2)
);endmodule

(2) 数码管驱动:segment.v

  module segment(input  wire [3:0] seg_data_1,  //四位输入数据信号input  wire [3:0] seg_data_2,  //四位输入数据信号output wire [8:0] seg_led_1,  //数码管1,MSB~LSB = SEG,DP,G,F,E,D,C,B,Aoutput wire [8:0] seg_led_2   //数码管2,MSB~LSB = SEG,DP,G,F,E,D,C,B,A);reg[8:0] seg [15:0];           //存储7段数码管译码数据initial beginseg[0] = 9'h3f;   //  0seg[1] = 9'h06;   //  1seg[2] = 9'h5b;   //  2seg[3] = 9'h4f;   //  3seg[4] = 9'h66;   //  4seg[5] = 9'h6d;   //  5seg[6] = 9'h7d;   //  6seg[7] = 9'h07;   //  7seg[8] = 9'h7f;   //  8seg[9] = 9'h6f;   //  9seg[10]= 9'h77;   //  Aseg[11]= 9'h7C;   //  bseg[12]= 9'h39;   //  Cseg[13]= 9'h5e;   //  dseg[14]= 9'h79;   //  Eseg[15]= 9'h71;   //  Fendassign seg_led_1 = seg[seg_data_1];assign seg_led_2 = seg[seg_data_2];endmodule

(3) 按键消抖:debounce.v

module debounce
(input      clk   ,			//时钟input      rst_n ,			//复位键input      key_in,			//对应楼层信号output reg clk_500hz,		//分频出的500Hz时钟脉冲信号(该板使用的是12M晶振)output     key_done		//按键按下动作完成标志
);
reg [25:0]div_cnt;			//分频计数器always@(posedge clk or negedge rst_n)begin	//获得500Hz时钟脉冲信号if(!rst_n)begindiv_cnt <= 0;clk_500hz <= 0;endelse if(div_cnt == 1999)begin			//计数两千次反转状态div_cnt <= 0;clk_500hz <= ~clk_500hz;endelse begindiv_cnt <= div_cnt + 1'b1;clk_500hz <= clk_500hz;endendreg qout;
reg key_tmp1,key_tmp2;
parameter n = 10;
reg [25:0] cnt;always@(posedge clk_500hz or negedge rst_n) beginif(!rst_n) begincnt <= 0;qout <= 0;end	  else if(key_in==0) begin	//按键按下if(cnt == n-1) begin		//持续2ms的话判定按下cnt <= cnt;qout <= 1;endelse begincnt <= cnt+1;qout <= 0;endendelse beginqout <= 0;cnt <= 0;endend	//提取前后按键信号
always@(posedge clk_500hz or negedge rst_n) beginif(!rst_n) beginkey_tmp1 <= 0;key_tmp2 <= 0;endelse beginkey_tmp1 <= qout;key_tmp2 <= key_tmp1;end	  endassign key_done = key_tmp1 & (~ key_tmp2);	endmodule 

2. 流水灯模块

(1) 流水灯:flashled.v

module flashled (clk,rst,led,sw);input clk,rst;	input sw;	//控制正反转output [7:0] led;				reg   [2:0] cnt ;                               //定义了一个3位的计数器,输出可以作为3-8译码器的输入wire clk1h;                                     //定义一个中间变量,表示分频得到的时钟,用作计数器的触发        //例化module decode38,相当于调用decode38 u1 (                                   .sw(cnt),                       //例化的输入端口连接到cnt,输出端口连接到led  .led(led));//例化分频器模块,产生一个1Hz时钟信号		divide #(.WIDTH(32),.N(12000000)) u2 (         //传递参数.clk(clk),.rst_n(rst),                   //例化的端口信号都连接到定义好的信号.clkout(clk1h));                             //1Hz时钟上升沿触发计数器,循环计数		always @(posedge clk1h or negedge rst)if (!rst)cnt <= 0;elseif(sw == 1'b0)cnt <= cnt +1;	//向下流水,模拟下降elsecnt <= cnt -1;	//向上流水,模拟上升endmodule

(2) 分频器:divide.v

 module divide (clk,rst_n,clkout);input 	clk,rst_n;                       //输入信号,其中clk连接到FPGA的C1脚,频率为12MHzoutput	clkout;                          //输出信号,可以连接到LED观察分频的时钟//parameter是verilog里常数语句parameter	WIDTH	= 3;             //计数器的位数,计数的最大值为 2**WIDTH-1parameter	N	= 5;             //分频系数,请确保 N < 2**WIDTH-1,否则计数会溢出reg 	[WIDTH-1:0]	cnt_p,cnt_n;     //cnt_p为上升沿触发时的计数器,cnt_n为下降沿触发时的计数器reg			clk_p,clk_n;     //clk_p为上升沿触发时分频时钟,clk_n为下降沿触发时分频时钟//上升沿触发时计数器的控制always @ (posedge clk or negedge rst_n )         //posedge和negedge是verilog表示信号上升沿和下降沿//当clk上升沿来临或者rst_n变低的时候执行一次always里的语句beginif(!rst_n)cnt_p<=0;else if (cnt_p==(N-1))cnt_p<=0;else cnt_p<=cnt_p+1;             //计数器一直计数,当计数到N-1的时候清零,这是一个模N的计数器end//上升沿触发的分频时钟输出,如果N为奇数得到的时钟占空比不是50%;如果N为偶数得到的时钟占空比为50%always @ (posedge clk or negedge rst_n)beginif(!rst_n)clk_p<=0;else if (cnt_p<(N>>1))          //N>>1表示右移一位,相当于除以2去掉余数clk_p<=0;else clk_p<=1;               //得到的分频时钟正周期比负周期多一个clk时钟end//下降沿触发时计数器的控制        	always @ (negedge clk or negedge rst_n)beginif(!rst_n)cnt_n<=0;else if (cnt_n==(N-1))cnt_n<=0;else cnt_n<=cnt_n+1;end//下降沿触发的分频时钟输出,和clk_p相差半个时钟always @ (negedge clk)beginif(!rst_n)clk_n<=0;else if (cnt_n<(N>>1))  clk_n<=0;else clk_n<=1;                //得到的分频时钟正周期比负周期多一个clk时钟endassign clkout = (N==1)?clk:(N[0])?(clk_p&clk_n):clk_p;      //条件判断表达式//当N=1时,直接输出clk//当N为偶数也就是N的最低位为0,N(0)=0,输出clk_p//当N为奇数也就是N最低位为1,N(0)=1,输出clk_p&clk_n。正周期多所以是相与
endmodule     

(3) 38译码器:decode38.v

module decode38 (sw,led);input  [2:0] sw;							//开关输入信号,利用了其中3个开关作为3-8译码器的输入output [7:0] led;						//输出信号控制特定LEDreg [7:0] led;                                                  //定义led为reg型变量,在always过程块中只能对reg型变量赋值//always过程块,括号中sw为敏感变量,当sw变化一次执行一次always中所有语句,否则保持不变always @ (sw)begincase(sw)                                                   //case语句,一定要跟default语句3'b000:	led=8'b0111_1111;                         //条件跳转,其中“_”下划线只是为了阅读方便,无实际意义  3'b001:	led=8'b1011_1111;                         //位宽'进制+数值是Verilog里常数的表达方法,进制可以是b、o、d、h(二、八、十、十六进制)3'b010:	led=8'b1101_1111;3'b011:	led=8'b1110_1111;3'b100:	led=8'b1111_0111;3'b101:	led=8'b1111_1011;3'b110:  led=8'b1111_1101;3'b111:	led=8'b1111_1110;default: ;endcaseendendmodule

3. 管脚配置 

        作者使用的板子是“10M02SCM153C8G”核心板,用其他板子的话就换对应的管脚就行。其中sw键是拨码开关,floor_signal和rst键是按键,led[i]是led灯,clk是时钟,segment是数码管。

 4. 可优化

        显然,这是一个很简陋的显示系统。按照最终设想,设计出来的一个项目应该包含完整的电梯操作,包含内外两面显示:1.对于外显示,应该可以预设人所在楼层,让电梯显示逐层变化到指定楼层;2.对于内显示,应该可以设置想去的任何楼层,确定后让电梯显示逐层变化到指定楼层。这个功能其实也不难,添加一个变量用于存储即可,在加个时钟用于自动变化。但是作者手上的板子不具有输入功能(很麻烦,需要一下一下按),加之只是心血来潮帮室友做个期末大作业,所以只完成了基本要求。可能哪一天有兴趣了再来完善。

        可以参考这个:使用Verilog实现FPGA双列电梯控制系统-阿里云开发者社区

后记

        相比于第一次设计篮球比赛计分器,这次设计就要熟练的多,整体设计过程大约1h。之所以这一次开发能这么快,得益于分模块开发的思想。稍加注意即可发现,这一项目中的数码管驱动,按键消抖,分频器和38译码器都是现成的。其中流水灯模块稍加修改了一下,添加的正反装的功能。

        所以说啊,电子这东西,入门难,但是入门之后很多东西都是相通的,稍加举一反三便可达到目的。最后提一嘴题外话,良好的开发习惯真的很造福开发过程,再接再厉。

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

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

相关文章

智能优化算法应用:基于纵横交叉算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于纵横交叉算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于纵横交叉算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.纵横交叉算法4.实验参数设定5.算法结果6.…

人工智能中的核心概念

1 概述 人工智能英文缩写为AI&#xff0c;是一种由人制造出来的机器&#xff0c;该机器可以模仿人的思想和行为&#xff0c;从而体现出一种智能的反应。 人工智能的产业链分为基础层、技术层、应用层三个层次。 基础层包括&#xff1a;芯片、大数据、算法系统、网络等多项基础…

【Gradle】创建第一个项目

文章目录 1. 前提2. 创建项目并初始化1&#xff09;创建项目2&#xff09;初始化项目 3. 介绍生成的文件结构4. 执行5. 包的作成 &#xff08;非必须&#xff09;6. 推送&#xff08;非必须&#xff09; 本节将继 Gradle 之初体验 安装之后&#xff0c;创建第一个 Hello World…

C++计算(a+b)*(c-b)的值 2023年9月c++一级 电子学会中小学生软件编程C++等级考试一级真题答案解析

目录 C计算(ab)*(c-b)的值 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 C计算(ab)*(c-b)的值 2023年9月 C编程等级考试一级编程题 一、题目要求 1、编程实现 给定3个整数a、b、c&#xff0c;计算表达…

[Android] ubuntu虚拟机上搭建 Waydroid 环境

1.安装虚拟机 略 2.安装waydroid Ubuntu/Debian and derivatives For Droidian and Ubuntu Touch, skip directly to the last step Install pre-requisites sudo apt install curl ca-certificates -y Add the official repository curl https://repo.waydro.id | sudo…

晚期食管癌肿瘤治疗线程分类

文章目录 1、肿瘤治疗的线数1.1 基础概念1.2 线程定义1.3 如何计算治疗线数 2 食管癌治疗指南2.1 食管癌诊疗指南2.1 CSCO 本文前半部分主要来源于参考文件1&#xff0c;其余部分来源于官方指南。无原创内容&#xff0c;全部为摘要。 1、肿瘤治疗的线数 1.1 基础概念 抗肿瘤药…

3 - Electron BrowserWindow对象 关于窗口

优雅的打开应用~ 当加载缓慢&#xff0c;打开应用的一瞬间会出现白屏&#xff0c;以下方法可以解决 const mainWindow new BrowserWindow({ show: false }) mainWindow.once(ready-to-show, () > {mainWindow.show() }) 设置背景颜色 const win new BrowserWindow({ b…

GZ015 机器人系统集成应用技术样题5-学生赛

2023年全国职业院校技能大赛 高职组“机器人系统集成应用技术”赛项 竞赛任务书&#xff08;学生赛&#xff09; 样题5 选手须知&#xff1a; 本任务书共 24页&#xff0c;如出现任务书缺页、字迹不清等问题&#xff0c;请及时向裁判示意&#xff0c;并进行任务书的更换。参赛队…

剑指 Offer(第2版)面试题 36:二叉搜索树与双向链表

剑指 Offer&#xff08;第2版&#xff09;面试题 36&#xff1a;二叉搜索树与双向链表 剑指 Offer&#xff08;第2版&#xff09;面试题 36&#xff1a;二叉搜索树与双向链表解法1&#xff1a;中序遍历 - 递归解法2&#xff1a;中序遍历 - 迭代 剑指 Offer&#xff08;第2版&am…

信息收集 - 域名

1、Whois查询: Whois 是一个用来查询域名是否已经被注册以及相关详细信息的数据库(如:域名所有人、域名注册商、域名注册日期和过期日期等)。通过访问 Whois 服务器,你可以查询域名的归属者联系方式和注册时间。 你可以在 域名Whois查询 - 站长之家 上进行在线查询。 2、…

【CMU 15-445】Lecture 12: Query Execution I 学习笔记

Query Execution I Processing ModelsIterator ModelMaterialization ModelVectorization Model Access MethodsSequential ScanIndex Scan Modification QueriesHalloween Problem 本节课主要介绍SQL语句执行的相关机制。 Processing Models 首先是处理模型&#xff0c;它定义…

基于JAVA+SpringBoot+Vue的前后端分离的学校请假管理系统

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 系统分为四个角色&…

机器学习 | 决策树 Decision Tree

—— 分而治之&#xff0c;逐个击破 把特征空间划分区域 每个区域拟合简单模型 分级分类决策 1、核心思想和原理 举例&#xff1a; 特征选择、节点分类、阈值确定 2、信息嫡 熵本身代表不确定性&#xff0c;是不确定性的一种度量。 熵越大&#xff0c;不确定性越高&#xff0c;…

MIT6.S081-实验准备

实验全程在Vmware虚拟机 (镜像&#xff1a;Ubuntu-20.04-beta-desktop-amd64) 中进行 一、版本控制 1.1 将mit的实验代码克隆到本地 git clone git://g.csail.mit.edu/xv6-labs-2020 1.2 修改本地git配置文件 创建github仓库&#xff0c;记录仓库地址 我的仓库地址就是htt…

C# 基本桌面编程(二)

一、前言 本章为C# 基本桌面编程技术的第二节也是最后一节。前一节在下面这个链接 C# 基本桌面编程&#xff08;一&#xff09;https://blog.csdn.net/qq_71897293/article/details/135024535?spm1001.2014.3001.5502 二、控件布局 1 叠放顺序 在WPF当中布局&#xff0c;通…

饥荒Mod 开发(十):制作一把AOE武器

饥荒Mod 开发(九)&#xff1a;物品栏排列 饥荒Mod 开发(十一)&#xff1a;修改物品堆叠 前面的文章介绍了很多基础知识以及如何制作一个物品&#xff0c;这次制作一把武器&#xff0c;装备之后可以用来攻击怪物。 制作武器贴图和动画 1.1 制作贴图。 先准备一张武器的贴图&a…

解决:AttributeError: module ‘scipy.misc’ has no attribute ‘imsave’

解决&#xff1a;AttributeError: module ‘scipy.misc’ has no attribute ‘imsave’ 文章目录 解决&#xff1a;AttributeError: module scipy.misc has no attribute imsave背景报错问题报错翻译报错位置代码报错原因解决方法方法一 scipy版本回退&#xff08;不推荐&#…

鸿蒙4.0核心技术-WebGL开发

场景介绍 WebGL主要帮助开发者在前端开发中完成图形图像的相关处理&#xff0c;比如绘制彩色图形等。 接口说明 表1 WebGL主要接口列表 接口名描述canvas.getContext获取canvas对象上下文。webgl.createBuffer(): WebGLBuffernullwebgl.bindBuffer(target: GLenum, buffer: …

饥荒Mod 开发(十三):木牌传送

饥荒Mod 开发(十二)&#xff1a;一键制作 饥荒Mod 开发(十四)&#xff1a;制作屏幕弹窗 一键传送源码 饥荒的地图很大&#xff0c;跑地图太耗费时间和饥饿值&#xff0c;如果大部分时间都在跑图真的是很无聊&#xff0c;所以需要有一个能够传送的功能&#xff0c;不仅可以快速…

Web前端-JavaScript(js表达式)

文章目录 JavaScript基础第01天1.编程语言概述1.1 编程1.2 计算机语言1.2.1 机器语言1.2.2 汇编语言1.2.3 高级语言 1.4 翻译器 2.计算机基础2.1 计算机组成2.2 数据存储2.3 数据存储单位2.4 程序运行 3.初始JavaScript3.1 JavaScript 是什么3.2 JavaScript的作用3.3 HTML/CSS/…