项目三 电梯控制器设计(FPGA综合应用设计)

这篇具有很好参考价值的文章主要介绍了项目三 电梯控制器设计(FPGA综合应用设计)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

(一个很简陋的电梯控制器设计,但是应该可以过关了吧?😶‍🌫️)

实验目的

通过实验,巩固有限状态机设计方法,并设计实现一个电梯控制器。

实验内容

利用 BASYS 开发板资源设计一个 5 层楼的电梯控制器系统,并能在开发板上
模拟电梯运行状态,具体要求如下:

  1. 利用开发板的 5 个按键作为电梯控制器的呼叫按钮;
  2. 利用 led 灯分别显示楼层 1~5 的呼梯状态;
  3. 利用数码管显示电梯运行时电梯所在楼层;
  4. 利用时钟分频设计电梯控制器控制电梯每秒运行一层。

实验方法及原理介绍

  1. 电梯控制器系统控制流程图(电梯厢内视角)
    电梯控制器设计,vivado实验,fpga开发,单片机,嵌入式硬件

  2. 系统输入/输出变量
    对于一个系统,首先需要一个时钟输入,设为 clk;按键输入,设为btn;数码管显示输出设为 seg;叫梯楼层状态灯输出,设为 nfloor。

  3. 按键设计

  • 本实验使用板上 5 个按键按钮模拟电梯的叫梯按键,1 层按键为 BTNU,2 层按键为 BTNL,3 层按键为 BTNC,4 层按键为 BTNR,5 层按键为 BTND。所以,定义一个 5 位按键寄存器 btn_pre_re,同时考虑到防抖(按键按下去和松开会产生抖动现象会影响到我们的操作),在对按键寄存器进行赋值的时候要注意时间延时。
  • 对于电梯按键,当没有叫梯时,按键相应的 LED 指示灯应处于熄灭状态;当有叫梯时,按键相应的 LED 指示灯应处于点亮状态;当在某一层已经叫梯,但是由于某种原因发现所叫梯不是自己想要的梯层时,能够取消此层的叫梯状态。
  • 防抖设计为每 200ms 读取一次叫梯按键信息,因此需要生成一个周期为 200ms 的时钟信号,程序代码如下:
parameter N=99_999999;
always@(posedge clk)
    begin
        clk_200ms<=0;
        if(count<N/5)
			count<=count+1;
		else 
		begin
			count<=0;
			clk_200ms<=1;
		end
	end
  • 叫梯按键赋值程序如下:
reg [4:0]btn_pre_re,btn_off;
always@(posedge clk_200ms)
	begin
		btn_pre_re=btn_pre_re^btn;
		btn_pre_re=btn_pre_re&btn_off;
	end
  • 需要注意的是,重复进行叫梯按键操作,可以进行叫梯或取消叫梯服务,因此使用了一个异或代码(请自行画出电路图)。
  1. 显示设计

电梯控制器包括两种显示,即数码管显示电梯所在楼层和 LED 灯显示所叫楼层服务。

下面给出完整的代码实现:

scan_led_hex_disp模板:

实现“电梯控制器包括两种显示,即数码管显示电梯所在楼层和 LED 灯显示所叫楼层服务”。

