往昔鸳鸯戏水,而今不相依偎,美景良辰纵然抚媚亦徒留伤悲。----《美人画卷》


本代码是一生一芯项目中,南京大学nvboard开源项目键盘扫描示例代码。我们抛开上层连接不谈,分析一下这个代码。同时我自己也理清一下思路,不然总是感觉些许混乱,或者说,明明用51单片机写的时序接收这么好理解,为什么这个程序我没有一眼看出来他在干什么。因为这段代码本身确实蕴含着一个设计思想,请务必读到最后。
南京大学数电实验网站:点此
nvboard GitHub(即本文源码出处):https://github.com/NJU-ProjectN/nvboard.git
源代码著作权归原作者所有。本文完全尊重原作者的著作权,仅引用、注释以供学习,不参与网站创作激励,不具有商业、盈利性质。

0. 源代码

module ps2_keyboard(clk,resetn,ps2_clk,ps2_data);input clk,resetn,ps2_clk,ps2_data;reg [9:0] buffer;        // ps2_data bitsreg [3:0] count;  // count ps2_data bitsreg [2:0] ps2_clk_sync;always @(posedge clk) beginps2_clk_sync <=  {ps2_clk_sync[1:0],ps2_clk};endwire sampling = ps2_clk_sync[2] & ~ps2_clk_sync[1];always @(posedge clk) beginif (resetn == 0) begin // resetcount <= 0;endelse beginif (sampling) beginif (count == 4'd10) beginif ((buffer[0] == 0) &&  // start bit(ps2_data)       &&  // stop bit(^buffer[9:1])) begin      // odd  parity$display("receive %x", buffer[8:1]);endcount <= 0;     // for nextend else beginbuffer[count] <= ps2_data;  // store ps2_datacount <= count + 3'b1;endendendendendmodule

1. 相关知识

键盘传输过来的有两个数据,分别是ps2_clk,ps2_data,即键盘的时钟,以及按键的通码断码。
扫描码:被规定的、某键被按下/弹起时所送出的代码。
通码是:约定的、按键按下是键盘送出的编码,现代键盘基本统一。
断码是:F0h加此按键的通码,如释放 W 键时输出的断码为F0h 1Dh,分两帧传输。

下图是键盘扫描表,原图出自南京大学数字电子电路实验课程网站,更多资料可以上网去搜。

下图是传输时序图,原图出自南京大学数字电子电路实验课程网站,网址点此

即:一帧数据共9位,最后一位P是奇偶校验(奇校验)。

2.代码分析

代码先定义了一个三位的时钟变量ps2_clk_sync,通过一个死循环,每次把ps2_clk时钟上的采样送入最低位,并丢弃最高位,即形成了一个三位的时间队列。
因为每次最新的采样放入的是最低位0位,所以计算的ps2_clk_sync[2] & ~ps2_clk_sync[1]。若为下降沿,则sampling为1,上升沿为0。

但是读到这里相信都不免有些疑问:
为什么不ps2_clk_sync[1] & ~ps2_clk_sync[0]?这样岂不更加及时?或者直接把ps2_clk设置成always的敏感变量,不是更一步到位?这样做的意义是什么?
请先思考,文末有笔者认为的原因。

reg [2:0] ps2_clk_sync;always @(posedge clk) beginps2_clk_sync <=  {ps2_clk_sync[1:0],ps2_clk};endwire sampling = ps2_clk_sync[2] & ~ps2_clk_sync[1];

如此,则sampling内存放的是当前是否是下降沿;若当前是下降沿,则判断了count == 4'd10,count就是个计数器,每次count <= count + 3'b1;,所以就是判断是否接收到了十位。看清这里是4'd10就好,我之前没看清以为是4'd10卡了半天。然后就是判断首位是否为0、1,并且使用了校验。
这里可以学习一下他写的奇偶校验,^buffer[9:1],需要注意的是这里的^缩减运算符,其运算方式是

ans = ((buffer[1] ^ buffer[2]) ^ buffer[3])^ ······

即从最低位开始向上计算。最后的结果也是一个布尔值。
如果上述判断条件都通过,就输出buffer。

但是你是否有这样的疑问:第十位是stop空位,并且奇偶校验在第九次收到之后就可以进行了,为什么非要等这个空的帧入队之后,第十一次才开始判断呢?

 reg [9:0] buffer;        // ps2_data bitsreg [3:0] count;  // count ps2_data bitsalways @(posedge clk) beginif (resetn == 0) begin // resetcount <= 0;endelse beginif (sampling) beginif (count == 4'd10) beginif ((buffer[0] == 0) &&  // start bit(ps2_data)       &&  // stop bit(^buffer[9:1])) begin      // odd  parity$display("receive %x", buffer[8:1]);endcount <= 0;     // for nextend else beginbuffer[count] <= ps2_data;  // store ps2_datacount <= count + 3'b1;endendendend

3. 摩尔型有限状态机

南大这个网站把状态机和键盘放在一起,让我很是不理解,明明两个风马牛不相及的东西,放一起干什么,但是仔细一想,其实是因为这段代码使用了摩尔型有限状态机的思想。
下面摘录一下摩尔型状态机的知识,同样参考南大的数电实验网站。

