zoukankan      html  css  js  c++  java
  • 【连载】【FPGA黑金开发板】Verilog HDL那些事儿PS2解码(九)

    声明:本文为原创作品,版权归akuei2及黑金动力社区(http://www.heijin.org)共同所有,如需转载,请注明出处http://www.cnblogs.com/kingst/

    2

    3.2 实验八:PS2解码

    PS2的简单认识

    在以前使用单片机对PS2进行解码的时候,一句话就是苦。 如果是CPLD 或者 FPGA 的前提下,PS2的解码才有意义。

    clip_image002[1]

    PS2的接口如上图,除了Pin 5 和 Pin 1 其他的引脚对解码没有什么意义。而下图是PS2协议的时序图。PS2协议对数据的移位是“Clock 的下降沿”有效。PS2时钟的频率比较慢,大约是10Khz左右。

    clip_image004[1]

    第N位

    属性

    0

    开始位

    1~8

    数据位

    9

    校验位

    10

    结束位

    PS2的一帧是11位。对PS2进行解码时,除了第1~8位数据位以外,其余的位都可以无视。

    对编码键盘“键盘码”的简单认识

    普通计算机采用的都是“编码键盘”,但是“编码键盘”的“编码方式”有分为“第一套”“第二套”和“第三套”。“第二套”的编码使用较为普遍,大致上的民用键盘都是采用“第二套”编码方式。

    clip_image006[1]

    键盘的编码有“通码”(Make)和“断码”(Break)之分。看得简单一点就是,“通码”是某按键的“按下事件”,“断码”是某按键的“释放事件”。

    假设,我按下“W”键不放,每秒大约会输出10个“0x1d”的“通码”。然后我释放“W”键,就会输出 “0xF0 0x1d” 的“断码”。 编码键盘还有一个老规则,就是一次只有一个输出。

    再假设我按下“W”键不放,然后我再按下“X”键不放,那么会输出“0x1d”“0x22”“0x22”........ 的通码。如果此时我放开“X”键,就会输出“0xf0 0x22”的“断码”,此时“W”键的“通码”已经无效。但是当我释放“W”键的时候,依然会输出“0xf0 0x1d”, “W”键的“断码”。

    至于组合键 “ Shift + ?” ,“ Ctrl + ?”都是软件的工作,我们就无视吧。

    实验八源码:

    实验八的目的很简单,实验主要对PS2进行解码,然后对“通码”进行判断,然而对 “断码”采取忽略的行为。

    clip_image008[1]

    在组合模块 ps2_module.v 中包含了两个功能块: “电平检测模块” detect_module.v 和 "ps2解码模块" ps2_decode_module 。detect_module.v 的添加时为了检查 PS2 时钟信号的“下降沿”,此外也是为了使模块的建立更简单。ps2_decode_module.v 如字面上的意思,对每帧(十一位一组数据)的数据进行解码和过滤的行为,最后将一字节数据输出 PS2_Data,然后 PS2_Done_Sig 产生一个高脉冲,表示完成一次性的操作。

    3.2.1 detect_module.v

    clip_image010[1]

    clip_image011[1]

    嗯!这个功能模块的解释可以参考实验实验三。

    3.2.2 ps2_decode_module

    clip_image013[1]

    clip_image014[1]

    ps2_decode_module.v 最主要的核心是在第31~55行。同样这个模块也是采用“仿顺序操作”的写法。步骤i一开始会停留在0(33行),当检查到 H2L_Sig 的变化,我们知道PS2一帧数据的第第0位是开始位,所以无视。在接下来的8个位都是数据位,PS2的数据位是从最低位开始,最高位结束。然后对 PS2_Data_Pin_In 引脚进行读值(第36~37行)。

    PS2一帧数据的第9~10位是校验位和结束位,执行无视操作(39~40行)。在 i 等于 11的时候(42行),我们要进行判断,读取的“数据是通码还是断码?”,如果是“通码”(44行),就进入49行随后产生一个高脉冲的完成信号(49~53行),最后返回33行,等待下一次的操作。

    如果是“断码”(43行),进入46行随后对“断码”采取无视的操作(46~47行),最后产生一个高脉冲的完成信号,然后返回第33行(49~53行)。

    3.2.3 ps2_module

    clip_image016[1]

    实验八说明 :

    实验八的PS2解码仅对“通码”执行操作,相反却对“断码”采取无视的行为。实验八的重点主要是如何实现“PS2时钟采样”和“PS2数据采样”操作?

    clip_image018[1]

    从上图中我们可以看到,黑金的时钟频率比起PS2的时钟频率,大约是2000倍。而 detect_module.v 就是利用这2000个时钟信号去采集每个PS2时钟的下降沿(小箭头)。

    当detect_module.v 检测到ps2时钟产生下降沿,(detect_module.v 32行)由于布尔的表达式关系,就会产生一个高脉冲经H2L_Sig 信号。PS2协议的一帧数据大约是11个数据位,换句话说就会产生11个下降沿,也就是说会产生11次高脉冲的H2L_Sig。

    PS2时钟在每一个下降沿的时候,PS2数据就会“设置”(移位)数据,而 ps2_decode_module.v 中的 31~55行,就是对PS2数据的移位进行“数据采样”。假设PS2时钟在第一次的下降沿,自然而然PS2数据会“设置”第0位数据( ps2_decode_module.v 34行 ),ps2_decode_module.v 采取无视的操作,接下来的八位数据位才是真正需要的数据位。

    有一点比较值得注意的是在 ps2_decode_module.v 第42~44行。从上面我们知道,黑金的时钟频率对ps2的时钟频率有 2000倍的相差,从另一个角度去理解的话,距离每一次PS2时钟信号的下降沿,黑金拥有2000个可以执行的时间。然而在第42~44行只用了一个时间去判断,余下还剩下1999个可空闲的时间。

    也就是说,采样和被采样的频率如果相差越大,采样方可执行的空余的时间就越多,在设计上就越轻松。

    完成扩展图:

    clip_image020[1]

    实验八结论 :

    实验八总归也就是属于PS2解码的部分。然而笔者在设计上,对 ps2_detect_module.v 添加了 PS2_Done_Sig, 这个信号无疑是表示了 “一次性操作”已经完成的次数。因为编码的键盘,只要按着不放就会一直发送“通码”,如果笔者针对“通码”去设计的话,笔者永远“只能得到键盘的数据”,已不是“通码”和“次数”这两方。

    实验八演示:

    clip_image022[1]

    实验八演示中的“命令控制模块”cmd_control_module.v 会对“W”,“X”和“Ctrl”键作出反应。在 cmd_control_module.v 的输出是4位的信号,初始值是4'b0001。当“W”键按下,就会产生左移的效果,“X”键则是右移。至于“Ctrl”键会产生“互换”。

    clip_image024[1]

    第16~35行是 cmd_control_module.v 的核心部分,当PS2_Done_Sig 产生高脉冲(23行),该控制模块就会对 PS2_Data 产生反应。8'h1d 是“W”键的通码,而 8'h22 是“X”键的通码,至于 8'h14 是“Ctrl”键的通码。

    “W”键,产生左移效果(26~27行),

    “X”键,产生右移效果(29~30行),

    “Ctrl”键,产生互换效果(32~33行)。

    clip_image026[1]

    exp08_demo.v 是 ps2_module 和 cmd_control_module.v 的组合模块。ps2_module.v 的具体介绍请参考实验七。

    实验八演示说明:

    在 cmd_control_module.v 中的第23行,PS2_Done_Sig 很有效被利用来控制执行的次数。而且cmd_control_module.v 仅对 “W”“X”“Ctrl”键的“通码”产生反应而已,换一句话说,cmd_control_module.v 只会在以上三个键在“按下”或者“按下不放”才会有所反应。

    完成扩展图:

    clip_image028[1]

    实验八演示结论:

    我以前接触过很多有关 PS2的解码实验,都非常执着与“字符”有关。其实无论是什么输出,只要有效的利用“通码”就不成问题。最重要的是如何编辑这些“通码”称为有效的“命令”!?

    还有另一点,编码键盘虽然很方便,但是编码键盘是无法取代独立键盘。在实验八演示中,在两个键同时按下的时候,仅有按下最迟的一方才有输出“通码”的权利。相反独立按键是完全“并行”执行, 不会出现对输出争先恐后的事件。所以在许多方面编码键盘还是不完美。

    最后还有一点,就是所有拥有PS2接口的设备,一般上都是“低速”设备,这一点要好好的记住。


    实验八总结:

    实验八主要是表达“低级建模”在“读取”或者“采样”上发挥的效果。在众多同样的试验中,笔者常常可以看到所有模块都是往一个 .v 文件里面写,虽然在编辑上会很方便,但是在“理解的方式上”,“理解的形状上”又是怎么一回事?

    同样的,实验八和实验七建模的数量都是不相上下,或者可以说这是“低级建模”的普遍缺点,但是读者是不是会察觉到?当你在组合模块,将一个一个模块实例化,思路无比是清晰,而且设计的工作也容易?

    好吧,换另一个话题去讨论实验八的重点:

    always @ ( posedge CLK )

    ......

    always @ ( posedge CLK )

    ......

    如上面的代码,在同样一个模块中出现了两个always 块,在一般的情况下,我们都会“从上往下”读,类似顺序操作那样看待。如果你的理解能力好,或者已经习惯了,那么这事儿不成问题。但是在实际的操作中,所有 always块都是“并行”执行者,很多新手都会被自身的“假概念”误导。如果将上述的问题反映在建模上,往往会使更多新手进入瓶颈。

    就像在第二章的实验,笔记一直在强调“并行”的概念和重要性。“低级建模”的多模块设计无疑是能很好的发挥“并行”的概念。如实验八演示中,detect_module.v,ps2_decode_module.v,cmd_control_module.v ,它们在每一个时钟的上升都是在独立工作着。至于它们会不会被触发或者协调执行,完全是依赖自身早已被设定好的功能。

    detect_module.v 在每一个时钟源的上升沿(posedge CLK),如果检测到 PS2时钟发生下降沿,就会经 H2L_Sig 产生高脉冲,除此之外它的工作就结束了。

    然而 ps2_decode_module.v 在每一个时钟源的上升沿(posedge CLK),如果检测到 H2L_Sig 的高脉冲,就会对 PS2数据一帧数据的执行采集和过滤的动作,最后将完整的数据输出至 PS2_Data, 然后 PS2_Done_Sig 产生一个时钟的高脉冲,它就完工了。

    cmd_control_module.v 在每一个时钟源的上升沿(posedge CLK),如果被PS2_Done_Sig 触发,那么它就会依据 PS2_Data 的数据作出相对的反应,否则它就一直保持沉默。

    虽然整体的主观上,它们会如同连线关系一方接着触发着一方。但是实际上,每一个模块都保持者独立关系,只有在“触发”的时候才工作。当然“低级建模”所强调的准则不仅是重视在“并行”的理解上,还有好多好多的故事会发生在这本笔记的后面。

  • 相关阅读:
    yii2 gii 命令行自动生成控制器和模型
    控制器中的方法命名规范
    Vue Property or method "" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based
    IDEA插件:GsonFormat
    Spring Boot : Access denied for user ''@'localhost' (using password: NO)
    Typora添加主题
    Git基础命令图解
    Java Joda-Time 处理时间工具类(JDK1.7以上)
    Java日期工具类(基于JDK1.7版本)
    Oracle SQL Developer 连接Oracle出现【 状态: 失败 -测试失败: ORA-01017: invalid username/password; logon denied】
  • 原文地址:https://www.cnblogs.com/kingst/p/1832185.html
Copyright © 2011-2022 走看看