VLSI/SoC设计综合实验(Ⅰ)

在这里插入图片描述

实验一:交通灯的设计及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的分频信号放加法器内(在交通灯灯的基础上添加一数字时钟显示功能)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值