|
发表于 2012-11-17 14:11:32
|
显示全部楼层
//时钟频率为 10 16.7kHz 从时钟脉冲的上升沿到一个数据转变的时间至少要有 5 微秒 数据变化到时
//钟脉冲的下降沿的时间至少要有 5 微秒并且不大于 25 微秒 这个定时非常重要 你应该严格遵循它
//主机可以在第 11 个时钟脉冲 停止位 之前把线拉低 导致设备放弃发送当前字节 这是非常罕见的
//在停止位发送后 设备在发送下个包前至少应该等待 50 毫秒 这将给主机时间当它处理接收到的字节
//时抑制发送 主机在收到每个包时 通常自动做这个 在主机释放抑制后 设备至少应该在发送任何
//数据前等 50 毫秒
module ps2_proc
(
input clk ,
input rst_n ,
input ps2_clk,
input ps2_dat,
output reg [7:0] key_dat
);
parameter IDLE = 5'b00001;
parameter REC = 5'b00010;
parameter CHECK = 5'b00100;
parameter END = 5'b01000;
parameter FIR = 5'b01000;
reg [2:0] ps2_clk_reg;
reg [1:0] ps2_dat_reg;
wire ps2_clk_syn;
reg [4:0] ps2_sta_cur;
reg [4:0] ps2_sta_nxt;
reg odd_even_check;
reg [9:0] ps2_cnt ;
reg [7:0] shift_reg ;
wire odd_even_check;
assign ps2_clk_syn = (~ps2_clk_reg[2])&ps2_clk_reg[1];//采样随路过来的时钟上升沿
always @(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
ps2_clk_reg <= 3'd0;
else
ps2_clk_reg <= {ps2_clk_reg[1:0],ps2_clk}; //时钟延拍
end
always @(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
ps2_dat_reg <= 2'd0;
else
ps2_dat_reg <= {ps2_dat_reg[0],ps2_dat};//数据沿拍
end
always @(*)
begin
case(ps2_sta_cur)
IDLE:
begin
if(ps2_clk_syn == 1'b1)
begin
if(ps2_dat_reg[1] == 1'b1)//在IDLE状态下的时候,如果采样到一个时钟上升沿,状态机跳到接收状态
ps2_sta_nxt = REC;
else
ps2_sta_nxt = FIR; //如果没有时钟上升沿过来,证明发过来的起始有错误,就直接跳到过滤状态
end
else
ps2_sta_nxt = IDLE; //如果没有上升沿就一直处于IDLE状态
end
REC:
begin
if(ps2_clk_syn == 1'b1)
begin
if(ps2_cnt >= 10'd7) //在接收状态下计数器计数到7次的时候,就表示数据已经接收完毕,跳到检验
ps2_sta_nxt = CHECK;
else
ps2_sta_nxt = REC; //如果计数器没有到7,就一直等待接收完毕
end
else
ps2_sta_nxt = REC;//没有来上升沿,就一直在接收状态
end
CHECK:
begin
if(ps2_clk_syn == 1'b1)
begin
if(odd_even_check == ps2_dat_reg[1]) //校验,校验成功,去找结束字符
ps2_sta_nxt = END;
else
ps2_sta_nxt = FIR; //校验,校验失败,直接去过滤状态
end
else
ps2_sta_nxt = CHECK;
end
END:
begin
if(ps2_clk_syn == 1'b1)
begin
if(ps2_dat_reg[1] == 1'b1) //结束字符如果是1,就跳转到IDLE
ps2_sta_nxt = IDLE;
else
ps2_sta_nxt = FIR; //否则就结束字符失败,跳转到过滤状态
end
end
FIR:
begin
if(ps2_cnt >= 10'd1023) //1m的时钟,过滤1.023ms以后,继续跳转到IDLE
ps2_sta_nxt = IDLE;
else
ps2_sta_nxt = FIR;
end
default:
begin
ps2_sta_nxt = IDLE;odd_even_check == ps2_dat_reg[1]
end
endtask
end
always @(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
ps2_sta_cur <= IDLE;
else
ps2_sta_cur <= ps2_sta_nxt;
end
always@(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
ps2_cnt <= 10'd0;
else if(sta_cur == REC&&ps2_clk_syn == 1'b1)
ps2_cnt <= ps2_cnt + 10'd1; //计数器计数,在接收状态
else if(sta_cur == FIR )
ps2_cnt <= ps2_cnt + 10'd1; //在过滤状态下,进行计数
else
ps2_cnt <= 10'd0; //其他状态对计数器进行清零
end
always @(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
shift_reg <= 8'd0;
else if(ps2_sta_cur == REC &&ps2_clk_syn == 1'b1)
shift_reg <= {shift_reg[6:0],ps2_dat_reg[1]}; //在接收状态,通过移位寄存器寄存
end
assign odd_even_check = ^shift_reg; //奇偶校验
always @(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
key_dat <= 8'd0;
else if((ps2_sta_cur == CHECK )&&(odd_even_check == ps2_dat_reg[1]))
key_dat <= shift_reg; //寄存,校验正确的情况下
end
endmodule |
|