回到首页 返回首页
回到顶部 回到顶部
返回上一页 返回上一页
best-icon

双掌控板打造摩尔斯码党史回忆录——致敬那段硝烟弥漫的峥嵘岁月 简单

头像 牟晓东 2021.06.28 1347 2

设计背景

在连续剧《叛逆者》中,有个“林楠笙用手指敲击摩尔斯电码,与老萧传递情报”情节,在审讯室中通过这种无声的语言进行了关键信息的有效交流。其实,类似的摩尔斯电码发送与接收桥段在谍战类影视片中经常出现。今年是建党100周年,为了致敬那段硝烟弥漫的峥嵘岁月,我们借助两个掌控板来打造一个使用摩尔斯码查询党史回忆录的“物联网”作品。

By the way:制作难度不大,三星级,一起来吧!

功能原理

        每个掌控板都设计有A和B两个按键和P、Y、T、H、O、N六个触摸键,在发送方掌控板中进行编程,将按键A和B分别设计对应发送摩尔斯电码的“滴”和“嗒”信号,而将触摸键P作为每组摩尔斯电码(即所表示的某一个字符)的结束信号,因为真实的摩尔斯电码的字符间隔是一个“嗒”的时长(相当于三个“滴”),对于初学者的操作难度较大,而简单地“碰”一下触摸键的动作则非常方便。另外,为了对按键和触摸键的按下与触摸操作进行即时反馈,编程时需要添加RGB灯闪烁和蜂鸣器播放音符模拟“滴”、“嗒”的声音,比如三支RGB灯分别对应按键A、B和触摸键P的“动作”;同时,在接收方掌控板中也进行同样的编程控制方式,模拟实现摩尔斯电码的发送与接收的“声光”同步响应,趣味性也更强。

        发送方通过摩尔斯电码发送一个四位的年代数字,比如“1921”;接收方收到后,在OLED显示屏上显示“1921年7月,中共一大宣布党的诞生。”如果发送的是“1949”,则显示输出“1949年10月,中华人民共和国成立。”其他的查询操作方法,均类似,前提是——只要在编程时添加了足够多的事件信息。

 

材料清单

  • 掌控板 X2
  • 联网电脑(安装有mPython) X1
  • WiFi X1
  • 百灵鸽(友情出演) X1

详细制作过程

1.预备知识:什么是摩尔斯电码?

摩尔斯电码(Morse code)是一种通过不同的排列顺序来表达相关字符(比如26个英文字母)的数字化通信形式,它的最基本代码是“滴”和“嗒”,分别对应短促的“一个点”信号和“一个划”信号,“一划”相当于“三个点”的时长。在各种故事情节中最为经典的摩尔斯电码应用,便是SOS国际通用求救信号的发送——字母S的摩尔斯电码是“滴、滴、滴”三个点,字母O的摩尔斯电码是“嗒、嗒、嗒”三个划,通过开关手电筒控制电路通断以光的形式,或是单根手指连续敲击桌面以声的形式,都能够快速发送“三点、三划、三点”的SOS求救摩尔斯电码。

然额,这次的重点不是这些字母,我们想要使用的是10个阿拉伯数字。通过刚才对字母的讲解,相信大家应该也立刻会对它们进行编码处理了吧?

project-image

2.发送方的mPython编程:Wi-Fi联网并进行“连接MQTT”设置

将一块掌控板通过数据线连接至联网电脑的USB接口,然后运行mPython进行程序的编写:

两个掌控板之间能够正常进行信号的发送与接收的“对话”前提条件是畅通的网络连接,因此程序的最开始必须是进行联网设置。从左侧的“Wi-Fi”中选择第一项“连接Wi-Fi名称‘’密码‘’”模块语句,然后补充完整所使用的无线网络名称及密码信息(明文显示)。

在mPython的“扩展”-“MQTT”中提供了若干种MQTT模块,以其中的“MQTT-Easy IoT”为例(其它的用法基本类似),这是由DFRobot提供的物联网MQTT服务,需要从浏览器访问网站(https://iot.dfrobot.com.cn/)先进行免费注册,然后登录进入自己账号的“工作间”;左侧有两处关键信息,一是“Iot_id(user)”(即用户名),将其值“XNbxt3rMR”复制粘贴至mPython编程中“MQTT-Easy IoT”模块语句中的第三项“Iot_id”中;二是“Iot_pwd(password)”(即密码),可点击“小眼睛”图标进行显示,将其值“uHxxpqrGRz”复制粘贴至第四项“Iot_pwd”中(前两项“服务器”和“Client ID”均保持默认值)。在“工作间”中执行三次“添加新的设备”操作,分别重命名为“mPython_1”、“mPython_2”和“mPython_3”,对应三个Topic“主题”的数值,可分别复制并粘贴至记事本中保存,这些信息在接收方掌控板中也要用到。

project-image

再次返回mPython编程界面,从“MQTT”中选择“连接MQTT”模块语句,添加至“MQTT-Easy IoT”模块语句后面,作用是根据之前的设置进行MQTT连接。

3.发送方的mPython编程:设置OLED显示提示信息

先从左侧的“显示”中选择“OLED显示‘清空’”模块语句;再使用“OLED第‘’行显示‘’模式‘普通’‘不换行’”,控制OLED显示屏的第1行显示“热烈庆祝建党100周年”提示信息;最后要添加“OLED显示生效”模块语句。

project-image

4.发送方的mPython编程:定义字典变量my_dict并进行数据的初始化

为了进行摩尔斯电码的分解与重组,可以将二进制代码“0”和“1”与摩尔斯电码的“滴”和“嗒”一一映射进行组合编码。比如:数字“1”的摩尔斯电码是“滴、嗒、嗒、嗒、嗒”,在字典中为它设置“键”(Key)为“01111”、“值”(Value)为“1”;再比如:数字“2”是“滴、滴、嗒、嗒、嗒”,在字典中的“键”就是“00111”。对应摩尔斯电码的编码规则,对字典变量my_dict进行定义和初始化,完成10个阿拉伯数字的“0”“1”编码映射。

project-image

5.发送方的mPython编程:a_func、b_func和p_func三个函数的编写

为了使主程序结构更加条理清晰,编写a_func、b_func和p_func三个函数来分别实现当按下按键A、B和触摸P时所触发的“动作”:声音提醒、RGB灯闪烁提醒等。值得注意的是,需要建立message、my_string和morse三个变量,目的是什么呢?变量message的作用是用来生成“0”或“1”,这个值取决于操作者按下的是A键还是B键:A键对应“0”,B键对应“1”;变量my_string相当于Python中的“列表”,它的作用是将变量message依次生成的“0”或“1”单个值通过“追加文本”的方式不断进行有序“补充”组合;当生成的最终组合值在字典my_dict中进行“键”的搜索时,如果有对应的“键”,则将变量morse的值设定为字典中该“键”所对应的“值”,即某一个阿拉伯数字。

project-image

比如:先连续按两次B键、再连续按三次A键、最后按一次P键的操作,变量message中就会依次存储“1”、“1”、“0”、“0”和“0”;当这五个数据按生成的先后次序追加至变量my_string中时,组合值就是“11000”;将“11000”与字典my_dict中的10个“键”去查找“配对”,找到对应的“值”是阿拉伯数字“7”,接下来就将数字“7”保存至变量morse中,表示发送的摩尔斯电码是数字“7”。在p_func函数中又一次控制OLED显示屏进行显示输出,其中变量i的作用是控制多个连续发送的摩尔斯电码进行依次显示(后面有“将变量i的值增加10”模块语句),对应的是OLED显示屏横坐标x的数值。

注意:在主程序中要将变量message、my_string和morse先进行文本型数据的“空值”设定,变量i的初值则设置为整型数据10;而在a_func、b_func和p_func三个函数中,每次获取对应的数据后还要根据情况进行变量值的“清空”或是“自增”操作。

6.发送方的mPython编程:设置三个“发送”主题的循环

建立一个“一直重复执行”的循环结构,注意在循环体最后要添加一条“等待0.01秒”的模块语句(防止程序运行过快而消耗过多的系统资源);循环内是一个三分支的选择结构,当检测到A键被按下时,调用执行a_func函数并且发布值为“ON”数据至第一个主题“Mqj-t39Gg”;当检测到B键被按下时,则调用执行b_func函数并且也发布值为“ON”的数据,但对应的是第二个主题“qagfpq9Gg”;当检测到P被触摸时,调用执行的是p_func函数,发布值为“ON”的数据至第三个主题“wP_Q-69GR”;注意此处需要添加内层选择结构,对字典变量my_dict中的“键”是否与变量my_string的值进行匹配检测。

project-image

这三个不同的主题所存储的“ON”消息值,是第二块掌控板(接收方)的响应动作触发条件,因此必须要在接收方掌控板中进行对应主题消息的“订阅”等操作。

7.接收方的mPython编程

将第二块掌控板通过数据线连接至第二台联网电脑的USB接口,运行mPython进行程序的编写:

与发送方掌控板的程序基本一致,包括Wi-Fi联网和MQTT设置(其中的Client ID须改动至少一位数字),OLED显示屏的显示信息稍作改动——“迎建党百年 展科技风采”;字典变量my_dict的定义与数据初始化,a_func、b_func和p_func三个函数的编写,以及变量message、my_string和morse等的初始赋值等均完全一致。

project-image

至于变量morse2,它的作用是生成由4个阿拉伯数字组,比如1921、1949。

最大的区别是取消了三个主题发送的循环结构,但同样是新建了一个极为类似的循环结构。先从左侧“循环”和“扩展”-“MQTT”中分别选择“一直重复执行”和“等待主题消息以‘阻塞’模式”模块语句,接着进行三个主题的同步“监听”,其中的主题名与发送方的三个主题是一一对应的,这就相当于进行主题的订阅:当收到对应主题有“ON”消息值到达时,分别调用执行对应的a_func、b_func和p_func函数,与发送方进行摩尔斯电码发送时的响应完全相同。

后面的多分支选择结构是对变量morse2的值进行判断,对应显示不同的文字信息。需要注意的是,当变量morse2中的值已经是四位数字后,必须要再进行一次“清零”操作,这样就可以再接收下一次的查询了。

project-image

8.测试摩尔斯电码的发送与接收:进行查询

程序编写完毕后进行保存,接着分别在发送方和接收方的mPython编程界面点击上方的“刷入”按钮,右下角的“控制台”区会有“代码刷入36%”、“刷入成功”和“Connection Wi-Fi”等提示信息。

想分别查询“1921”和“1949”年,在发送方如何操作呢?而在接收方又会有什么样的响应呢?

看视频咯——

代码
#mPythonType:0
from mpython import *

import network

my_wifi = wifi()

my_wifi.connectWiFi('TP-LINK_108', 'zyyz0108')

from umqtt.simple import MQTTClient

mqtt = MQTTClient('0805e3d04f3b34e8', '182.254.130.180', 1883, 'XNbxt3rMR', 'uHxxpqrGRz', keepalive=30)

try:
    mqtt.connect()
    print('Connected')
except:
    print('Disconnected')

import music

import time

def a_func():
    global morse, my_dict, message, my_string, i
    music.play('F#5:1')
    rgb[0] = (int(255), int(204), int(0))
    rgb.write()
    time.sleep_ms(1)
    time.sleep(0.02)
    rgb[0] = (0, 0, 0)
    rgb.write()
    time.sleep_ms(1)
    message = '0'
    my_string = str(my_string) + str(message)
    message = ''

def b_func():
    global morse, my_dict, message, my_string, i
    music.play('F#5:2')
    rgb[2] = (int(0), int(153), int(0))
    rgb.write()
    time.sleep_ms(1)
    time.sleep(0.02)
    rgb[2] = (0, 0, 0)
    rgb.write()
    time.sleep_ms(1)
    message = '1'
    my_string = str(my_string) + str(message)
    message = ''

def p_func():
    global morse, my_dict, message, my_string, i
    morse = my_dict.get(my_string)
    oled.DispChar(morse, i, 30, 1)
    oled.show()
    music.play('F#5:1')
    rgb[1] = (int(255), int(0), int(0))
    rgb.write()
    time.sleep_ms(1)
    time.sleep(0.02)
    rgb[1] = (0, 0, 0)
    rgb.write()
    time.sleep_ms(1)
    i = i + 10
    my_string = ''
    morse = ''
oled.fill(0)

oled.DispChar(' 热烈庆祝建党100周年', 0, 0, 1)
oled.show()
my_dict = {"01111":'1', "00111":'2', "00011":'3', "00001":'4', "00000":'5', "10000":'6', "11000":'7', "11100":'8', "11110":'9', "11111":'0'}
message = ''
my_string = ''
morse = ''
i = 10
while True:
    if button_a.was_pressed():
        a_func()
        mqtt.publish('Mqj-t39Gg', 'ON')
    elif button_b.was_pressed():
        b_func()
        mqtt.publish('qagfpq9Gg', 'ON')
    elif touchpad_p.was_pressed():
        if my_string in my_dict:
            p_func()
            mqtt.publish('wP_Q-69GR', 'ON')
    time.sleep(0.01)
代码
#mPythonType:0
from mpython import *

import network

my_wifi = wifi()

my_wifi.connectWiFi('TP-LINK_108', 'zyyz0108')

from umqtt.simple import MQTTClient

mqtt = MQTTClient('0805e3d04f3b34e7', '182.254.130.180', 1883, 'XNbxt3rMR', 'uHxxpqrGRz', keepalive=30)

try:
    mqtt.connect()
    print('Connected')
except:
    print('Disconnected')

from machine import Timer

import ubinascii

def mqtt_topic_4d716a2d7433394767(_msg):
    global morse, morse2, my_dict, my_string, message
    a_func()

def mqtt_topic_716167667071394767(_msg):
    global morse, morse2, my_dict, my_string, message
    b_func()

def mqtt_topic_77505f512d36394752(_msg):
    global morse, morse2, my_dict, my_string, message
    if my_string in my_dict:
        p_func()
    if morse2 == '1921':
        oled.DispChar('        1921年7月,党诞生。', 0, 16, 1, True)
    elif morse2 == '1927':
        oled.DispChar('        1927年8月,南昌起义标志党领导军队的开始。', 0, 16, 1, True)
    elif morse2 == '1935':
        oled.DispChar('        1935年1月,遵义会议确定以毛泽东为核心的中央领导。', 0, 16, 1, True)
    elif morse2 == '1938':
        oled.DispChar('        1938年5月,毛泽东发表《论持久战》。', 0, 16, 1, True)
    elif morse2 == '1945':
        oled.DispChar('        1945年9月,抗日战争全面胜利。', 0, 16, 1, True)
    elif morse2 == '1949':
        oled.DispChar('        1949年10月,中华人民共和国成立。', 0, 16, 1, True)
    oled.show()
    if len(morse2) == 4:
        morse2 = ''

import music

import time

def a_func():
    global morse, morse2, my_dict, my_string, message, _msg
    music.play('F#5:1')
    rgb[0] = (int(255), int(204), int(0))
    rgb.write()
    time.sleep_ms(1)
    time.sleep(0.02)
    rgb[0] = (0, 0, 0)
    rgb.write()
    time.sleep_ms(1)
    message = '0'
    my_string = str(my_string) + str(message)
    message = ''

def b_func():
    global morse, morse2, my_dict, my_string, message, _msg
    music.play('F#5:2')
    rgb[2] = (int(0), int(153), int(0))
    rgb.write()
    time.sleep_ms(1)
    time.sleep(0.02)
    rgb[2] = (0, 0, 0)
    rgb.write()
    time.sleep_ms(1)
    message = '1'
    my_string = str(my_string) + str(message)
    message = ''

def p_func():
    global morse, morse2, my_dict, my_string, message, _msg
    morse = my_dict.get(my_string)
    morse2 = str(morse2) + str(morse)
    music.play('F#5:1')
    rgb[1] = (int(255), int(0), int(0))
    rgb.write()
    time.sleep_ms(1)
    time.sleep(0.02)
    rgb[1] = (0, 0, 0)
    rgb.write()
    time.sleep_ms(1)
    my_string = ''
    morse = ''

def mqtt_callback(topic, msg):
    try:
        topic = topic.decode('utf-8', 'ignore')
        _msg = msg.decode('utf-8', 'ignore')
        eval('mqtt_topic_' + bytes.decode(ubinascii.hexlify(topic)) + '("' + _msg + '")')
    except: print((topic, msg))

mqtt.set_callback(mqtt_callback)

mqtt.subscribe("Mqj-t39Gg")

def timer14_tick(_):
    mqtt.ping()

tim14 = Timer(14)
tim14.init(period=20000, mode=Timer.PERIODIC, callback=timer14_tick)

mqtt.subscribe("qagfpq9Gg")

mqtt.subscribe("wP_Q-69GR")
oled.fill(0)
oled.DispChar(' 迎建党百年 展科技风采', 0, 0, 1)
oled.show()
my_dict = {"01111":'1', "00111":'2', "00011":'3', "00001":'4', "00000":'5', "10000":'6', "11000":'7', "11100":'8', "11110":'9', "11111":'0'}
message = ''
my_string = ''
morse = ''
morse2 = ''
while True:
    mqtt.wait_msg()

        测试过程截图如下:

project-image
project-image
project-image
project-image
project-image
project-image
project-image

评论

user-avatar
  • YaYaLiou

    YaYaLiou2021.09.25

    新思路!

    0
    • DFrJoDzHFkd

      DFrJoDzHFkd2021.09.08

      妙啊!

      0