⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ps2_keyboard_interface.v

📁 周立功公司的SOPC源代码
💻 V
📖 第 1 页 / 共 2 页
字号:
//*****************************************************************************//
//                               PS2键盘接口程序                               //
//                                系统时钟48MHz                                //
//                            最后修改日期2006.04.05                           //
//*****************************************************************************//
//程序源于John Clayton的"ps2_keyboard_interface"
//------------------------------------------------------------------------------
//部分输入输出接口说明
//rx_extended:为扩展码(8'hE0)输出的标志位,当输出为'1'时说明输出的扫描码是扩展码。
//            如:按下"右ALT"键时(键码通码E0,11),rx_extended=1'b1,rx_scan_code=8'h11.
//rx_released:为断码(8'hF0)输出的标志位,当输出为'1'时说明输出的扫描码是断码。
//            如:按下"M"键后松开(M键断码F0,3A),rx_released=1'b1,rx_scan_code=8'h3A.
//            当扫描键码即是扩展码又是断码,则,rx_extended,rx_released都为1.
//            如:按下"右CTRL"键后松开(断码E0,F0,14),rx_extended=1'b1,rx_released=1'b1,
//             rx_scan_code=8'h14.
//rx_shift_key_on:"SHIFT"键标志位,当输出为'1'时,表示"SHIFT"键是按住的.

//------------------------------------------------------------------------------
//传输数据时帧格式:
//收低位在前,高位在后
//   bit0    bit1  bit2  bit3  bit4  bit5  bit6  bit7  bit8   bit9      bit10
//  开始(0)   D0    D1    D2    D3    D4    D5    D6    D7   奇校验位   停止(1) 
//------------------------------------------------------------------------------


//******************************************************************************//
`define TOTAL_BITS   11          // 一个帧数据有11位数据
`define EXTEND_CODE  16'hE0      //扩展码如R_CTRL的通码为(E0,14)
`define RELEASE_CODE 16'hF0      //断码如R_CTRL的断码为(E0,F0,14);"F"的断码为(F0,2B)
`define LEFT_SHIFT   16'h12      //左SHIFT键通码
`define RIGHT_SHIFT  16'h59      //右SHIFT键断码


module ps2_keyboard_interface (
	clock,  
	reset,  
	ps2_clk_in,  
	ps2_data_in,  
	ps2_clk_out,  
	ps2_data_out,
	ps2_clk_dir,
	ps2_data_dir,  
	rx_extended,           
	rx_released,           
	rx_shift_key_on,  
	rx_scan_code,  
	rx_ascii,  
	rx_data_ready,        
	rx_read,                
	tx_data,  
	tx_write,  
	tx_write_ack,  
	tx_error_no_keyboard_ack);  
  
 
//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 rx_extended;   		//扩展码标志
output rx_released;         //断码标志
output rx_shift_key_on;	    //shift键状态标志
output [7:0] rx_scan_code;	//扫描码输出
output [7:0] rx_ascii;		//ASCII码输出
output rx_data_ready;       //收到新数据置位,读取后清零
input rx_read;       //读数据指示,有新数据且rx_read=1时,清rx_data_ready标志
input [7:0] tx_data;        //要发送给PS/2键盘的数据或指令
input tx_write;             //发送指令请求,高电平有效
output tx_write_ack;//写指令状态,写指令前为1,写过程为0,写完为1.结束写请求后为0
output tx_error_no_keyboard_ack;//PS/2键盘应答出错指示.

//I/O寄存器
reg rx_extended_r;
reg rx_released_r;
reg [7:0] rx_scan_code_r;
reg [7:0] rx_ascii_r;
reg rx_data_ready_r;
reg tx_error_no_keyboard_ack_r;
reg ps2_clk_out_r;
reg ps2_data_out_r;
reg ps2_clk_dir_r;
reg ps2_data_dir_r;

//内部寄存器
reg [`TOTAL_BITS-1:0] q;   //移位寄存器,用于接收或发送数据
reg [3:0] m1_state;        //状态机M1
reg [3:0] m1_next_state;
reg m2_state;              //状态机M2
reg m2_next_state;
reg [3:0] bit_count;       //移位计数器
reg enable_timer_400usec;  //400uS计数器使能控制
reg enable_timer_5usec;    //5uS计数器使能控制
reg [TIMER_400USEC_BITS-1:0] timer_400usec_count;  //400uS计数器
reg [TIMER_5USEC_BITS-1:0] timer_5usec_count;      //5uS计数器
reg [6:0] ascii;           //ASCII码
reg left_shift_key;        //左SHIFT键标志
reg right_shift_key;       //左SHIFT键标志
reg hold_extended; //保持原先的值,复位或有新的值输出(rx_output_event=1)清零
reg hold_released; //保持原先的值,复位或有新的值输出(rx_output_event=1)清零
reg ps2_clk_in_r;     //同步PS/2时钟信号
reg ps2_data_in_r;    //同步PS/2数据信号



//内部信号
wire timer_400usec_done;     //400uS计数器溢出标志
wire timer_5usec_done;       //5uS计数器溢出标志
wire extended;               //扩展码标志
wire released;               //断码标志
                    
wire rx_output_event;  //收到键盘发送过来的一帧数据置位,且不是0xE0和0xF0 
wire rx_output_strobe; //收到键盘发送过来的一帧数据置位,且不是0xE0、0xF0和SHIFT键值 

wire tx_parity_bit;    			//奇偶验证位
wire rx_shifting_done; 			//接收一帧数据完毕置位
wire tx_shifting_done; 			//发送一帧数据完毕置位
wire [8:0] shift_key_plus_code; //包含shift键状态的扫描码

//计时器参数
//以下参数值按48MHz时钟计算
parameter TIMER_400USEC_VALUE = 19200;      //400us延时,系统时钟的计数值
parameter TIMER_400USEC_BITS  = 15;         //400us计时,计数器位宽
parameter TIMER_5USEC_VALUE = 240;          //5us延时,系统时钟的计数值
parameter TIMER_5USEC_BITS  = 8;            //5us计时,计数器位宽
parameter TRAP_SHIFT_KEYS = 0;              //Default: No shift key trap.       

//状态机M1状态参数表
parameter   m1_rx_clk_h                 = 4'd1,
			m1_rx_clk_l                 = 4'd0,
			m1_rx_falling_edge_marker   = 4'd12,
			m1_rx_rising_edge_marker    = 4'd13,
			m1_tx_force_clk_l           = 4'd3,
			m1_tx_first_wait_clk_h      = 4'd10,
			m1_tx_reset_timer           = 4'd11,
			m1_tx_wait_clk_h            = 4'd2,
			m1_tx_clk_h                 = 4'd4,
			m1_tx_clk_l                 = 4'd5,
			m1_tx_wait_keyboard_ack     = 4'd6,
			m1_tx_done_recovery         = 4'd7,
			m1_tx_error_no_keyboard_ack = 4'd8,
			m1_tx_rising_edge_marker    = 4'd9;

//状态机M2状态参数表
parameter   m2_rx_data_ready            = 1'd1,
			m2_rx_data_ready_ack        = 1'd0;
//******************************************************************************//

//******************************************************************************//
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 rx_extended = rx_extended_r;
assign rx_released = rx_released_r;
assign rx_scan_code = rx_scan_code_r;
assign rx_ascii = rx_ascii_r;
assign rx_data_ready = rx_data_ready_r;
assign tx_error_no_keyboard_ack = tx_error_no_keyboard_ack_r;


//同步输入时钟、数据信号
always @(posedge clock)
begin
    ps2_clk_in_r <= ps2_clk_in;
    ps2_data_in_r <= ps2_data_in;
end

//**************************************************************************************
//状态机M1
always @(posedge clock)
begin 
    if (reset) 
		m1_state <= m1_rx_clk_h;
    else 
		m1_state <= m1_next_state;
end

