|
旧式鼠标普遍采用ps/2协议和电脑进行通信,ps/2数据线使用开漏上拉的两根信号线和主机进行双向通信,一根数据线,一根时钟线。无论通信方向,时钟信号始终由ps/2设备产生;而无论何时,主机都拥有对通信的控制权,这可以通过拉低时钟信号超过一个从设备时钟周期时间(约100us)来抑制设备通信或者发起对设备的数据传输过程。
不过主机要告诉设备通信即将开始时,要经过如下过程:
1. Inhibit state 这时候主机将时钟线拉低(100us),数据线为高。
2. request state,这时候主机释放时钟线(高电平),同时拉低数据线,表示数据传输即将开始。
设备检测到这两个状态后,在不超过10ms的时间内,会产生时钟信号。且设备在时钟上升沿采样主机送来的数据,从而,主机可以利用时钟上升沿来移位数据到数据线,发送数据到设备。
主机发送数据到设备的格式为11bit(网络上的资料认为是12bit,包括一个起始位(始终为零)8bit数据,一个奇偶校验位(奇校验,即奇数个1时为1),一个停止位(高电平),一个ack位(低电平);不过据鄙人观察应该为11bit,没有起始位,因为设备给的时钟信号上升沿只有11个,当然你可以理解为主机释放时钟信号时候的上升沿为起始位),这11bit数据,真正由主机发起的只有9位,8个数据位和一个奇偶校验位,在传送完奇偶校验位后,主机应该释放数据线,从设备在下一个周期检测到数据线为高电平后,会在下下个时钟周期拉低数据线,作为acknowlegement表示数据已经收到。
设备在收到任何一个主机来的控制指令后,会首先发送一个response字节给主机,如果收到的为错误指令,会发送FC或者FE错误码给主机,如果是正确指令,发送FA码给主机。
鼠标在上电复位后会执行如下操作:
1. 发送FA,00,AA给系统。
2. 设置缺省模式,进入流模式(stream mode),禁止数据发送。
这时候设备等待主机发送指令给它,如果发送使能数据传输指令(0xF4)给设备,则设备在缺省模式下开始工作,并传送数据给主机,数据格式为每帧数据33bit,分为三个11bit,每11bit包括一个起始位(零),8bit数据,一个奇偶校验,一个停止位。第一个11bit的数据包含按键信息,滚轮信息。
第二个11bit数据包含X方向位移数据,以二进制补码格式发送,第三个11bit数据为Y方向位移信息,同样为二进制补码。
附上代码:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
entity ps2 is
port(clkin,rst :in std_logic;
ps2_clk,ps2_data :inout std_logic;
lefbut,rigbut,midbut ut std_logic;
x_mov1,x_mov2,y_mov1,y_mov2 ut std_logic_vector(6 downto 0));
end entity;
architecture behav of ps2 is
--
signal byte_cnt,delay td_logic_vector(3 downto 0);
signal lef_latch,rig_latch,mid_latch td_logic;
signal x_latch,y_latch td_logic_vector(7 downto 0);
signal ps2_clk_in,ps2_clk_out,ps2_data_in,ps2_data_out td_logic;
signal shift_reg td_logic_vector(32 downto 0);
signal clk_div td_logic_vector(8 downto 0);
signal clk,ce,de td_logic;
signal dout_reg td_logic_vector(9 downto 0);
signal cnt td_logic_vector(7 downto 0);
--enable instruction 0xF4;
constant enable_data td_logic_vector(9 downto 0):="0111101000";
signal ct :std_logic_vector(5 downto 0);
--
signal ps2_clk_syn0,ps2_clk_syn1,ps2_dat_syn0,ps2_dat_syn1,dout_syn1,dout_syn0 :std_logic;
--type define
type st is (listen,pullclk,pulldata,trans);
signal state :st ;
component SEG7_LUT is
port(oSEG ut std_logic_vector(6 downto 0);
iDIG :in std_logic_vector(3 downto 0));
end component;
begin
U1: SEG7_LUT port map(oSEG=>x_mov1,iDIG=>x_latch(3 downto 0));
U2: SEG7_LUT port map(oSEG=>x_mov2,iDIG=>x_latch(7 downto 4));
U3: SEG7_LUT port map(oSEG=>y_mov1,iDIG=>y_latch(3 downto 0));
U4: SEG7_LUT port map(oSEG=>y_mov2,iDIG=>y_latch(7 downto 4));
--clk_div,50MHz to 97.65625KHz;
process
begin
wait until clkin='1';
clk_div<=clk_div+1;
end process;
clk<=clk_div(8);
--sampling frame data;
process(ps2_clk_in,state)
begin
if state=listen then
if ps2_clk_in'event and ps2_clk_in='0' then
shift_reg(31 downto 0)<=shift_reg(32 downto 1);
shift_reg(32)<=ps2_data_in;
end if;
end if;
end process;
--after the controller send a command to device ,it'll sendback a response,with 11 bit.
--so when ct's value less than 16,no load activity.
process(ps2_clk_in,cnt,state)
begin
if cnt="11111111" then
ct<=(others=>'0');
elsif state=listen then
if rising_edge(ps2_clk_in) then
ct<=ct+1;
end if;
end if;
end process;
---idle state counter, watchdog like activity;
process(clk)
begin
if clk'event and clk='1' then
if (ps2_data_in='1' and ps2_clk_in='1') then
cnt<=cnt+1;
else
cnt<=(others=>'0');
end if;
end if;
end process;
----
----latch data from shift_reg;output is of 2's complement;
process(clk)
begin
if clk'event and clk='1' then
if cnt="00011110" and (ct(5)='1'or ct(4)='1') then
lef_latch<=shift_reg(1);
rig_latch<=shift_reg(2);
mid_latch<=shift_reg(3);
x_latch<=conv_integer(x_latch)+shift_reg(19 downto 12);
y_latch<=conv_integer(y_latch)+shift_reg(30 downto 23);
end if;
end if;
end process;
lefbut<=lef_latch;
rigbut<=rig_latch;
midbut<=mid_latch;
--
ps2_clk_syn0<=ps2_clk;
ps2_dat_syn0<=ps2_data;
--tristate output for ps2_clk and ps2_data;
process(ps2_clk,ce,ps2_clk_out)
begin
if ce='1' then
ps2_clk<=ps2_clk_out;
else
ps2_clk<='Z';
end if;
end process;
--tristate output of ps2_data;
process(ps2_data,de,ps2_data_out)
begin
if de='1' then
ps2_data<=ps2_data_out;
else
ps2_data<='Z';
end if;
end process;
--synchronize
process
begin
wait until clk='1';
ps2_clk_syn1<=ps2_clk_syn0;
ps2_dat_syn1<=ps2_dat_syn0;
ps2_clk_in<=ps2_clk_syn1;
ps2_data_in<=ps2_dat_syn1;
end process;
--tranceive 0xF4 to device when you press the rst button,additional debouncing work
considered.enables data transfer.
process(clk)
begin
if clk'event and clk='1' then
case state is
when listen => if rst='0' and cnt="11111111" then state<=pullclk;
end if;
ce<='0';de<='0';
when pullclk => if delay="1100" then state<=pulldata;
end if;
ce<='1';de<='0';
when pulldata=> state<=trans;
ce<='1';de<='1';
when trans => if byte_cnt="1010" then state<=listen;
end if;
ce<='0';de<='1';
when others => state<=listen;
end case;
end if;
end process;
--pull clk low for about 100us
process(clk,state)
begin
if state=pullclk then
if clk'event and clk='1' then
delay<=delay+1;
end if;
else
delay<=(others=>'0');
end if;
end process;
--tranceive data;adds up byte
process(ps2_clk_in,state)
begin
if state=trans then
if ps2_clk_in'event and ps2_clk_in='0' then
dout_reg<='0'&dout_reg(9 downto 1);
end if;
else
dout_reg<=enable_data;
end if;
end process;
process(ps2_clk_in,state)
begin
if state=trans then
if ps2_clk_in'event and ps2_clk_in='0' then
byte_cnt<=byte_cnt+1;
end if;
else
byte_cnt<=(others=>'0');
end if;
end process;
--output assignment;
ps2_data_out<=dout_reg(0);
ps2_clk_out<='0';
--
end behav; |
评分
-
1
查看全部评分
-
|