`timescale 1ns / 1ps

module scan_led_hex_disp(clk,reset,btn,an,sseg,current_floor,Floor_call_state_output);
    	parameter       n  =  5;  
        input clk;
    input reset;
    input [n-1:0] btn; //第一个数码管显示的数字:电梯叫梯楼层

    //input [3:0] dp_in, //小数点控制
    output reg [3:0] an;   //片选,使能端
    output reg [7:0] sseg; //段选

    output [n-1:0] current_floor;
     output  [n-1:0]   Floor_call_state_output;       //第一个数码管显示的数字:电梯所在楼层
     wire stop;

	localparam N = 18; //使用低16位对50Mhz的时钟进行分频(50MHZ/2^16)
	reg [N-1:0] regN; //高两位作为控制信号,低16位为计数器,对时钟进行分频
	reg [n-1:0] hex_in; //段选控制信号
	
    always@(posedge clk, posedge reset)
	begin
		if(reset)
			regN <= 0;
		else
			regN <= regN + 1;
	end
	
	reg dp; 
debounce_button u2(.clk(clk),.rst(reset),.key(btn),.key_pulse(),.current_floor(current_floor),.Floor_call_state_output(Floor_call_state_output),.stop(stop));

	always@ *
	begin
		case(regN[N-1:N-2])
		2'b00:begin
			an = 4'b0111; //选中第1个数码管
			hex_in = current_floor; //数码管显示的数字由hex_in控制,显示current_floor:电梯所在楼层
			dp = ~stop; //控制该数码管的小数点的亮灭
		end
		2'b01:begin
			an = 4'b0111; //选中第二个数码管
			hex_in = current_floor;//数码管显示的数字由hex_in控制,显示current_floor;电梯所在楼层
			dp = ~stop;
		end
		2'b10:begin
			an = 4'b1110;//选中第三个数码管
			hex_in = Floor_call_state_output;//数码管显示的数字由hex_in控制,显示Floor_call_state_output,也就是电梯叫梯的楼层;
			dp = 1;
		end
		default:begin
			an = 4'b1110;//选中第四个数码管
			hex_in =  Floor_call_state_output;//数码管显示的数字由hex_in控制,显示Floor_call_state_output,也就是电梯叫梯的楼层;
			dp = 1;
		end
		
		endcase
	
	end
	always@ *
	begin
		case(hex_in)
			5'b00000: sseg[6:0] = 7'b0000001;   //共阳极数码管
			5'b00001: sseg[6:0] = 7'b1001111;
			5'b00010: sseg[6:0] = 7'b0010010;
			5'b00100: sseg[6:0] = 7'b0000110;
			5'b01000: sseg[6:0] = 7'b1001100;
			5'b10000: sseg[6:0] = 7'b0100100;
			default: sseg[6:0] = 7'b1111111;
		endcase
		    sseg[7] = dp;   //控制小数点,小数点亮,代表电梯停止移动了;不亮,则是电梯上移动或者下移
	end
endmodule

debounce_button模板:

实现“按键消抖”。
本实验使用板上 5 个按键按钮模拟电梯的叫梯按键,1 层按键为 BTNU2 层按键为 BTNL3 层按键为 BTNC4 层按键为 BTNR5 层按键为 BTND。所以,定义一个 5 位按键寄存器 key_pulse,同时考虑到防抖(按键按下去和松开会产生抖动现象会影响到我们的操作),在对按键寄存器进行赋值的时候要注意时间延时。
最后,实现了“对于电梯按键,当没有叫梯时,按键相应的 LED 指示灯应处于熄灭状态;当有叫梯时,按键相应的 LED 指示灯应处于点亮状态;当在某一层已经叫梯,但是由于某种原因发现所叫梯不是自己想要的梯层时,能够取消此层的叫梯状态”。

`timescale 1ns / 1ps


