基于FPGA的PS/2鼠标接口设计方法及其应用
S后进入m2_data_low_1状态,此时向鼠标 发送起始 位和d[0]、d[1](d[0]=d[1]=0)。完成后进入m2_data_high_1状态, 发送d[2](d[2]=1)并进入m2_data_low_2状态,此时向鼠标发送d[3]位(d[3]=0), 完成发送进入m2_data_high_2状态,向鼠标发送d[4]、d[5]、d[6]、d[7](d[4]=d[5]=d[6]=d[7]=1),完成发送进入m2_data_low_3状 态,向鼠标发送奇偶校验位,然后进入m2_data_high_3状态,将数据线拉高,等待鼠标返回应答信号。若PS/2时钟信号下降沿来临时,数据线仍未变为高电平,则进入m2_error_no_ack状态,此时握手失败,系统将保持m2_error_no_ack状态直到下一次复位,否则进入m2_await_response状态接收应答字,接收完成进入m2_verify数据校验,然后进入m2_use状态,锁存输出数据,并进入m2_wait状态,等待接收数据。当检测到时钟下降沿后进入m2_gather状态,接收鼠标数据包,接收完成进入m2_verify状态,此时便形成了数据接收循环。
PS/2程序源码
entity mouse is
Port (clk : in std_logic; reset : in std_logic; ps2_clk : inout std_logic; ps2_data : inout std_logic; left_button : out std_logic; right_button : out std_logic; mousex: buffer std_logic_vector(9 downto 0); mousey: buffer std_logic_vector(9 downto 0); data_ready : out std_logic; error_no_ack : out std_logic);
end mouse;
architecture Behavioral of mouse is
--变量、信号定义(略)
begin
ps2_clk = '0' when ps2_clk_hi_z='0' else 'Z';
ps2_data = '0' when ps2_data_hi_z='0' else 'Z';
--检测ps2clk上升沿和下降沿(略)
m2statech: process (reset, clk) ------------------m2 状态
begin
if (reset='0') then
m2_state = m2_reset;
elsif (clk'event and clk='1') then
m2_state = m2_next_state;
end if;
end procESS;
--m2 状态传输逻辑
m2statetr: process (m2_state, q, fall,rise,watchdog_timer_done,bitcount,ps2_data,packet_good)
begin
ps2_clk_hi_z = '1';
ps2_data_hi_z = '1';
error_no_ack = '0';
output_strobe = '0';
case m2_state is
when m2_reset => -- 复位后向鼠标发送命令字
m2_next_state = m2_hold_clk_l;
when m2_wait =>
if (fall='1') then
m2_next_state = m2_gather;
else
m2_next_state = m2_wait;
end if;
when m2_gather =>
if ((watchdog_timer_done='1') and (bitcount=TOTAL_BITS))then
m2_next_state = m2_verify;
else
m2_next_state = m2_gather;
end if;
when m2_verify =>
--if (bitcount TOTAL_BITS) then
--m2_next_state = m2_wait;
--else
m2_next_state = m2_use;
--end if;
when m2_use =>
output_strobe = '1';
m2_next_state = m2_wait;
-- 用状态机的9个状态实现命令字传输,使鼠标进入"streaming"模式,并等待鼠标正确应答
when m2_hold_clk_l =>
ps2_clk_hi_z = '0'; -- 启动看门狗!
if (watchdog_timer_done='1') then
m2_next_state = m2_data_low_1;
else
m2_next_state = m2_hold_clk_l;
end if;
when m2_data_low_1 =>
ps2_data_hi_z = '0'; -- 数据位 开始位, d[0] and d[1]
if (fall='1' and (bitcount = 2)) then
m2_next_state = m2_data_high_1;
else
m2_next_state = m2_data_low_1;
end if;
when m2_data_high_1 =>
ps2_data_hi_z = '1'; -- 数据位 d[2]
if (fall='1' and (bitcount = 3)) then
m2_next_state = m2_data_low_2;
else
m2_next_state = m2_data_high_1;
end if;
when m2_data_low_2 =>
ps2_data_hi_z = '0'; -- 数据位 d[3]
if (fall='1' and (bitcount = 4)) then
m2_next_state = m2_data_high_2;
else
m2_next_state = m2_data_low_2;
end if;
when m2_data_high_2 =>
ps2_data_hi_z = '1'; -- 数据位 d[4],d[5],d[6],d[7]
if (fall='1' and (bitcount = 8)) then
m2_next_state = m2_data_low_3;
else
m2_next_state = m2_data_high_2;
end if;
when m2_data_low_3 =>
ps2_data_hi_z = '0'; -- 奇偶校验位
if (fall='1') then
m2_next_state = m2_data_high_3;
else
m2_next_state = m2_data_low_3;
end if;
when m2_data_high_3 =>
ps2_data_hi_z = '1'; -- 允许鼠标拉成低电平(ACK脉冲)
if (fall='1' and (ps2_data='1')) then
m2_next_state = m2_error_no_ack;
elsif (fall='1' and (ps2_data='0')) then
m2_next_state = m2_await_response;
else
m2_next_state = m2_data_high_3;
end if;
when m2_error_no_ack =>
error_no_ack = '1';
m2_next_state = m2_error_no_ack;
-- 为了鼠标正确进入"streaming"模式,状态极必须等待足够长的时间,确保鼠标正确应答0xFA。
when m2_await_response =>
--if (bitcount = 22) then
m2_next_state = m2_verify;
--else
-- m2_next_state = m2_await_response;
--end if;
when others => m2_next_state = m2_wait;
end case;
end process;-----------------------------m2 状态结束
-- 位计数器 (略)
-- 数据移位寄存器(略)
-- 看门狗时间计数器(略)
watchdog_timer_done = '1' when (watchdog_timer_count=WATCHDOG-1) else '0';
packet_good = '1'; -- 接收数据包有效标志
outdata: process (reset, clk) -- 输出数据
begin
if (reset='0') then
left_button = '0';
right_button = '0';
elsif (clk'event and clk='1') then
if (output_strobe='1') then
left_button = q(1);
right_button = q(2);
mouseyy = not (q(6) q(6) q(30 downto 23)) + "1";
end if;
end if;
end process;
cordinatex: process (reset, clk)
begin
if (reset='0') then
mousex = "0110010000"; -- 400
elsif (clk'event and clk='1') then
if (output_strobe='1') then
if ((mousex >= 797 and q(5)='0') or (mousex = 2 and
q(5)='1')) then
mousex = mousex;
else
mousex = mousex + (q(5) q(5) q(19 downto
12));--q(5):xsign q(6):ysign
end if;
end if;
end if;
end process;
cordinatey: process (reset, clk)
begin
if (reset='0') then
mousey = "0100101100"; -- 300
elsif (clk'event and clk='1') then
if (output_strobe='1') then
if ((mousey >= 597 and q(6)='1') or (mousey = 2
and q(6)='0')) then
mousey = mousey;
else
m ousey = mousey + mouseyy; --(q(6) q(6) q(30
downto 23));
end if;
end if;
end if;
end process;
data_ready = output_strobe;
end Behavioral;
- 在采用FPGA设计DSP系统中仿真的重要性 (06-21)
- 基于 DSP Builder的FIR滤波器的设计与实现(06-21)
- 基于FPGA的快速并行FFT及其在空间太阳望远镜图像锁定系统中的应用(06-21)
- 3DES算法的FPGA高速实现(06-21)
- 用FPGA实现FFT算法(06-21)
- FPGA的DSP性能揭秘(06-16)