PS/2接口是目前最常见的鼠标接口,最初是IBM公司的专利,俗称“小口”。这是一种鼠标和键盘的专用接口,是一种6针的圆型接口。
本设计完成了ps2键盘驱动,并将键盘对应的16进制ascii码值在数码管输出。
一、ps2接口协议
协议参考文档链接:
http://wenku.baidu.com/link?url=HBkLHCwo2zwdScmz2zPfig4T5eJZhcpj4qC65zTjQBE47GiubPOfg0QOKxflxTMs9F_vzyEtTNjX4fq1qsiMciBprAFxoeEkc3hpFaWnMZ3
主要内容:常见的PS/2端口有两类:一种5脚的DIN或6脚的mini-DIN,这两种连接器在电气特性上是十分类似的,两者只有一点不同那就是管脚的排列,具有6 脚mini-DIN 的键盘
通常被叫做PS/2 键盘,而那些有5 脚DIN 叫做 AT 设备。常见ps2键盘接口如下所示:
由于电源和地都是主机接口提供,主要用于驱动设计的管脚只有两个,data和clock,该clock时钟是键盘产生的,最大的时钟频率是33kHz 而且大多数设备工作在10 20kHz。
PS/2 鼠标和键盘履行一种双向同步串行协议, 换句话说每次数据线上发送一位数据并且每在时钟线上发一个脉冲就被读入,键盘/ 鼠标可以发送数据到主机,而主机也可以发送数据到设备
。
从键盘/ 鼠标发送到主机的数据在时钟信号的下降沿, 当时钟从高变到低的时候 被读取 。从主机发送到键盘/鼠标的数据在上升沿,当时钟从低变到高的时候被读取。
不管通讯的方向怎样键盘/鼠标总是产生时钟信号
该同步串行协议的帧结构如下:(从键盘到主机的帧长度为11bit)
注意校验位是对数据位的校验,且是
奇校验,当数据位为偶数个1时该位置为1,为奇数个1时该位为0.总是保证1的个数为奇数个。
每一位都是在时钟的下降沿被读取:
二、电气接口协议(扫描码)
:键盘的处理器花费很多的时间来扫描或监视按键矩阵,如果它发现有键被按下释放或按住,键盘将发送扫描码的信息包到计算机。
扫描码有两种不同的类型: 通码和断码
当一个键被按下或按住就发送通码,当一个键被释放就发送断码。每个按键被分配了唯一的通码和断码,这样主机通过查找唯一的扫描码就可以测定是哪个按键。 每个键一整套的通断码组成了 扫描码集, 有三套标准的扫描码集分别是第一套、 第二套和第三套, 所有现代的键盘默认使用第二套扫描码。
只要一个键被按下这个键的通码就被发送到计算机,记住通码只表示键盘上的一个按键,它不表示印刷在按键上的那个字符。这就意味着在通码和ASCII 码之间没有已定义的关联,直到主机把扫描码翻译成一个字符或命令。在verilog 语句中需要将通码用case语句转换层所需要的ascii码。
多数通码长度为一个字节,少数扩展码为2或4个字节,这种码都含有E0H。
同理,只要键一释放断码就会被发送每个键都有它自己唯一的通码
它们也都有唯一的断码,不用总是通过查表来找出按键的断码。在通码和断码之间存在着必然的联系,多数第二套断码有两字节长。它们的第一个字节是F0h ,第二个字节是这个键的通码扩
展按键的断码,通常有三个字节。它们前两个字节是E0h,F0h 。最后一个字节是这个按键通码的最后一个字节,一些例子如下。
三、设计过程。
主要包括键盘驱动模块,ascii码转换,数码管显示等模块构成,其中数码管显示部分可以参考我的前一篇博文:
http://blog.csdn.net/baijingdong/article/details/20220363
主要程序如下:主要思路将在注释中阐述
module ps2_keyboard_driver(clk,rst_n,ps2k_clk,ps2k_data,sm_bit,sm_seg,ps2_state);
input clk; //50M时钟信号
input rst_n; //复位信号
input ps2k_clk; //PS2接口时钟信号
input ps2k_data; //PS2接口数据信号
wire [7:0] ps2_byte; // 1byte键值,只做简单的按键扫描
output ps2_state; //键盘当前状态,ps2_state=1表示有键被按下
output reg [1:0] sm_bit='b01;
output reg [7:0]sm_seg;
//------------------------------------------
reg ps2k_clk_r0,ps2k_clk_r1,ps2k_clk_r2; //ps2k_clk状态寄存器
//wire pos_ps2k_clk; // ps2k_clk上升沿标志位
wire neg_ps2k_clk; // ps2k_clk下降沿标志位
//设备发送向主机的数据在下降沿有效,首先检测PS2k_clk的下降沿
//利用上面逻辑赋值语句可以提取得下降沿,neg_ps2k_clk为高电平时表示数据可以被采集
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
ps2k_clk_r0 <= 1'b0;
ps2k_clk_r1 <= 1'b0;
ps2k_clk_r2 <= 1'b0;
else begin //锁存状态,进行滤波
ps2k_clk_r0 <= ps2k_clk;
ps2k_clk_r1 <= ps2k_clk_r0;
ps2k_clk_r2 <= ps2k_clk_r1;
assign neg_ps2k_clk = ~ps2k_clk_r1 & ps2k_clk_r2; //下降沿
//-----------------数据采集-------------------------
帧结构:设备发往主机数据帧为11比特,(主机发送数据包为12bit)
1bit start bit ,This is always 0,
8bit data bits,
1 parity bit,(odd parity)校验位,奇校验,
data bits 为偶数个1时该位为1,
data bits 为奇数个1时该位为0.
1bit stop bit ,this is always 1.
num 范围为 'h00,'h0A;
reg[7:0] ps2_byte_r; //PC接收来自PS2的一个字节数据存储器
reg[7:0] temp_data; //当前接收数据寄存器
reg[3:0] num; //计数寄存器
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
num <= 4'd0;
temp_data <= 8'd0;
else if(neg_ps2k_clk) begin //检测到ps2k_clk的下降沿
case (num)
帧结构中数据位为一个字节,且低位在前,高位在后,
这里要定义一个buf,size is one Byte.
4'd0: num <= num+1'b1;
4'd1: begin
num <= num+1'b1;
temp_data[0] <= ps2k_data; //bit0
4'd2: begin
num <= num+1'b1;
temp_data[1] <= ps2k_data; //bit1
4'd3: begin
num <= num+1'b1;
temp_data[2] <= ps2k_data; //bit2
4'd4: begin
num <= num+1'b1;
temp_data[3] <= ps2k_data; //bit3
4'd5: begin
num <= num+1'b1;
temp_data[4] <= ps2k_data; //bit4
4'd6: begin
num <= num+1'b1;
temp_data[5] <= ps2k_data; //bit5
4'd7: begin
num <= num+1'b1;
temp_data[6] <= ps2k_data; //bit6
4'd8: begin
num <= num+1'b1;
temp_data[7] <= ps2k_data; //bit7
4'd9: begin
num <= num+1'b1; //奇偶校验位,不做处理
4'd10: begin
num <= 4'd0; // num清零
default: ;
endcase
reg key_f0; //松键标志位,置1表示接收到数据8'hf0,再接收到下一个数据后清零
reg ps2_state_r; //键盘当前状态,ps2_state_r=1表示有键被按下
//+++++++++++++++数据处理开始++++++++++++++++=============
always @ (posedge clk or negedge rst_n) begin //接收数据的相应处理,这里只对1byte的键值进行处理
if(!rst_n) begin
key_f0 <= 1'b0;
ps2_state_r <= 1'b0;
else if(num==4'd10) ///一帧数据是否采集完。
begin //刚传送完一个字节数据
if(temp_data == 8'hf0) key_f0 <= 1'b1;//判断该接收数据是否为断码
begin
//========================理解困难==================================
if(!key_f0)
begin //说明有键按下
ps2_state_r <= 1'b1;
ps2_byte_r <= temp_data; //锁存当前键值
begin
ps2_state_r <= 1'b0;
key_f0 <= 1'b0;
//=====================================================
/*+++++++++++++等效写法+++++++++++++++++++++++++++++
reg key_released;//收到码段后是否松开
reg [7:0] ps2_byte;
always @(posedge clk or negedge rst)
begin
if(!rst)
key_released<='b0;
else if(cnt=='h0A)//一帧数据是否采集完。
begin
if(ps2_byte_buf==8'hF0)//数据为段码f0
key_released<='b1;//松开标志位置位
key_released<='b0;
always @ (posedge clk or negedge rst)
begin
if(!rst)
key_pressed<= 0;
else if (cnt == 4'hA) // 采集完一个字节?
begin
if (!key_released) // 有键按过?
begin
ps2_byte<= ps2_byte_buf; // 锁存当前键值
key_pressed <= 'b1; // 按下标志置一
key_pressed <= 'b0; // 按下标志清零
reg[7:0] ps2_asci; //接收数据的相应ASCII码
always @ (ps2_byte_r) begin
case (ps2_byte_r) //键值转换为ASCII码,这里做的比较简单,只处理字母
8'h15: ps2_asci <= 8'h51; //Q
8'h1d: ps2_asci <= 8'h57; //W
8'h24: ps2_asci <= 8'h45; //E
8'h2d: ps2_asci <= 8'h52; //R
8'h2c: ps2_asci <= 8'h54; //T
8'h35: ps2_asci <= 8'h59; //Y
8'h3c: ps2_asci <= 8'h55; //U
8'h43: ps2_asci <= 8'h49; //I
8'h44: ps2_asci <= 8'h4f; //O
8'h4d: ps2_asci <= 8'h50; //P
8'h1c: ps2_asci <= 8'h41; //A
8'h1b: ps2_asci <= 8'h53; //S
8'h23: ps2_asci <= 8'h44; //D
8'h2b: ps2_asci <= 8'h46; //F
8'h34: ps2_asci <= 8'h47; //G
8'h33: ps2_asci <= 8'h48; //H
8'h3b: ps2_asci <= 8'h4a; //J
8'h42: ps2_asci <= 8'h4b; //K
8'h4b: ps2_asci <= 8'h4c; //L
8'h1a: ps2_asci <= 8'h5a; //Z
8'h22: ps2_asci <= 8'h58; //X
8'h21: ps2_asci <= 8'h43; //C
8'h2a: ps2_asci <= 8'h56; //V
8'h32: ps2_asci <= 8'h42; //B
8'h31: ps2_asci <= 8'h4e; //N
8'h3a: ps2_asci <= 8'h4d; //M
default: ;
endcase
assign ps2_byte = ps2_asci;
assign ps2_state = ps2_state_r;
//==================keyboard driver part over======================
//=======================1KHz div====display part start===================
parameter N2=50000;
reg clk3=1'b0;
reg [16:0]count3=17'd0;
//assign clk_out=clk3;
always @(posedge clk or negedge rst_n)
begin
if (!rst_n)
begin
count3<=17'd0;
clk3<=1'b0;
if(count3<N2-1)
begin
count3<=count3+1'b1;
if(count3<(N2/2-1))
clk3<=1'b0;
clk3<=1'b1;
begin
count3<=17'd0;
clk3<=1'b0;
//==================state select================
reg[3:0] Num;
always @(posedge clk3)
begin
case (sm_bit)
'b01: begin
Num<=ps2_byte[7:4];
sm_bit<='b10;
'b10: begin
Num<=ps2_byte[3:0];
sm_bit<='b01;
default:
Num<='b0;
endcase
/*if(sm_bit=='b01)
begin
Num<=ps2_byte[3:0];
sm_bit<='b10;
else if(sm_bit=='b10)
begin
Num<=ps2_byte[7:4];
sm_bit<='b01;
//=========================================================
always @ (Num)//
begin
case (Num)
4'h0 : sm_seg = 8'h3f; // "0"
4'h1 : sm_seg = 8'h06; // "1"
4'h2 : sm_seg = 8'h5b; // "2"
4'h3 : sm_seg = 8'h4f; // "3"
4'h4 : sm_seg = 8'h66; // "4"
4'h5 : sm_seg = 8'h6d; // "5"//共阴极数码管表
4'h6 : sm_seg = 8'h7d; // "6"
4'h7 : sm_seg = 8'h07; // "7"
4'h8 : sm_seg = 8'h7f; // "8"
4'h9 : sm_seg = 8'h6f; // "9"
4'ha : sm_seg = 8'h77; // "a"
4'hb : sm_seg = 8'h7c; // "b"
4'hc : sm_seg = 8'h39; // "c"
4'hd : sm_seg = 8'h5e; // "d"
4'he : sm_seg = 8'h79; // "e"
4'hf : sm_seg = 8'h71; // "f"
endcase
//==============================================
endmodule
PS/2接口是目前最常见的鼠标接口,最初是IBM公司的专利,俗称“小口”。这是一种鼠标和键盘的专用接口,是一种6针的圆型接口。本设计完成了ps2键盘驱动,并将键盘对应的16进制ascii码值在数码管输出。一、ps2接口协议协议参考文档链接:http://wenku.baidu.com/link?url=HBkLHCwo2zwdScmz2zPfig4T5eJZhcpj4qC65zTjQBE4
文章目录一、 设计内容二、设计原理1 实验器材2 实验原理2.1 红外遥控2.1.1 红外发射原理简介2.1.3 红外遥控器解码2.1.4 NEC数据格式:
一、 设计内容
基于STC15W5K32S4实验箱,用红外遥控,PS2游戏手柄,ADC矩阵键盘来实现一些小项目合集(计算器、遥控画线、弹一弹、俄罗斯方块、短动画等)
二、设计原理
1 实验器材
本综合设计用到STC15W5K32S4实验箱、红外遥控、PS2游戏手柄
2 实验原理
2.1 红外遥控
2.1.1 红外发射原理简介
通用红外遥控系统主要由发射
写在前面的话
我们从小就开始接触电脑,曾经多么羡慕那些在
键盘上洋洋洒洒的人,手指轻柔的飞舞,刻画出一章章美丽的篇幅…那么作为工程师的我们,同样拥有着属于我们的情怀。如果曾经的向往变成我们喜欢的玩具;如果曾经的神秘变成我们夜以继日的痴迷。那么,一切又将如何?梦翼师兄携手大家一起来欣赏、来品味。
设计一个
ps2
键盘的接口
驱动电路。
ps2的接口如下图所示:
ST(Structured Text)是一种用于工业自动化系统的编程
语言,它支持模拟量的模拟。下面是一个简单的例子,演示了如何使用ST编程实现对模拟量的读取和操作。
PROGRAM AnalogInput;
AnalogValue : REAL;
BEGIN
AnalogValue := AI.0;
IF AnalogValue > 10 THEN
目录FPGA模拟PS/2键盘PS/2协议简介首先,重要的话说三遍新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入
FPGA模拟PS/2键盘
———— VerilogHDL + SpinalHDL
众所周知,PS
键盘和鼠标是现在绝大部分人使用电脑的标配物件。它们有发光的,有花花绿绿的,有长尾巴的,有带电池的。但又有谁人记得,曾经那六孔的插口?作为本专栏的第一篇文章,就让笔者带领大家来认识计算机与
键盘、鼠标进行通信的这一远古协议——SP/2。
1987年,大家熟知的IBM公司推出了一款用于
键盘与主机进行通信的接口标准——SP2。
PS2接口一共有六根引脚,但其中只有四根引脚是有意义的:Clock(时钟),Data(数据),电源,接地。值得注意的是,其中的Clock与Data是双向的引脚。因此,
PS/
PS/2键盘解码实验程序:
CPLD通过PS/2接收键盘的数据,然后把接收到的大写字母A-Z的键值转换成相应的ASCII码,再通过串口传送给PC机。只要字母按键被按下,就能够在串口调试助手里显示相应的字母。
文件中包括Verilog和VHDL的两种语言的Quartus II程序,请您参考。
reg [ROWS-1:0] row_select;
wire [COLS-1:0] col_input;
assign col_input = key_input & {(8-COLS){1'b0}, COLS{1'b1}};
// 定义键码表
parameter [7:0] KEYCODES [ROWS][COLS] = {
{8'b11101110, 8'b11011110, 8'b10111110, 8'b01111110},
{8'b11101101, 8'b11011101, 8'b10111101, 8'b01111101},
{8'b11101011, 8'b11011011, 8'b10111011, 8'b01111011},
{8'b11100111, 8'b11010111, 8'b10110111, 8'b01110111}
// 定义
键盘扫描器
always @(*) begin
case (row_select)
4'b0111: key_code = KEYCODES[0][{COLS-1}:0]; // 第1行
4'b1011: key_code = KEYCODES[1][{COLS-1}:0]; // 第2行
4'b1101: key_code = KEYCODES[2][{COLS-1}:0]; // 第3行
4'b1110: key_code = KEYCODES[3][{COLS-1}:0]; // 第4行
default: key_code = 8'b11111111; // 没有按键按下
endcase
// 定义
键盘扫描器
always @(posedge clk) begin
if (reset) begin
row_select <= 4'b1110;
end else begin
row_select <= {row_select[ROW-2:0], 1'b0};
endmodule
这个模块使用一个4x4的矩阵式
键盘,并采用轮询扫描的方式来检测
键盘输入。在扫描过程中,根据每一行的row_select信号,将对应的列col_input值读取出来,并通过键码表KEYCODES来获取相应的键码。最后,将键码值存储到key_code寄存器中,以便其他模块使用。
需要注意的是,这只是一个简单的
键盘输入模块代码骨架,需要根据具体的硬件平台和需求进行修改。同时,还需要与其他模块(如LED
驱动模块、数码管
驱动模块等)进行整合,以实现完整的功能。