實驗一:交通燈的設計及FPGA實作
作者: Saint
掘金:https://juejin.im/user/5aa1f89b6fb9a028bb18966a
微網誌:https://weibo.com/5458277467/profile?topnav=1&wvr=6&is_all=1
GitHub:github.com/saint-000
一、實驗目的:
熟練使用VHDL進行RTL級代碼的編寫;熟練運用EDA工具(modelsim、ISE)和 FPGA 開發闆,完成較複雜的系統設計;鍛煉系統級的設計能力及原型驗證能力。完成模拟交通燈的設計及 FPGA 實驗驗證。
二、實驗原理:
(1)交通信号燈的基本轉換原理
本實驗要求模拟的交通信号燈的轉換原理如下圖所示:
預設的初始狀态為紅燈狀态,做 30 秒減計時。當時間從 30 秒遞減到 0 秒後,紅燈狀态變為綠燈狀态;重新 30 秒減計時,遞減到 0 秒後,綠燈狀态變為黃燈狀态;做 5 秒減計時,遞減到 0 秒後,黃燈狀态變為紅燈狀态。如此循環進行轉換。
(2)共陽數位管
實驗主機闆上的 8 個數位管為共陽極型,即數位管的公共端接正極,顯示段碼信号接負極。8個數位管的顯示段碼信号複用,公共端則互相獨立。數位管和 LCD 子產品共用一組 IO 控制接口,使用者做這倆實驗時,注意數位管和 LCD 不要同時工作。通過數位管旁邊的J1 跳線控制。
(3)撥碼開關
實驗主機闆上設計了一組8位的撥碼開關,ON為低電平,OFF為高電平。撥碼開關可供使用者 輸入一些高低電平。
(4)LED燈電路(啟用需短接J4)
實驗主機闆上 LED 燈電路屬于闆内資源,要使用它,需把 J4 短接。LED 燈的陽極接電源, 陰級接 FPGA、CPLD 的 I/0 口,是以是低電平驅動,隻要由 FPGA、CPLD 在相應引腳給出 低電平,LED 就會發光。LED 燈電路原理圖如圖 1-6 所示,對應 FPGA 管腳如表 1-3 所示。
三、實驗器材(裝置、元器件):
計算機、FPGA 開發闆、開發闆附件
四、實驗内容:
編寫 VHDL 代碼、生成下載下傳檔案,下載下傳設計到 FPGA 實作如下功能:模拟路口交通信号燈的紅、黃、綠燈的變化過程,分别用三個 LED 燈表示,并在數位管上動态顯示目前狀态剩餘時間。要求紅燈持續時間為 30 秒,黃燈 5 秒,綠燈 30秒。
五、實驗步驟:
(1)建立工程
1.打開 Xilinx ISE 7.1i。選擇 File-New Project 建立工程,根據需要設定工程名 稱和工程路徑。
2.點選下一步配置工程屬性, Device Family 選擇 Spartan2,Device 選擇 XC2S50, Package 選擇 TQ144,Speed Grade 選擇-6。
3.直到完成工程的建立。
(2)建立和編寫源檔案
1.在 Sources in Project 中點右鍵,選擇 New Source。在彈出的對話框中選擇 VHDL Module,自己設定 File Name,一路下一步,建立一個新的源檔案。
2.在新的源檔案中錄入設計,完成數字時鐘的功能。
(3)設計的仿真
編寫 test_bench,用 Modelsim 對設計進行仿真,驗證功能正确性。
(4)上闆調試
将設計下載下傳到闆上進行調試,驗證設計的正确性。
六、實驗資料及結果分析:
一.分頻子產品(将40MHZ的時鐘頻率變成1HZ的頻率):
process(clr,clk_40Mhz)
begin
if(clr='0')then
count_25<="0000000000000000000000000";
elsif(rising_edge(clk_40Mhz))then
if(count_25="1111111111111111111111111")then
count_25<="0000000000000000000000000";
else
count_25<=count_25+'1';
end if;
end if;
end process;
clk_1hz<=count_25(24);(計數分頻1hz)
通過分頻子產品可以得到一秒鐘的時鐘信号。
二.計數子產品(紅燈30秒,黃燈5秒,綠燈30秒):
1.綠燈30秒:
when s0 => --
if(high = "0000" and low = "0000") then --黃燈時間結束
current_state <= s1; --
green <= '0';
red <= '1';
yellow <= '1';
high <= "0010"; low <= "1001"; --綠燈顯示時間為30
end if;
2.黃燈5秒
when s1 => --
if(high = "0000" and low = "0000") then --綠燈時間結束
current_state <= s2; --
yellow <= '0';
green <= '1';
red <= '1';
high <= "0000"; low <= "0100"; --黃燈時間為5
end if;
3.紅燈30秒
when s2 =>
if(high = "0000" and low = "0000") then --黃燈時間結束
current_state <= s3;
red <= '0';
green <= '1';
yellow <= '1';
high <= "0010"; low <= "1001"; --紅燈時間為30
end if;
三.動态顯示子產品
begin
case he is
when "0000"=>xianshi_z<="11000000";
when "0001"=>xianshi_z<="11111001";
when "0010"=>xianshi_z<="10100100";
when "0011"=>xianshi_z<="10110000";
when "0100"=>xianshi_z<="10011001";
when "0101"=>xianshi_z<="10010010";
when "0110"=>xianshi_z<="10000010";
when "0111"=>xianshi_z<="11111000";
when "1000"=>xianshi_z<="10000000";
when "1001"=>xianshi_z<="10010000";
when "1011"=>xianshi_z<="11000001";
when "1100"=>xianshi_z<="01100011";
when "1101"=>xianshi_z<="10000101";
when "1110"=>xianshi_z<="01100001";
when "1111"=>xianshi_z<="01110001";
when others=>xianshi_z<="00000011";
end case;
end process;
xianshi<=xianshi_z;
end BEHAVIORAL;
四.源碼:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity TrafficLight is
Port(reset: in std_logic;
led_r,led_y,led_g:out std_logic;
xianshi:out std_logic_vector(7 downto 0);
clr:in std_logic;
clk_40Mhz:in std_logic;
EN:out std_logic_vector(7 downto 0)
);
end TrafficLight;
architecture BEHAVIORAL of TrafficLight is
type mmp is(s0,s1, s2,s3);
signal current_state: mmp;
signal red, yellow, green: std_logic;
signal high: std_logic_vector(3 downto 0); --倒計時顯示的高位數
signal low: std_logic_vector(3 downto 0); --倒計時顯示的低位數
signal xianshi_z,xianshi_h_z:std_logic_vector(7 downto 0);
signal he:std_logic_vector(3 downto 0);
signal count_25:std_logic_vector(24 downto 0);
signal s:std_logic_vector(7 downto 0);
signal clk_1hz,clk_sm:std_logic;
begin
p1:
process(clr,clk_40Mhz)
begin
if(clr='0')then
count_25<="0000000000000000000000000";
elsif(rising_edge(clk_40Mhz))then
if(count_25="1111111111111111111111111")then
count_25<="0000000000000000000000000";
else
count_25<=count_25+'1';
end if;
end if;
end process;
clk_1hz<=count_25(24);
clk_sm<=count_25(14); --分頻
p2:
process(clk_sm,clr)
begin
if(clr='0')then
s<="11111110";
elsif(rising_edge(clk_sm))then
s(1)<= not s(1);
s(0)<= not s(0);
end if;
EN<=s;
end process;
p3:
process(s,he,low,high)
begin
if(s="11111110")then
he<=low;
else
he<=high;
end if;
end process; --位選
p4: process(reset, clk_1hz, current_state)
begin
if(clk_1hz = '1' and clk_1hz'event) then --當clk_1hz處于上升沿
if reset = '0' then
current_state <= s0; --複位時強行進入s0狀态
low <= "0000";
high <= "0000";
else
if(low = "0000" and not(high = "0000")) then --如果低位不夠減,則高位減一,低位置9
low <= "1001";
high <= high - 1;
else --每掃描一次,時間減一,如果低位夠減,則隻需低位減一,高位不變
low <= low - 1;
high <= high;
end if;
case current_state is --檢測目前狀态
when s0 => --
if(high = "0000" and low = "0000") then --黃燈時間結束
current_state <= s1; --
green <= '0';
red <= '1';
yellow <= '1';
high <= "0010"; low <= "1001"; --綠燈顯示時間為30
end if;
when s1 => --
if(high = "0000" and low = "0000") then --綠燈時間結束
current_state <= s2; --
yellow <= '0';
green <= '1';
red <= '1';
high <= "0000"; low <= "0100"; --黃燈時間為5
end if;
when s2 => --
if(high = "0000" and low = "0000") then --黃燈時間結束
current_state <= s3; --
red <= '0';
green <= '1';
yellow <= '1';
high <= "0010"; low <= "1001"; --紅燈時間為30
end if;
when s3 => --
if(high = "0000" and low = "0000") then --綠燈時間結束
current_state <= s0; --
yellow <= '0';
green <= '1';
red <= '1';
high <= "0000"; low <= "0100"; --黃燈時間為5
end if;
end case;
end if;
end if;
end process;
led_r<=red;
led_g<=green;
led_y<=yellow;
p5: process(he)
begin
case he is
when "0000"=>xianshi_z<="11000000";
when "0001"=>xianshi_z<="11111001";
when "0010"=>xianshi_z<="10100100";
when "0011"=>xianshi_z<="10110000";
when "0100"=>xianshi_z<="10011001";
when "0101"=>xianshi_z<="10010010";
when "0110"=>xianshi_z<="10000010";
when "0111"=>xianshi_z<="11111000";
when "1000"=>xianshi_z<="10000000";
when "1001"=>xianshi_z<="10010000";
when "1011"=>xianshi_z<="11000001";
when "1100"=>xianshi_z<="01100011";
when "1101"=>xianshi_z<="10000101";
when "1110"=>xianshi_z<="01100001";
when "1111"=>xianshi_z<="01110001";
when others=>xianshi_z<="00000011";
end case;
end process;
xianshi<=xianshi_z;
end BEHAVIORAL;
五.闆上的顯示結果:
七、實驗結論:
起始狀态黃燈熄滅,綠燈點亮,數位管數值顯示跳變到30并每一秒鐘遞減一位。當數位管數值顯示變為零0的時候,綠燈熄滅,紅燈點亮,數位管數值顯示跳變到30并每一秒鐘遞減一位。當數位管數值顯示變為零0的時候,紅燈熄滅,黃燈點亮,數位管數值顯示跳變到5并每一秒鐘遞減一位,當數位管數值顯示變為零0的時候回到起始狀态。
八、總結及心得體會:
1.此次實驗一開始我們想用狀态機來控制紅黃綠燈的顯示,用一個總時間為75秒的計數器來顯示紅黃綠燈的秒數,并在其基礎上分出兩個30秒和一個5秒的計數器,但最後編寫程式的時候發現程式太過複雜,程式編譯時也存在許多錯誤,并且修改難度太大于是我們就換了另外一種方法。
2.第二種方法:我們把狀态機取消,同時也把75秒的計數器給取消掉,在此基礎上的兩個30秒和一個5秒的計數器保持不變,然後把控制不同LED燈亮滅的代碼放在計數器清零的末端,進而實作了數位管顯示變為零的時候,一個LED燈亮,一個LED燈滅。
3.實驗過程中最大的問題就是數位管的動态掃描子產品(因為不太了解相關的代碼及原理);我們把代碼下載下傳到闆子時,LED的顯示正常但是數位管的顯示是亂碼,然後反複修改動态掃描子產品,直到最後得正确的數位管顯示。
4.通過此次實驗我們掌握了用VHDL進行RTL級代碼的編寫,并學會了如何用彙編語言編寫分屏子產品,計數子產品,動态掃描子產品的代碼,同時也學會了FPGA實驗驗證和調試。
九、對本實驗過程及方法、手段的改進建議:
1.外部可以設計一個中斷源,當出現緊急情況時可以暫停交通燈的運作;
2.可以将1HZ的分頻信号放加法器内(在交通燈燈的基礎上添加一數字時鐘顯示功能)