最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

【深圳 IO 攻略】PGA33X6 的高級(jí)用法:狀態(tài)翻轉(zhuǎn)

2022-10-03 20:28 作者:ココアお姉ちゃん  | 我要投稿

本文首發(fā)于 B 站《深圳 IO》文集(https://www.bilibili.com/read/readlist/rl569860)。原創(chuàng)不易,轉(zhuǎn)載請(qǐng)注明出處。

前一篇 PGA33X6 的攻略里(傳送門:【深圳 IO 攻略】番外篇:介紹一下 PGA33X6 這個(gè)冷門元件),我們利用 PGA33X6 自帶的 data 鎖存器做出了一個(gè)用兩個(gè)按鈕控制的,可以自由開啟/關(guān)閉的電燈。電路圖如下所示:

按下第一個(gè)按鈕時(shí),將 data 置為 1 并鎖存;按下第二個(gè)按鈕時(shí),將 data 置為 0 并鎖存。第一路輸出和燈泡相連,輸出的狀態(tài)值和 data 一致,所以僅當(dāng)?data 為 1 時(shí)燈泡才會(huì)被點(diǎn)亮。

你可能會(huì)覺得用兩個(gè)按鈕控制燈泡有點(diǎn)多余,能不能用一個(gè)按鈕來控制呢?按鈕按下時(shí),如果燈泡處于點(diǎn)亮狀態(tài),那么就熄滅,反之亦然。正好我們的 data 值既可以做輸出量也可以做輸入量。這時(shí)候你嘗試著把電路板改成下面的樣子:

我們觀察 PGA 中的點(diǎn)亮的小方塊,將其中的邏輯轉(zhuǎn)換成 C 語言的形式,如下:

乍一看,很合理嘛!但是當(dāng)你點(diǎn)擊下方的【模擬】運(yùn)行程序時(shí),意想不到的事情發(fā)生了:

按下按鈕的時(shí)候,燈泡竟然在開啟和關(guān)閉的狀態(tài)間反復(fù)橫跳,直到松開按鈕時(shí),燈泡會(huì)隨機(jī)停留在開啟/關(guān)閉中的一種狀態(tài)上。

我們嘗試復(fù)一下盤:

初始狀態(tài)下,data 為 0,按鈕也沒有按下。

當(dāng)按鈕按下的時(shí)候,PGA 是滿足第一列條件的(A 路輸出為 true,且 data 為 0),此時(shí)執(zhí)行第一列的邏輯,將 data 置 1。

但是,事情還沒有結(jié)束!data 被置 1 后,PGA 就不再滿足第一列的條件,轉(zhuǎn)而變成滿足第二列的條件了(A 路輸出為 true,且 data 為 1)。那么,PGA 在執(zhí)行了上述指令,將 data 置 1 后,第二列的條件又重新被滿足了,根據(jù)第二列的要求,data 又需要重新置為 0。

data 被置 0 后,第一列的邏輯又重新被滿足了……于是,只要按鈕是按下的,PGA?就永遠(yuǎn)無法進(jìn)入穩(wěn)定狀態(tài),這時(shí)候的 data 是一個(gè)薛定諤的 data,它既是 0 又是 1。

這是我們?cè)谑褂?PGA 時(shí)要特別注意的一點(diǎn):更新 data 值時(shí),不能以 data 自身的值作為判定依據(jù),否則 PGA 會(huì)無法進(jìn)入穩(wěn)定狀態(tài)。也就是說:同一列里,第 5、6 行的方塊(data 輸入)不能和第 9、10 行的方塊(data 輸出)同時(shí)點(diǎn)亮。

那么問題來了:按下按鈕時(shí),我確實(shí)要根據(jù)燈泡此前的狀態(tài)值來更新燈泡現(xiàn)在的開關(guān)狀態(tài)啊,先前是熄滅的我就點(diǎn)亮,先前是點(diǎn)亮的我就熄滅?,F(xiàn)在我已經(jīng)不能用這個(gè) data 作為判定依據(jù)了,還有別的辦法嗎?

答案是:有!因?yàn)榈谌愤@個(gè)和 data 無關(guān)的輸出量我們還沒有用上,我們完全可以把這一路輸出量作為另一個(gè) data?反饋給 PGA。我們現(xiàn)在嘗試著搭出這樣的電路圖:

這里,我們把燈泡的開關(guān)量移到了 3 路輸出上,并將這一路輸出同時(shí)作為反饋量接到 PGA 的 3 號(hào)輸入上。這時(shí)候我們?cè)僦匦掠^察 PGA 中的點(diǎn)亮的小方塊,將邏輯轉(zhuǎn)換成 C 語言的形式,如下:

在本方案里,我們將內(nèi)置的 data 量和真正的燈泡開關(guān)做了分離。按鈕按下時(shí),根據(jù)燈泡的開關(guān)調(diào)整 data 值,但不改變真正的燈泡開關(guān);當(dāng)按鈕抬起時(shí),再根據(jù) data 值改變燈泡開關(guān),同時(shí)令 data 值保持不變。如此,即可避免【以 data 自身為依據(jù)修改 data 值,導(dǎo)致 data 反復(fù)橫跳】這樣的現(xiàn)象。

以上方案我們還需要做一些調(diào)整。我們的 3 路輸出不能直接用導(dǎo)線跟 3 路輸入相連,否則會(huì)觸發(fā)如上圖所示的自連錯(cuò)誤。這里我們有兩種辦法:

①3 路輸出和 3 路輸入間加一個(gè)或門:

或門有兩個(gè)輸入口,如果只接了一個(gè),那么另一個(gè)沒有接入輸入量的口會(huì)被視為恒假。由于 A or FALSE = A,只接了一個(gè)輸入量的或門,輸出的值為該輸入量自己。

②3 路輸出和 3 路輸入間加一個(gè)非門:

接非門的好處是非門的占地面積小,但與此同時(shí)反饋的輸入量也會(huì)被取反。所以接非門以后,原先點(diǎn)亮第 7 行小方塊的地方要改為點(diǎn)亮第 8 行小方塊,反之也一樣,原先點(diǎn)亮第 8 行小方塊的地方要改為點(diǎn)亮第 7 行小方塊。如上圖所示,接非門以后,第 7、8 行的小方塊全部換了位置。

此時(shí)我們?cè)龠\(yùn)行這個(gè)程序:

成功了!我們成功做出了用一個(gè)按鈕控制的電燈泡!

下面我會(huì)使用這個(gè) PGA 技巧完成一些官方謎題,設(shè)計(jì)出一些最省行數(shù)的解決方案。

例 1:龍騰第 4 關(guān)《動(dòng)畫 ESPORTS 標(biāo)志》

本關(guān)我們可以使用 PGA 將代碼行數(shù)減少到 2 行。

左上方的芯片用于生成點(diǎn)擊 0 的時(shí)序,點(diǎn)擊 0 按照 100→0→100→0→……的順序反復(fù)橫跳,所以該芯片的代碼是 gen p0 1 1。點(diǎn)擊 1 的時(shí)序跟點(diǎn)擊 0 互反,只需要將點(diǎn)擊 0 的信號(hào)經(jīng)過非門輸出給點(diǎn)擊 1 就 OK 了。

左下方的芯片用于生成喝 0 的時(shí)序,觀察時(shí)序圖,我們可以發(fā)現(xiàn)喝 0 先是連續(xù) 6 秒的 100 信號(hào),再是連續(xù) 4 秒的 0 信號(hào),以 10 秒為周期循環(huán)。所以該芯片的代碼是 gen p1?6 4。

然后是我們的重頭戲——PGA。這個(gè) PGA 的三路輸出量里,只有 3 號(hào)輸出連接了導(dǎo)線,且接到了喝 2 上。很明顯,這個(gè) PGA 就是用來輸出喝 2 量的。

我們將點(diǎn)擊 0 和喝 0 的時(shí)序復(fù)制了一份到 PGA 的第 1、2 路輸入量上,意圖很明顯:喝 2 的時(shí)序和點(diǎn)擊 0 及喝 0 相關(guān),我們需要根據(jù)點(diǎn)擊 0 和喝 0 的時(shí)序來生成喝 2 的時(shí)序。現(xiàn)在我們忽略無關(guān)的點(diǎn)擊 1 和喝 1,重點(diǎn)觀察點(diǎn)擊 0、喝 0 和喝 2 的對(duì)應(yīng)關(guān)系:

注意我圈出來的這部分。如果我們把點(diǎn)擊 0 當(dāng)成按鈕,喝 2 當(dāng)成燈泡的話,我們驚奇地發(fā)現(xiàn):當(dāng)喝 0 為 0 時(shí),點(diǎn)擊 0 和喝 2 的邏輯完美形成了【單按鈕燈泡】:當(dāng)點(diǎn)擊 0(按鈕)從按下變?yōu)樘饡r(shí),翻轉(zhuǎn)喝 2(燈泡)的開關(guān)狀態(tài)。而當(dāng)喝 0 為 100 時(shí),我們只要無視點(diǎn)擊 0 的點(diǎn)擊效果,令喝 2 保持關(guān)閉狀態(tài)就可以了。

現(xiàn)在我們?cè)賮碛^察這個(gè)用于生成喝 2 時(shí)序的 PGA:

我們將所有的邏輯改寫成 C 語言的形式,如下:

以上的三條邏輯都必須要在喝 0 為 0 時(shí)生效,喝 0 為 100 時(shí)則不滿足以上任何一條邏輯,所以喝 0 為 100 時(shí),任憑點(diǎn)擊 0 如何變化,喝 2 也是雷打不動(dòng)地處于關(guān)閉狀態(tài)。

最后的喝 1,跟之前的方案一樣,為喝 0 和喝 2 的【或非】值。僅當(dāng)喝 0 和喝 2 均為 0 時(shí),喝 1 才為 100。

點(diǎn)擊左下角的【模擬】,稍等片刻,便會(huì)彈出結(jié)算界面:

本方案的兩行代碼里,一行用于生成點(diǎn)擊 0 的時(shí)序,一行用于生成喝 0 的時(shí)序。點(diǎn)擊 1 的時(shí)序由點(diǎn)擊 0 取反得到,無需代碼行數(shù);喝 2 的時(shí)序由 PGA 根據(jù)點(diǎn)擊 0 和喝 0 推導(dǎo)而來,無需代碼行數(shù);最后的喝 1 再由點(diǎn)擊 0 和點(diǎn)擊 2 取或非值得到,仍然無需任何代碼行數(shù)。本題里我們需要手動(dòng)生成的時(shí)序只有點(diǎn)擊 0 和喝 0 這兩路,其余路的時(shí)序都可以由已知條件推導(dǎo)而來。這就是為什么這道題只用兩行代碼就可以搞定的原因。

例 2:阿瓦隆城第 1 關(guān)《冷庫機(jī)器人》

本關(guān)使用 PGA 的話可以把代碼行數(shù)減少到 23 行,而且芯片的話只要一塊 MC4000 和一塊 MC6000 就足夠了。紙面難度變得和龍騰系列的關(guān)卡差不多了。

現(xiàn)在再看到這樣的時(shí)序圖你就應(yīng)該有條件反射了:伸出和抓握的邏輯形成了完美的【單按鈕燈泡】:當(dāng)【伸出】信號(hào)由開啟變?yōu)殛P(guān)閉時(shí),反轉(zhuǎn)【抓握】信號(hào)。

本次的芯片代碼和上一版攻略相比改動(dòng)較大,因此我從頭再解讀一遍。

上一版方案里,我們安排了一個(gè)總監(jiān)芯片、一個(gè)數(shù)據(jù)庫管理員芯片和兩個(gè)工人芯片。由于總監(jiān)和數(shù)據(jù)庫管理員的工作量都較少,本方案里總監(jiān)和數(shù)據(jù)庫管理員的工作合并到了一塊 MC6000 里。

根據(jù)游戲設(shè)定,所有官方謎題提供的 C2S-RF901 都不會(huì)在第一秒里提供數(shù)據(jù)。所以第一秒可以放心讓 MC6000 休眠(slp 1)。從第二秒起,檢查 C2S-RF901 有沒有提供新的數(shù)據(jù)包。C2S-RF901 的首數(shù)字有三種可能性:-999、1、2。因此首先肯定是一個(gè)三態(tài)判定(tcp x3?1)。當(dāng)首數(shù)字是 -999 時(shí),什么事都不用做,直接跳回第一行睡覺(- jmp 1)。讀到另外兩個(gè)數(shù)字時(shí)再開始干活。下面我們依次分析。

讀到 1 開頭的數(shù)據(jù)包時(shí),說明要向冷庫內(nèi)【存】新的食物;讀到 2 開頭的數(shù)據(jù)包時(shí),說明要從冷庫內(nèi)【取】對(duì)應(yīng)編號(hào)的食物。我們需要這樣操作 RAM:讀到 1 時(shí),從 RAM 中找第一個(gè)數(shù)字為 0 的格子(空格),將對(duì)應(yīng)的格子改寫為數(shù)據(jù)包的第二個(gè)數(shù)字(向空格內(nèi)存食物);讀到 2 時(shí),從 RAM 中找到和數(shù)據(jù)包的第二個(gè)數(shù)字相等的格子,并將對(duì)應(yīng)的格子重置為 0(從冷庫中取出食物)。

這塊 MC6000 的 dat 寄存器就是用來記錄要在 RAM 里找什么數(shù)字的。我們現(xiàn)在觀察第 4~6 行的代碼:開始搜索之前,我們首先將 RAM 的地址歸零(mov 0 x1)。接下來我們根據(jù)數(shù)據(jù)包的首數(shù)字來確定接下來要執(zhí)行的任務(wù):如果首數(shù)字是 1,那么我們要在 RAM 中找值為 0 的格子,此時(shí)將 dat 置為 0(mov 0 dat);如果首數(shù)字是 2,那么我們要在 RAM 中找值和數(shù)據(jù)包第二個(gè)數(shù)字相等的格子,此時(shí)我們需要讀取數(shù)據(jù)包的第二個(gè)數(shù)字放入 dat(+ mov x3 dat)。

第 7~9 行是一個(gè)循環(huán),首先將當(dāng)前的地址值放入 acc 暫存(mov x1 acc),然后判斷當(dāng)前格子的值是否和 dat 一致(teq x0 dat)。若不一致,跳回第 7 行繼續(xù)找,直到找到和 dat 一致的格子為止(- jmp 7)。

第 10~14 行用于改寫 RAM 中對(duì)應(yīng)格子的值,并通知后面的 MC4000 和 PGA 執(zhí)行任務(wù)。首先將 RAM 的地址重新定位到第 acc 格,準(zhǔn)備改寫對(duì)應(yīng)格子內(nèi)的值(mov acc x1)。此時(shí)判斷 dat 的值是 0 還是非 0(teq dat 0)。若 dat 是 0,說明當(dāng)前要執(zhí)行【存】任務(wù),我們從 C2S-RF901 中讀取第二個(gè)數(shù)字放到 RAM 的這一格里(+ mov x3 x0);若 dat 是非 0,說明當(dāng)前要執(zhí)行【取】任務(wù),我們將該格內(nèi)容改寫為 0(- mov 0 x0)。改寫完畢后,將當(dāng)前任務(wù)類型發(fā)給右邊的 MC4000 芯片(mov dat x2)。接下來我們來看 MC4000 芯片:

MC4000 的 x0 口連接著 RAM 的地址口;x1 口連接著?MC6000 的 x2 口,用于芯片間的通訊;p1 口連接著【電機(jī)】輸出;p0 口連接著 PGA 的 1 路輸入,用于提供模擬的按鈕信號(hào)。

為了節(jié)省行數(shù),我調(diào)整了 MC4000 的代碼順序。下面我貼一個(gè)優(yōu)化前的代碼:

首先二話不說將電機(jī)信號(hào)初始化為 50(@ mov 50 p1),然后等待 MC6000 的喚醒信號(hào)(slx x1)。MC6000 會(huì)把自己的 dat 值發(fā)過來,這里我們只關(guān)心這個(gè)值是 0 還是非 0(teq x1 0)。

這里我們首先回顧一下電機(jī)的工作模式:

④電機(jī)初始在第 0 格,新食物也總會(huì)在第 0 格出現(xiàn)。當(dāng)你收到 1 開頭的數(shù)據(jù)包時(shí),需要將新食物放入冷庫。首先令電機(jī)【伸出】1 秒,然后讓電機(jī)【抓握】住食物,并【向右移動(dòng)】,找到冷庫中的第一個(gè)空位后,令電機(jī)【伸出】1 秒,把爪子【放開】,將食物送入冷庫。最后,令電機(jī)【向左移動(dòng)】回到原點(diǎn)待命。


⑤當(dāng)你收到 2 開頭的數(shù)據(jù)包時(shí),令電機(jī)【向右移動(dòng)】,找到對(duì)應(yīng)的食物后,令電機(jī)【伸出】1 秒,然后讓電機(jī)【抓握】住食物,并【向左移動(dòng)】到原點(diǎn),將食物運(yùn)送到出口。到達(dá)原點(diǎn)后,令電機(jī)【伸出】1 秒,把爪子【放開】,釋放食物。 作者:ココアお姉ちゃん https://www.bilibili.com/read/cv17128944?出處:bilibili

當(dāng) MC6000 發(fā)來的值是 0 時(shí),說明當(dāng)前要執(zhí)行的是【存】任務(wù),這時(shí)候首先要給右邊的 PGA 發(fā)送一個(gè)模擬按鈕按下→抬起的信號(hào)(+ gen p0 1 1),令電機(jī)【抓握】住位于 0 號(hào)位置的食物,然后再令電機(jī)右移。當(dāng) MC6000 發(fā)來的值不是 0 時(shí),說明當(dāng)前要執(zhí)行的是【取】任務(wù),此時(shí)不需要令電機(jī)執(zhí)行抓握指令,直接令電機(jī)右移即可。

