写在前面的话

我们从小就开始接触电脑,曾经多么羡慕那些在键盘上洋洋洒洒的人,手指轻柔的飞舞,刻画出一章章美丽的篇幅…那么作为工程师的我们,同样拥有着属于我们的情怀。如果曾经的向往变成我们喜欢的玩具;如果曾经的神秘变成我们夜以继日的痴迷。那么,一切又将如何?梦翼师兄携手大家一起来欣赏、来品味。

项目需求

设计一个ps2键盘的接口驱动电路。

原理分析

ps2的接口如下图所示:

其中,1是数据线DATA;

2是预留N/C;

3是GND;

4是VCC(+5V);

5是时钟信号线CLK;

6是预留N/C;

数据传输的时序图如下图所示:

一般的ps2接口,都是ps2产生时钟信号,而且是在上升沿的时候把数据发送出去,而在下降沿的时候数据被采样,大多数的ps2设备发送数据的时钟频率是15Khz-20Khz。每一帧的数据有11位或者12位数据,其中包括:

1位起始位:总为逻辑0;

8位数据位:低位在前;

1位奇偶校验位;

1位停止位:总为逻辑1;

1位答应位:仅用于主机对设备通信中(在本次键盘接口设计中不用)

当键盘的某一个按键被按下的时候,键盘会向外发送那一个按键的通码,当按键松开的时候,键盘就会向外发送那一个按键的断码,需要注意的是,如果按着一个按键不放的话,键盘会以一定的频率发送那一个按键的通码。

右侧小键盘的0-9的通码与断码如下图所示:

现在我们具体举一个例子来说明ps2接口的工作原理,假设我现在按下小键盘中的0键,再按下按键9,然后把按键0松开,最后再松开按键9,ps2往FPGA发送的数据就会如下,先发0按键的通码8’h70,再发9按键的通码8’h7d,接着发0按键的断码8’hf0 8’h70,接着再发9按键的断码8’hf0 8’h7d,发送数据的顺序如下: 8’h70→8’h7d→8’hf0→8’h70→8’hf0→8’h7d。

系统架构

当ps2_data_out信号有效的时候,valid会拉高一个周期(valid可用于同其他级联模块的握手)。

模块功能介绍

模块名

功能描述

ps2_scan

将ps2接口传输过来数据转成通码或者断码

顶层模块端口描述

端口名

端口说明

clk

系统时钟输入

rst_n

系统复位

Ps2_clk

时钟信号线

Ps2_data_in

数据线

valid

通、断码有效信号(高电平有效)

Ps2_data_out

通、断码信号

 用signaltap ii 分析波形

打开signaltap ii ,将采样时钟设置为clk,采样深度为64K。将ps2_clk和ps2_data_in两个输入信号引出来,并将ps2_clk的的触发条件改为下降沿(我们是在ps2_clk为下降沿的时候采集数据),之后进行全编译,并将编译好的sof文件下载到开发板中。

按下数字键“1”(数字小键盘),波形图上出现如下波形:

在ps2_clk每个下降沿,我们进行读数据,分别是:“01001011011”。第一位是起始位“0”,后面连续的8位是低位在前的有效数据:“10010110”,改成高位在前就是“01101001”,也就是我们的8‘h69(1的通码就是8’h69)。第十位“1”为奇偶校验位,第十一位“1”是停止位,这两位不需要我们关心。

放开按键“1”,出现了如下的波形:

在ps2_clk每个下降沿,我们进行读数据,分别是:“00000111111”。第一位是起始位“0”,后面连续的8位是低位在前的有效数据:“00001111”,改成高位在前就是“11110000”,也就是我们的8‘hf0(1的断码就是8‘hf0和8’h69 ,8’h69由于采样深度的原因显示不出来波形,不过我们也能分析出来它是怎么来的)。第十位“1”为奇偶校验位,第十一位“1”是停止位,这两位不需要我们关心。

根据ps2接口的原理和下板实测,我们得知了ps2接口传输数据的方式,那么就可以很容易地编写出我们的代码。

 代码解释

Ps2_scan模块代码

/****************************************************

*   Engineer      :   梦翼师兄

*   QQ             :   761664056

*   The module function: 将ps2接口传输过来的数据译成通、断码

*****************************************************/

000 module ps2_scan (

001 clk, //系统输入时钟

002 rst_n,//系统复位

003 ps2_data_in,//ps2的数据

004 ps2_data_out,//按键的通、断码

005 ps2_clk,//ps2的时钟

006 valid//通、断码有效信号

007 );

008 //系统输入

009 input clk;//系统输入时钟

010 input rst_n;//系统复位

011 input ps2_clk;//ps2的时钟

012 input ps2_data_in;//ps2的数据

013 //系统输出

014 output reg [7:0] ps2_data_out;//按键的通、断码

