此试验我一人调试许久都未成功,但发送ff时,读出来的数据确是对的,一开始让我窃喜,但发送f4时,读出来的数据确是错的,哎让苦恼啊,能力有限,只能先暂时就这样吧,那位什么还要贴出来呢,有两个原因:
1、等自己能力达到一定时,在回过头来,把这个问题解决掉,我相信,一定能实现的。
2、晒出来就是希望能得到各位网友能帮忙指点哪个地方容易出问题。在此先拜谢了!
>>PS2鼠标实验是一个双向通信实验,那就得知道PS2鼠标传输协议,本人觉得自己对PS2传输协议有所掌握(也许理解的还不够到位)。具体传输协议就不多描述,还是看专业的“PS/2 技术参考”。
>>在写代码之前,我参考网上一个例子,链接“http://www.360doc.com/content/13/0612/20/2260882_292421295.shtml”,这位网友例化时,看起来有点累,思路基本能看懂,自己稍微整理了一下,整体框架如下图。
步骤:
1、先由控制模块启动发送模块,把指令“0XF4”发送给鼠标。
2、发送模块发送完后,产生一个发送完标志,传给控制模块,在由控制模块启动接收模块。
3、接收模块接收完数据,产生一个接收完标志,传给控制模块,模块在进行相应的数据处理。
4、数据处理完后,传给显示模块进行显示。
代码实现:
ps2_data_control.v
module ps2_data_control(
//input
sys_clk,
rst_n,
send_done_sig, //发送完标志
rx_done_sig, //接收完标志
data_buf, //接收到的数据 //output
rx_en, //接收使能
send_en, //发送使能
send_cmd, //要发送的命令
dis_data_low1, //要显示的数据
dis_data_hig1, dis_data_low2, //要显示的数据
dis_data_hig2, dis_data_low3, //要显示的数据
dis_data_hig3, dis_data_low4, //要显示的数据
dis_data_hig4, dis_data_btn
);
input sys_clk;
input rst_n;
input send_done_sig;
input rx_done_sig;
input [:] data_buf; output rx_en;
output send_en;
output [:] send_cmd;
output [:] dis_data_low1;
output [:] dis_data_hig1;
output [:] dis_data_low2;
output [:] dis_data_hig2;
output [:] dis_data_low3;
output [:] dis_data_hig3;
output [:] dis_data_low4;
output [:] dis_data_hig4;
output [:] dis_data_btn;
/**********************************************************************/
parameter T100MS = 'd4_999_999;
parameter T500MS = 'd24_999_999;
parameter T100US = 'd4_999;
parameter PS2_RST = 'hf4; //复位cmd
parameter PS2_EN = 'hf4; //数据报告使能cmd
parameter IDLE = 'd0,
SEND_PS2_RST = 'd1,
RX_EN1 = 'd2,
RX_ANSWER_FA = 'd3,
RX_ANSWER_AA = 'd4,
RX_ANSWER_ID = 'd5,
SEND_PS2_EN = 'd6,
RX_EN2 = 'd7,
RX_ANSWER2 = 'd8,
RX_BYTE1 = 'd9,
RX_BYTE2 = 'd10,
RX_BYTE3 = 'd11,
DELAY = 'd12,
STOP = 'd13;
/**********************************************************************/
//assign send_cmd = STREAM;
/**********************************************************************/
//200us计数器
reg [:] cnt;
always @(posedge sys_clk or negedge rst_n)
if(!rst_n)
cnt <= 'd0;
else if(!cnt_en || cnt == T500MS)
cnt <= 'd0;
else
cnt <= cnt + 'b1;
/**********************************************************************/
reg send_en;
reg rx_en;
reg [:] data_answer; //保存应答位
reg x_sign; //x的符号位
reg y_sign; //y的符号位
reg [:] x_move; //x的偏移量
reg [:] y_move; //y的偏移量
reg [:] state;
reg [:] dis_data_temp1;
reg [:] dis_data_temp2;
reg [:] dis_data_temp3;
reg [:] dis_data_temp4;
reg [:] dis_data_btn;
reg cnt_en;
reg [:] send_cmd;
always @(posedge sys_clk or negedge rst_n)
if(!rst_n) begin
send_en <= 'b0;
rx_en <= 'b0;
data_answer <= 'h00;
x_sign <= 'b0;
y_sign <= 'b0;
state <= IDLE;
dis_data_temp1 <= 'h00;
dis_data_temp2 <= 'h00;
dis_data_temp3 <= 'h00;
dis_data_temp4 <= 'h00;
cnt_en <= 'b0;
dis_data_btn <= "X";
send_cmd <= 'h00;
end
else begin
case(state)
IDLE:
begin
state <= SEND_PS2_RST;
cnt_en <= 'b1;
end SEND_PS2_RST: //发送复位 0xff
if(cnt == T100MS) begin
cnt_en <= 'b0;
send_en <= 'b1; //启动发送
send_cmd <= PS2_RST;
state <= RX_EN1;
end RX_EN1:
if(send_done_sig) begin
rx_en <= 'b1;
send_en <= 'b0;
state <= RX_ANSWER_FA;
end RX_ANSWER_FA: //接收鼠标发回的应答数据0xfa
if(rx_done_sig) begin
dis_data_temp1 <= data_buf;
state <= RX_ANSWER_AA;//RX_BYTE1;
end RX_ANSWER_AA: //接收鼠标发回的应答数据0xaa
if(rx_done_sig) begin
dis_data_temp2 <= data_buf;
state <= RX_ANSWER_ID;
end RX_ANSWER_ID: //接收鼠标发回的应答数据0x00
if(rx_done_sig) begin
dis_data_temp3 <= data_buf;
cnt_en <= 'b1;
state <= SEND_PS2_RST;
end SEND_PS2_EN: //发送0xf4
if(cnt == T100MS)begin
rx_en <= 'b0;
cnt_en <= 'b0;
send_en <= 'b1; //启动发送
send_cmd <= PS2_EN;
state <= RX_EN2;
end RX_EN2:
if(send_done_sig) begin
rx_en <= 'b1; //启动接收
send_en <= 'b0;
state <= RX_ANSWER2;
end RX_ANSWER2: //第二次应答位
if(rx_done_sig) begin
dis_data_temp4 <= data_buf;
state <= RX_BYTE1;
end RX_BYTE1:
if(rx_done_sig) begin
if(data_buf[] == 'b1)//左键被按下
dis_data_btn <= "L";
else if(data_buf[] == 'b1) //右键被按下
dis_data_btn <= "R";
else if(data_buf[] == 'b1) //中键被按下
dis_data_btn <= "M"; x_sign <= data_buf[];
y_sign <= data_buf[]; state <= RX_BYTE2;
end RX_BYTE2:
if(rx_done_sig) begin //接收到第二个字节
x_move <= data_buf;
state <= RX_BYTE3;
end RX_BYTE3: //接收到第三个字节
if(rx_done_sig) begin
y_move <= data_buf;
state <= STOP;
cnt_en <= 'b1;
end STOP:
if(cnt == T100MS) begin
cnt_en <= 'b0;
state <= RX_BYTE1;
end
endcase
end reg [:] dis_data_low1;
always @(dis_data_temp1[:])
case(dis_data_temp1[:])
'h0: dis_data_low1 = "0";
'h1: dis_data_low1 = "1";
'h2: dis_data_low1 = "2";
'h3: dis_data_low1 = "3";
'h4: dis_data_low1 = "4";
'h5: dis_data_low1 = "5";
'h6: dis_data_low1 = "6";
'h7: dis_data_low1 = "7";
'h8: dis_data_low1 = "8";
'h9: dis_data_low1 = "9";
'ha: dis_data_low1 = "a";
'hb: dis_data_low1 = "b";
'hc: dis_data_low1 = "c";
'hd: dis_data_low1 = "d";
'he: dis_data_low1 = "e";
'hf: dis_data_low1 = "f";
endcase reg [:] dis_data_hig1;
always @(dis_data_temp1[:])
case(dis_data_temp1[:])
'h0: dis_data_hig1 = "0";
'h1: dis_data_hig1 = "1";
'h2: dis_data_hig1 = "2";
'h3: dis_data_hig1 = "3";
'h4: dis_data_hig1 = "4";
'h5: dis_data_hig1 = "5";
'h6: dis_data_hig1 = "6";
'h7: dis_data_hig1 = "7";
'h8: dis_data_hig1 = "8";
'h9: dis_data_hig1 = "9";
'ha: dis_data_hig1 = "a";
'hb: dis_data_hig1 = "b";
'hc: dis_data_hig1 = "c";
'hd: dis_data_hig1 = "d";
'he: dis_data_hig1 = "e";
'hf: dis_data_hig1 = "f";
endcase reg [:] dis_data_low2;
always @(dis_data_temp2[:])
case(dis_data_temp2[:])
'h0: dis_data_low2 = "0";
'h1: dis_data_low2 = "1";
'h2: dis_data_low2 = "2";
'h3: dis_data_low2 = "3";
'h4: dis_data_low2 = "4";
'h5: dis_data_low2 = "5";
'h6: dis_data_low2 = "6";
'h7: dis_data_low2 = "7";
'h8: dis_data_low2 = "8";
'h9: dis_data_low2 = "9";
'ha: dis_data_low2 = "a";
'hb: dis_data_low2 = "b";
'hc: dis_data_low2 = "c";
'hd: dis_data_low2 = "d";
'he: dis_data_low2 = "e";
'hf: dis_data_low2 = "f";
endcase reg [:] dis_data_hig2;
always @(dis_data_temp2[:])
case(dis_data_temp2[:])
'h0: dis_data_hig2 = "0";
'h1: dis_data_hig2 = "1";
'h2: dis_data_hig2 = "2";
'h3: dis_data_hig2 = "3";
'h4: dis_data_hig2 = "4";
'h5: dis_data_hig2 = "5";
'h6: dis_data_hig2 = "6";
'h7: dis_data_hig2 = "7";
'h8: dis_data_hig2 = "8";
'h9: dis_data_hig2 = "9";
'ha: dis_data_hig2 = "a";
'hb: dis_data_hig2 = "b";
'hc: dis_data_hig2 = "c";
'hd: dis_data_hig2 = "d";
'he: dis_data_hig2 = "e";
'hf: dis_data_hig2 = "f";
endcase reg [:] dis_data_low3;
always @(dis_data_temp3[:])
case(dis_data_temp3[:])
'h0: dis_data_low3 = "0";
'h1: dis_data_low3 = "1";
'h2: dis_data_low3 = "2";
'h3: dis_data_low3 = "3";
'h4: dis_data_low3 = "4";
'h5: dis_data_low3 = "5";
'h6: dis_data_low3 = "6";
'h7: dis_data_low3 = "7";
'h8: dis_data_low3 = "8";
'h9: dis_data_low3 = "9";
'ha: dis_data_low3 = "a";
'hb: dis_data_low3 = "b";
'hc: dis_data_low3 = "c";
'hd: dis_data_low3 = "d";
'he: dis_data_low3 = "e";
'hf: dis_data_low3 = "f";
endcase reg [:] dis_data_hig3;
always @(dis_data_temp3[:])
case(dis_data_temp3[:])
'h0: dis_data_hig3 = "0";
'h1: dis_data_hig3 = "1";
'h2: dis_data_hig3 = "2";
'h3: dis_data_hig3 = "3";
'h4: dis_data_hig3 = "4";
'h5: dis_data_hig3 = "5";
'h6: dis_data_hig3 = "6";
'h7: dis_data_hig3 = "7";
'h8: dis_data_hig3 = "8";
'h9: dis_data_hig3 = "9";
'ha: dis_data_hig3 = "a";
'hb: dis_data_hig3 = "b";
'hc: dis_data_hig3 = "c";
'hd: dis_data_hig3 = "d";
'he: dis_data_hig3 = "e";
'hf: dis_data_hig3 = "f";
endcase reg [:] dis_data_low4;
always @(dis_data_temp4[:])
case(dis_data_temp4[:])
'h0: dis_data_low4 = "0";
'h1: dis_data_low4 = "1";
'h2: dis_data_low4 = "2";
'h3: dis_data_low4 = "3";
'h4: dis_data_low4 = "4";
'h5: dis_data_low4 = "5";
'h6: dis_data_low4 = "6";
'h7: dis_data_low4 = "7";
'h8: dis_data_low4 = "8";
'h9: dis_data_low4 = "9";
'ha: dis_data_low4 = "a";
'hb: dis_data_low4 = "b";
'hc: dis_data_low4 = "c";
'hd: dis_data_low4 = "d";
'he: dis_data_low4 = "e";
'hf: dis_data_low4 = "f";
endcase reg [:] dis_data_hig4;
always @(dis_data_temp4[:])
case(dis_data_temp4[:])
'h0: dis_data_hig4 = "0";
'h1: dis_data_hig4 = "1";
'h2: dis_data_hig4 = "2";
'h3: dis_data_hig4 = "3";
'h4: dis_data_hig4 = "4";
'h5: dis_data_hig4 = "5";
'h6: dis_data_hig4 = "6";
'h7: dis_data_hig4 = "7";
'h8: dis_data_hig4 = "8";
'h9: dis_data_hig4 = "9";
'ha: dis_data_hig4 = "a";
'hb: dis_data_hig4 = "b";
'hc: dis_data_hig4 = "c";
'hd: dis_data_hig4 = "d";
'he: dis_data_hig4 = "e";
'hf: dis_data_hig4 = "f";
endcase
endmodule
ps2_send_control.v (注意ps2_clk和ps2_data控制方向)
module ps2_send_control(
//input
sys_clk,
rst_n,
send_en, //发送使能
send_cmd, //要发送的数据 0xf4 //output
send_done_sig,//发送完标志 //inout
ps2_clk, //鼠标时钟
ps2_data //鼠标数据
); input sys_clk;
input rst_n;
input send_en;
input [:] send_cmd; output send_done_sig; inout ps2_clk;
inout ps2_data;
/**************************************************************/
parameter T200US = 'd9999;
parameter T40US = 'd1999;
parameter IDLE = 'd0,
PS2_CLK_SET0 = 'd1, //时钟拉低
PS2_DATA_SET0 = 'd2, //数据拉低
PS2_CLK_SET1 = 'd3, //释放时钟,拉高
SEND_DATA = 'd4, //发送8bit数据和校验位
PS2_DATA_SET1 = 'd5, //释放数据,拉高
STOP = 'd6;
/**************************************************************/
//如果send_data中有偶数个1,那么^send_data结果为0,否则为1,在取反即为奇校验位应设置的值
wire odd_parity;
assign odd_parity = ~(^send_cmd);
//上面这句,一位网友说是下面的操作方式
// ~(odd_parity ^send_cmd[0]) -> ~(~(odd_parity ^send_cmd[0]) ^send_cmd[1])
// -> ~(~(~(odd_parity ^send_cmd[0]) ^send_cmd[1]) ^send_cmd[2])... 一次类推
/**************************************************************/
//控制鼠标时钟和数据的方向
//link_clk = 1,ps2_clk为output ,link_clk = 0,ps2_clk为input,FPGA内部得把该管脚设置为高阻态,以便接收时钟
//link_data = 1,ps2_data为output ,link_data = 0,ps2_data为input,FPGA内部得把该管脚设置为高阻态,以便接受数据
assign ps2_clk = link_clk ? ps2_clk_out : 'bz;
assign ps2_data = link_data ? ps2_data_out : 'bz;
/**************************************************************/
//200us计数器
reg [:] cnt;
always @(posedge sys_clk or negedge rst_n)
if(!rst_n)
cnt <= 'd0;
else if(!cnt_en || cnt == T200US)
cnt <= 'd0;
else
cnt <= cnt + 'b1;
/**************************************************************/
reg ps2_clk_1;
reg ps2_clk_2;
always @(posedge sys_clk or negedge rst_n)
if(!rst_n) begin
ps2_clk_1 <= 'b1;
ps2_clk_2 <= 'b1;
end
else begin
ps2_clk_1 <= ps2_clk;
ps2_clk_2 <= ps2_clk_1;
end wire ps2_clk_n;
assign ps2_clk_n = ps2_clk_2& (~ps2_clk_1);
/**************************************************************/
reg link_clk;
reg link_data;
reg cnt_en;
reg ps2_clk_out;
reg ps2_data_out;
reg send_done_sig;
reg [:] state;
reg [:] i;
reg [:] s_data;
always @(posedge sys_clk or negedge rst_n)
if(!rst_n) begin
link_clk <= 'b0;
link_data <= 'b0;
cnt_en <= 'b0;
ps2_clk_out <= 'b1;
ps2_data_out <= 'b1;
send_done_sig <= 'b0;
state <= IDLE;
i <= 'd0;
s_data <= 'd0;
end
else if(send_en) begin
case(state)
IDLE:
begin
state <= PS2_CLK_SET0;
s_data <= /*{1'b0,send_cmd}*/{odd_parity,send_cmd};
end PS2_CLK_SET0:
begin
link_clk <= 'b1; //输出状态
ps2_clk_out <= 'b0;
cnt_en <= 'b1; //启动计数器
state <= PS2_DATA_SET0;
end PS2_DATA_SET0:
if(cnt == T200US) begin //200us后 拉低数据线
cnt_en <= 'b0;
link_data <= 'b1;
ps2_data_out <= 'b0;
state <= PS2_CLK_SET1;
end PS2_CLK_SET1:
/*if(cnt == T40US)*/begin
// cnt_en <= 1'b0;
link_clk <= 'b0; //输入状态 link_clk置0的话,LCD上没有数据显示,写0还能显示几个数据
// ps2_clk_out <= 1'b1; //释放时钟线
state <= SEND_DATA;
end SEND_DATA:
if(ps2_clk_n) begin //在时钟的下降沿设置数据
if(i == 'd9) begin
i <= 'd0;
state <= PS2_DATA_SET1;
end
else begin
link_clk <= 'b0;
link_data <= 'b1;
ps2_data_out <= s_data[i];
i <= i + 'b1;
state <= SEND_DATA;
end
end PS2_DATA_SET1: //释放数据线 发送停止位
if(ps2_clk_n) begin
link_data <= 'b1;
ps2_data_out <= 'b1;
state <= STOP;
send_done_sig <= 'b1;
end STOP:
begin
link_data <= 'b0; //link_data置1的话,LCD上没有数据显示,写0还能显示几个数据
state <= IDLE;
end
endcase
end endmodule
ps2_rx_control.v
module ps2_rx_control(
//input
sys_clk,
rst_n,
ps2_clk_in, //鼠标时钟
ps2_data_in, //鼠标数据
rx_en, //接收模块使能信号 //output
rx_done_sig, //接收完标志信号
data_buf //保存接收到的数据
);
input sys_clk;
input rst_n;
input ps2_clk_in;
input ps2_data_in;
input rx_en; output rx_done_sig;
output [:] data_buf;
/**************************************************************/
reg ps2_clk_in_1;
reg ps2_clk_in_2;
wire ps2_clk_in_n;
always @(posedge sys_clk or negedge rst_n)
if(!rst_n) begin
ps2_clk_in_1 <= 'b1;
ps2_clk_in_2 <= 'b1;
end
else begin
ps2_clk_in_1 <= ps2_clk_in;
ps2_clk_in_2 <= ps2_clk_in_1;
end assign ps2_clk_in_n = ps2_clk_in_2 & (~ps2_clk_in_1);
/**************************************************************/
reg [:] i;
reg [:] data_buf;
reg rx_done_sig;
always @(posedge sys_clk or negedge rst_n)
if(!rst_n) begin
i <= 'd0;
data_buf <= 'h00;
rx_done_sig <= 'b0;
end
else if(rx_en/*ps2_clk_in_n*/) begin //ps2_clk_in_n不能写在这个地方,rx_done_sig置1和置0没必要等到ps2_clk_in下降沿时设置,否则会出问题
case(i)
'd0:
if(ps2_clk_in_n) begin
i <= i + 'b1; //起始位不处理
end
'd1,4'd2,'d3,4'd4,'d5,4'd6,'d7,4'd8: //接收8位数据
if(ps2_clk_in_n) begin
i <= i + 'b1;
data_buf[i-] <= ps2_data_in;
end 'd9:
if(ps2_clk_in_n)
i <= i + 'b1; //奇校验位不处理 'd10:
if(ps2_clk_in_n)
i <= i + 'b1; //停止位不处理 'd11:
begin
rx_done_sig <= 'b1; //标志着一帧数据接收完
i <= i + 'b1;
end 'd12:
begin
rx_done_sig <= 'b0; //置0,给下次接收做好准备
i <= 'd0;
end
endcase
end endmodule
LCD12864.v
module LCD12864(
//input
sys_clk,
rst_n,
dis_data_low1,
dis_data_hig1, dis_data_low2,
dis_data_hig2, dis_data_low3,
dis_data_hig3, dis_data_low4,
dis_data_hig4, dis_data_btn, //output
lcd_rs,
lcd_rw,
lcd_en,
lcd_data,
lcd_psb
);
input sys_clk;// 50MHZ
input rst_n;
input [:] dis_data_low1;
input [:] dis_data_hig1;
input [:] dis_data_low2;
input [:] dis_data_hig2;
input [:] dis_data_low3;
input [:] dis_data_hig3;
input [:] dis_data_low4;
input [:] dis_data_hig4; input [:] dis_data_btn; output lcd_rs;//H:data L:command
output lcd_rw;//H:read module L:write module
output lcd_en;//H active
output [:] lcd_data;
output lcd_psb;//H:parallel module L:SPI module /***************************************************/
parameter T3MS = 'd149_999;
parameter IDLE = 'd0,
INIT_FUN_SET1 = 'd1,
INIT_FUN_SET2 = 'd2,
INIT_DISPLAY = 'd3,
INIT_CLEAR = 'd4,
INIT_DOT_SET = 'd5,
SET_DDRAM = 'd6,
WRITE_DATA0 = 'd7,
WRITE_DATA1 = 'd8,
WRITE_DATA2 = 'd9,
WRITE_BLANK1 = 'd10,
WRITE_DATA3 = 'd11,
WRITE_DATA4 = 'd12,
WRITE_BLANK2 = 'd13,
WRITE_DATA5 = 'd14,
WRITE_DATA6 = 'd15,
SET_DDRAM1 = 'd16,
WRITE_DATA7 = 'd17,
WRITE_DATA8 = 'd18,
WRITE_DATA9 = 'd19,
SET_DDRAM2 = 'd20,
WRITE_DATA10 = 'd21,
WRITE_DATA11 = 'd22; /***************************************************/
//产生周期为6MS的lcd_clk给LCD
reg [:] cnt;
reg lcd_clk;
always @(posedge sys_clk or negedge rst_n)
if(!rst_n) begin
cnt <= 'd0;
lcd_clk <= 'b0;
end
else if(cnt == T3MS)begin
cnt <= 'd0;
lcd_clk <= ~lcd_clk;
end
else
cnt <= cnt + 'b1; /***************************************************/
reg lcd_rs;
always @(posedge lcd_clk or negedge rst_n)
if(!rst_n)
lcd_rs <= 'b0;
else if( (state == WRITE_DATA1) || (state == WRITE_DATA2)
|| (state == WRITE_DATA3) || (state == WRITE_DATA4)
|| (state == WRITE_DATA5) || (state == WRITE_DATA6)
|| (state == WRITE_DATA7) || (state == WRITE_DATA8)
|| (state == WRITE_DATA9) || (state == WRITE_DATA10)
|| (state == WRITE_DATA11) || (state == WRITE_DATA0)
||(state == WRITE_BLANK1) || (state == WRITE_BLANK2))
lcd_rs <= 'b1; //写数据模式
else
lcd_rs <= 'b0; //写命令模式
/***************************************************/
reg [:] state;
reg [:] lcd_data;
reg [:] num;
reg en;
always @(posedge lcd_clk or negedge rst_n)
if(!rst_n) begin
state <= IDLE;
lcd_data <= 'h00;
en <= 'b1;
num <= 'd0;
end
else
case(state)
IDLE:
begin
state <= INIT_FUN_SET1;
lcd_data <= 'hzz;
en <= 'b1;
end INIT_FUN_SET1:
begin
lcd_data <= 'h30; //功能设定
state <= INIT_FUN_SET2;
end INIT_FUN_SET2:
begin
lcd_data <= 'h30; //功能设定
state <= INIT_DISPLAY;
end INIT_DISPLAY:
begin
lcd_data <= 'h0c; //显示设定
state <= INIT_CLEAR;
end INIT_CLEAR:
begin
lcd_data <= 'h01; //清屏
state <= INIT_DOT_SET;
end INIT_DOT_SET:
begin
lcd_data <= 'h06; //进入点设定
state <= SET_DDRAM;
end SET_DDRAM:
begin
lcd_data <= 'h90;//2 line
state <= WRITE_DATA0;
end WRITE_DATA0: ////ff应答::
begin
if(num == 'd7)
state <= WRITE_DATA1;
else begin
num <= num + 'b1;
lcd_data <= dis_data;
state <= WRITE_DATA0;
end
end WRITE_DATA1: //回应的第一个数据高字节
begin
lcd_data <= dis_data_hig1;
state <= WRITE_DATA2;
end WRITE_DATA2://回应的第一个数据低字节
begin
lcd_data <= dis_data_low1;
state <= WRITE_BLANK1;
end WRITE_BLANK1: //写一个空格
begin
lcd_data <= " ";
state <= WRITE_DATA3;
end WRITE_DATA3: //回应的第二个数据高字节
begin
lcd_data <= dis_data_hig2;
state <= WRITE_DATA4;
end WRITE_DATA4://回应的第二个数据低字节
begin
lcd_data <= dis_data_low2;
state <= WRITE_BLANK2;
end WRITE_BLANK2: //写一个空格
begin
lcd_data <= " ";
state <= WRITE_DATA5;
end WRITE_DATA5: //回应的第三个数据高字节
begin
lcd_data <= dis_data_hig3;
state <= WRITE_DATA6;
end WRITE_DATA6://回应的第三个数据低字节
begin
lcd_data <= dis_data_low3;
state <= SET_DDRAM1;
end SET_DDRAM1:
begin
lcd_data <= 'h88;//3 line
state <= WRITE_DATA7;
end WRITE_DATA7: //f4应答
begin
if(num == 'd14) begin
state <= WRITE_DATA8;
end
else begin
num <= num + 'b1;
lcd_data <= dis_data;
state <= WRITE_DATA7;
end
end ////
WRITE_DATA8: //第二次回应的高字节
begin
lcd_data <= dis_data_hig4;
state <= WRITE_DATA9;
end WRITE_DATA9://第二次回应的低字节
begin
lcd_data <= dis_data_low4;
state <= SET_DDRAM2;
end SET_DDRAM2:
begin
lcd_data <= 'h98;//4 line
state <= WRITE_DATA10;
end WRITE_DATA10:
begin
if(num == 'd19) begin
num <= 'd0;
state <= WRITE_DATA11;
end
else begin
num <= num + 'b1;
lcd_data <= dis_data;
state <= WRITE_DATA10;
end
end WRITE_DATA11:
begin
lcd_data <= dis_data_btn;
state <= SET_DDRAM;
end
/* STOP:
begin
en <= 1'b0;//显示完了,lcd_e就一直拉为低
state <= STOP;
end */ default: state <= IDLE;
endcase reg [:] dis_data;
always @(posedge sys_clk or negedge rst_n)
if(!rst_n)
dis_data <= 'hzz;
else
case(num)
//ff应答:
'd0 : dis_data <= "f";//8'h66;
'd1 : dis_data <= "f";//8'h66;
'd2 : dis_data <= 8'hd3;
'd3 : dis_data <= 8'ha6;
'd4 : dis_data <= 8'hb4;
'd5 : dis_data <= 8'hf0;
'd6 : dis_data <= " ";
//f4应答:
'd7 : dis_data <= "f";
'd8 : dis_data <= "4";
'd9 : dis_data <= 8'hd3;
'd10 : dis_data <= 8'ha6;
'd11 : dis_data <= 8'hb4;
'd12 : dis_data <= 8'hf0;
'd13 : dis_data <= " ";
//按键:
'd14 : dis_data <= 8'hb0;
'd15 : dis_data <= 8'hb4;
'd16 : dis_data <= 8'hbc;
'd17 : dis_data <= 8'hfc;
'd18 : dis_data <= " ";
default: dis_data <= 'h00;
endcase
/***************************************************/
assign lcd_rw = 'b0;//只有写模式
assign lcd_psb = 'b1;//并口模式
assign lcd_en = en ? lcd_clk : 'b0;
/***************************************************/
endmodule
ps2_mouse_top.v
module ps2_mouse_top(
//input
sys_clk,
rst_n, //inout
ps2_clk,
ps2_data, //output
lcd_rs,
lcd_rw,
lcd_en,
lcd_data,
// lcd_psb
); input sys_clk;
input rst_n; inout ps2_clk;
inout ps2_data; output lcd_rs;//H:data L:command
output lcd_rw;//H:read module L:write module
output lcd_en;//H active
output [:] lcd_data;
//output lcd_psb;//H:parallel module L:SPI module wire send_done_sig;
wire rx_done_sig;
wire [:] data_buf;
wire rx_en;
wire send_en;
wire [:] send_cmd;
wire [:] dis_data_low1;
wire [:] dis_data_hig1;
wire [:] dis_data_low2;
wire [:] dis_data_hig2;
wire [:] dis_data_low3;
wire [:] dis_data_hig3;
wire [:] dis_data_low4;
wire [:] dis_data_hig4;
wire [:] dis_data_btn;
//控制模块例化
ps2_data_control u1_control(
//input
.sys_clk(sys_clk),
.rst_n(rst_n),
.send_done_sig(send_done_sig), //发送完标志
.rx_done_sig(rx_done_sig), //接收完标志
.data_buf(data_buf), //接收到的数据 //output
.rx_en(rx_en), //接收使能
.send_en(send_en), //发送使能
.send_cmd(send_cmd), //要发送的命令
.dis_data_low1(dis_data_low1), //要显示的数据
.dis_data_hig1(dis_data_hig1), .dis_data_low2(dis_data_low2), //要显示的数据
.dis_data_hig2(dis_data_hig2), .dis_data_low3(dis_data_low3), //要显示的数据
.dis_data_hig3(dis_data_hig3), .dis_data_low4(dis_data_low4), //要显示的数据
.dis_data_hig4(dis_data_hig4), .dis_data_btn(dis_data_btn)
);
//显示模块例化
LCD12864 u2_lcd(
//input
.sys_clk(sys_clk),
.rst_n(rst_n),
.dis_data_low1(dis_data_low1), //要显示的数据
.dis_data_hig1(dis_data_hig1), .dis_data_low2(dis_data_low2), //要显示的数据
.dis_data_hig2(dis_data_hig2), .dis_data_low3(dis_data_low3), //要显示的数据
.dis_data_hig3(dis_data_hig3), .dis_data_low4(dis_data_low4), //要显示的数据
.dis_data_hig4(dis_data_hig4), .dis_data_btn(dis_data_btn), //output
.lcd_rs(lcd_rs),
.lcd_rw(lcd_rw),
.lcd_en(lcd_en),
.lcd_data(lcd_data),
// .lcd_psb(lcd_psb)
);
//发送模块例化
ps2_send_control u3_send(
//input
.sys_clk(sys_clk),
.rst_n(rst_n),
.send_en(send_en), //发送使能
.send_cmd(send_cmd), //要发送的命令 0xf4 //output
.send_done_sig(send_done_sig),//发送完标志 //inout
.ps2_clk(ps2_clk), //鼠标时钟
.ps2_data(ps2_data) //鼠标数据
);
//接收模块例化
ps2_rx_control u4_rx(
//input
.sys_clk(sys_clk),
.rst_n(rst_n),
.ps2_clk_in(ps2_clk), //鼠标时钟
.ps2_data_in(ps2_data), //鼠标数据
.rx_en(rx_en), //接收模块使能信号 //output
.rx_done_sig(rx_done_sig), //接收完标志信号
.data_buf(data_buf) //保存接收到的数据
);
endmodule
现象1、发送0xff命令给鼠标时,PS/2 技术参考上有写,发送此命令进入复位模式,鼠标并会给主机三个数据0xfa、0xaa、0x00(ID)作为回应,如下图,显示是正确的,那说明传送和接收应该没错,但在发送0xf4命令,按道理接收到回应数据应该是0xfa,而这里没有收到数据:
现象2、若直接先发送0xf4命令时,接收到回应的数据是0xfe,按复位又变为0xfc,在按一次又变为0xfe,反复按复位,一直在这两数据变动,查PS/2 技术参考资料,说是校验位出错或是干扰造成,换了两个板子都是这样,换了鼠标也是这样。如下图:
以上两个现象让我彻底的无语了,估计我现在的思维已定死了,无法想到其他方法去调试,想写个仿真嘛,又觉得比较棘手,毕竟要模拟一个鼠标还是有费点功夫,哎。。
按键 后面本来是要显示 左(L)右(R)中(M)几个字母,若没有接收到数据,显示默认值X。