📄 ps2_mouse_interface.v
字号:
else
m2_state <= m2_next_state;
end
//M2转换逻辑
always @(m2_state
or q
or falling_edge
or rising_edge
or watchdog_timer_done
or bit_count
or packet_good
or ps2_data_in_r
or sync_clk
)
begin
ps2_clk_out_r <= 1'b1;
ps2_data_out_r <= 1'b1;
ps2_clk_dir_r <= 1'b0;
ps2_data_dir_r <= 1'b0;
data_ready_r <= 1'b0;
case (m2_state)
m2_reset : //复位后,发送命令到PS2鼠标
begin
m2_next_state <= m2_hold_clk_l;
end
m2_wait :
begin
if (falling_edge)
m2_next_state <= m2_gather;
else
m2_next_state <= m2_wait;
end
m2_gather : //判断数据是否收完
begin
if (watchdog_timer_done && (bit_count == `TOTAL_BITS))
m2_next_state <= m2_verify;
else if (watchdog_timer_done && (bit_count < `TOTAL_BITS))
m2_next_state <= m2_hold_clk_l;
else
m2_next_state <= m2_gather;
end
m2_verify : //检验数据包是否正确
begin
if (packet_good)
m2_next_state <= m2_use;
else
m2_next_state <= m2_wait;
end
m2_use : //数据包是否正确
begin
data_ready_r <= 1'b1;
m2_next_state <= m2_wait;
end
//复位或出错时进入以下状态,主机向PS2发送复位指令0xFF,PS2鼠标收到
//复位指令时应答0xFA,大约360mS后,鼠标完成自检,自检成功发送0xAA,
//不成功发送0xFC;然后发送ID号0x00.之后进入Stream 模式Stream 模式.
//此时PS2鼠标默认属性为:采样速率100 采样点/秒;分辨率4 个计数值/毫米;
//缩放比例1:1;数据报告被禁止,为简化程序,不修改默认属性。
//最后发送0xF4命令使能数据报告,等PS2鼠标应答0xFA.致此,初使化PS2鼠标完毕.
//为简化程序,发送复位指令部分省略(复位由鼠标上电复位完成),只发送使能数据报告指令。
m2_hold_clk_l : //拉低时钟线400US,准备发送命令
begin
ps2_clk_dir_r <= 1'b1;
ps2_clk_out_r <= 1'b0;
if(watchdog_timer_done && ~sync_clk)
m2_next_state <= m2_data_low_1;
else
m2_next_state <= m2_hold_clk_l;
end
m2_data_low_1 : //发送起始位"0",d[0],d[1]
begin
ps2_data_dir_r <= 1'b1;
ps2_data_out_r <= 1'b0;
if (falling_edge && (bit_count == 6'd2))
m2_next_state <= m2_data_high_1;
else
m2_next_state <= m2_data_low_1;
end
m2_data_high_1 : //发送位d[2]
begin
ps2_data_dir_r <= 1'b1;
if (falling_edge)
m2_next_state <= m2_data_low_2;
else
m2_next_state <= m2_data_high_1;
end
m2_data_low_2 :
begin
ps2_data_dir_r <= 1'b1;
ps2_data_out_r <= 1'b0; //发送位d[3]
if (falling_edge)
m2_next_state <= m2_data_high_2;
else
m2_next_state <= m2_data_low_2;
end
m2_data_high_2 : //发送位d[4],d[5],d[6],d[7]
begin
ps2_data_dir_r <= 1'b1;
if (falling_edge && (bit_count == 6'd8))
m2_next_state <= m2_data_low_3;
else
m2_next_state <= m2_data_high_2;
end
m2_data_low_3 : //发送奇偶校验位
begin
ps2_data_dir_r <= 1'b1;
ps2_data_out_r <= 1'b0;
if(falling_edge)
m2_next_state <= m2_data_high_3;
else
m2_next_state <= m2_data_low_3;
end
m2_data_high_3 : //停止位"1",应答处理
begin
if (falling_edge && ps2_data_in_r)
m2_next_state <= m2_hold_clk_l; //有错误产生,重新复位
else if (falling_edge && ~ps2_data_in_r)
m2_next_state <= m2_await_response;
else
m2_next_state <= m2_data_high_3;
end
//等待SP2鼠标回应:这里不对回应做处理,如果指令没有被鼠标正确收到,
//鼠标会回应(0xFC)要求重新发送指令,也可能回应(0xFE)表示收到的数
//据出错。如果正确收到会回应(0xFA)。
//注:如果鼠标的回应时间超过400us,bit_count将被复位,这时应收到
//的位数应该是11。但一般鼠标的回应时间较短,所以bit_count没被复,
//这时的位数值应该是22。
m2_await_response :
begin
if (bit_count == 6'd22)
m2_next_state <= m2_verify;
else
m2_next_state <= m2_await_response;
end
default : m2_next_state <= m2_wait;
endcase
end
//**********************************************************//
//移位计数器
//在PS2时钟的下降沿加计数
always @(posedge clock)
begin
if(reset == 1'b1)
bit_count <= 6'd0; //复位时计数器清零
else if(falling_edge)
bit_count <= bit_count + 6'd1;
else if(watchdog_timer_done)
bit_count <= 6'd0; //接收完一个数据包后计数器清零
end
//移位寄存器,在时钟的下降沿锁存数据
//功能:接收PS2发送到来的数据
always @(posedge clock)
begin
if (reset == 1'b1)
q <= `TOTAL_BITS'd0;
else if (falling_edge)
q <= {ps2_data_in_r,q[`TOTAL_BITS-1:1]};
end
//看门狗计时器
//PS2无时钟脉冲超过400us,watchdog_timer_done 置位
//功能:发送数据时抑制时钟线标志,接收数据包后状态指示。
always @(posedge clock)
begin
if(reset || rising_edge || falling_edge)
watchdog_timer_count <= 0;
else if(~watchdog_timer_done)
watchdog_timer_count <= watchdog_timer_count + 1;
end
assign watchdog_timer_done = (watchdog_timer_count==WATCHDOG_TIMER_VALUE-1);
//缓冲时间5US计数器
always @(posedge clock)
begin
if (reset || falling_edge || rising_edge )
timer_5us_count <= 0;
else
timer_5us_count <= timer_5us_count + 1;
end
assign timer_5us_done = (timer_5us_count == TIMER_5US_VALUE-1);
//验证收到的数据包数据是否有效、正确
assign packet_good = (
(q[0] == 1'b0) //第一字节起始位
&& (q[10] == 1'b1) //第一字节停止位
&& (q[11] == 1'b0) //第二字节起始位
&& (q[21] == 1'b1) //第二字节停止位
&& (q[22] == 1'b0) //第三字节起始位
&& (q[32] == 1'b1) //第三字节停止位
&& (q[9] == ~^q[8:1]) //第一字节奇验证位
&& (q[20] == ~^q[19:12]) //第二字节奇验证位
&& (q[31] == ~^q[30:23]) //第三字节奇验证位
);
//锁存输出新的数据
always @(posedge clock)
begin
if (reset == 1'b1)
begin
left_button_r <= 1'b0;
right_button_r <= 1'b0;
middle_button_r <= 1'b0;
x_increment_r <= 1'b0;
y_increment_r <= 1'b0;
end
else if (data_ready_r == 1'b1)
begin
left_button_r <= q[1]; //BIT1[0]
right_button_r <= q[2]; //BIT1[1]
middle_button_r <= q[3]; //BIT1[2]
x_increment_r <= {q[5],q[19:12]}; //BIT1[4],BIT2
y_increment_r <= {q[6],q[30:23]}; //BIT1[5],BIT3
end
end
endmodule
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -