原创 VHDL写的鼠标驱动器+VGA显示

2008-9-16 14:44 3233 6 9 分类: FPGA/CPLD

这是我们假期参加ALTERA电子竞赛时用的鼠标驱动器的VHDL代码.已经过测试成功.以下是源代码.无需修改就可以使用.


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity mousecontroller 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;-- rx_read_o
error_no_ack : out std_logic
);
end mousecontroller;
architecture Behavioral of mousecontroller is
constant TOTAL_BITS : integer :=33; -- 数据包位数
constant WATCHDOG : integer :=320; -- 400usec所需sys_clk脉冲数
--constant DEBOUNCE_TIMER : integer := 2;
--type m1statetype is ( m1_clk_h, m1_falling_edge, m1_falling_wait,
-- m1_clk_l, m1_rising_edge, m1_rising_wait);
type m2statetype is (m2_reset, m2_wait, m2_gather, m2_verify, m2_use, m2_hold_clk_l,
m2_data_low_1, m2_data_high_1, m2_data_low_2, m2_data_high_2, m2_data_low_3,
m2_data_high_3, m2_error_no_ack, m2_await_response);
--signal m1_state,m1_next_state : m1statetype;
signal m2_state,m2_next_state : m2statetype;
--signal m3_state,m3_next_state : std_logic;
signal watchdog_timer_done : std_logic;--命令传输超时标志
signal q : std_logic_vector(TOTAL_BITS-1 downto 0);--位序列
signal bitcount : std_logic_vector(5 downto 0);--位计数器
signal watchdog_timer_count : std_logic_vector(8 downto 0); --等待时间
--signal debounce_timer_count : std_logic_vector(1 downto 0);
signal ps2_clk_hi_z : std_logic;
signal ps2_data_hi_z : std_logic;
signal fallsig,risesig : std_logic_vector(2 downto 0);
signal clean_clk : std_logic; -- 从m1跟随ps2_clk反向输出
signal rise,n_rise : std_logic; -- m1状态机输出数据
signal fall,n_fall : std_logic; -- m1状态机输出数据
signal output_strobe : std_logic; -- 锁存数据到输出寄存器
signal packet_good : std_logic; -- 检查数据是否有效
--signal x_increment : std_logic_vector(8 downto 0);
--signal y_increment : std_logic_vector(7 downto 0);
signal mouseyy : std_logic_vector(9 downto 0);
signal tempx,tempy:std_logic_vector(9 downto 0);