module debounce_button (clk,rst,key,key_pulse,current_floor,Floor_call_state_output,stop);
 
        parameter       N  =  5;                      //要消除的按键的数量
 
	input             clk;
        input             rst;
        input 	[N-1:0]   key;                        //输入的按键					
	output  [N-1:0]   key_pulse;                  //按键动作产生的脉冲	
	       output [N-1:0]   current_floor;
	    output  [N-1:0]   Floor_call_state_output; 
	      output stop;
	

	reg [N-1:0]   key_pulse;  
 
        reg     [N-1:0]   key_rst_pre;                //定义一个寄存器型变量存储上一个触发时的按键值
        reg     [N-1:0]   key_rst;                    //定义一个寄存器变量储存储当前时刻触发的按键值
 
        wire    [N-1:0]   key_edge;                   //检测到按键由高到低变化是产生一个高脉冲
 
        //利用非阻塞赋值特点,将两个时钟触发时按键状态存储在两个寄存器变量中
        always @(posedge clk  or  negedge rst)
          begin
             if (rst) begin
                 key_rst <= {N{1'b1}};                //初始化时给key_rst赋值全为1,{}中表示N个1
                 key_rst_pre <= {N{1'b1}};
             end
             else begin
                 key_rst <= key;                     //第一个时钟上升沿触发之后key的值赋给key_rst,同时key_rst的值赋给key_rst_pre
                 key_rst_pre <= key_rst;             //非阻塞赋值。相当于经过两个时钟触发,key_rst存储的是当前时刻key的值,key_rst_pre存储的是前一个时钟的key的值
             end    
           end
 
        assign  key_edge = key_rst_pre & (~key_rst);//脉冲边沿检测。当key检测到下降沿时,key_edge产生一个时钟周期的高电平
 
        reg	[17:0]	  cnt;                       //产生延时所用的计数器,系统时钟12MHz,要延时20ms左右时间,至少需要18位计数器     
 
        //产生20ms延时,当检测到key_edge有效是计数器清零开始计数
        always @(posedge clk or negedge rst)
           begin
             if(rst)
                cnt <= 18'h0;
             else if(key_edge)
                cnt <= 18'h0;
             else
                cnt <= cnt + 1'h1;
             end  
 
        reg     [N-1:0]   key_sec_pre;                //延时后检测电平寄存器变量
        reg     [N-1:0]   key_sec;                    
 
 
        //延时后检测key,如果按键状态变低产生一个时钟的高脉冲。如果按键状态是高的话说明按键无效
        always @(posedge clk  or  negedge rst)
          begin
             if (rst) 
                 key_sec <= {N{1'b1}};                
             else if (cnt==18'h3ffff)
                 key_sec <= key;  
          end
       always @(posedge clk  or  negedge rst)
          begin
             if (rst)
                 key_sec_pre <= {N{1'b1}};
             else                   
                 key_sec_pre <= key_sec;             
         end      
       
       always @(posedge clk  or  negedge rst)
          begin
             if (rst)
                 key_pulse <= {N{1'b0}};
             else 
                 begin                                
       /*按键被按下后,存在一个时钟周期:key_sec_pre[x]=1和key_sec[x]=0。这时,key_pulse[x]<= ~key_pulse[x],反转一下。
                      实现要求中的“重复进行叫梯按键操作,可以进行叫梯或取消叫梯服务” */                  
                 if(~key_sec_pre[4] & key_sec[4])                 
                 key_pulse[4] <= ~key_pulse[4];    
                 if(~key_sec_pre[3] & key_sec[3])                  
                 key_pulse[3] <= ~key_pulse[3];   
                 if(~key_sec_pre[2] & key_sec[2])                  
                 key_pulse[2] <= ~key_pulse[2];    
                 if(~key_sec_pre[1] & key_sec[1])                  
                 key_pulse[1] <= ~key_pulse[1];  
                 if(~key_sec_pre[0] & key_sec[0])                  
                 key_pulse[0] <= ~key_pulse[0];
                 end  
         end  
       

       Elevator u1(
.clk(clk), .rst(rst),.Floor_call_state(key_pulse),.current_floor(current_floor),.Floor_call_state_output(Floor_call_state_output),.stop(stop)
    );
 
endmodule

Elevator模板:

实现“利用时钟分频设计电梯控制器控制电梯每秒运行一层”。

`timescale 1ns / 1ps

module Elevator(
clk, rst,Floor_call_state,current_floor,Floor_call_state_output,stop
    );
      	input             clk;
        input              rst;
        input 	 [4:0]   Floor_call_state;        //输入的按键	
        output reg [4:0]   current_floor;
        output reg [4:0]   Floor_call_state_output; 
        output reg stop;
        
        integer k;
        reg [30:0] cnt=30'b0;
        parameter M=100000000;             //1s=1000000000ns
        reg clk_out=0;
        
        initial begin
             stop=1;
             Floor_call_state_output=5'b00001;
             current_floor=5'b00001;
        end
        
       //时钟分频器:每过1s,clk_out=~clk_out。实现“每一秒钟,电梯移动一层”。
        always @(posedge clk)                
            begin
                if(rst)
                    begin
                        clk_out=0;
                    end
               //从0开始计时的,所以cnt==M-1,一个循环是 1s
                if (cnt==M-1)                   
                    begin
                        clk_out=~clk_out;
                        cnt=0;
                    end
                else 
                    begin
                        clk_out=0;             //每次重新开始,都使  clk_out=0。好在cnt==M-1时,clk_out=~clk_out,产生clk_out的上升沿,
                        cnt=cnt+1'd1;
                    end
            end
            
 //当Floor_call_state发证变化,或者rst发生变化时,将Floor_call_state赋给Floor_call_state_output。
       always @(*/*Floor_call_state,rst,current_floor,Floor_call_state_output*/)    
            begin
                 if(rst)
                     begin
                         Floor_call_state_output=5'b00001;
                     end
                 else
                     begin
                         Floor_call_state_output=Floor_call_state;
                     end
            end
              
        
       always @(posedge clk_out or posedge rst)
           begin
               if(rst)
                   begin
                       stop=1;
                       current_floor=5'b00001;
                   end
               else if(Floor_call_state_output!=5'b00000)
                   begin
                       stop=0;
                       if(current_floor<Floor_call_state_output)               //电梯所在楼层 低于 叫梯,就上升
                           current_floor={current_floor[3:0],current_floor[4]};
                       else if(current_floor>Floor_call_state_output)         //电梯所在楼层 高于 叫梯,就下降
                           current_floor={current_floor[0],current_floor[4:1]};
                       else
                           stop=1;
                   end
               else
                   begin
                       stop=1;
                   end
           end
           
endmodule

引脚分配文件:

set_property IOSTANDARD LVCMOS33 [get_ports {an[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {an[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {an[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {an[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {Floor_call_state_output[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {Floor_call_state_output[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {Floor_call_state_output[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {Floor_call_state_output[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {Floor_call_state_output[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {btn[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {btn[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {btn[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {btn[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {btn[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {current_floor[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {current_floor[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {current_floor[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {current_floor[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {current_floor[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sseg[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sseg[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sseg[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sseg[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sseg[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sseg[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sseg[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sseg[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports reset]
set_property PACKAGE_PIN W4 [get_ports {an[3]}]
set_property PACKAGE_PIN V4 [get_ports {an[2]}]
set_property PACKAGE_PIN U4 [get_ports {an[1]}]
set_property PACKAGE_PIN U2 [get_ports {an[0]}]
set_property package_pin W18 [get_ports {Floor_call_state_output[4]}]
set_property PACKAGE_PIN U17 [get_ports {btn[4]}]
set_property package_pin V19 [get_ports {Floor_call_state_output[3]}]
set_property PACKAGE_PIN T17 [get_ports {btn[3]}]
set_property package_pin U19 [get_ports {Floor_call_state_output[2]}]
set_property PACKAGE_PIN U18 [get_ports {btn[2]}]
set_property package_pin E19 [get_ports {Floor_call_state_output[1]}]
set_property PACKAGE_PIN W19 [get_ports {btn[1]}]
set_property package_pin U16 [get_ports {Floor_call_state_output[0]}]
set_property PACKAGE_PIN T18 [get_ports {btn[0]}]
set_property PACKAGE_PIN U3 [get_ports {current_floor[0]}]
set_property PACKAGE_PIN P3 [get_ports {current_floor[1]}]
set_property PACKAGE_PIN N3 [get_ports {current_floor[2]}]
set_property PACKAGE_PIN P1 [get_ports {current_floor[3]}]
set_property PACKAGE_PIN L1 [get_ports {current_floor[4]}]
set_property PACKAGE_PIN W7 [get_ports {sseg[6]}]
set_property PACKAGE_PIN W6 [get_ports {sseg[5]}]
set_property PACKAGE_PIN U8 [get_ports {sseg[4]}]
set_property PACKAGE_PIN V8 [get_ports {sseg[3]}]
set_property PACKAGE_PIN U5 [get_ports {sseg[2]}]
set_property PACKAGE_PIN V5 [get_ports {sseg[1]}]
set_property PACKAGE_PIN U7 [get_ports {sseg[0]}]
set_property PACKAGE_PIN V7 [get_ports {sseg[7]}]
set_property PACKAGE_PIN W5 [get_ports clk]
set_property PACKAGE_PIN R2 [get_ports reset]
  • 上板子的逻辑可以这么想:最初电梯在1楼,叫梯为0楼(不叫梯);然后按下叫梯的楼层“2楼”,(2-1)s后,电梯运行到2楼,自动开门上人,然后再按下“2楼”,关门;接下来再按下想要去的楼层,重复以上操作。
  • 左边的七段数码管显示当前电梯所在楼层。
  • 右边的七段数码管显示当前叫梯楼层。(当前的代码,只能一层一层的叫梯,即叫完一梯后,要再按一次该梯,取消当前叫梯后,才能叫下一梯

上板实验效果:

电梯控制器设计,vivado实验,fpga开发,单片机,嵌入式硬件
当按下“5楼”叫梯,5s后:
电梯控制器设计,vivado实验,fpga开发,单片机,嵌入式硬件文章来源地址https://www.toymoban.com/news/detail-776889.html

到了这里,关于项目三 电梯控制器设计(FPGA综合应用设计)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于FPGA的PID控制器设计

    PID控制应该算是应用非常广泛的控制算法了。常见的比如控制环境温度,控制无人机飞行高度速度等。PID我们将其分成三个参数,如下: P-比例控制,基本作用就是控制对象以线性的方式增加,在一个常量比例下,动态输出,缺点是会产生一个稳态误差。 I-积分控制,基本作

    2024年02月03日
    浏览(59)
  • FPGA实验四:交通灯控制器设计

    目录 一、实验目的 二、设计要求 三、实验代码 1.design source文件代码

    2024年02月13日
    浏览(52)
  • FPGA智能交通灯控制器系统系统设计

    把由5OM的有源晶振产生的现场可编程逻辑器件FPGA 的系统时钟输入到分频模块,经分频模块分频产生频率为1Hz的时钟脉冲,作为控制定时模块、控制模块、紧急模块、计数模块的时钟信号,然后再由定时模块来控制紧急模块和控制模块,按照交通管理规则控制交通工作状态的

    2024年02月04日
    浏览(49)
  • VIVADO三层电梯控制器VHDL代码ego1开发板

    名称:VIVADO三层电梯控制器VHDL代码ego1开发板 软件:VIVADO 语言:VHDL 代码功能: 3层电梯控制 (1)电梯运行规则:当电梯处于上升模式时,只响应比电梯所在位置高的上楼请求信号,由下而上逐个执行,直到最后一个上楼请求执行完毕;如果高层有下楼请求,则直接升到由下

    2024年02月04日
    浏览(48)
  • 基于 STM32+FPGA 的多轴运动控制器的设计

    运动控制器是数控机床 、 高端机器人等自动化设备控制系统的核心 。 为保证控制器的实用性 、 实时性和稳定 性, 提出一种以 STM32 为主控制器 、 FPGA 为辅助控制器的多轴运动控制器设计方案 。 给出了运动控制器的硬件电路设计 , 将 S 形加减速算法融入运动控制器 ,

    2024年01月17日
    浏览(77)
  • 基于 RK3399+fpga 的 VME 总线控制器设计(一)总体设计

    2.1 需求分析及技术指标 2.1.1 需求分析 VME 总线控制器需要实现数据传输、中断处理、测量显示等功能。同时还需 要具有操作系统、底层驱动程序以及功能接口等,以方便用户进行上层应用软件开 发及使用。 本课题需要实现 VME 控制器的国产化开发,因此需要选择一款国产处

    2024年02月14日
    浏览(50)
  • 基于 RK3399+fpga 的 VME 总线控制器设计(二)硬件和FPGA逻辑设计

    3.2 FPGA 最小系统设计 FPGA 最小系统是指可以使 FPGA 正常工作的最基本的系统,主要包括电源电 路、配置电路、时钟和复位电路。本次设计使用的 FPGA 为紫光同创的 PG2L100H, 接下来具体介绍 FPGA 最小系统各个部分的电路设计。 ( 1 )电源电路设计 FPGA 所需要的电源电压有 3.3V

    2024年02月12日
    浏览(50)
  • 基于 STM32+FPGA 的通用工业控制器设计(一)系统方案设计

    本章首先介绍了现有 PLC 系统的概况,然后提出了本文设计的通用工业控制器的 整体方案架构,分析了硬件和软件上需要实现的功能,最后对各部分功能进行分析并提 出具体的实现方案。 2.1 PLC 系统简介 可编程逻辑控制器( Programmable Logic Controller , PLC )是以微处理器为基

    2024年02月15日
    浏览(66)
  • 基于ARM+FPGA的驱控一体机器人控制器设计

    目前市场上工业机器人,数控机床等多轴运动控制系统普遍采用运动控制器加 伺服驱动器的分布式控制方式。在这种控制方式中,控制器一方面完成人机交互,另 一方面进行 NC 代码的解释执行,插补运算,继而将计算出来的位置指令通过轴组模 块下发给各个伺服驱动器。下

    2024年02月14日
    浏览(52)
  • ZYNQ ARM+FPGA双目立体视觉控制器设计与实现(一)

    通过 ZYNQ 板卡实现 FPGA+ARM 架构的双目立体视觉系统 本设计采用实验室自主开发的 Zynq-7020 板卡,提出了基于 FPGA+ARM 架构的双 目立体视觉的软硬件系统设计方案。根据对系统软硬件功能划分, PL(FPGA) 端主要实现 了双目摄像头图像的采集存储和 HDMI 显示, PS(ARM) 端主要实现了

    2024年02月10日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包