(一個(gè)很簡陋的電梯控制器設(shè)計(jì),但是應(yīng)該可以過關(guān)了吧???????)
實(shí)驗(yàn)?zāi)康?/h2>
通過實(shí)驗(yàn),鞏固有限狀態(tài)機(jī)設(shè)計(jì)方法,并設(shè)計(jì)實(shí)現(xiàn)一個(gè)電梯控制器。
實(shí)驗(yàn)內(nèi)容
利用 BASYS 開發(fā)板資源設(shè)計(jì)一個(gè) 5 層樓的電梯控制器系統(tǒng),并能在開發(fā)板上
模擬電梯運(yùn)行狀態(tài),具體要求如下:
- 利用開發(fā)板的 5 個(gè)按鍵作為電梯控制器的呼叫按鈕;
- 利用 led 燈分別顯示樓層 1~5 的呼梯狀態(tài);
- 利用數(shù)碼管顯示電梯運(yùn)行時(shí)電梯所在樓層;
- 利用時(shí)鐘分頻設(shè)計(jì)電梯控制器控制電梯每秒運(yùn)行一層。
實(shí)驗(yàn)方法及原理介紹
-
電梯控制器系統(tǒng)控制流程圖(電梯廂內(nèi)視角)
-
系統(tǒng)輸入/輸出變量
對(duì)于一個(gè)系統(tǒng),首先需要一個(gè)時(shí)鐘輸入,設(shè)為 clk;按鍵輸入,設(shè)為btn;數(shù)碼管顯示輸出設(shè)為 seg;叫梯樓層狀態(tài)燈輸出,設(shè)為 nfloor。 -
按鍵設(shè)計(jì)
- 本實(shí)驗(yàn)使用板上 5 個(gè)按鍵按鈕模擬電梯的叫梯按鍵,1 層按鍵為 BTNU,2 層按鍵為 BTNL,3 層按鍵為 BTNC,4 層按鍵為 BTNR,5 層按鍵為 BTND。所以,定義一個(gè) 5 位按鍵寄存器 btn_pre_re,同時(shí)考慮到防抖(按鍵按下去和松開會(huì)產(chǎn)生抖動(dòng)現(xiàn)象會(huì)影響到我們的操作),在對(duì)按鍵寄存器進(jìn)行賦值的時(shí)候要注意時(shí)間延時(shí)。
- 對(duì)于電梯按鍵,當(dāng)沒有叫梯時(shí),按鍵相應(yīng)的 LED 指示燈應(yīng)處于熄滅狀態(tài);當(dāng)有叫梯時(shí),按鍵相應(yīng)的 LED 指示燈應(yīng)處于點(diǎn)亮狀態(tài);當(dāng)在某一層已經(jīng)叫梯,但是由于某種原因發(fā)現(xiàn)所叫梯不是自己想要的梯層時(shí),能夠取消此層的叫梯狀態(tài)。
- 防抖設(shè)計(jì)為每 200ms 讀取一次叫梯按鍵信息,因此需要生成一個(gè)周期為 200ms 的時(shí)鐘信號(hào),程序代碼如下:
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
- 需要注意的是,重復(fù)進(jìn)行叫梯按鍵操作,可以進(jìn)行叫梯或取消叫梯服務(wù),因此使用了一個(gè)異或代碼(請(qǐng)自行畫出電路圖)。
- 顯示設(shè)計(jì)
電梯控制器包括兩種顯示,即數(shù)碼管顯示電梯所在樓層和 LED 燈顯示所叫樓層服務(wù)。
下面給出完整的代碼實(shí)現(xiàn):
scan_led_hex_disp模板:
實(shí)現(xiàn)“電梯控制器包括兩種顯示,即數(shù)碼管顯示電梯所在樓層和 LED 燈顯示所叫樓層服務(wù)”。
`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; //第一個(gè)數(shù)碼管顯示的數(shù)字:電梯叫梯樓層
//input [3:0] dp_in, //小數(shù)點(diǎn)控制
output reg [3:0] an; //片選,使能端
output reg [7:0] sseg; //段選
output [n-1:0] current_floor;
output [n-1:0] Floor_call_state_output; //第一個(gè)數(shù)碼管顯示的數(shù)字:電梯所在樓層
wire stop;
localparam N = 18; //使用低16位對(duì)50Mhz的時(shí)鐘進(jìn)行分頻(50MHZ/2^16)
reg [N-1:0] regN; //高兩位作為控制信號(hào),低16位為計(jì)數(shù)器,對(duì)時(shí)鐘進(jìn)行分頻
reg [n-1:0] hex_in; //段選控制信號(hào)
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個(gè)數(shù)碼管
hex_in = current_floor; //數(shù)碼管顯示的數(shù)字由hex_in控制,顯示current_floor:電梯所在樓層
dp = ~stop; //控制該數(shù)碼管的小數(shù)點(diǎn)的亮滅
end
2'b01:begin
an = 4'b0111; //選中第二個(gè)數(shù)碼管
hex_in = current_floor;//數(shù)碼管顯示的數(shù)字由hex_in控制,顯示current_floor;電梯所在樓層
dp = ~stop;
end
2'b10:begin
an = 4'b1110;//選中第三個(gè)數(shù)碼管
hex_in = Floor_call_state_output;//數(shù)碼管顯示的數(shù)字由hex_in控制,顯示Floor_call_state_output,也就是電梯叫梯的樓層;
dp = 1;
end
default:begin
an = 4'b1110;//選中第四個(gè)數(shù)碼管
hex_in = Floor_call_state_output;//數(shù)碼管顯示的數(shù)字由hex_in控制,顯示Floor_call_state_output,也就是電梯叫梯的樓層;
dp = 1;
end
endcase
end
always@ *
begin
case(hex_in)
5'b00000: sseg[6:0] = 7'b0000001; //共陽極數(shù)碼管
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; //控制小數(shù)點(diǎn),小數(shù)點(diǎn)亮,代表電梯停止移動(dòng)了;不亮,則是電梯上移動(dòng)或者下移
end
endmodule
debounce_button模板:
實(shí)現(xiàn)“按鍵消抖”。
本實(shí)驗(yàn)使用板上 5 個(gè)按鍵按鈕模擬電梯的叫梯按鍵,1 層按鍵為 BTNU,2 層按鍵為 BTNL,3 層按鍵為 BTNC,4 層按鍵為 BTNR,5 層按鍵為 BTND。所以,定義一個(gè) 5 位按鍵寄存器 key_pulse,同時(shí)考慮到防抖(按鍵按下去和松開會(huì)產(chǎn)生抖動(dòng)現(xiàn)象會(huì)影響到我們的操作),在對(duì)按鍵寄存器進(jìn)行賦值的時(shí)候要注意時(shí)間延時(shí)。
最后,實(shí)現(xiàn)了“對(duì)于電梯按鍵,當(dāng)沒有叫梯時(shí),按鍵相應(yīng)的 LED 指示燈應(yīng)處于熄滅狀態(tài);當(dāng)有叫梯時(shí),按鍵相應(yīng)的 LED 指示燈應(yīng)處于點(diǎn)亮狀態(tài);當(dāng)在某一層已經(jīng)叫梯,但是由于某種原因發(fā)現(xiàn)所叫梯不是自己想要的梯層時(shí),能夠取消此層的叫梯狀態(tài)”。
`timescale 1ns / 1ps
module debounce_button (clk,rst,key,key_pulse,current_floor,Floor_call_state_output,stop);
parameter N = 5; //要消除的按鍵的數(shù)量
input clk;
input rst;
input [N-1:0] key; //輸入的按鍵
output [N-1:0] key_pulse; //按鍵動(dòng)作產(chǎn)生的脈沖
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; //定義一個(gè)寄存器型變量存儲(chǔ)上一個(gè)觸發(fā)時(shí)的按鍵值
reg [N-1:0] key_rst; //定義一個(gè)寄存器變量儲(chǔ)存儲(chǔ)當(dāng)前時(shí)刻觸發(fā)的按鍵值
wire [N-1:0] key_edge; //檢測到按鍵由高到低變化是產(chǎn)生一個(gè)高脈沖
//利用非阻塞賦值特點(diǎn),將兩個(gè)時(shí)鐘觸發(fā)時(shí)按鍵狀態(tài)存儲(chǔ)在兩個(gè)寄存器變量中
always @(posedge clk or negedge rst)
begin
if (rst) begin
key_rst <= {N{1'b1}}; //初始化時(shí)給key_rst賦值全為1,{}中表示N個(gè)1
key_rst_pre <= {N{1'b1}};
end
else begin
key_rst <= key; //第一個(gè)時(shí)鐘上升沿觸發(fā)之后key的值賦給key_rst,同時(shí)key_rst的值賦給key_rst_pre
key_rst_pre <= key_rst; //非阻塞賦值。相當(dāng)于經(jīng)過兩個(gè)時(shí)鐘觸發(fā),key_rst存儲(chǔ)的是當(dāng)前時(shí)刻key的值,key_rst_pre存儲(chǔ)的是前一個(gè)時(shí)鐘的key的值
end
end
assign key_edge = key_rst_pre & (~key_rst);//脈沖邊沿檢測。當(dāng)key檢測到下降沿時(shí),key_edge產(chǎn)生一個(gè)時(shí)鐘周期的高電平
reg [17:0] cnt; //產(chǎn)生延時(shí)所用的計(jì)數(shù)器,系統(tǒng)時(shí)鐘12MHz,要延時(shí)20ms左右時(shí)間,至少需要18位計(jì)數(shù)器
//產(chǎn)生20ms延時(shí),當(dāng)檢測到key_edge有效是計(jì)數(shù)器清零開始計(jì)數(shù)
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; //延時(shí)后檢測電平寄存器變量
reg [N-1:0] key_sec;
//延時(shí)后檢測key,如果按鍵狀態(tài)變低產(chǎn)生一個(gè)時(shí)鐘的高脈沖。如果按鍵狀態(tài)是高的話說明按鍵無效
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
/*按鍵被按下后,存在一個(gè)時(shí)鐘周期:key_sec_pre[x]=1和key_sec[x]=0。這時(shí),key_pulse[x]<= ~key_pulse[x],反轉(zhuǎn)一下。
實(shí)現(xiàn)要求中的“重復(fù)進(jìn)行叫梯按鍵操作,可以進(jìn)行叫梯或取消叫梯服務(wù)” */
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模板:
實(shí)現(xiàn)“利用時(shí)鐘分頻設(shè)計(jì)電梯控制器控制電梯每秒運(yùn)行一層”。文章來源:http://www.zghlxwxcb.cn/news/detail-776889.html
`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
//時(shí)鐘分頻器:每過1s,clk_out=~clk_out。實(shí)現(xiàn)“每一秒鐘,電梯移動(dòng)一層”。
always @(posedge clk)
begin
if(rst)
begin
clk_out=0;
end
//從0開始計(jì)時(shí)的,所以cnt==M-1,一個(gè)循環(huán)是 1s
if (cnt==M-1)
begin
clk_out=~clk_out;
cnt=0;
end
else
begin
clk_out=0; //每次重新開始,都使 clk_out=0。好在cnt==M-1時(shí),clk_out=~clk_out,產(chǎn)生clk_out的上升沿,
cnt=cnt+1'd1;
end
end
//當(dāng)Floor_call_state發(fā)證變化,或者rst發(fā)生變化時(shí),將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后,電梯運(yùn)行到2樓,自動(dòng)開門上人,然后再按下“2樓”,關(guān)門;接下來再按下想要去的樓層,重復(fù)以上操作。
- 左邊的七段數(shù)碼管顯示當(dāng)前電梯所在樓層。
- 右邊的七段數(shù)碼管顯示當(dāng)前叫梯樓層。(當(dāng)前的代碼,只能一層一層的叫梯,即叫完一梯后,要再按一次該梯,取消當(dāng)前叫梯后,才能叫下一梯)
上板實(shí)驗(yàn)效果:
當(dāng)按下“5樓”叫梯,5s后:文章來源地址http://www.zghlxwxcb.cn/news/detail-776889.html
到了這里,關(guān)于項(xiàng)目三 電梯控制器設(shè)計(jì)(FPGA綜合應(yīng)用設(shè)計(jì))的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!