015 output reg valid;//通、断码有效信号

016

017 wire neg;//下降沿标志线

018 reg ps2_clk_temp;//时钟寄存器

019

020 always @ (posedge clk or negedge rst_n)

021 begin

022 if (!rst_n)

023 ps2_clk_temp <= 0;

024 else

025         ps2_clk_temp <= ps2_clk;//时钟寄存器中的值永远比ps2_clk晚一拍

026 end

027

028

029 //当寄存器里面是1,ps2_clk为0的时候

030 assign neg = ps2_clk_temp && (~ps2_clk);//正好就是ps2_clk为下降沿。

031

032 reg [3:0] num;//接收到数据线上数据的个数

033

034 always @ (posedge clk or negedge rst_n)

035 begin

036 if (!rst_n)

037 begin

038 num <= 0;

039 valid <= 0;

040 ps2_data_out <= 0;

041 end

042 else

043 begin

044 if (neg)

045 begin

046 case (num)

047 0 : num <= num + 1;//起始位

048

049 1 : begin//有效数据的第0位

050 num <= num + 1;

051 ps2_data_out[0] <= ps2_data_in;

052 end

053

054 2 : begin//有效数据的第1位

055 num <= num + 1;

056 ps2_data_out[1] <= ps2_data_in;

057 end

058

059 3 : begin//有效数据的第2位

060 num <= num + 1;

061 ps2_data_out[2] <= ps2_data_in;

062 end

063

064 4 : begin//有效数据的第3位

065 num <= num + 1;

066 ps2_data_out[3] <= ps2_data_in;

067 end

068

069 5 : begin//有效数据的第4位

070 num <= num + 1;

071 ps2_data_out[4] <= ps2_data_in;

072 end

073

074 6 : begin//有效数据的第5位

075 num <= num + 1;

076 ps2_data_out[5] <= ps2_data_in;

077 end

078

079 7 : begin//有效数据的第6位

080 num <= num + 1;

081 ps2_data_out[6] <= ps2_data_in;

082 end

083

084 8 : begin//有效数据的第7位

085 num <= num + 1;

086 ps2_data_out[7] <= ps2_data_in;

087 end

088

089 9 : begin//奇偶校验位

090 num <= num + 1;

091 valid <= 1;//拉高通、断码有效标志

092 end

093

094 10 : num <= 0;//停止位

095

096 default : ;

097 endcase

098 end

099 else

100 begin

101 valid <= 0;//拉低通、断码有效标志

102 end

103 end

104 end

105

106 endmodule

代码中第47行,我们知道第一个是起始位是”0“,故并没有判断,而是直接跳转到下一个状态。

代码中第89行,ps2_data_in发送的是奇偶校验位,在此我们并没有做出判断,而是直接跳转到下一个状态。

代码中第91行,直接拉高通、断码的有效标志信号。

代码中第101行,直接拉低通、断码的有效标志信号。

代码中第94行,ps2_data_in发送的是停止位“0”。

测试代码

/****************************************************

*   Engineer      :   梦翼师兄

*   QQ             :   761664056

*   The module function: 测试ps2_scan模块

*****************************************************/

