电玩圈游戏网 搜一搜

安卓手游去频道 >

角色扮演 射击枪战 棋牌卡牌 体育运动 角色扮演 赛车竞速 休闲益智 音乐舞蹈 模拟经营 战棋塔防 推理解谜 策略战争

安卓应用去频道 >

社交通讯 系统工具 影音视听 拍摄美化 效率办公 学习教育 生活服务 旅游出行 资讯阅读 金融理财 网络购物 游戏助手

游戏视频去频道 >

动作冒险 射击枪战 棋牌卡牌 体育运动 角色扮演 赛车竞速 音乐舞蹈 模拟经营 战棋塔防 推理解谜 策略战争 休闲益智

资讯攻略去频道 >

手游资讯 手游攻略 手游问答 游戏资讯 游戏杂谈 游戏攻略 软件教程 软件资讯

专题合集去频道 >

游戏专题 应用专题

排行榜单去频道 >

游戏排行 应用排行
首页 游戏 应用 视频 资讯 专题 榜单

首页>资讯>游戏攻略>深圳SHENZHENIO第18关远程退出开关攻略

深圳SHENZHENIO第18关远程退出开关攻略

作者:佚名来源:百度2022/06/07

深圳IO是一款硬核的编程游戏,有着严谨的游戏内容,那么一起来看看第18关的远程退出开关的攻略吧。

主界面

由于游戏过分硬核,先放个手册中的图看看冰山一角:

不过这也正对应了嵌入式开发中会遇到的海量数据手册,相当程度上还原了嵌入式日常开发的情景。

游戏中设计到部分的编程有些类似于汇编语言,这里上手还是有一些些难度的,大家请做好准备,继续直接扔核弹:

不用害怕,在游戏过程中,会逐步引导你学会使用新的指令,对于新的器件,也是随着主线的进行逐步开放的

在游戏中,你不仅可以完成指定的基本目标,还可以挑战全网玩家,看谁能达成最佳优化目标。

鱼和熊掌不可兼得,多数情况下想要达成更好的性能就要增加成本啦,不过这正是优秀的嵌入式开发人员的意义所在——比你好,还比你的便宜。

第 18 关:远程退出开关

关卡展示

本关要求当你收到 C2S-RF901 发来的数据包时,按照如下规则更新三个电源的开关状态:

-1:保持原始状态不变;

0:关闭一个电源,具体关闭的电源由第二个数决定;

1:开启一个电源,具体开启的电源由第二个数决定。

与此同时,当你 5 秒钟内没收到任何数据包时(包括 -1 保持状态的数据包也算在内),关闭所有电源。

这一关我们很容易想到将置位指令和 DX-300 结合使用。我们将电源 0~2 分别和 DX-300 的 p0~p2 口相连,用芯片中的 acc 寄存器记录实时的电源状态。然后:当我们收到 -1 数据包时,不做任何操作;当我们收到以 0 开头的数据包时,将第二个数所指示的位数置 0,并将新的 acc 值发送给 DX-300;当我们收到以 1 开头的数据包时,将第二个数所指示的位数置 1,并将新的 acc 值发送给 DX-300。

可问题在于另一条需求:6 秒钟没收到数据包时要将所有电源关闭。可我们的 acc 已经被占用了,dat 又不能做数学运算,那我该拿什么玩意来计时呢?

其实,计时这方面,我们并不需要 acc 寄存器所支持的所有数学运算。我们只需要两种运算:加一和归零。说到这里,不知道读者有没有一种灵机一动的感觉:上一节提到的 ROM 和 RAM,读数据口时地址值会自增!因此,我们完全可以用 ROM 来实现计时功能!

我们用这样的方法来操作 ROM:

将 ROM 的 4 号地址空间写上 -1(作为关闭所有电源的信号),其余位置保持 0;

收到数据包时,将 ROM 的地址值 0(相当于让计时器归零)

