📄 ps2_mouse_interface.v
字号:
//*****************************************************************************//
// PS2鼠标接口程序 //
// 系统时钟48MHz //
// 最后修改日期2006.03.27 //
//*****************************************************************************//
//PS2鼠标数据包格式:
//使用标准的PS2接口,无扩展Intellimouse,数据包格式由3个字节,
//PS2数据格式
// D7 D6 D5 D4 D3 D2 D1 D0
//字节0 Y溢出 X溢出 Y符号位 X符号位 1 中间键 右键 左键
//字节1 X方向计数值
//字节2 Y方向计数值
//------------------------------------------------------------------------------
//传输数据时帧格式:
//收低位在前,高位在后
// bit0 bit1 bit2 bit3 bit4 bit5 bit6 bit7 bit8 bit9 bit10
// 开始(0) D0 D1 D2 D3 D4 D5 D6 D7 奇校验位 停止(1)
//------------------------------------------------------------------------------
//数据输出格式:
//PS2鼠标有按键按下,相应接口(left_button/right_button/middle_button)输出1,没按
//键按下输出0
//X、Y方向有位移,相应接口(x_increment/y_increment)输出位移增量,输出数据格式为9
//位二进制补码。
//------------------------------------------------------------------------------
//说明:
//本程序只支持标准PS2鼠标(即只能使用左、右、中三键和X、Y方向位移数据)
//对于带滚轮及有第四、五按键的鼠标,其多扩展的功能键无效。
//本程序的复位信号不能对鼠标进行复位。
//鼠标正常工作于Stream模式,该模式的进入是利用鼠标上电自动复位而进入的。
//为简化程序,本程序没有写鼠标复位程序。如出现异常状况,需重新插拔鼠标。
//data_ready输出脉冲信号(脉冲宽度为系统时钟周期)时,说明有新的数据更新。
//******************************************************************************//
`define TOTAL_BITS 33 // 一个数据包有33位数据
module ps2_mouse_interface (
clock,
reset, //复位,高电平有效
ps2_clk_in,
ps2_data_in,
ps2_clk_out,
ps2_data_out,
ps2_clk_dir,
ps2_data_dir,
left_button,
right_button,
middle_button,
x_increment,
y_increment,
data_ready); //数据已经正确收到
//I/O 口定义
input clock;
input reset;
input ps2_clk_in; //PS/2时钟线,输入口
input ps2_data_in; //PS/2数据线,输入口
output ps2_clk_out; //PS/2时钟线,输出口
output ps2_data_out; //PS/2数据线,输出口
output ps2_clk_dir; //PS/2时钟方向控制,高电平为输出,低电平为输入
output ps2_data_dir; //PS/2数据方向控制,高电平为输出,低电平为输入
output left_button;
output right_button;
output middle_button;
output [8:0] x_increment;
output [8:0] y_increment;
output data_ready;
//输出寄存器
reg left_button_r;
reg right_button_r;
reg middle_button_r;
reg [8:0] x_increment_r;
reg [8:0] y_increment_r;
reg data_ready_r;
reg ps2_clk_out_r;
reg ps2_data_out_r;
reg ps2_clk_dir_r;
reg ps2_data_dir_r;
//内部节点
wire watchdog_timer_done; //看门狗状态指示,SP2无时钟脉冲超过400US置位
wire timer_5us_done; //用于延时缓冲,防止毛刺干扰
wire packet_good; //数据包正确收到-状态指示
//内部寄存器
reg [`TOTAL_BITS-1:0] q; //移位寄存器
reg [2:0] m1_state;
reg [2:0] m1_next_state;
reg [3:0] m2_state;
reg [3:0] m2_next_state;
reg [5:0] bit_count; //发送接收数据是的位计数器
reg [WATCHDOG_TIMER_BITS-1:0] watchdog_timer_count; //看门狗计时器,400us
reg [TIMER_5US_BITS-1:0] timer_5us_count; //5uS计时器
reg ps2_clk_in_r; //同步后的PS2时钟
reg ps2_data_in_r; //同步后的PS2数据
reg sync_clk; //滤波后的PS2时钟--------由状态机M1产生输出
reg rising_edge; //PS2时钟上升沿标志------由状态机M1产生输出
reg falling_edge; //PS2时钟下降沿标志------由状态机M1产生输出
//计时器参数
//当系统时钟改变时要得新计算参数值
//参数值要求:
//WATCHDOG_TIMER_VALUE: 大于100uS 小于15mS
//TIMER_5US_VALUE: 1uS到20uS都行
parameter WATCHDOG_TIMER_VALUE = 19200; //看门狗计时器,400uS
parameter WATCHDOG_TIMER_BITS = 15; //400uS计时器所需计数器位数
parameter TIMER_5US_VALUE = 240; // 5uS计数值
parameter TIMER_5US_BITS = 8; // 5uS计时器所需计数器位数
//状态机M1参数表
parameter m1_clk_h = 3'b000,
m1_falling_edge = 3'b001,
m1_falling_wait = 3'b011,
m1_clk_l = 3'b010,
m1_rising_edge = 3'b110,
m1_rising_wait = 3'b100;
//状态机M2参数表
parameter m2_reset = 4'b0000,
m2_wait = 4'b0001,
m2_gather = 4'b0011,
m2_verify = 4'b0010,
m2_use = 4'b0110,
m2_hold_clk_l = 4'b0111,
m2_data_low_1 = 4'b0101,
m2_data_high_1 = 4'b0100,
m2_data_low_2 = 4'b1100,
m2_data_high_2 = 4'b1101,
m2_data_low_3 = 4'b1001,
m2_data_high_3 = 4'b1011,
m2_await_response = 4'b1010;
//**********************************************************//
//**********************************************************//
//模块代码开始
//**********************************************************//
assign ps2_clk_out = ps2_clk_out_r; //PS2时钟线输出
assign ps2_data_out = ps2_data_out_r; //PS2数据线输出
assign ps2_clk_dir = ps2_clk_dir_r; //PS2时钟方向
assign ps2_data_dir = ps2_data_dir_r; //PS2数据方向
assign left_button = left_button_r;
assign right_button = right_button_r;
assign middle_button = middle_button_r;
assign y_increment = y_increment_r;
assign x_increment = x_increment_r;
assign data_ready = data_ready_r;
//**********************************************************//
//同步PS2时钟、数据信号
always @(posedge clock)
begin
ps2_clk_in_r <= ps2_clk_in;
ps2_data_in_r <= ps2_data_in;
end
//**********************************************************//
//**********************************************************//
//状态机M1
//功能:同步PS2时钟,在PS2的时钟边沿产生边沿标志
//**********************************************************//
//M1状态转向
always @(posedge clock)
begin
if (reset == 1'b1)
m1_state <= m1_clk_h;
else
m1_state <= m1_next_state;
end
//M1转换逻辑
always @(m1_state or ps2_clk_in_r or timer_5us_done or watchdog_timer_done)
begin
sync_clk <= 1'b0;
rising_edge <= 1'b0;
falling_edge <= 1'b0;
case (m1_state)
m1_clk_h : //时钟高电平
begin
sync_clk <= 1'b1;
if(~ps2_clk_in_r)
m1_next_state <= m1_falling_edge;
else
m1_next_state <= m1_clk_h;
end
m1_falling_edge : //时钟下降沿
begin
falling_edge <= 1'b1;
m1_next_state <= m1_falling_wait;
end
m1_falling_wait : //等待5US延时防止毛刺干扰
begin
if(timer_5us_done)
m1_next_state <= m1_clk_l;
else
m1_next_state <= m1_falling_wait;
end
m1_clk_l : //时钟低电平
begin
if(ps2_clk_in_r)
m1_next_state <= m1_rising_edge;
else
m1_next_state <= m1_clk_l;
end
m1_rising_edge : //时钟上升沿
begin
rising_edge <= 1'b1;
m1_next_state <= m1_rising_wait;
end
m1_rising_wait : //等待5US延时防止毛刺干扰
begin
sync_clk <= 1'b1;
if(timer_5us_done)
m1_next_state <= m1_clk_h;
else
m1_next_state <= m1_rising_wait;
end
default : m1_next_state <= m1_clk_h;
endcase
end
//**********************************************************//
//**********************************************************//
//状态机M2
//功能:初始化PS2鼠标,接收PS2鼠标数据包
//**********************************************************//
//M2状态转向
always @(posedge clock)
begin
if(reset == 1'b1)
m2_state <= m2_reset;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -