0
汕 头 大 学 实 验 报 告
学院: 工学院 系: 电子系 专业:电子 年级: 2009 地点:工西407 姓 学号:09141068 合作者: 实验时间: 2012-4-21
实验二 时序逻辑电路的VHDL模型实验
一、 实验目的
1、 了解普通4×4键盘扫描的原理。
2、 掌握组合逻辑电路和时序逻辑电路的混和设计。 3、 进一步加深七段码管显示过程的理解。 二、实验原理
本实验主要完成的实验是完成4×4键盘扫描的,然后获取其键值,并对其进行编码,从而进行按键的识别,并将相应的按键值进行显示。
键盘扫描的实现过程如下:对于4×4键盘,通常连接为4行、4列,因此要识别按键,只需要知道是哪一行和哪一列即可,为了完成这一识别过程,我们的思想是,首先固定输出4行为高电平,然后输出4列为低电平,在读入输出的4行的值,通常高电平会被低电平拉低,如果读入的4行均为高电平,那么肯定没有按键按下,否则,如果读入的4行有一位为低电平,那么对应的该行肯定有一个按键按下,这样便可以获取到按键的行值。同理,获取列值也是如此,先输出4列为高电平,然后在输出4行为低电平,再读入列值,如果其中有哪一位为低电平,那么肯定对应的那一列有按键按下。
获取到行值和列值以后,组合成一个8位的数据,根据实现不同的编码在对每个按键进行匹配,找到键值后在7段码管和LED显示。 三、实验内容及步骤
本实验内容是完成4×4键盘的扫描,然后将正确的键值进行显示,实验步骤如下: 1、编写键盘扫描和显示的VHDL代码。 2、用Quartus对其进行编译仿真。
3、在仿真确定无误后,选择芯片ACEX1K EP1K30QC208。 4、给芯片进行管脚绑定,在此进行编译。
5、根据自己绑定的管脚,在实验箱上对键盘接口、显示接口和FPGA之间进行正确连线。
0
6、给目标板下载代码,在4×4键盘输入键值,观看实验结果。 四、实验中主要仪器设备
1、4×4键盘阵列。 2、FPGA主芯片。 3、可变时钟源。 4、七段码显示区。 5、LED显示模块。 五、实验程序分析
4×4键盘的扫描VHDL代码:
library ieee;
use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; entity scanf is
port( clk : in std_logic;-------------扫描时钟信号
start : in std_logic;-------------开始信号,高电平有效
kbcol : in std_logic_vector(3 downto 0);--------------行扫描信号 kbrow : out std_logic_vector(3 downto 0);-------------列扫描信号
seg7_out : out std_logic_vector(6 downto 0);-------------七段显示控制信号(abcdefg)
scan : out std_logic_vector(2 downto 0));-----------数码管地址选择控制信号 end scanf;
architecture one of scanf is
signal count : std_logic_vector(1 downto 0); signal sta : std_logic_vector(1 downto 0); signal seg7 : std_logic_vector(6 downto 0); signal dat : std_logic_vector(4 downto 0);
signal fn : std_logic;------------------按键标志位,判断是否有键被按下 begin
scan<=\只使用一个数码管显示 ---------------------循环扫描计数器 process(clk) begin
if clk'event and clk='1' then count<=count+1; end if; end process;
---------------------循环列扫描 process(clk) begin
0
if clk'event and clk='1' then case count is
when \ when \ when \ when \ when others=>kbrow<=\ end case; end if; end process;
---------------------行扫描译码 process(clk,start) begin
if start='0' then seg7<=\ elsif clk'event and clk='1' then case sta is when \
case kbcol is
when \ when \ when \ when \ when others=>seg7<=\ end case;
when \
case kbcol is
when \ when \ when \ when \ when others=>seg7<=\ end case;
when \
case kbcol is
when \ when \ when \ when \ when others=>seg7<=\ end case;
when \
case kbcol is
when \
0
when \ when \ when \ when others=>seg7<=\ end case;
when others=>seg7<=\ end case; end if; end process;
fn<=not(dat(0)and dat(1)and dat(2)and dat(3)and dat(4)); -------------------产生按键标志位,用于存储按键信息 process(fn) begin
if fn'event and fn='1' then------------按键信息存储 seg7_out<=seg7; end if; end process; end one;
从实验的结果可以看出,当使能端处于高电平即有效电平时,把时钟输出按键打开。
2、按键加1或减1显示并且移位VHDL代码: library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; entity abc2 is port(
key1: in std_logic; key2: in std_logic; clk : in std_logic;
wei: out std_logic_vector(2 downto 0); led_seg : out std_logic_vector(7 downto 0); out0: out std_logic_vector(2 downto 0); out1: out std_logic_vector(2 downto 0); out2: out std_logic_vector(2 downto 0); out3: out std_logic_vector(2 downto 0); out4: out std_logic_vector(2 downto 0);
out5: out std_logic_vector(2 downto 0) ); end;
architecture a of abc2 is
signal temp1: std_logic_vector(2 downto 0); signal temp2: std_logic_vector(2 downto 0); signal flag1: std_logic_vector(1 downto 0); signal flag2: std_logic_vector(1 downto 0);
0
---signal wei_si: std_logic_vector(2 downto 0); signal num : std_logic_vector(2 downto 0); signal num0 : std_logic_vector(2 downto 0); signal num1 : std_logic_vector(2 downto 0); signal num2 : std_logic_vector(2 downto 0); signal num3 : std_logic_vector(2 downto 0); signal num4 : std_logic_vector(2 downto 0); signal num5 : std_logic_vector(2 downto 0); signal num6 : std_logic_vector(2 downto 0); signal num7 : std_logic_vector(2 downto 0); begin p1: process(clk)
variable wei_si: std_logic_vector(2 downto 0):=\begin
if clk'event and clk = '1' then temp1(0)<= key1; temp1(1)<= temp1(0); temp1(2)<= temp1(1); temp2(0)<= key2; temp2(1)<= temp2(0); temp2(2)<= temp2(1); if temp1=\ flag1(0) <= '1';
flag1(1) <= flag1(0); end if;
if temp1=\ flag1(0) <= '0';
flag1(1) <= flag1(0); end if ;
if temp2=\ flag2(0) <= '1';
flag2(1) <= flag2(0); end if ;
if temp2=\ flag2(0) <= '0' ; flag2(1) <= flag2(0); end if;
if flag1 = \ num0 <= num0 + 1; num1 <= num0; num2 <= num1; num3 <= num2; num4 <= num3; num5 <= num4;
0
num6 <= num5; num7 <= num6; end if ; if flag2 = \ num0 <=num0 - 1 ; num1 <= num0; num2 <= num1; num3 <= num2; num4 <= num3; num5 <= num4; num6 <= num5; num7 <= num6; end if;
wei_si := wei_si +1 ; wei <= wei_si; case wei_si is
when \=> num <= num0 ; when \=> num <= num1 ; when \=> num <= num2 ; when \=> num <= num3 ; when \=> num <= num4 ; when \=> num <= num5 ; when \=> num <= num6 ; when \=> num <= num7 ; end case; end if; end process p1;
--p3: process (clk,wei_si) --begin
---end process p3; p4: process (clk,num) begin
case num is
when \ when \ when \ when \ when \ when \ when \ when \ when others => null; end case; end process p4;
0
out0 <= num ; out1 <= num1 ; out2 <= num2 ; out3 <= num3 ; out4 <= num4 ; out5 <= num5 ; end;
3、键盘扫描带有去抖并且移位 VHDL代码: --按键
library ieee ;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all ;
entity jianpan is port(
clk: in std_logic ; --100mhz ==0.01us 1us 100 col: in std_logic_vector(3 downto 0); row: out std_logic_vector(3 downto 0); wei: out std_logic_vector(2 downto 0); duan: out std_logic_vector(7 downto 0) ); end ;
architecture a of jianpan is
signal count : std_logic_vector(16 downto 0); signal wei_s : std_logic_vector(2 downto 0); signal t : std_logic_vector(5 downto 0); signal flag : std_logic;
signal num0 : std_logic_vector(4 downto 0);-- integer; signal num1 : std_logic_vector(4 downto 0);-- integer; signal num2 : std_logic_vector(4 downto 0);-- integer; signal num3 : std_logic_vector(4 downto 0);-- integer; signal num4 : std_logic_vector(4 downto 0);-- integer; signal num5 : std_logic_vector(4 downto 0);-- integer; signal num6 : std_logic_vector(4 downto 0);-- integer; signal num7 : std_logic_vector(4 downto 0);-- integer; signal num8 : std_logic_vector(4 downto 0);-- integer; signal duan_s : std_logic_vector(4 downto 0);-- integer; signal old_num : std_logic_vector(4 downto 0);-- integer; signal p_num : std_logic_vector(4 downto 0);-- integer; signal state : std_logic_vector(4 downto 0);-- integer; begin
0
process(clk) begin
if clk'event and clk = '1' then count<=count+1;
if count = \then
count <= (others=>'0'); end if; end if;
end process ;
process(clk,count(16)) begin
if count(16)'event and count(16) = '0' --if clk'event and clk ='1'then wei_s<=wei_s+1; t<=t+1; end if ; end process ; wei<=wei_s;
process(wei_s) begin
case wei_s is
when \=> duan_s<=num1; when \=> duan_s<=num2; when \=> duan_s<=num3; when \=> duan_s<=num4; when \=> duan_s<=num5; when \=> duan_s<=num6; when \=> duan_s<=num7; when \=> duan_s<=num8; --when others => wei_s<= \ end case; end process; process(duan_s,clk) case duan_s is
when \ when \ when \ when \ when \ when \ when \ when \
then begin
0
--
when \ when \ when \ when \ when \ when \ when \ when \ when others => null; end case; end process;
process(clk,state) begin
case state is
when \=> row <= \ when \=> row <= \ when \=> row <= \ when \=> row <= \ when others => null ; end case; end process ;
process(count(16),state,clk) begin
if count(16)'event and count(16) = '0' then if (clk'event and clk = '1') then num0<=\ case state is
when \=> case col is
when \num0 <= \ when \num0 <= \ when \num0 <= \ when \num0 <= \ when others => state <= state + '1'; end case;
when \=> case col is
when \num0 <= \ when \num0 <= \ when \num0 <= \ when \num0 <= \ when others => state <= state + '1'; end case;
when \=>
0
case col is
when \num0 <= \ when \num0 <= \ when \num0 <= \ when \num0 <= \ when others => state <= state + '1'; end case;
when \=> case col is
when \num0 <= \ when \num0 <= \ when \num0 <= \ when \num0 <= \ when others => state <= \ end case;
when others => state <= \ end case;
old_num <= num0; end if ; end process; process(num0) begin
if old_num =num0 and num0 /= \ flag <= '1'; p_num <=old_num;
elsif old_num =num0 and num0 =\ flag <= '0'; end if ; end process;
process(clk,flag,num0) begin
if flag'event and flag='0' then num1<=p_num; num2<=num1; num3<=num2; num4<=num3; num5<=num4; num6<=num5; num7<=num6; num8<=num7; end if ; end process; end ;
0
六、思考题
1、 总结FPGA是如何识别按键的?与单片机读取键值有何不同?
答:对于4×4键盘,通常连接为4行、4列,因此要识别按键,只需要知道是哪一行和哪一列即可,为了完成这一识别过程,我们的思想是,首先固定输出4行为高电平,然后输出4列为低电平,在读入输出的4行的值,通常高电平会被低电平拉低,如果读入的4行均为高电平,那么肯定没有按键按下,否则,如果读入的4行有一位为低电平,那么对应的该行肯定有一个按键按下,这样便可以获取到按键的行值。同理,获取列值也是如此,先输出4列为高电平,然后在输出4行为低电平,再读入列值,如果其中有哪一位为低电平,那么肯定对应的那一列有按键按下。
单片机读取键值的话,首先是设定一个按键变量ch_key,然后判断ch_key的值,从而直接可以知道输入的是什么数了。相比之下就方便多了。
2、 在深入理解了4×4键盘实现的原理基础上,试试利用VHDL在目标器件FPGA/CPLD上实现PS/2键盘接口
答:第一种、FPGA管脚多,不用去动态扫描。这样,其实只要给一个判定时间,不要产生抖动等。
第二种,还是像单片机那样给扫描信号,这就与单片机一样了。
3、比较4×4键盘与PS/2键盘接口用FPGA实现方法的异同点。
答:键盘作为嵌入式系统的一种最常用人机接口设备, 在嵌入式系统中有着相当广泛的应用。但开发者一般均采用自行设计的简易矩阵键盘, 这类键盘仅仅是按行、列排列起来的矩阵开关, 往往需要单独设计并制作, 通用性不强。当需要较多的按键时, 则会占用较多的I/O 端口, 在软件上则要进行上电复位按键扫描及通信处理, 而且还要加上按键的去抖动处理, 增大了系统的软硬件开销。
相比之下,PS/2设备有主从之分,主设备采用Female插座,从设备采用Male插头.现在广泛使用的PS/2键盘鼠标均在从设备方式下工作.PS/2接口的时钟与数据线都是集电极开路结构,必须外接上拉电阻(一般上拉电阻设置在主设备中).主从设备之间数据通信采用双向同步串行方式传输,时钟信号由从设备产生.大大节省了系统的软硬件的开销。
0
六、思考题
1、 总结FPGA是如何识别按键的?与单片机读取键值有何不同?
答:对于4×4键盘,通常连接为4行、4列,因此要识别按键,只需要知道是哪一行和哪一列即可,为了完成这一识别过程,我们的思想是,首先固定输出4行为高电平,然后输出4列为低电平,在读入输出的4行的值,通常高电平会被低电平拉低,如果读入的4行均为高电平,那么肯定没有按键按下,否则,如果读入的4行有一位为低电平,那么对应的该行肯定有一个按键按下,这样便可以获取到按键的行值。同理,获取列值也是如此,先输出4列为高电平,然后在输出4行为低电平,再读入列值,如果其中有哪一位为低电平,那么肯定对应的那一列有按键按下。
单片机读取键值的话,首先是设定一个按键变量ch_key,然后判断ch_key的值,从而直接可以知道输入的是什么数了。相比之下就方便多了。
2、 在深入理解了4×4键盘实现的原理基础上,试试利用VHDL在目标器件FPGA/CPLD上实现PS/2键盘接口
答:第一种、FPGA管脚多,不用去动态扫描。这样,其实只要给一个判定时间,不要产生抖动等。
第二种,还是像单片机那样给扫描信号,这就与单片机一样了。
3、比较4×4键盘与PS/2键盘接口用FPGA实现方法的异同点。
答:键盘作为嵌入式系统的一种最常用人机接口设备, 在嵌入式系统中有着相当广泛的应用。但开发者一般均采用自行设计的简易矩阵键盘, 这类键盘仅仅是按行、列排列起来的矩阵开关, 往往需要单独设计并制作, 通用性不强。当需要较多的按键时, 则会占用较多的I/O 端口, 在软件上则要进行上电复位按键扫描及通信处理, 而且还要加上按键的去抖动处理, 增大了系统的软硬件开销。
相比之下,PS/2设备有主从之分,主设备采用Female插座,从设备采用Male插头.现在广泛使用的PS/2键盘鼠标均在从设备方式下工作.PS/2接口的时钟与数据线都是集电极开路结构,必须外接上拉电阻(一般上拉电阻设置在主设备中).主从设备之间数据通信采用双向同步串行方式传输,时钟信号由从设备产生.大大节省了系统的软硬件的开销。