begin
ps2_clk <= '0' when ps2_clk_hi_z='0' else 'Z';
ps2_data <= '0' when ps2_data_hi_z='0' else 'Z';
------------------------------------
--检测ps2clk上升沿和下降沿
------------------------------------
detect_ps2clkfall : process(clk,reset,ps2_clk)
begin
if reset='0' then
fallsig <= "000";
elsif clk'event and clk='1' then
fallsig(0) <= ps2_clk;
fallsig(1) <= fallsig(0);
fallsig(2) <= fallsig(1);
end if;
end process;
fall <= '1' when fallsig="110" else '0';
detect_ps2clkrise : process(clk,reset,ps2_clk)
begin
if reset='0' then
risesig <= "000";
elsif clk'event and clk='1' then
risesig(0) <= ps2_clk;
risesig(1) <= risesig(0);
risesig(2) <= risesig(1);
end if;
end process;
rise <= '1' when risesig="001" else '0';
------------------m2 状态
m2statech: process (reset, clk)
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 --替换 " packet_good='1' "
--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 状态结束
--位计数器
bitcoun: process (reset, clk)
begin
if (reset='0') then
bitcount <= (others=>'0'); -- normal reset
elsif (clk'event and clk='1') then
if (fall='1') then
bitcount <= bitcount + 1;
elsif (watchdog_timer_done='1') then
bitcount <= (others=>'0'); -- rx watchdog timer reset
end if;
end if;
end process;
-- 数据移位寄存器
dataseq: process (reset, clk)
begin
if (reset='0') then
q <= (others=>'0');
elsif (clk'event and clk='1') then
if (fall='1') then
q <= ps2_data & q(TOTAL_BITS-1 downto 1);
end if;
end if;
end process;
-- 看门狗时间计数器
watchcount: process (reset,rise,fall, clk)
begin
if ((reset='0') or (rise='1') or (fall='1')) then
watchdog_timer_count <= (others=>'0');
elsif (clk'event and clk='1') then
if (watchdog_timer_done='0') then
watchdog_timer_count <= watchdog_timer_count + 1;
end if;
end if;
end process;
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';
--x_increment <= (others=>'0');
--y_increment <= (others=>'0');
elsif (clk'event and clk='1') then
if (output_strobe='1') then
left_button <= q(1);
right_button <= q(2);
--x_increment <= '0' & q(19 downto 12);
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
tempx <= "0110010000"; -- 400
elsif (clk'event and clk='1') then
if (output_strobe='1') then
if ((tempx >= 635 and q(5)='0') or (tempx <= 5 and q(5)='1')) then
tempx <= tempx;
else
tempx <= tempx + (q(5) & q(5) & q(19 downto 12));--q(5):xsign q(6):ysign
if(tempx >= 635 and q(5)='0' ) then tempx <= "1001111011";
elsif((tempx<=5 and  q(5)='1') or (tempx>=645 and q(5)='1') or q(7)='1') then tempx  <= "0000000101";
end if;


end if;
mousex<=tempx;


end if;
end if;
end process;
cordinatey: process (reset, clk)
begin
if (reset='0') then
tempy <= "0100101100"; -- 300
elsif (clk'event and clk='1') then
if (output_strobe='1') then
if ((tempy >= 475 and q(6)='1') or (tempy <= 5 and q(6)='0')) then
tempy <= tempy;
else
tempy <= tempy + mouseyy; --(q(6) & q(6) & q(30 downto 23));
if(tempy >= 475 and q(6)='1') then tempy <="0111011011";
elsif((tempy<=5 and q(6)='0') or (tempy>=485 and q(6)='0') or q(8)='1') then  tempy <="0000000101";
end if;
end if;
mousey<=tempy;


end if;
end if;
end process;
--mousey <= "1001010101"-mouseyy;
data_ready <= output_strobe;
end Behavioral;


 


点击看大图


点击看大图

PARTNER CONTENT

文章评论3条评论)

登录后参与讨论

用户377235 2013-1-28 08:17

谢谢分享,这个对我很有用呀,太谢谢了,Gauss积分算法应该是最快的积分算法了吧!

用户1449502 2009-7-28 11:07

又1602.12864的vhdl程序发份给我,谢谢。jckxx@163.com

用户398455 2009-6-30 22:53

哇,真牛啊。我现在就是只写LCD1602,写了好长时间都没写出来。待会还要写12864的。请问你有这方面的程序吗,指点一下啊哈!!

用户516935 2008-9-18 09:19

很崇拜你! 我现在是初学者,什么都看不懂 以后想多问问你
相关推荐阅读
用户394541 2009-03-23 22:46
对某网友的不理解解释一下(12864坐标问题)
你可以看一下12864的资料,因为在每次写入地址并写好数据后,地址是自动加一的,也就是X坐标每次自动加一,所以,大循环里每次改变Y坐标,X坐标是在小循环里自动加的。因此只要每次把X的初始坐标一给即可。...
用户394541 2008-10-26 21:01
找工作好难,而某些公司的做法更让人可气
        今天又像以往跑出去找工作了,到了一个比较牛的大学去了,经过一个多小时的宣讲会,开始投简历,然后完了是等两个小时看通知有没有笔试机会,在操场上闲聊了两个小时 ,然后跑去看结果,我靠,居然...
用户394541 2008-10-09 23:55
AT24C04调试成功
经过一天的努力,终于把AT24C02 的驱动程序给搞定了。真是不容易,这个东西不是很好弄,而且时序的把握要非常好,稍有差迟,就不行了,现在把原程序传上来。89S52驱动+LCD1602显示。解压密码:...
用户394541 2008-09-25 11:49
SPCE061A的12864驱动程序
#include "spce061a.h"const unsigned char bmp3[]={0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,      0x05,...
用户394541 2008-07-11 11:28
大三的生活结束了
今天是考完试的最后一天,这也就意味着我的大三生活结束了.回顾这一学期的所做所为,感觉没有虚度,先后制作了好多小电子玩艺,也学到了一些东西.马上就要开始ALTERA的SOPC竞赛了,打算好好准备,争取拿...
EE直播间
更多
我要评论
3
6
关闭 站长推荐上一条 /3 下一条