没有收到数据包时,读一下 ROM 的数据口,此时地址值会自己 +1(相当于计时器 +1)。如果读到的数值是 0,那么就维持现状;若读到了 -1,那么就给 DX-300 赋 0,关闭所有的电源。

为什么要在 ROM 的 4 号地址空间里写 -1 呢?因为收到数据包的时候,我们要将地址值置 0,相当于让计时器回到“第 0 秒”。而我们选择在“第 5 秒”时关闭,读第 4 秒的数据时,计时器自增 1 就正好到达了第 5 秒,而我们读到的却仍然是“上一秒”的值。所以我们要“提前预判”,在读第 4 秒的时候就要告知我们的芯片,该关闭全部电源了。

这样,我们就成功借助了 ROM 实现了“第二个 acc”用于计时。电路图和代码如下:

首先我们将当前时钟周期里的首数字读入 dat 暂存(mov x3 dat)。然后我们判断首数字到底是 -999 还是 -1、0、1(tcp dat -2)。如果是 -999,那么读一次 ROM 的数据口,令地址值自增 1,相当于计了 1 秒钟(- tcp x0 0)。如果读到了小于 0 的值,那么就说明是时候关闭所有的电源信号了,将 acc 归零,同时将 DX-300 连接的三个电源输出也都全部归零(- mov 0 x2, - mov 0 acc)。回到开头,如果读到的首数字不是 -999,那么首先将 ROM 的地址值归零,相当于将计时器归零(+ mov 0 x1)。然后进一步判断首数字到底是 -1 还是另两种值。如果首数字是 -1,则我们只把计时器清零,不对 acc 的值做任何改变。如果首数字是 0(teq dat 0),那么读入第二个数字,并将 acc 对应位置(0:个位,1:十位,2:百位)上的数字置为 0(+ dst x3 0);如果首数字是 1(teq dat 1),那么读入第二个数字,并将 acc 对应位置上的数字置为 1(+ dst x3 1)。操作完毕后,将当前的 acc 发送给 DX-300(mov acc x2),然后休眠一秒(slp 1),进入下一个机器周期。

点击左下角的【模拟】,稍等片刻,便会弹出结算界面:

优化电量和代码行数

注意我提到的以上解释说明中的这一部分:

如果首数字是 0(teq dat 0),那么读入第二个数字,并将 acc 对应位置(0:个位,1:十位,2:百位)上的数字置为 0(+ dst x3 0);

如果首数字是 1(teq dat 1),那么读入第二个数字,并将 acc 对应位置上的数字置为 1(+ dst x3 1)。

首数字是 0 时将对应位置 0,首数字是 1 时将对应位置 1。发现了没?这两句话可以合并成“当首数字 >-1 时,将对应位置修改成这个首数字”!我们的代码也可以相应地化简,不需要依次判断 dat 是否为 0 和 1 了,只需要判断 dat 是否大于 -1,满足条件时将 dst 指令中的第二个操作数改成 dat 就行了。于是我们将代码改成了下面这样:

甚至我们将 mov acc x2 这条指令也加上了 + 号。只有当 acc 的值变化了的时候才需要传给 DX-300,平时没有变化的时候完全不需要反复传同样的信号。现在我们再来试着运行一下:

电量由 434 骤降到 287,代码行数也由 12 行减少到了 10 行。

进一步优化电量和代码行数

依然是利用那个“读只写 p 口,或连接着这些 p 口的 DX-300 时,会得到立即数 0,同时清零这些 p 口,一举两得”的技巧,我们将第 4 行和第 5 行的

- mov 0 x2

- mov 0 acc

两行代码合并成下面一行代码:

- mov x2 acc

很好,电量降到了 286,代码行数降到了 9 行。

碎碎念

虽然压缩到了 9 行代码,最终也只用了 4 个 x 口,但因为用到了 dat 寄存器,所以这块 MC6000 无法替换成只有四个 x 口的 MC4000X 芯片,成本是降不下来的……

评论 (0)

相关阅读
网友评论0条评论

上拉或点击查看更多