ps2解码

1,PS2接口描述

6脚Mini-DIN(PS/2):1 数据;2 未实现,保留;3 电源地;4 电源+5V;5 时钟;6:未实现。重要的是1脚和5脚

2,时序图

注意点:1)PS2的数据格式与UART十分相似,但是对数据的读取是是时钟的下降沿;2)PS2的时钟频率比较慢,大约是10kHz

3,编码键盘

键盘的编码分为通码make和断码break。通码对应某按键的按下事件,断码对应某按键的释放事件。例如按下A键,会输出0x1C的通码,释放A键,会输出0xF0,0x1C的断码。每个按键具有唯一的通码和断码。编码键盘的一个规则:一次只能有一个输出,若同时按下多个按键,只有其中一个有效。
民用键盘都是采用第二套编码方式。通常通码只有一个字节(短码),少部分扩展按键的通码是两字节或四字节(长码)。多数断码是两字节,第一个字节是8’hf0,第二个字节是按键的通码。扩展按键的断码有三字节,前两个字节是8’he0,8’hf0,最后一字节是按键的通码。


4,代码设计思路

1)检测PS2时钟信号的下降沿;
2)仿顺序操作,对每帧数据(11位)解码,判断是通码还是断码,忽略断码之后的通码;
3)输出一个字节的数据。

5,代码

ps2_decode.v

module ps2_decode(
    input   wire        sclk,
    input   wire        ps2_clk,
    input   wire        ps2_data,
    output  wire[7:0]   make_data,
    output  wire        ps2_done
);
reg [2:0]   ps2_clkr = 3'b111;
reg [4:0]   i = 0;
reg [7:0]   ps2_datar = 0;
reg         flag_done = 0;
wire        nege_ps2_clk;

//ps2_clk的下降沿
always@(posedge sclk)
begin
    ps2_clkr <= {ps2_clkr[1:0],ps2_clk};
end
assign nege_ps2_clk = ~ps2_clkr[1] & ps2_clkr[2];

always@(posedge sclk)
begin
    case(i)
        0:begin//起始位
            if(nege_ps2_clk)begin
                i <= i + 1;
                end
            end
        1,2,3,4,5,6,7,8:begin//数据位,低位在前
            if(nege_ps2_clk)begin
                ps2_datar[i-1] <= ps2_data;
                i <= i + 1;
                end
            end
        9,10:begin//校验位和停止位
            if(nege_ps2_clk)begin
                i <= i + 1;
                end
            end
        11:begin
            if(ps2_datar == 8'hf0)begin//判断是否是断码
                i <= i + 1;
                end
            else begin
                i <= 23;
                end
            end
        12,13,14,15,16,17,18,19,20,21,22:begin//忽略断码之后的通码
            if(nege_ps2_clk)begin
                i <= i + 1;
                end
            end
        23:begin
            flag_done <= 1;
            i <= i + 1;
            end
        24:begin
            flag_done <= 0;
            ps2_datar <= 0;//使得每次接收寄存器的初值都为零
            i <= 0;
            end
    endcase
end

assign make_data = ps2_datar;
assign ps2_done = flag_done;

endmodule 

该程序对通码和断码都适用,接收通码,对于断码忽略其后的通码,体现在i=12,13,14,15,16,17,18,19,20,21,22时直接自加1.具体分析见仿真截图。代码参考了《FPGA那些事儿--verilog HDL建模设计》中PS2解码部分并结合了自己的思考编写,欢迎交流指正。

6,仿真

tb_ps2.v

//ps2_clk的频率为10KHz
`timescale 1ns / 1ns
module tb_ps2();
reg	        sclk,ps2_clk,ps2_data;
wire[7:0]	make_data;
wire		ps2_done;
ps2_decode	ps2_decode_inst(
	.sclk		(sclk),
	.ps2_clk	(ps2_clk),
	.ps2_data	(ps2_data),
	.make_data	(make_data),
	.ps2_done	(ps2_done)
);

initial begin
	sclk = 0;
	forever #10 sclk=~sclk;//50MHz
end

initial begin
	ps2_clk=1;
	ps2_data=1;
	#50000;
	key_event(8'h1C);//发送A
	#50000;
	key_event(8'h32);//发送B
	#50000;
	key_event(8'h21);//发送C	
	#50000;

end

task key_event;
	input	[7:0]	key_number;
begin
	data_send(key_number);//通码
	#50000;
	data_send(8'hf0);//断码
	#50000;
	data_send(key_number);
	#50000; 
end
endtask

task data_send;
	input [7:0]data;
begin
	ps2_data=0;#50000;//发送起始位
	ps2_clk=0;#50000;//ps2_clk=0保持20000ns,注:延时操作是对前一句的赋值语句进行延时
	
	ps2_clk=1;
	ps2_data=data[0];#50000;//发送第0位数据
	ps2_clk=0;#50000;
	
	ps2_clk=1;
	ps2_data=data[1];#50000;//发送第0位数据
	ps2_clk=0;#50000;
	
	ps2_clk=1;
	ps2_data=data[2];#50000;//发送第0位数据
	ps2_clk=0;#50000;
	
	ps2_clk=1;
	ps2_data=data[3];#50000;//发送第0位数据
	ps2_clk=0;#50000;
	
	ps2_clk=1;
	ps2_data=data[4];#50000;//发送第0位数据
	ps2_clk=0;#50000;
	
	ps2_clk=1;
	ps2_data=data[5];#50000;//发送第0位数据
	ps2_clk=0;#50000;
	
	ps2_clk=1;
	ps2_data=data[6];#50000;//发送第0位数据
	ps2_clk=0;#50000;
	
	ps2_clk=1;
	ps2_data=data[7];#50000;//发送第0位数据
	ps2_clk=0;#50000;
	
	ps2_clk=1;
	ps2_data=0;#50000;//发送校验位,未设置,保留
	ps2_clk=0;#50000;
	
	ps2_clk=1;
	ps2_data=1;#50000;//发送停止位
	ps2_clk=0;#50000;
	
	ps2_clk=1;
end
endtask

endmodule

仿真截图:



分析:箭头所指处ps2_done为1,表示完成一次ps2解码操作。下面一张图是方框的放大部分,可以看出在读取结束位的时候把ps2_done拉高一个时钟周期,解码数据(8'h1c)输出,下一个时钟周期解码数据清零,使得每次接收寄存器的初值为零。


  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值