电玩圈游戏网 搜一搜

安卓手游去频道 >

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

安卓应用去频道 >

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

游戏视频去频道 >

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

资讯攻略去频道 >

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

专题合集去频道 >

游戏专题 应用专题

排行榜单去频道 >

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

首页>资讯>游戏攻略>深圳SHENZHENIO第31关安全网追踪徽章攻略

深圳SHENZHENIO第31关安全网追踪徽章攻略

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

深圳IO是一款硬核的编程游戏,有着严谨的游戏内容,那么一起来看看第31关安全网追踪徽章的攻略吧。

主界面

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

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

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

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

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

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

第30关:安全网追踪徽章

关卡展示

这一关我们需要结合数据手册来分析

我们首先看【同步雷达】信号,【同步雷达】的值是用于指示雷达当前所在方位的,0 = -30°~30°,20 = 30°~90°,40 = 90° ~ 150°,60 = 150° ~ -150°, 80 = -150° ~ -90°,100 = -90° ~ -30°。时序图里,【同步雷达】信号永远按照 0→20→40→60→80→100→0…… 的方式循环,说明雷达在不断按逆时针方向旋转。

再看【脉冲雷达】信号。当雷达未朝向用户时,该信号会保持为 0;而当雷达正面朝向用户时,该信号的值会在瞬间变为“距离用户的直线距离”。

最后,无线 rx 会不定期地发送一些数据包。当你收到了 1 开头的数据包时,说明这是一个声音波形的数据包。这个数据包的第二个数字表示波形长度,后续的数字数量等同于该长度。你需要将这些波形原封不动地输出到【扬声器】中。当你收到了 2 开头的数据包,且第二个数字和锁中的数字一致时,我们需要根据雷达的方向、雷达和用户的直线距离这两个数据,计算用户当前所在的区域,并将对应的区域代码发送给【无线 tx】。例如,方位为 60,距离为 50 时,说明用户在工业区,需要发送 700。

这一关仍然是分工合作,一块芯片用于随时确定用户的位置,另一块芯片用于接收并处理无线 rx 发来的数据包。

两块写得满满的芯片。我们先来分析左边的芯片,左边的芯片要完成的任务是:当右边的芯片发来请求信号时,左边的芯片通过雷达的方向,以及和用户的直线距离这两个数据,计算用户所在区域,并将区域代码回传给右边的芯片。

首先我们等待右边的芯片发来信号(slx x3)。右边芯片发来的一定是非 0 的【脉冲雷达】信号的值(也就是和实时的 p0 值相等),第一句 tcp x3 79 和 tcp p0 79 完全等价,这里使用 x3 而不使用 p0 的原因是为了释放掉从右边芯片发来的数据,防止阻塞。

首先我们检查距离值是否 ≥80(tcp x3 79)。根据地图上的指示,一旦距离 ≥80 时,用户不论处于什么方位,都一定位于政府大楼。所以满足以上条件时,直接回传政府大楼的区域编号 100(+ mov 100 x3),同时跳回第一行,不再执行下方的一切代码(+ jmp 1)。

然后再检查方位值是否在 -30°~30° 范围内(teq p1 0)。根据地图指示,方位为 0 且距离小于 80 时,用户一定位于港口。而执行到此处时,距离一定是小于 80 的。所以执行到此处时,只需要方位为 0 就可判定用户位于港口,直接回传港口的区域编号 600 即可(+ mov 600 x3),同时跳回第一行,不再执行下方的一切代码(+ jmp 1)。

接下来,继续判断距离值是否不大于 50(tgt p0 50)。根据地图指示,距离在 0~50 范围内,且方位不在 -30°~30° 范围内时,用户一定位于工业区。执行到此处时,第二个条件一定是成立的,所以只要距离不大于 50,就直接回传工业区的区域编号 700 即可(- mov 700 x3)。而当距离在 50~80 范围内时,回传的区域编号和方位值有关:方位值为 20 时,区域编号为 200;方位值为 40 时,区域编号为 201……方位值为 100 时,区域编号为 204。我们发现距离 50~80 且方位值不为 0 时,区域编号和方位值满足如下函数关系:

除以 20 相当于乘以 5 再除以 100,相当于乘以 5 后取百位。因此,当距离 50~80 且方位值不为 0 时,我们将方位值放入 acc(+ mov p1 acc),将它乘以 5(+ mul 5),取得百位数字(+ dgt 2),再加上 199(+ add 199)即得到了对应的区域编号,将该编号回传给右边的芯片,即完成任务(+ mov acc x3)。

然后我们看右边的芯片。右边芯片有两个任务:一个是在收到【脉冲雷达】信号时,委托左边的芯片计算用户所在的区域;另一个是收到无线 rx 的数据包时做出相应处理。

首先我们检查是否出现了【脉冲雷达】信号(tcp p0 0),一旦出现,将当前的信号值发给左边,唤醒左边的芯片(+ mov p0 x0),等待它将用户所在的区域编号计算好后,将该编号存入 dat 寄存器(+ mov x0 dat)。

第 4~7 行用于检查是否仍有尚未播放完的音频数据,我们暂时跳过去,先从第 8 行开始看。当没有音频数据时,我们需要将扬声器置为静音(mov 50 p1)。然后我们读取数据包。当数据包的首数字是 1 时(teq x2 1),我们将第二个表示长度的数字读入 acc(+ mov x2 acc),然后跳回到第 5 行开始播放音效(+ jmp 5)。现在跳回第 5 行,我们播放一格声音波形(+ mov x2 p1),令音频剩余长度 -1(+ sub 1),然后跳到最后休眠一秒(+ jmp e, slp 1)。后面的时间里,只要声音没有播放完,我们的程序就一边检测用户位置有没有改变(1~3 行),一边播放剩下的声音(4~7 行及 14 行),直到声音播放完毕后,将扬声器静音(第 8 行)。

现在看第 12 行。无论是无线 rx 队列里没有数字,读到了 -999,还是数据包的首数字不是 1,我们都尝试去读入第二个数字,检查它和锁中的数字是否相等(teq x2 x1)。如果数据包中没有数字时,读到的一定还是 -999,和锁中的数字一定不一致(这是游戏里的设定),直接什么都不做,跳到最后休眠(slp 1)。仅当第二个数字和锁中的数字一致时,我们先将用户当前所在的区域编号发送给 tx(+ mov dat x3),然后再休眠(slp 1)。

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

这一关需要特别注意这样一个小细节:播放音频的过程中仍然需要不断探测用户的位置改变了没有。我们上面的代码里的 4~7 行将播放音频的过程从循环中分离了出来,变成了每个时钟周期的例行公事。每个时钟周期里,右边的芯片要做两件例行公事:①检查是否出现了【脉冲雷达】信号,一旦出现就要通知左边的芯片计算用户所在区域。②检查是否仍有没播放完的音频,若仍有,则从无线 rx 中读取波形信号发送到扬声器。

如果我们还按常规思路,将播放音频的过程写在循环里,每播放一格就睡一秒,令 acc -1,直到 acc 减为 0 之前一直循环读取,把代码写成类似下面这个样子的话:

第 5~10 行代码是用传统思维实现的【播放声音波形】任务

那么就会造成一个问题:播放声音的过程中,芯片不再检测外部是否产生了【脉冲雷达】信号,不再更新用户所在的区域位置。最终运行时会卡在这么一个样例上:

这个错误就是典型的“播放声音的过程中,用户的位置都变了,你却只顾着播放声音了,忘了去更新用户的位置”。

评论 (0)

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

上拉或点击查看更多