Moore 型有限状态机的输出信号只与有限状态机的当前状态有关,与输入信号的当前值无关,输入信号的当前值只会影响到状态机的次态,不会影响状态机当前的输出。即Moore 型有限状态机的输出信号是直接由状态寄存器译码得到。 Moore型有限状态机在时钟CLK信号有效后经过一段时间的延迟,输出达到稳定值。即使在这个时钟周期内输入信号发生变化,输出也会在这个完整的时钟周期内保持稳定值而不变。输入对输出的影响要到下一个时钟周期才能反映出来。Moore有限状态机最重要的特点就是将输入与输出信号隔离开来。

观察这段代码,不难发现使用的就是Moore(摩尔)型有限状态机的思想。因为:

  1. 它对时间序列进行了一个存储,当前时序判断前两个时序是否存在下降沿,而不是接收到时钟信号立即判断下降沿。
  2. 对于buffer也不是收到第十位(count == 9)就立即输出,而是第十位也放入buffer内后才进行校验、输出。如果存在第十一位的话,其实现在已经是第十一位了。

看来前面我们对为什么要存储时间序列的疑问解决了。甚好。

回忆斑驳微醉,叹相思未随,几春几秋几段轮回。----《美人画卷》

verilog键盘输入示例代码及分析(摩尔型有限状态机)相关推荐

  1. python键盘输入代码,python监控键盘输入实例代码

    本文研究的主要是python监控键盘输入的相关代码,用到了os,sys,time等,具体实现代码如下: #!/usr/bin/env python # -*- coding: utf-8 -*- im ...

  2. 微信公众平台nbsp;示例代码nbsp;分析

    一.摘要 微信公众平台提供了一个简单的php示例代码,在做进一步开发之前,我们有必要将其详细了解一下. 二.获取代码 微信官网:http://mp.weixin.qq.com/mpres/htmled ...

  3. python中从键盘输入的代码_python如何从键盘获取输入实例

    python中使用input()函数来获取用户输入 函数 input() 让程序暂停运行,等待用户输入一些文本,获取用户的输入后,Python将其存储到一个变量中,以方便后期使用. name = in ...

  4. python中从键盘输入的代码_Python读取键盘输入的2种方法

    Python提供了两个内置函数从标准输入读入一行文本,默认的标准输入是键盘.如下: 1.raw_input 2.input raw_input函数 raw_input() 函数从标准输入读取一个行,并 ...

  5. html读取用户输入,HTML表单处理用户输入(示例代码)

    1.HTML表单用于收集用户输入.通过 标签定义 2. 元素是最重要的文本元素. 2.1.text定义常规文本输入,password定义密码字段 User name: User password: 2 ...

  6. python 监控键盘输入_python监控键盘输入实例代码

    {"moduleinfo":{"card_count":[{"count_phone":1,"count":1}],&q ...

  7. 在java中通过过键盘输入_java中从键盘输入

    控制台输入数据 1.1 主方法的形式参数 在 Java 中利用 main(Str... Java中获取键盘输入值的三种方法 2012-11-13 00:00比特网悠虎关键字:Java 程序开发过程中, ...

  8. 校招小白机考入坑之从键盘输入java的各种数据类型

    //1.从键盘输入一个整型(其他基本类型类似) Scanner sc =new Scanner(System.in); sc.hasNextInt(); int str1 = sc.nextInt() ...

  9. java输出数组的最大值_JAVA 键盘输入数组,输出数组内容和最大值、最小值(示例代码)...

    package shuzu; import java.util.Scanner; public class shuzu { /** * @param args */ public static voi ...

最新文章

  1. Redis问题——Error: 磁盘在使用中,或被另一个进程锁定。
  2. 电脑怎么打印文件步骤_电脑中毒后怎么办 电脑中毒后解决方法【详细步骤】...
  3. 你对webpack了解多少?
  4. [JavaWeb-HTTP]HTTP_请求消息_请求头请求体
  5. [html] 你知道微信端的浏览器内核是什么吗?
  6. Centos7中安装python3.7、pip3以及pipenv(亲测有效)
  7. 互联网晚报 | 8月10日 星期二 | 携程启动“2021混合办公试验”;网易云音乐暂缓IPO;上汽通用五菱年累销量突破百万...
  8. css取消聚焦边框[Chrome,Safari]
  9. “vueuse“ 中文索引与用例
  10. 单例模式(Singleton mode)实战讲解
  11. java 代码生成器 generator
  12. ebm风扇选型手册_德国EBM全系列散热风扇
  13. 介绍鲜花视频的html模板,HTML黄色欧美形式鲜花介绍网页模板代码
  14. 2019111 控制台上实现极乐净土(有图有背景音乐)
  15. 经典聚类算法——Kmeans详解
  16. Web3依赖参与型经济,而它缺少的正是参与
  17. 网页加载java慢_为什么开网页很慢 网页打开速度慢的原因【解决方法】
  18. 19年拿了19个诺贝尔奖,日本科学为何“井喷”?
  19. 大师级管理人物盘点:“颠覆性技术“提出者-克里斯坦森
  20. 短视频app开发:如何实现视频直播功能

热门文章

  1. 对校招生培养工作的建议_对我校招生工作的一些粗浅想法(精)
  2. CentOS7下安装和配置MySQL5.7亲测有效(附图文)
  3. ubuntu双系统引导梅花_Win10+ubuntu 双系统安装顺顺利利!
  4. excel超链接应用:快速生成目录的几个方法-下
  5. ISO7816协议中psam卡片的延时单元etu
  6. Problem -B DBZ的钥匙
  7. three.js 控制动画进度 进度条拖拽控制
  8. Android MediaPlayer控制进度播放音频
  9. AIX 操作系统安全配置指南
  10. vue通过for循环生成的checkbox点击一个选中全部的问题