任务1:I型模块的逆时针旋转测试与动作
1. 完成实验表格
本实验的解决关键在于能否正确填写下发的实验表格。如果能理解表格中填写的各位置函数关系并在代码相应位置对应更改,就可以轻松完成所有实验内容。
上图为下发的实验表格,经观察可知:示例的I型模块旋转过程分为四个form,每旋转90°为一个form,依次对应“00”“01”“10”“11”状态。旋转前组成I型模块的四个点阵由数字1-4表示,旋转后的I型模块位置用〇表示,旋转过程中的阻挡位置用×表示。旋转中心用带圈的数字③表示。每个点阵由两个坐标函数pnx, pny表示。坐标原点位于点阵屏的左上角,即从左往右,八列点阵的坐标分别为000, 001, 010, 011, 100, 101, 110, 111,从上往下,八行点阵的坐标分别为000, 001, 010, 011, 100, 101, 110, 111(注意是从0开始,0代表第一行,这里非常重要!!!)。同时,表中还给出了旋转中心的坐标限制"000" 旋转过程中,测试空位和测试阻挡的坐标均由原始点阵坐标导出。以forms="00"点“4”上方的阻挡为例(下图标红×),其坐标可由点“4”写出,由于其与“4”位于同一列,故横坐标相同,其位于“4”上方一个单位,故纵坐标为p4y-1。因此此阻挡的坐标可表示为p4x, p4y-1。 旋转后的坐标由对应的点坐标导出。以forms="00"点“1”为例,其逆时针旋转90°后位置见下图标红〇。与原坐标相比,向右移动两个单位,向下移动两个单位。故其旋转后坐标可表示为p1x+2, p1y+2。 综上,我们可以补全表1,得到以下完整表格。 本实验的主要控制过程代码在模块ctrl_Irotate.vhd中给出,故我们可以研究此模块代码,来分析如何实现模块的旋转功能。通过观察给出的代码,我们可以发现影响模块旋转功能的代码主要有以下几个部分组成: 这里给出的是四种测试项,对应实验设计任务上的正常旋转、靠近点阵四周、位置被占、旋转路径有阻挡。由第一节已知各点坐标的表示方法,即可表示出四种情况的对应坐标。其中p5表示一种可能的阻挡,在前两种情况中无需考虑,将p5设置为任意远离模块的坐标即可。在第三种情况中,需要考虑测试位置被占的情况,因此可以将p5置于p3下方,模拟旋转目标点阵位置被占的情况。同理,在第四种情况中,将p5置于p4下方。 在以上函数中,依次判断表中填写的边界条件、空位和阻挡。首先判断旋转中心p3位置是否在边界之内,否则无法旋转,跳出。在满足边界条件的情况下,依次判断空位1、空位2、空位3、阻挡1、阻挡2、阻挡3、阻挡4的点是否亮起(高电平),如果亮起则表示该位置无法旋转,跳出。注意这里的空位和阻挡要按顺序写,即空位1为表中每种状态下填写的第一个空位点(下图用黄色标出),以此类推。空位和阻挡的个数可视具体问题增删,在后续实验任务中会解释。 此函数内需要我们填写旋转后的各点坐标,与表中最后一列内容对应。注意最后“显示新片”位置需要考虑旋转轴,示例的旋转轴为p3,因此p3位置始终不更新,只需要更新p1, p2, p4的位置。 至此,I型模块的逆时针旋转测试与动作实验所有内容全部实现,相信你也掌握了旋转控制代码的原理。接下来将更新任务2:I型模块的顺时针旋转测试与动作。敬请期待。 2. 理解表格中坐标如何在代码中实现
2.1 test_n函数
when test_n=>
case next_n is--共4种测试项
when"00"=>--测试旋转
forms<="00";--I型模块,p1 p2 p3 p4
--
--
--p1 p2 p3 p4,左上,第三行
p1x<="000";p2x<="001";p3x<="010";p4x<="011";
p1y<="010";p2y<="010";p3y<="010";p4y<="010";
p5x<="111";p5y<="010";
when"01"=>--测试边界
forms<="00";
--
--p1 p2 p3 p4,左上角,第2行
p1x<="000";p2x<="001";p3x<="010";p4x<="011";
p1y<="001";p2y<="001";p3y<="001";p4y<="001";
p5x<="110";p5y<="111";
when"10"=>--测试位置被占
forms<="00";
--p1 p2 p3 p4,居中
-- p5
p1x<="010";p2x<="011";p3x<="100";p4x<="101";
p1y<="100";p2y<="100";p3y<="100";p4y<="100";
p5x<="100";p5y<="101";
when"11"=>--测试旋转路径有阻挡
forms<="00";
--p1 p2 p3 p4,居中
-- p5
p1x<="010";p2x<="011";p3x<="100";p4x<="101";
p1y<="100";p2y<="100";p3y<="100";p4y<="100";
p5x<="101";p5y<="101";
when others=>null;
end case;
make<=X"1"; state<=display;
2.2 测试边界、空位与阻挡
--测试I型模块能否以p3为轴心逆时针旋转--
--测试边界、空位与阻挡--
when test_Lp3=>
case test is
--测试边界与空位1--
when X"1"=>--test
if(forms="00")then
if(p3y>"000" and p3y<"110")then--边界条件
cx<=p3x; cy<=p3y-1; test<=X"2";--测试空位1
else
state<=wait_btn;--不能旋转,等待操作键
end if;
elsif(forms="01")then
if(p3x>"000" and p3x<"110")then
cx<=p3x-1; cy<=p3y; test<=X"2";
else
state<=wait_btn;
end if;
elsif(forms="10")then
if(p3y>"001" and p3y<"111")then
cx<=p3x; cy<=p3y-2; test<=X"2";
else
state<=wait_btn;
end if;
elsif(forms="11")then
if(p3x>"001" and p3x<"111")then
cx<=p3x-2; cy<=p3y; test<=X"2";
else
state<=wait_btn;
end if;
end if;
when X"2"=>
if(dotin="1")then--高电平点亮,位置已被占
state<=wait_btn;--不能旋转,等待操作键
else
test<=X"3";--有空位,测试下一个位置
end if;
--测试空位2--
when X"3"=>--test
if(forms="00")then
cx<=p3x; cy<=p3y+1; test<=X"4";
elsif(forms="01")then
cx<=p3x+1; cy<=p3y; test<=X"4";
elsif(forms="10")then
cx<=p3x; cy<=p3y-1; test<=X"4";
elsif(forms="11")then
cx<=p3x-1; cy<=p3y; test<=X"4";
end if;
when X"4"=>
if(dotin="1")then state<=wait_btn;
else
test<=X"5";
end if;
--测试空位3--
when X"5"=>--test
if(forms="00")then
cx<=p3x; cy<=p3y+2; test<=X"6";
elsif(forms="01")then
cx<=p3x+2; cy<=p3y; test<=X"6";
elsif(forms="10")then
cx<=p3x; cy<=p3y+1; test<=X"6";
elsif(forms="11")then
cx<=p3x+1; cy<=p3y; test<=X"6";
end if;
when X"6"=>
if(dotin="1")then state<=wait_btn;
else
test<=X"7";
end if;
--测试阻挡1--
when X"7"=>--test
if(forms="00")then
cx<=p1x; cy<=p1y+1; test<=X"8";
elsif(forms="01")then
cx<=p1x+1; cy<=p1y; test<=X"8";
elsif(forms="10")then
cx<=p1x; cy<=p1y-1; test<=X"8";
elsif(forms="11")then
cx<=p1x-1; cy<=p1y; test<=X"8";
end if;
when X"8"=>
if(dotin="1")then --高电平点亮,有阻挡
state<=wait_btn;--不能旋转,等待操作键
else
test<=X"9";--无阻挡,测试下一个位置
end if;
--测试阻挡2--
when X"9"=>--test
if(forms="00")then
cx<=p2x; cy<=p2y+1; test<=X"A";
elsif(forms="01")then
cx<=p2x+1; cy<=p2y; test<=X"A";
elsif(forms="10")then
cx<=p2x; cy<=p2y-1; test<=X"A";
elsif(forms="11")then
cx<=p2x-1; cy<=p2y; test<=X"A";
end if;
when X"A"=>
if(dotin="1")then
state<=wait_btn;
else
test<=X"B";
end if;
--测试阻挡3--
when X"B"=>--test
if(forms="00")then
cx<=p2x; cy<=p2y+2; test<=X"C";
elsif(forms="01")then
cx<=p2x+2; cy<=p2y; test<=X"C";
elsif(forms="10")then
cx<=p2x; cy<=p2y-2; test<=X"C";
elsif(forms="11")then
cx<=p2x-2; cy<=p2y; test<=X"C";
end if;
when X"C"=>
if(dotin="1")then
state<=wait_btn;
else
test<=X"D";
end if;
--测试阻挡4--
when X"D"=>--test
if(forms="00")then
cx<=p4x; cy<=p4y-1; test<=X"E";
elsif(forms="01")then
cx<=p4x-1; cy<=p4y; test<=X"E";
elsif(forms="10")then
cx<=p4x; cy<=p4y+1; test<=X"E";
elsif(forms="11")then
cx<=p4x+1; cy<=p4y; test<=X"E";
end if;
when X"E"=>
if(dotin="1")then
state<=wait_btn;
else
make<=X"8"; state<=rotate_Lp3;
end if;
when others=>null;
end case;
2.3 I型模块以p3为轴逆时针旋转
--I型模块以p3为轴心逆时针旋转--
when rotate_Lp3=>
case make is --make:8~F
--清空原片--
when X"8"=>
wen_tmp<="1";--开写使能
dotout_tmp<="0";--低电平,熄灭led灯
cx<=p1x; cy<=p1y; make<=X"9";
when X"9"=>
cx<=p2x; cy<=p2y; make<=X"A";
when X"A"=>
cx<=p4x; cy<=p4y; make<=X"B";
--更新p1,p2,p4新片位置--
when X"B"=>--make
if(forms="00")then
p1x<=p1x+2; p1y<=p1y+2;
p2x<=p2x+1; p2y<=p2y+1;
p4x<=p4x-1; p4y<=p4y-1;
elsif(forms="01")then
p1x<=p1x+2; p1y<=p1y-2;
p2x<=p2x+1; p2y<=p2y-1;
p4x<=p4x-1; p4y<=p4y+1;
elsif(forms="10")then
p1x<=p1x-2; p1y<=p1y-2;
p2x<=p2x-1; p2y<=p2y-1;
p4x<=p4x+1; p4y<=p4y+1;
elsif(forms="11")then
p1x<=p1x-2; p1y<=p1y+2;
p2x<=p2x-1; p2y<=p2y+1;
p4x<=p4x+1; p4y<=p4y-1;
end if;
make<=X"C";
--显示新片--
when X"C"=>--make
dotout_tmp<="1";--高电平,点亮led灯
cx<=p1x; cy<=p1y; make<=X"D";
when X"D"=>
cx<=p2x; cy<=p2y; make<=X"E";
when X"E"=>
cx<=p4x; cy<=p4y; make<=X"F";
when X"F"=>--make
wen_tmp<="0";--关写使能
附:本章节需要用到的代码:
Irotate_top.vhd:
--库
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
--实体
entity Irotate_top is
port (clk_50M : in std_logic; --50MHz
rst : in std_logic;
btn_in : in std_logic_vector(2 downto 0);
DIN: out std_logic;
CS: out std_logic;
CLK_MAX7219 : out std_logic);
end;
--结构体
architecture behavioral of Irotate_top is
component clkdiv_50M
port (clk_50M : in std_logic; --50MHz
rst : in std_logic;
clk_btn: out std_logic;
clk_game:out std_logic;
clk_rama : out std_logic);
end component;
component btn_detect
port (clk_btn : in std_logic;
rst : in std_logic;
btn_in : in std_logic_vector(2 downto 0);
btn_en : out std_logic;
btn_nlr : out std_logic_vector(2 downto 0));
end component;
component ctrl_Irotate
port (clk_game : in std_logic;
rst : in std_logic;
btn_en : in std_logic;
dotin : in std_logic_vector(0 downto 0);
btn_nlr : in std_logic_vector(2 downto 0);
addrb : out std_logic_vector(8 downto 0);
web : out std_logic_vector(0 downto 0);
dotout : out std_logic_vector(0 downto 0));
end component;
component ctrl_dotcasebitT
port (clk_rama : in std_logic;
rst : in std_logic;
dataa : in std_logic_vector(0 downto 0);
btn_en:in std_logic;
dispgame:in std_logic;
din : out std_logic;
load_cs : out std_logic;
clk_max7219 : out std_logic;
addra : out std_logic_vector(8 downto 0));
end component;
component ram2ip
port (clka : in std_logic;
addra : in std_logic_vector(8 downto 0);
wea : in std_logic_vector(0 downto 0):="0";
dina : in std_logic_vector(0 downto 0):="0";
clkb : in std_logic;
addrb : in std_logic_vector(8 downto 0);
web : in std_logic_vector(0 downto 0);
dinb : in std_logic_vector(0 downto 0);
douta : out std_logic_vector(0 downto 0);
doutb : out std_logic_vector(0 downto 0));
end component;
signal clk_rama1:std_logic;
signal clk_game: std_logic;
signal clk_btn:std_logic;
signal btn_en1:std_logic;
signal btn_nlr: std_logic_vector(2 downto 0);
signal dotin1:std_logic_vector(0 downto 0);
signal addrb:std_logic_vector(8 downto 0);
signal web:std_logic_vector(0 downto 0);
signal dotout1:std_logic_vector(0 downto 0);
signal dataa1:std_logic_vector(0 downto 0);
signal addra:std_logic_vector(8 downto 0);
begin
--元件例化语句
u1:clkdiv_50M port map(
clk_50M => clk_50M,
rst => rst,
clk_rama => clk_rama1,
clk_game => clk_game,
clk_btn => clk_btn);
u2:btn_detect port map(
clk_btn => clk_btn,
rst => rst,
btn_in => btn_in,
btn_en => btn_en1,
btn_nlr => btn_nlr);
u3:ctrl_Irotate port map(
rst => rst,
clk_game => clk_game,
btn_en => btn_en1,
btn_nlr => btn_nlr,
dotin => dotin1,
addrb => addrb,
web => web,
dotout => dotout1);
u4:ctrl_dotcasebitT port map(
clk_rama => clk_rama1,
rst => rst,
btn_en => btn_en1,
dataa => dataa1,
dispgame => btn_nlr(2),
addra => addra,
din => DIN,
load_cs => CS,
clk_max7219 => CLK_MAX7219);
u5:ram2ip port map(
clka => clk_rama1,
addra => addra,
clkb => clk_50M,
addrb => addrb,
web => web,
dinb => dotout1,
douta => dataa1,
doutb => dotin1);
end behavioral;
clkdiv_50M.vhd:
--库
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
--实体
entity clkdiv_50M is
port (clk_50M : in std_logic; --50MHz
rst : in std_logic;
clk_btn: out std_logic;
clk_game:out std_logic;
clk_rama : out std_logic);
end;
--结构体
architecture behavioral of clkdiv_50M is
signal cnt:std_logic_vector(25 downto 0);
begin
process(rst,clk_50M)
begin
if(rst='1')then
cnt<=(others=>'0');
elsif rising_edge(clk_50M)then
cnt<=cnt+1;
end if;
end process;
clk_btn<=cnt(7);
clk_game<=cnt(2);
clk_rama<=cnt(8);
end behavioral;
btn_detect.vhd:
--库
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
--实体
entity btn_detect is
port (clk_btn : in std_logic;
rst : in std_logic;
btn_in : in std_logic_vector(2 downto 0);
btn_en : out std_logic;
btn_nlr : out std_logic_vector(2 downto 0));
end;
--结构体
architecture behavioral of btn_detect is
component debounce is
port(clk:in std_logic;
rst:in std_logic;
start:in std_logic;
done:out std_logic);
end component;
signal start,done:std_logic:='0';
signal btn_down,en_tmp:std_logic:='0';
begin
process(rst,clk_btn,btn_in)
begin
if(rst='1')then
btn_down<='0';
elsif rising_edge(clk_btn)then
if(btn_in/="000")then --有键按下
if(done='0')then
start<='1';
else
start<='0';
end if;
if(start&done="11")then
btn_nlr<=btn_in;
btn_down<='1'; --确实有键按下
end if;
else
btn_down<='0';
start<='0';
end if;
end if;
end process;
--检测到有键按下,则btn_en翻转,控制ctrl_Irotate
process(btn_down)
begin
if rising_edge(btn_down)then
en_tmp<=not en_tmp;
end if;
end process;
btn_en<=en_tmp;
u2i:debounce port map(
clk=>clk_btn,
rst=>rst,
start=>start,
done=>done);
end behavioral;
debounce.vhd:
--库
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
--实体
entity debounce is
port (clk: in std_logic;
rst: in std_logic;
start: in std_logic;
done: out std_logic);
end;
--结构体
architecture behavioral of debounce is
signal cnt_delay:std_logic_vector(13 downto 0);--延时计数
signal done_tmp:std_logic:='0';
begin
process(rst,clk,start)
begin
if(rst='1')then
done_tmp<='0';
cnt_delay<=(others=>'0');
elsif rising_edge(clk)then
if(start='1')then --有键按下
if(cnt_delay>X"300")then
done_tmp<='1'; --确实有键按下
else
cnt_delay<=cnt_delay+1;
end if;
else --无键按下
done_tmp<='0';
cnt_delay<=(others=>'0');
end if;
end if;
done<=done_tmp;
end process;
end behavioral;
crtl_Irotate.vhd:
--库
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
--实体
entity ctrl_Irotate is
port (clk_game: in std_logic;
rst: in std_logic;
btn_en: in std_logic;
dotin: in std_logic_vector(0 downto 0);
btn_nlr: in std_logic_vector(2 downto 0);
addrb: out std_logic_vector(8 downto 0);
web: out std_logic_vector(0 downto 0);
dotout: out std_logic_vector(0 downto 0));
end;
--结构体
architecture behavioral of ctrl_Irotate is
type state_group is(wait_btn,clr_screen,test_n,display,test_Lp3,rotate_Lp3);
signal state:state_group:=wait_btn;
signal test:std_logic_vector(3 downto 0):=X"0";--测试
signal make:std_logic_vector(3 downto 0):=X"0";--动作
signal makex,makey:std_logic_vector(3 downto 0):=X"0";--清屏
signal next_n:std_logic_vector(1 downto 0):="00";--切换测试项
signal rst_en,btnen_tmp:std_logic:='0';
signal wen_tmp:std_logic_vector(0 downto 0):="0";
signal dotout_tmp:std_logic_vector(0 downto 0);
signal cy:std_logic_vector(2 downto 0):="000";--8行
signal cx:std_logic_vector(2 downto 0):="000";--8列
signal p1x,p2x,p3x,p4x,p5x:std_logic_vector(2 downto 0):="000";
signal p1y,p2y,p3y,p4y,p5y:std_logic_vector(2 downto 0):="000";
signal forms:std_logic_vector(1 downto 0):="00";--I型模块的形状
begin
web<=wen_tmp;
addrb<="01"&cy&"1"&cx;--俄罗斯方块旋转测试界面的地址
dotout<=dotout_tmp;
process(rst,clk_game,btn_en,dotin,state,make,test)
begin
if(rst='1')then
rst_en <= '1';
btnen_tmp <= btn_en;
makey <= X"0";
makex <= X"0";
state <= clr_screen;
elsif rising_edge(clk_game)then
--识别操作键
if(btnen_tmp/=btn_en)then
btnen_tmp<=not btnen_tmp;
--BTN3:切换测试项
if(btn_nlr="100" and state=wait_btn)then
next_n<=next_n+1;
makey<=X"0"; makex<=X"0"; state<=clr_screen;
--BTN2:逆时针旋转(向左转)
elsif(btn_nlr="010"and state=wait_btn)then
test<=X"1"; state<=test_Lp3;
--BTN1:顺时针旋转(向右转),此功能待开发(实验任务)
elsif(btn_nlr="001"and state=wait_btn)then
test<=X"1";state<=test_Rp3;
end if;
else
case state is
--等待按键操作--
when wait_btn=>null;
--清屏--
when clr_screen=>
if(makex
ctrl_dotcasebitT.vhd:
--库
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
--实体
entity ctrl_dotcasebitT is
port (clk_rama : in std_logic;
rst : in std_logic;
dataa : in std_logic_vector(0 downto 0);
btn_en:in std_logic;
dispgame:in std_logic;
din : out std_logic;
load_cs : out std_logic;
clk_max7219 : out std_logic;
addra : out std_logic_vector(8 downto 0));
end;
--结构体
architecture behavioral of ctrl_dotcasebitT is
type state_group is(load_shiften,SISO_16,clkedgeR_upaddr);
signal state:state_group:=load_shiften;
signal shift_en:std_logic:='0';
signal btnen_tmp:std_logic:='0';
signal addr_init:std_logic:='1';--1控制寄存器,0数据寄存器
signal addr_game:std_logic:='0';--游戏界面/go
signal addr_reg:std_logic_vector(2 downto 0):="000";
signal addr_bit:std_logic_vector(3 downto 0):=X"0"; --16位数据的每一位
begin
addra<=addr_init&addr_game&addr_reg&addr_bit;
process(rst,clk_rama,btn_en,state,dataa)
variable cnt_shift:std_logic_vector(3 downto 0):=X"0";--移位计数
variable cnt_delay:std_logic_vector(2 downto 0):="000";--延时计数
begin
if(rst='1')then
addr_init<='0'; addr_game<='0'; --进入go界面
addr_reg<="000"; addr_bit<=X"0";
btnen_tmp<=btn_en;
shift_en<='0'; load_cs<='1'; clk_max7219<='0';
cnt_shift:=X"0"; cnt_delay:="000";
state<=load_shiften;
elsif rising_edge(clk_rama)then
if(btnen_tmp/=btn_en and dispgame='1')then--切换测试项按钮
btnen_tmp<=not btnen_tmp;
addr_init<='0'; addr_game<='1'; --进入游戏的旋转测试界面
addr_reg<="000"; addr_bit<=X"0";
shift_en<='0'; load_cs<='1'; clk_max7219<='0';
cnt_shift:=X"0"; cnt_delay:="000";
state<=load_shiften;
else
case state is
when load_shiften=>--装载锁存数据/移位使能
clk_max7219<='0';
if(shift_en='1')then
load_cs<='0';--允许移位
state<=SISO_16;
else
load_cs<='1';--装载锁存数据
if(cnt_delay="111")then--延时,间隔各寄存器信息
shift_en<='1'; cnt_delay:="000";
else
cnt_delay:=cnt_delay+1;
end if;
end if;
when SISO_16=>--16位数据串行输入、串行输出
clk_max7219<='0';
din<=dataa(0);
addr_bit<=addr_bit+1;--16位数据中的下一位
state<=clkedgeR_upaddr;
when clkedgeR_upaddr=>--产生时钟上升沿,切换寄存器地址
clk_max7219<='1';--产生时钟clk_max7219上升沿
--MAX7219各寄存器的切换
if(cnt_shift=X"F")then--16位移完
if(addr_init='1')then--MAX7219初始化
if(addr_reg="100")then--初始化只执行一遍
addr_init<='0'; addr_reg<="000";
else
addr_reg<=addr_reg+1;--下一个控制寄存器
end if;
else
addr_reg<=addr_reg+1;--下一个数据寄存器
end if;
shift_en<='0';
cnt_shift:=X"0"; state<=load_shiften;
else
cnt_shift:=cnt_shift+1; state<=SISO_16;
end if;
end case;
end if;
end if;
end process;
end behavioral;
还没有评论,来说两句吧...