000 `timescale 1ns/1ps //定义时间单位和精度

001

002 module ps2_scan_tb;

003     //系统输入

004     reg clk;//系统输入时钟

005     reg rst_n;//系统复位

006     reg ps2_clk;//ps2的时钟

007     reg ps2_data_in;//ps2的数据

008     //系统输出

009     wire [7:0] ps2_data_out;//按键的通、断码

010     wire valid;//通、断码有效信号

011

012     initial begin

013         clk = 1;

014         rst_n = 0;

015         ps2_clk = 1;

016         ps2_data_in = 1;

017         #200.1

018         rst_n = 1;

019         //数字“1”的通码

020         ps2_data_in = 0;//起始位“0”

021         #60

022         ps2_clk = 0;

023         #120

024         ps2_clk = 1;

025         #60

026         ps2_data_in = 1;//“1”

027         #60

028         ps2_clk = 0;

029         #120

030         ps2_clk = 1;

031         #60

032         ps2_data_in = 0;//“0”

033         #60

034         ps2_clk = 0;

035         #120

036         ps2_clk = 1;

037         #60

038         ps2_data_in = 0;//“0”

039         #60

040         ps2_clk = 0;

041         #120

042         ps2_clk = 1;

043         #60

044         ps2_data_in = 1;//“1”

045         #60

046         ps2_clk = 0;

047         #120

048         ps2_clk = 1;

049         #60

050         ps2_data_in = 0;//“0”

051         #60

052         ps2_clk = 0;

053         #120

054         ps2_clk = 1;

055         #60

056         ps2_data_in = 1;//“1”

057         #60

058         ps2_clk = 0;

059         #120

060         ps2_clk = 1;

061         #60

062         ps2_data_in = 1;//“1”

063         #60

064         ps2_clk = 0;

065         #120

066         ps2_clk = 1;

067         #60

068         ps2_data_in = 0;//“0”

069         #60

070         ps2_clk = 0;

071         #120

072         ps2_clk = 1;

073         #60

074         ps2_data_in = 1;//奇偶校验位“1”

075         #60

076         ps2_clk = 0;

077         #120

078         ps2_clk = 1;

079         #60

080         ps2_data_in = 1;//停止位“1”

081         #60

082         ps2_clk = 0;

083         #120

084         ps2_clk = 1;

085         #2000

086         //断码中“f0”

087         ps2_data_in = 0;//起始位“0”

088         #60

089         ps2_clk = 0;

090         #120

091         ps2_clk = 1;

092         #60

093         ps2_data_in = 0;//“0”

094         #60

095         ps2_clk = 0;

096         #120

097         ps2_clk = 1;

098         #60

099         ps2_data_in = 0;//“0”

100         #60

101         ps2_clk = 0;

102         #120

103         ps2_clk = 1;

104         #60

105         ps2_data_in = 0;//“0”

106         #60

107         ps2_clk = 0;

108         #120

109         ps2_clk = 1;

110         #60

111         ps2_data_in = 0;//“0”

112         #60

113         ps2_clk = 0;

114         #120

115         ps2_clk = 1;

116         #60

117         ps2_data_in = 1;//“1”

118         #60

119         ps2_clk = 0;

120         #120

121         ps2_clk = 1;

122         #60

123         ps2_data_in = 1;//“1”

124         #60

125         ps2_clk = 0;

126         #120

127         ps2_clk = 1;

128         #60

129         ps2_data_in = 1;//“1”

130         #60

131         ps2_clk = 0;

132         #120

133         ps2_clk = 1;

134         #60

135         ps2_data_in = 1;//“1”

136         #60

137         ps2_clk = 0;

138         #120

139         ps2_clk = 1;

140         #60

141         ps2_data_in = 1;//奇偶校验位“1”

142         #60

143         ps2_clk = 0;

144         #120

145         ps2_clk = 1;

146         #60

147         ps2_data_in = 1;//停止位“1”

148         #60

149         ps2_clk = 0;

150         #120

151         ps2_clk = 1;

152         #2000

153         //数字“1”的通码

154         ps2_data_in = 0;//起始位“0”

155         #60

156         ps2_clk = 0;

157         #120

158         ps2_clk = 1;

159         #60

160         ps2_data_in = 1;//“1”

161         #60

162         ps2_clk = 0;

163         #120

164         ps2_clk = 1;

165         #60

166         ps2_data_in = 0;//“0”

167         #60

168         ps2_clk = 0;

169         #120

170         ps2_clk = 1;

171         #60

172         ps2_data_in = 0;//“0”

173         #60

174         ps2_clk = 0;

175         #120

176         ps2_clk = 1;

177         #60

178         ps2_data_in = 1;//“1”

179         #60

180         ps2_clk = 0;

181         #120

182         ps2_clk = 1;

183         #60

184         ps2_data_in = 0;//“0”

185         #60

186         ps2_clk = 0;

187         #120

188         ps2_clk = 1;

189         #60

190         ps2_data_in = 1;//“1”

191         #60

192         ps2_clk = 0;

193         #120

194         ps2_clk = 1;

195         #60

196         ps2_data_in = 1;//“1”

197         #60

198         ps2_clk = 0;

199         #120

200         ps2_clk = 1;

201         #60

202         ps2_data_in = 0;//“0”

203         #60

204         ps2_clk = 0;

205         #120

206         ps2_clk = 1;

207         #60

208         ps2_data_in = 1;//奇偶校验位“1”

209         #60

210         ps2_clk = 0;

211         #120

212         ps2_clk = 1;

213         #60

214         ps2_data_in = 1;//停止位“1”

215         #60

216         ps2_clk = 0;

217         #120

218         ps2_clk = 1;

219     end

220

221     always # 10 clk = ~clk;//50M的时钟

222

223      ps2_scan  ps2_scan (

224                     .clk(clk), //系统输入时钟

225                     .rst_n(rst_n),//系统复位

226                     .ps2_data_in(ps2_data_in),//ps2的数据

227                     .ps2_data_out(ps2_data_out),//按键的通、断码

228                     .ps2_clk(ps2_clk),//ps2的时钟

229                     .valid(valid)//通、断码有效信号

230                 );

231

232 endmodule

测试中,我们发送了数字”1“的通码,断码,模仿了数字键”1“的按下和抬起。

 仿真分析

在仿真中,测试了数字 “1”的通、断码的接收和发送,每当检测出一个八位有效数据的时候,valid都会出现一个时钟周期的尖峰脉冲。

转载于:https://www.cnblogs.com/mengyi1989/p/11521092.html

进阶项目(12)PS2键盘驱动程序设计讲解相关推荐

  1. linux GPIO模拟PS2 键盘驱动

    背景:公司有一个PS2键盘驱动的项目,没有控制器,需要模拟PS2协议,检测按键并通过input子系统将按键时间上报 一.准备: 1.PS2协议: PS2有两个控制线,时钟线和数据线.当按键按下或抬起, ...

  2. 键盘驱动程序设计(中)

    问题 键盘扫描码可以直接使用吗?扫描码代表键位上的字符吗? 键盘扫描码不可以直接使用,扫描码不代表键位上的字符. 常用编码区别 扫描码(Scan Code) 与键盘厂商有关,不同厂商的扫描码可能不同 ...

  3. verilog语言的ps2键盘驱动设计

    PS/2接口是目前最常见的鼠标接口,最初是IBM公司的专利,俗称"小口".这是一种鼠标和键盘的专用接口,是一种6针的圆型接口.本设计完成了ps2键盘驱动,并将键盘对应的16进制as ...

  4. 基于GD32VF103 的vga显示器 和ps2键盘 驱动

    基于GD32VF103的vga和ps2键盘驱动 前言 gd32vf103 是国内一款很不错的riscv架构微处理器,但是网上gd32vf103的应用还比较少,这里我决定分享一下利用这个微处理器制作的v ...

  5. 键盘驱动程序设计(上)

    问题 计算机已经接入了键盘,为啥按键没反应啊? 因为键盘是外设,当按键被按下时会向处理器发送中断,而我们并没有编写相应的中断处理函数. 键盘的本质 键盘是一种计算机外部设备 键盘与计算机的通信 (数据 ...

  6. linux ps2键盘驱动,通用键盘鼠标模拟(包括USB和PS2)

    通过直接调用Kbdclass的回调函数KeyboardClassServiceCallback直接给上层发送键盘驱动.这个方法网上已经公开,参考Hook KeyboardClassServiceCal ...

  7. linux ps2键盘驱动,Linux下USB模拟ps2鼠标驱动

    在linu-kernel/drivers/input/mouse/psmouse-base.c是ps2鼠标驱动的主体,如psmouse_reset.psmouse_connect等函数具体实现在此文件 ...

  8. java流水线工程设计_进阶项目(7)流水线设计讲解

    写在前面的话 作为初学者,通常情况下我们所设计的电路都是低速的电路,一般都在百兆以下.那么,当我们需要设计高速电路的时候,就需要用到流水线.本节,梦翼师兄和大家一起初步地学习流水线. 流水线基本概念 ...

  9. ps2键盘测试软件,51单片机驱动PS2键盘完整程序

    // PS2键盘测试程序5(完整程序) // 功能:1602显示PS2键盘第1类按键的键值,可以显示大小写,显示在第2行 // 显示pageup.pagedown.方向键(上.下.左.右)的按下次数, ...

最新文章

  1. HYSBZ - 1798 Seq 维护序列seq 线段树lazy标记
  2. 15条有用的Linux/Unix 磁带管理指令
  3. 【Unity|C#】基础篇(1)——基础入门
  4. 谁说 JavaScript 简单的?
  5. mysql 头行关联_mysql实现一样变多行(表关联,批量实现)
  6. Servlet and Tomcat
  7. 【转】kubernetes 中 deployment 支持哪些键值
  8. atitit knowmng知识管理 索引part2
  9. 让IIS只监听一个IP上的80端口
  10. 简单的嵌入式人脸识别系统
  11. 举办计算机知识竞赛的意义,计算机专业成功举办“计算机基础知识竞赛”
  12. C语言程序计算自己活了多少天
  13. python语法31[函数]
  14. GTS、GCK,GSR全称
  15. ST公司三轴加速度计LIS3DH应用
  16. clickhouse-backup 备份恢复测试
  17. nokia x7 android 9.0,诺基亚X7升级Android 9.0系统 HDR拍照画质大幅提升
  18. ECNU_OJ_1026
  19. The channel is not accessible or is invalid
  20. shell脚本系列-正则表达式介绍

热门文章

  1. chart.js基本知识——调整图表尺寸
  2. Anthony_tester(博客链接)
  3. Open Cascade 多视图-多个3D视图
  4. pc端点击图片放大效果
  5. c++头文件iomanip.h中的setw、setprecision、setfill和setbase函数
  6. 【干货】Python:load_workbook用法(持续更新)
  7. html网页收藏夹小图标,在网页标题栏上和收藏夹显示网站logo的实现方法
  8. 数据库连接池 ( 二 ) 连接池概念
  9. TensorFlow使用Keras Tuner自动调参
  10. 用C++语言写游戏——打怪小游戏