首页>资讯>游戏攻略>深圳SHENZHENIO第3关脉冲发生器攻略
深圳IO是一款硬核的编程游戏,有着严谨的游戏内容,那么一起来看看第3关信号脉冲发生器的攻略吧。
概念MAIL:任务中心,游戏的主题都在其中,为了仿照认真工作的样子,所有的任务背景和内容都模拟邮件的形式进行
数据手册:嵌入式开发必经之路,相当于正常游戏的新手引导,哈哈,读起来很有感觉呢
控制面板:就是控制台啦,这不需要过多叙述了
纸牌游戏:这个会在游戏前期解锁,一旦解锁,这个游戏可能就变成了一款蜘蛛牌游戏。
主界面
由于游戏过分硬核,先放个手册中的图看看冰山一角:
游戏中DX300参考
像这样的器件足足有17个!!!! 哈哈,有没有已经感觉到挑战了呢?
不过这也正对应了嵌入式开发中会遇到的海量数据手册,相当程度上还原了嵌入式日常开发的情景。
游戏中设计到部分的编程有些类似于汇编语言,这里上手还是有一些些难度的,大家请做好准备,继续直接扔核弹:
游戏中主要使用的编程语言
不用害怕,在游戏过程中,会逐步引导你学会使用新的指令,对于新的器件,也是随着主线的进行逐步开放的
在游戏中,你不仅可以完成指定的基本目标,还可以挑战全网玩家,看谁能达成最佳优化目标。
鱼和熊掌不可兼得,多数情况下想要达成更好的性能就要增加成本啦,不过这正是优秀的嵌入式开发人员的意义所在——比你好,还比你的便宜。
第1关:安全摄像头
第2关:信号放大器
第3关:脉冲发生器
关卡展示
这一关需要让你在按钮未按下时(对应的输入信号为 0)保持待命,而在按钮按下时(对应的输入信号为 100)生成 100×1s,0×1s 的循环脉冲信号。
这一关我们需要了解【测试指令】这个新概念。
测试指令一共有 4 条:
1,teq I1/R1/P1 I2/R2/P2,测试(test)第一个操作数是否等于(equals)第二个操作数。若两数相等,激活所有带 + 前缀的指令,关闭所有带 - 前缀的指令。若两数不等,激活所有带 - 前缀的指令,关闭所有带 + 前缀的指令。
2,tlt I1/R1/P1 I2/R2/P2,测试第一个操作数是否小于(lower than)第二个操作数。若第一个数小于第二个数,激活所有带 + 前缀的指令,关闭所有带 - 前缀的指令。若第一个数大于或等于第二个数,激活所有带 - 前缀的指令,关闭所有带 + 前缀的指令。
3,tgt I1/R1/P1 I2/R2/P2,测试第一个操作数是否大于(greater than)第二个操作数。若第一个数大于第二个数,激活所有带 + 前缀的指令,关闭所有带 - 前缀的指令。若第一个数小于或等于第二个数,激活所有带 - 前缀的指令,关闭所有带 + 前缀的指令。
4,tcp I1/R1/P1 I2/R2/P2,比较(compare)两个操作数的大小。若第一个数小于第二个数,激活所有带 - 前缀的指令,关闭所有带 + 前缀的指令。若第一个数大于第二个数,激活所有带 + 前缀的指令,关闭所有带 - 前缀的指令。若两数相等,关闭所有带 + 和 - 前缀的指令。
5,带 + - 前缀的指令会一直保持自己的激活或关闭状态,直到遇到下一条测试指令。测试指令前也是可以带 + - 前缀的,这意味着测试指令不是一定会被执行。这属于高阶技巧,以后我们再详细讲解。
举例说明:
1: teq p0 100
2:+ mov 50 p1
3:- mov 0 p1
4: slp 1
首先,我们测试 p0 端口的值是否为 100。如果是 100,那么后续 + 前缀的指令(mov 50 p1)将会被执行,而 - 前缀的指令(mov 0 p1)将不会被执行,那么 p1 口收到的值很明显是 50。反之,p0 端口的值不是 100 时,+ 前缀的指令不执行,- 前缀的指令正常执行,p1 口收到的值就会是 0。
回到这一关,我们需要在按钮按下时(按钮端口的值为 100)时生成脉冲方波(使用 gen 指令生成);而在按钮抬起时(按钮端口的值为 0)时安心休眠待命(使用 slp 指令)。经过以上分析后,这一关的答案已经呼之欲出:
按钮端口只有 0 和 100 两种值,我们首先对和按钮端口相连接的 p0 口执行测试指令 tcp p0 50。当 p0 小于 50 时,按钮处于抬起状态,激活 - 前缀的指令,我们需要执行休眠指令原地待命(- slp 1);当 p0 大于 50 时,按钮处于按下状态,激活 + 前缀的指令,我们需要不断执行 gen 指令生成 100 和 0 各占一秒的方波(+ gen p1 1 1),直到某刻 tcp 测试指令变为 - 生效为止。
点击左下角的【模拟】,稍等片刻,便会弹出结算界面:
优化代码行数
这里要提到一个隐藏特性:slp 里的休眠时间,和 gen 里的两个休眠时间是可以指定为 0 的。
mov 0 p0
slp 1
等价于
mov 100 p0
slp 0
mov 0 p0
slp 1
等价于
gen p0 0 1
我们在同一个时钟周期里可以反复给同一个 p 口赋不同的值,当前的时钟周期过去了之后,确认面板上会显示出对应 p 口【最后一次】赋的值。所以,我们在同一时钟周期里给 p0 依次赋值 100 和 0 后,p0 口这一个时钟周期内的实际值只会是 0。
现在,我们要再了解一个新的元件:DX-300。这个原件最多可以同时对 3 个简单 I/O 口进行读取或写入操作,具体的做法和二进制的【位运算】有点相似。
我们先说 DX-300 怎么同时读三个口的数据。我们将 DX-300 的 p0、p1、p2 分别和三个简单 I/O 口相连,然后另一侧的三个 X 口会实时传送一个三位数表示三个简单 I/O 口的状态:p0 为 0/100 时,个位数为 0/1;p1 口为 0/100 时,十位数为 0/1;p2 口为 0/100 时,百位数为 0/1。那么 DX-300 的 X 口所传出的三位数就有以下 8 种可能:000、001、010、011、100、101、110、111,依次对应三个简单 I/O 的开/关状态的 8 种排列组合。
同时写三个简单 I/O 的原理也很类似,我们往 DX-300 的任意一个 X 口写入以上 8 种三位数中的一种,就达到了用一条指令同时控制三个简单 I/O 的目的。比如你想让 p0 和 p2 变为 100,p1 变为 0,那么你就给 DX-300 传 101 就可以了。
那么这道题,我们怎么优化到 1 条指令呢?我们的第一种方案里,芯片里的代码是这样的:
1: tcp p0 50
2:- slp 1
3:+ gen p1 1 1
然后,我们可以推断出来,当执行到【- slp 1】时,p1 口的值一定是 0。由于 gen 指令一定以将对应 p 口赋 0 终结,所以以上 slp 指令也可以替换成 gen 指令,我们的代码可以改写成下面的样子
1: tcp p0 50
2:- gen p1 0 1
3:+ gen p1 1 1
这两条 gen 指令只有一个操作数不一样,那么它们能不能合并成一条呢?答案是可以的。我们不难发现:当 p0 是 0 时,执行的是 gen p1 0 1;当 p0 是 100 时,执行的是 gen p1 1 1。如果我们有一种办法能把 p0 的 100 转换成 1,那么只要一条 gen p1 (?) 1 指令就够了,问号处是经过转换后的数字。
这时候,我们的 DX-300 闪亮登场。我们将【按钮】端口接到 DX-300 的 p0 口上,其余两个口空着不接(视为对应端口的值恒为 0)。这样,当【按钮】端口的值为 0 时,经过 DX-300 加工后为 000;反之,当【按钮】端口的值为 100 时,这个值经过 DX-300 加工后会变成 001。这个加工后的值正好是我们需要在 gen 指令中用到的值!
于是,只用一行代码的设计方案顺利完成!
评论 (0)分享