雙掌控板收發(fā)摩爾斯電碼


文/山東省招遠(yuǎn)第一中學(xué) 牟曉東
本文發(fā)表于《電腦報(bào)》2021年20期
作為國(guó)內(nèi)開(kāi)源硬件的杰出代表,掌控板是一款非常優(yōu)秀的國(guó)產(chǎn)“創(chuàng)客”微控制器板,支持Python代碼編程以及Mind+、mPython等主流圖形化編程軟件。使用單塊掌控板進(jìn)行編程,可以實(shí)現(xiàn)噪音計(jì)、身高測(cè)量?jī)x、高溫報(bào)警系統(tǒng)和天黑自動(dòng)收衣服系統(tǒng)等案例;如果有兩塊掌控板,就可以借助藍(lán)牙與WiFi雙無(wú)線通訊,遵循MQTT(消息隊(duì)列遙測(cè)傳輸)協(xié)議在SIoT開(kāi)發(fā)平臺(tái)(如Mind+的SIoT本地物聯(lián)網(wǎng)、DFRobot的Easy IoT)或OneNET(移動(dòng)物聯(lián)網(wǎng)開(kāi)放平臺(tái))等開(kāi)放平臺(tái)上進(jìn)行更為豐富的物聯(lián)網(wǎng)應(yīng)用創(chuàng)意項(xiàng)目設(shè)計(jì),比如實(shí)現(xiàn)諜戰(zhàn)影視片中摩爾斯電碼的發(fā)送與接收。
1.預(yù)備知識(shí):摩爾斯電碼
摩爾斯電碼(Morse code)是一種通過(guò)不同的排列順序來(lái)表達(dá)相關(guān)字符(比如26個(gè)英文字母)的數(shù)字化通信形式,它的最基本代碼是“滴”和“嗒”,分別對(duì)應(yīng)短促的“一個(gè)點(diǎn)”信號(hào)和“一個(gè)劃”信號(hào),“一劃”相當(dāng)于“三個(gè)點(diǎn)”的時(shí)長(zhǎng)(如圖1)。在各種故事情節(jié)中最為經(jīng)典的摩爾斯電碼應(yīng)用,便是SOS國(guó)際通用求救信號(hào)的發(fā)送——字母S的摩爾斯電碼是“滴、滴、滴”三個(gè)點(diǎn),字母O的摩爾斯電碼是“嗒、嗒、嗒”三個(gè)劃,通過(guò)開(kāi)關(guān)手電筒控制電路通斷以光的形式,或是單根手指連續(xù)敲擊桌面以聲的形式,都能夠快速發(fā)送“三點(diǎn)、三劃、三點(diǎn)”的SOS求救摩爾斯電碼。
?

2.收發(fā)操作方法規(guī)劃
每個(gè)掌控板都有A和B兩個(gè)按鍵和P、Y、T、H、O、N六個(gè)觸摸鍵供我們選用。在發(fā)報(bào)方掌控板中進(jìn)行編程,將按鍵A和B分別設(shè)計(jì)對(duì)應(yīng)發(fā)送摩爾斯電碼的“滴”和“嗒”信號(hào),而將觸摸鍵P作為每組摩爾斯電碼(即所表示的某一個(gè)字符)的結(jié)束信號(hào),因?yàn)檎鎸?shí)的用摩爾斯電碼發(fā)報(bào)字母間隔是一個(gè)“嗒”的時(shí)長(zhǎng)(相當(dāng)于3個(gè)“滴”),單詞間間隔是7個(gè)“滴”,這需要專門(mén)訓(xùn)練才能做好,對(duì)于初學(xué)者來(lái)說(shuō)操作難度較大,而簡(jiǎn)單地“碰”一下觸摸鍵的動(dòng)作則非常方便。另外,為了對(duì)按鍵和觸摸鍵的按下與觸摸操作進(jìn)行即時(shí)反饋,還要添加RGB燈閃爍和蜂鳴器播放音符模擬“滴”“嗒”聲,比如三支RGB燈分別對(duì)應(yīng)按鍵A、B和觸摸鍵P的“動(dòng)作”;同時(shí),在收?qǐng)?bào)方掌控板中也進(jìn)行同樣的編程控制方式,模擬實(shí)現(xiàn)摩爾斯電碼的發(fā)報(bào)與收?qǐng)?bào)的“聲光”同步響應(yīng),趣味性更強(qiáng)。
3.掌控板發(fā)報(bào)方的mPython編程
將一塊掌控板通過(guò)數(shù)據(jù)線連接至聯(lián)網(wǎng)電腦的USB接口,然后運(yùn)行mPython進(jìn)行程序的編寫(xiě)。
(1)通過(guò)Wi-Fi模塊將掌控板聯(lián)網(wǎng)
兩個(gè)掌控板之間能夠正常進(jìn)行信號(hào)的發(fā)送與接收的“對(duì)話”前提條件是暢通的網(wǎng)絡(luò)連接,因此程序的最開(kāi)始必須是進(jìn)行聯(lián)網(wǎng)設(shè)置。從左側(cè)的“Wi-Fi”中選擇第一項(xiàng)“連接Wi-Fi名稱……密碼……”模塊語(yǔ)句,然后補(bǔ)充完整所使用的無(wú)線網(wǎng)絡(luò)名稱及密碼信息(明文顯示)。
(2)進(jìn)行“連接MQTT”設(shè)置
在mPython的“擴(kuò)展”-“MQTT”中提供了若干種MQTT模塊,以其中的“MQTT-Easy?IoT”為例(其它的用法基本類似),這是由DFRobot提供的物聯(lián)網(wǎng)MQTT服務(wù),需要從瀏覽器訪問(wèn)網(wǎng)站(https://iot.dfrobot.com.cn/)先進(jìn)行免費(fèi)注冊(cè),然后登錄進(jìn)入自己賬號(hào)的“工作間”;左側(cè)有兩處關(guān)鍵信息,一是“Iot_id(user)”(即用戶名),將其值“XNbxt3rMR”復(fù)制粘貼至mPython編程中“MQTT-Easy?IoT”模塊語(yǔ)句中的第三項(xiàng)“Iot_id”中;二是“Iot_pwd(password)”(即密碼),可點(diǎn)擊“小眼睛”圖標(biāo)進(jìn)行顯示,將其值“uHxxpqrGRz”復(fù)制粘貼至第四項(xiàng)“Iot_pwd”中(前兩項(xiàng)“服務(wù)器”和“Client?ID”均保持默認(rèn)值)。在“工作間”中執(zhí)行三次“添加新的設(shè)備”操作,分別重命名為“mPython_1”、“mPython_2”和“mPython_3”,對(duì)應(yīng)三個(gè)Topic“主題”的數(shù)值,可分別復(fù)制并粘貼至記事本中保存,這些信息在收?qǐng)?bào)方掌控板中也要用到(如圖2)。
再次返回mPython編程界面,從“MQTT”中選擇“連接MQTT”模塊語(yǔ)句,添加至“MQTT-Easy?IoT”模塊語(yǔ)句后面,作用是根據(jù)之前的設(shè)置進(jìn)行MQTT連接。
?

?
(3)設(shè)置OLED顯示屏的顯示提示信息
先從左側(cè)的“顯示”中選擇“OLED顯示‘清空’”模塊語(yǔ)句;再使用兩次“OLED第‘’行顯示‘’模式‘普通’‘不換行’”,控制OLED顯示屏的第1行、第2行分別顯示“連接MQTT-Easy IoT !”和“長(zhǎng)江長(zhǎng)江,我是黃河!”提示信息;最后要添加“OLED顯示生效”模塊語(yǔ)句(如圖3)。
?

(4)定義字典變量my_dict并進(jìn)行數(shù)據(jù)的初始化
為了進(jìn)行摩爾斯電碼的分解與重組,可以將二進(jìn)制代碼“0”和“1”與摩爾斯電碼的“滴”和“嗒”一一映射進(jìn)行組合編碼。比如:字母“A”的摩爾斯電碼是“滴、嗒”,在字典中為它設(shè)置“鍵”(Key)為“01”,“值”(Value)為“A”;再比如:字母“B”是“嗒、滴、滴、滴”,在字典中的“鍵”就是“1000”。對(duì)應(yīng)摩爾斯電碼的編碼規(guī)則,對(duì)字典變量my_dict進(jìn)行定義和初始化,完成26個(gè)大寫(xiě)英文字母的“0”“1”編碼映射(如圖4)。
?

(5)a_func、b_func和p_func三個(gè)函數(shù)的編寫(xiě)
為了使主程序結(jié)構(gòu)更加條理清晰,編寫(xiě)a_func、b_func和p_func三個(gè)函數(shù)來(lái)分別實(shí)現(xiàn)當(dāng)按下按鍵A、B和觸摸P時(shí)所觸發(fā)的“動(dòng)作”:聲音提醒、RGB燈閃爍提醒等。注意我們建立message、my_string和morse三個(gè)變量的作用。變量message的作用是用來(lái)生成“0”或“1”,這個(gè)值取決于操作者按下的是A鍵還是B鍵:A鍵對(duì)應(yīng)“0”,B鍵對(duì)應(yīng)“1”;變量my_string相當(dāng)于Python中的“列表”,它的作用是將變量message依次生成的“0”或“1”單個(gè)值通過(guò)“追加文本”的方式不斷有序的“補(bǔ)充”組合;當(dāng)生成的最終組合值在字典my_dict中進(jìn)行“鍵”的搜索時(shí),如果有對(duì)應(yīng)的“鍵”,則將變量morse的值設(shè)定為字典中該“鍵”所對(duì)應(yīng)的“值”,即某一個(gè)英文字母(如圖5)。
?

比如:先按一次B鍵、再按一次B鍵、再按一次A鍵、最后按一次P鍵的操作,變量message中就會(huì)依次存儲(chǔ)“1”、“1”和“0”;當(dāng)這三個(gè)數(shù)據(jù)按生成的先后次序追加至變量my_string中時(shí),組合值就是“110”;將“110”與字典my_dict中的26個(gè)“鍵”去查找“配對(duì)”,找到對(duì)應(yīng)的“值”是字母“G”,接下來(lái)就將字母“G”保存至變量morse中,表示發(fā)送的摩爾斯電碼是字母“G”。在p_func函數(shù)中又一次控制OLED顯示屏進(jìn)行顯示輸出,其中變量i的作用是控制多個(gè)連續(xù)發(fā)送的摩爾斯電碼能夠依次顯示(通過(guò)后面的“將變量i的值增加10”的語(yǔ)句實(shí)現(xiàn)),對(duì)應(yīng)的是OLED顯示屏橫坐標(biāo)x的數(shù)值(如圖6)。
?

注意:在主程序中要將變量message、my_string和morse先進(jìn)行文本型數(shù)據(jù)的“空值”設(shè)定,變量i的初值則設(shè)置為整型數(shù)據(jù)10;而在a_func、b_func和p_func三個(gè)函數(shù)中,每次獲取對(duì)應(yīng)的數(shù)據(jù)后還要根據(jù)情況進(jìn)行變量值的“清空”或是“自增”操作。
(6)設(shè)置三個(gè)“發(fā)送”主題的循環(huán)
建立一個(gè)“一直重復(fù)執(zhí)行”的循環(huán)結(jié)構(gòu),注意在循環(huán)體最后要添加一條“等待0.01秒”的模塊語(yǔ)句(防止程序運(yùn)行過(guò)快而消耗過(guò)多的系統(tǒng)資源);循環(huán)內(nèi)是一個(gè)三分支的選擇結(jié)構(gòu),當(dāng)檢測(cè)到A鍵被按下時(shí),調(diào)用執(zhí)行a_func函數(shù)并且發(fā)布值為“ON”數(shù)據(jù)至第一個(gè)主題“Mqj-t39Gg”;當(dāng)檢測(cè)到B鍵被按下時(shí),則調(diào)用執(zhí)行b_func函數(shù)并且也發(fā)布值為“ON”的數(shù)據(jù),但對(duì)應(yīng)的是第二個(gè)主題“qagfpq9Gg”;當(dāng)檢測(cè)到P被觸摸時(shí),調(diào)用執(zhí)行的是p_func函數(shù),發(fā)布值為“ON”的數(shù)據(jù)至第三個(gè)主題“wP_Q-69GR”;注意此處需要添加內(nèi)層選擇結(jié)構(gòu),對(duì)字典變量my_dict中的“鍵”是否與變量my_string的值進(jìn)行匹配檢測(cè)(如圖7)。
?

這三個(gè)不同的主題所存儲(chǔ)的“ON”消息值,是第二塊掌控板(收?qǐng)?bào)方)的響應(yīng)動(dòng)作觸發(fā)條件,要在收?qǐng)?bào)方掌控板中進(jìn)行對(duì)應(yīng)主題消息的“訂閱”等一系列操作后才會(huì)起效。
4.掌控板收?qǐng)?bào)方的mPython編程
將第二塊掌控板通過(guò)數(shù)據(jù)線連接至第二臺(tái)聯(lián)網(wǎng)電腦的USB接口,運(yùn)行mPython進(jìn)行程序的編寫(xiě)。
與發(fā)報(bào)方掌控板的程序基本一致,包括Wi-Fi聯(lián)網(wǎng)和MQTT設(shè)置(其中的Client?ID須改動(dòng)至少一位數(shù)字),OLED顯示屏的顯示提示信息稍作改動(dòng)——“黃河黃河,我是長(zhǎng)江!”;字典變量my_dict的定義與數(shù)據(jù)初始化,a_func、b_func和p_func三個(gè)函數(shù)的編寫(xiě),以及變量message、my_string和morse、i等的初始賦值等均完全一致(如圖8)。
?

最大的區(qū)別是取消了三個(gè)主題發(fā)送的循環(huán)結(jié)構(gòu),但同樣是新建了一個(gè)極為類似的循環(huán)結(jié)構(gòu)。先從左側(cè)“循環(huán)”和“擴(kuò)展”-“MQTT”中分別選擇“一直重復(fù)執(zhí)行”和“等待主題消息以‘阻塞’模式”模塊語(yǔ)句,接著進(jìn)行三個(gè)主題的同步“監(jiān)聽(tīng)”,其中的主題名與發(fā)報(bào)方的三個(gè)主題是一一對(duì)應(yīng)的,這就相當(dāng)于進(jìn)行主題的訂閱:當(dāng)收到對(duì)應(yīng)主題有“ON”消息值到達(dá)時(shí),分別調(diào)用執(zhí)行對(duì)應(yīng)的a_func、b_func和p_func函數(shù),與發(fā)報(bào)方進(jìn)行摩爾斯電碼發(fā)報(bào)時(shí)的響應(yīng)完全相同(如圖9)。
?

5.測(cè)試摩爾斯電碼的發(fā)報(bào)與接收
程序編寫(xiě)完畢后進(jìn)行保存,接著分別在發(fā)報(bào)方和收?qǐng)?bào)方的mPython編程界面點(diǎn)擊上方的“刷入”按鈕,右下角的“控制臺(tái)”區(qū)會(huì)有“代碼刷入36%”、“刷入成功”和“Connection?Wi-Fi”等提示信息。很快,兩塊掌控板的OLED顯示屏第一行都會(huì)顯示“連接MQTT-Easy IoT!”提示信息,第二行則是表明自己身份的信息(“黃河”與“長(zhǎng)江”)。
在發(fā)報(bào)方掌控板上進(jìn)行SOS國(guó)際通用求救信號(hào)的發(fā)送操作:先連續(xù)按三次A鍵、碰一下觸摸鍵P,顯示出字母“S”,同時(shí)在收?qǐng)?bào)方掌控板上也同樣會(huì)有字母“S”出現(xiàn),而且都會(huì)有“滴”聲響起和RGB燈閃爍;接著再連續(xù)按三次B鍵、碰一下觸摸鍵P,又顯示出字母“O”;然后重復(fù)第一次的操作,字母“S”再次出現(xiàn),在收?qǐng)?bào)方掌控板的OLED顯示屏上也是正常顯示出了完整的“SOS”信息(如圖10)。
?

同樣,如果再進(jìn)行其它字母的發(fā)送與接收測(cè)試,比如最簡(jiǎn)單的字母“E”和“T”,分別是“滴”和“嗒”,對(duì)應(yīng)的操作是按A再碰P、按B再碰P,測(cè)試均正常,完成雙掌控板mPython編程“隔空”收發(fā)摩爾斯電碼實(shí)驗(yàn)項(xiàng)目的設(shè)計(jì)。
6.對(duì)本實(shí)驗(yàn)的改進(jìn)與升級(jí)設(shè)想
在編程和測(cè)試結(jié)束之后,感覺(jué)并不完美,仍有若干處需要改進(jìn)和升級(jí)的地方:
(1)發(fā)報(bào)方與收?qǐng)?bào)方是進(jìn)行“單向”通信的,收?qǐng)?bào)方掌控板在收到“SOS”求救信號(hào)后并不能對(duì)發(fā)報(bào)方掌控板做出回應(yīng),比如再發(fā)送回“OK”。將雙方的程序各自進(jìn)行對(duì)應(yīng)功能模塊的添加,發(fā)報(bào)方需要添加主題訂閱,收?qǐng)?bào)方需要添加主題發(fā)送。另外,在“雙向”響應(yīng)的基礎(chǔ)之上還可以考慮進(jìn)行“一對(duì)多”、“多對(duì)一”甚至是“多對(duì)多”的升級(jí),也就是將多塊掌控板組成一個(gè)彼此獨(dú)立但又能相互進(jìn)行摩爾斯電碼的發(fā)報(bào)與接收。
(2)程序中的字典my_dict只包含了26個(gè)英文大寫(xiě)字母,可以根據(jù)國(guó)際摩爾斯電碼將10個(gè)阿拉伯?dāng)?shù)字、斜杠和括號(hào)等標(biāo)點(diǎn)符號(hào)也進(jìn)行添加,可以傳輸表達(dá)更多的信息。除了這些通用的國(guó)際摩爾斯電碼之外,我們還可以考慮對(duì)字典進(jìn)行自定義式擴(kuò)充,比如若干使用頻率極高的漢字,只要各掌控板程序中使用的字典是相同的,并且均進(jìn)行了“鍵”、“值”的惟一對(duì)應(yīng)編碼,就可以直接進(jìn)行漢字的摩爾斯電碼發(fā)報(bào)與接收。
(3)在進(jìn)行摩爾斯電碼的發(fā)報(bào)和接收時(shí)均為“明文”,保密性幾乎為零。其實(shí)可以添加各種加密算法來(lái)嘗試摩爾斯密碼的發(fā)報(bào)與接收,比如凱撒加密,相當(dāng)于對(duì)字典文件中的“鍵”、“值”進(jìn)行不確定量的偏移計(jì)算,解密的過(guò)程就是將該運(yùn)算進(jìn)行反向即可。
(4)實(shí)驗(yàn)項(xiàng)目中是將掌控板的觸摸鍵P作為每個(gè)摩爾斯電碼的結(jié)束標(biāo)志,如果按照標(biāo)準(zhǔn)的摩爾斯電碼發(fā)報(bào)操作,也就是只有對(duì)應(yīng)“滴”和“嗒”的兩種操作,正好分別分配給按鍵A和B。只不過(guò)相鄰兩個(gè)信號(hào)的間隔必須要控制好,比如點(diǎn)與劃之間的停頓、單詞間的停頓,還有句子間的長(zhǎng)停頓,具體可查閱摩爾斯電碼的標(biāo)準(zhǔn)操作規(guī)范。此時(shí)的程序就簡(jiǎn)單了很多,比如省略掉一個(gè)主題、精簡(jiǎn)p_func函數(shù),變量的使用也簡(jiǎn)單不少,只不過(guò)對(duì)操作者的發(fā)報(bào)操作方法要求比較高,但會(huì)更酷一些,大家不妨一試。