由于 RAM 中的地址是以 0 起始的,而冷庫中的位置編號(hào)是以 1 起始的,所以冷庫地址 = RAM 地址 +1。而恰好,我們?cè)谧x/寫 RAM 后,地址會(huì)自增 1。因此我們可以直接將自增后的 RAM 地址作為“冷庫目標(biāo)地址”。這時(shí)候,我們需要讓電機(jī)保持這么多秒的 100 信號(hào),令電機(jī)右移到相應(yīng)的位置(gen p1 x0 0)。

右移到對(duì)應(yīng)的位置后,首先將電機(jī)信號(hào)重置為 50(mov 50 p1)。如果電機(jī)當(dāng)前抓握著食物,說明當(dāng)前在執(zhí)行的是【存】任務(wù),到達(dá)位置后,需要給 PGA 發(fā)送一個(gè)模擬按鍵信號(hào)(gen p0 1 1),令電機(jī)把食物【放下】。反之,如果電機(jī)當(dāng)前沒有抓握著食物,說明當(dāng)前在執(zhí)行的是【取】任務(wù),到達(dá)位置后同樣需要給 PGA 發(fā)送一個(gè)模擬按鍵信號(hào),令電機(jī)【抓握】住對(duì)應(yīng)位置的食物。也就是說,到達(dá)目標(biāo)位置后,無論當(dāng)前在執(zhí)行的是什么任務(wù),都要發(fā)送模擬按鍵的信號(hào),令電機(jī)改變抓握狀態(tài)。

最后我們給電機(jī)發(fā)送同樣時(shí)長(zhǎng)的 0 信號(hào),令電機(jī)回到原點(diǎn)(gen p1 0 x0)?;氐皆c(diǎn)后,首先將電機(jī)信號(hào)重置為 50(mov 50 p1)。然后判定,如果當(dāng)前執(zhí)行的是【取】任務(wù),那么在回到原點(diǎn)后,要給 PGA 發(fā)送一個(gè)模擬按鍵信號(hào),令電機(jī)把食物【放下】(- gen p0 1 1)。

總結(jié):執(zhí)行【存】任務(wù)時(shí),要在開始移動(dòng)前以及到達(dá)目標(biāo)位置后各發(fā)送一次模擬按鍵信號(hào);執(zhí)行【取】任務(wù)時(shí),要在到達(dá)目標(biāo)位置后,以及回到原點(diǎn)后各發(fā)送一次模擬按鍵信號(hào)。

由于上電時(shí) + - 號(hào)都不會(huì)激活,所以我們可以將最后兩行代碼挪到開頭,并去掉冗余的 @ mov 50 p1 指令,即可將 10 行代碼減少到 9 行,正好能夠放到一塊 MC4000 里。

最后是 PGA:

PGA 的 2 路輸入用于接收 MC4000 發(fā)來的模擬按鍵信號(hào),3 路輸入用于接收反饋的【抓握】信號(hào)(注意經(jīng)過了非門)。我們將 PGA 的邏輯改寫成 C 語言,如下:

每當(dāng) MC4000 發(fā)送一個(gè)模擬按鍵的信號(hào)時(shí),若按鍵處于按下狀態(tài),【伸出】信號(hào)會(huì)被激活;若按鍵處于抬起狀態(tài),【抓握】信號(hào)會(huì)被反轉(zhuǎn)。

點(diǎn)擊左下角的【模擬】,稍等片刻,便會(huì)彈出結(jié)算界面:

看到了嗎,用 PGA 做這道“模擬電燈泡”題,只需要 23 行代碼就足夠了哦。

【深圳 IO 攻略】PGA33X6 的高級(jí)用法:狀態(tài)翻轉(zhuǎn)的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
共和县| 朝阳县| 盐边县| 兴业县| 安阳县| 深水埗区| 开封市| 息烽县| 柳江县| 特克斯县| 望都县| 彭阳县| 清苑县| 甘泉县| 来宾市| 威远县| 长乐市| 和政县| 板桥市| 哈密市| 高平市| 抚顺市| 芒康县| 池州市| 高淳县| 准格尔旗| 织金县| 大丰市| 鹤岗市| 巴林左旗| 奉化市| 固安县| 邹平县| 鞍山市| 榆树市| 德兴市| 杭锦旗| 浮梁县| 托里县| 娄底市| 平泉县|