//M1状态转换逻辑
always @(m1_state
		or q         
		or tx_shifting_done         
		or tx_write         
		or ps2_clk_in_r         
		or ps2_data_in_r         		 
		or timer_400usec_done
		or timer_5usec_done         
		)
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;
	tx_error_no_keyboard_ack_r <= 1'b0;
	enable_timer_400usec <= 1'b0;
	enable_timer_5usec <= 1'b0;
	case (m1_state)
	
        //以下四个状态为从PS/2键盘读数据到主机的状态
        //-----------------------------------------------   
	    m1_rx_clk_h :                 //读状态时钟高电平
	    begin
	        enable_timer_400usec <= 1'b1;
	        if (tx_write)
				m1_next_state <= m1_tx_reset_timer;          
	        else if (~ps2_clk_in_r)                      
				m1_next_state <= m1_rx_falling_edge_marker;  
	        else
				m1_next_state <= m1_rx_clk_h;
	    end
	      
	    m1_rx_falling_edge_marker :  //读状态时钟下降沿标志
	    begin
	        m1_next_state <= m1_rx_clk_l;
	    end

	    m1_rx_clk_l :               //读状态时钟低电平
	    begin
	        enable_timer_400usec <= 1'b1;
	        if (tx_write) 
				m1_next_state <= m1_tx_reset_timer;
	        else if (ps2_clk_in_r) 
				m1_next_state <= m1_rx_rising_edge_marker;
	        else 
				m1_next_state <= m1_rx_clk_l;
	    end

	    m1_rx_rising_edge_marker :   //读状态时钟上升沿标志
	    begin
	        m1_next_state <= m1_rx_clk_h;
	    end
        //------------------------------------------------

        //以下为发送指令到PS/2键盘的转换状态
        //------------------------------------------------ 
	    m1_tx_reset_timer:         //写指令开始状态
	    begin
	        m1_next_state <= m1_tx_force_clk_l;
	    end

	    m1_tx_force_clk_l :        //抑制通讯,拉低时钟线(100uS以上)准备发送指令给PS/2键盘
	    begin
	        enable_timer_400usec <= 1'b1;
			ps2_clk_dir_r <= 1'b1;    //置PS2时钟线为输出
	        ps2_clk_out_r <= 1'b0;    //强制拉低ps2_clk时钟线
	        if (timer_400usec_done) 
				m1_next_state <= m1_tx_first_wait_clk_h;
	        else 
				m1_next_state <= m1_tx_force_clk_l;
	    end

	    m1_tx_first_wait_clk_h :  //等待PS/2键盘把时钟线拉低
	    begin
	        enable_timer_5usec <= 1'b1;
			ps2_data_dir_r <= 1'b1;        //置PS2数据线为输出
	        ps2_data_out_r <= 1'b0;        // 发送起始位
	        if (~ps2_clk_in_r && timer_5usec_done)
	            m1_next_state <= m1_tx_clk_l;
	        else
	            m1_next_state <= m1_tx_first_wait_clk_h;
	    end
	      
	    m1_tx_clk_l :
	    begin
			ps2_data_dir_r <= 1'b1;        //置PS2数据线为输出
	        ps2_data_out_r <= q[0];
	        if (ps2_clk_in_r) 
				m1_next_state <= m1_tx_wait_clk_h;
	        else 
				m1_next_state <= m1_tx_clk_l;
	    end
	
	
	    m1_tx_wait_clk_h :
	    begin
	        enable_timer_5usec <= 1'b1;
			ps2_data_dir_r <= 1'b1;        //置PS2数据线为输出
	        ps2_data_out_r <= q[0];
	        if (ps2_clk_in_r && timer_5usec_done)
	          m1_next_state <= m1_tx_rising_edge_marker;
	        else
	          m1_next_state <= m1_tx_wait_clk_h;
	    end

	    m1_tx_rising_edge_marker :
	    begin
			ps2_data_dir_r <= 1'b1;        //置PS2数据线为输出
	        ps2_data_out_r <= q[0];
	        m1_next_state <= m1_tx_clk_h;
	    end

	    m1_tx_clk_h :
	    begin
			ps2_data_dir_r <= 1'b1;        //置PS2数据线为输出
	        ps2_data_out_r <= q[0];
	        if (tx_shifting_done) 
				m1_next_state <= m1_tx_wait_keyboard_ack;
	        else if (~ps2_clk_in_r) 
				m1_next_state <= m1_tx_clk_l;
	        else 
				m1_next_state <= m1_tx_clk_h;
	    end

	    m1_tx_wait_keyboard_ack :
	    begin
	        if (~ps2_clk_in_r && ps2_data_in_r)
	            m1_next_state <= m1_tx_error_no_keyboard_ack;  //应答出错
	        else if (~ps2_clk_in_r && ~ps2_data_in_r)
	            m1_next_state <= m1_tx_done_recovery;
	        else 
				m1_next_state <= m1_tx_wait_keyboard_ack;
	    end

	    m1_tx_done_recovery :
	    begin
	        if (ps2_clk_in_r && ps2_data_in_r) 
				m1_next_state <= m1_rx_clk_h;
	        else 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -