7438浏览
查看: 7438|回复: 13

[项目] FireBeetle 声音摩尔斯

[复制链接]
在电报发明之前,长距离通信对人类来说是十分艰难的事情,在中国古代是通过驿站、驿道来实现的;在近代的欧洲他们使用信号塔的方法。但是显而易见,无论哪种办法都很难实现长距离实时的通信。塞缪尔·莫尔斯(SamuelFinley Breese Morse, 1791年4月27日—1872年4月2日),是一名享有盛誉的画家、电报之父。
到了近代,法拉第发现了电和磁是可以相互转化,人们就开始思考是不是可以利用“电”来传递信号呢?于是,许多人开始投身于用电来传递信号的事业当中,在这些人当中,真正实现用“电”来传递信号并且大规模商用的人就是莫尔斯。他出生于1791年,是美国“地理学之父”迦地大·莫尔斯的长子。因为莫尔斯电码实在太有名气,让很多人以为莫尔斯是一个发明家。实际上,他的职业是画家,并且是在美国历史上都数得上名次的伟大画家,尤其擅长肖像画。
1818年,他与卢克丽霞·沃克(LucretiaWalker)结婚,在他们短暂的生活中,他们有了三个孩子。莫尔斯发现,他的大型历史题材绘画作引起了极大的关注,但销量并不高,而肖像画在这个时候最受欢迎。为此他成为一名巡回艺术家,从新英格兰到卡罗莱纳州寻找机会。尽管很困难,莫尔斯在此期间画了一些他最著名的作品,其中包括《拉斐特侯爵》和《乔治·华盛顿的肖像 》。他的作品将熟练的技术与浪漫主义气息相结合,产生了戏剧性的绘画效果。
从 1825 年至 1835 年的十年间,莫尔斯的生活非常悲惨。1825 年 2 月,在生下第三个孩子后,卢克丽霞去世。莫尔斯听说他的妻子病重时正在离家从事绘画委托工作,而当他回到家时,她已经被埋葬了。次年,莫尔斯的父亲去世,三年后他的母亲也去世了。悲痛欲绝的莫尔斯于 1829 年前往欧洲。1832 年,在他回家的途中,他遇到了发明家查尔斯·托马斯·杰克逊(Charles ThomasJackson),两人开始讨论如何通过电线长距离传输电子脉冲。莫尔斯立即产生了兴趣,并绘制了一些他机械装置的草图。
在研究了美国物理学家约瑟夫·亨利的理论后,莫尔斯发明了电报的原型。1836 年,欧洲的其他人也在研究这项发明,但还没有人开发出一种可以远距离传输的完全可操作的设备。1838 年,莫尔斯与同为发明家的艾尔菲德·维尔(AlfredVail)建立了合作伙伴关系,后者提供资金并帮助开发了用于发送信号的点和划线系统,这种信号最终被称为摩尔斯电码。
摩尔斯电码是一种早期的数字化通信形式,但是它不同于现代只使用零和一两种状态的二进制代码,它的代码包括五种:点,划,每个字符间短的停顿,每个词之间中等的停顿,以及句子之间长的停顿。
最早的摩尔斯电码是一些表示数字的点和划。数字对应单词,需要查找一本代码表才能知道每个词对应的数。用一个电键可以敲击出点、划以及中间的停顿。
虽然摩尔斯发明了电报,但他缺乏相关的专门技术。他与艾尔菲德·维尔签定了一个协议,让他帮自己制造更加实用的设备。艾尔菲德·维尔构思了一个方案,通过点、划和中间的停顿,可以让每个字符和标点符号彼此独立地发送出去。他们达成一致,同意把这种标识不同符号的方案放到摩尔斯的专利中。这就是现在我们所熟知的美式摩尔斯电码,它被用来传送了世界上第一条电报。
上面就是关于摩尔斯电码的基本知识。   这次的作品使用 DFRobot 的 FireBeetle ESP32 作为主控,通过BLE蓝牙键盘输入信息,输入的字符会显示在 OLED12864显示屏上,当用户输入回车时,程序将这个信息转化为摩尔斯电码然后通过板子上的蜂鸣器将这个信号以声音的形式发送出去。通过手机上的MorseCode APP 将声音解码为字符。
FireBeetle 声音摩尔斯图10

首先进行硬件设计,电路设计如下:
FireBeetle 声音摩尔斯图1
图1电路图
可以看到这个作品主要有两部分:一个是用于连接FireBeetle的排母和蜂鸣器;另外一个是包括电池和充放电模块的电源部分。
FireBeetle 通过IO17Pin连接到一个SS8050三极管用于控制蜂鸣器。这里选择的有源蜂鸣器,当它通电时就会发出声响;出于体积考虑作品使用CR123A可充电式锂电池(DFRobot:FIT0615),它的标准电压为3.6V,额定容量:1000mAh,直径1.6cm长3.4cm,相比 18650 电池的尺寸直径1.8cm,长6.5cm,这个电池更加小巧适合在轻便设备上使用。此外还有一个考量是: 10x10CM 的板子可以在嘉立创免费制作。
FireBeetle 声音摩尔斯图2
图2CR123A 锂电池
为了配合电池,淘宝选购了下面这种充放电一体模块,它的核心是IP5306芯片,这个芯片是专门为充电宝设计的,配合预留的USB公头,可以实现对CR123A电池的充电。电源部分当于将充电做到了设备上。需要注意的是,这种模块有两种,一种不支持小电流输出,当输出电流小于一定值时,经过一段时间会自动切断输出;另外一种则没有这种限制。这里使用的是没有限制的。
FireBeetle 声音摩尔斯图3
图3充放电模块
PCB 设计如下:
FireBeetle 声音摩尔斯图4
图4PCB 设计
FireBeetle 声音摩尔斯图5
图5PCB  3D 预览
因为充放电模块灯光刺眼,所以该模块设计在PCB背面,然后对应灯光位置位置加入了阻焊层,这样充放电模块的指示灯能够透到正面,并且不会特别强烈。
FireBeetle 声音摩尔斯图6
图5制作好的PCB 板
最终组装好的模块如下:
FireBeetle 声音摩尔斯图7
图7组装后的照片
接下来进行软件设计。代码基于esp32beans的BLE_HID_Client例子修改而来(在BLE 通讯中,负责提供数据的被称作“Server”,与之对应的是 “Client”。这里数据来自BLE  Keyboard,FireBeetle 作为接收端,所以是 Client)。特别注意,代码只适用于BLE 键盘,并不支持 Bluetooth 2.0 的传统蓝牙键盘,这次试验我使用的是雷柏X220T。
FireBeetle 声音摩尔斯图8
图8雷柏 X220T 是一款支持 BLE的蓝牙键盘
示例代码会完成框架性的工作,比如:搜索连接键盘设备。我们只需要在下面的回调函数中完成收到按键信息的处理即可。

  1. void notifyCB(NimBLERemoteCharacteristic* pRemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify) {
  2.   std::string str = (isNotify == true) ? "Notification" : "Indication";
  3.   str += " from ";
  4.   /** NimBLEAddress and NimBLEUUID have std::string operators */
  5.   str += std::string(pRemoteCharacteristic->getRemoteService()->getClient()->getPeerAddress());
  6.   str += ": Service = " + std::string(pRemoteCharacteristic->getRemoteService()->getUUID());
  7.   str += ", Characteristic = " + std::string(pRemoteCharacteristic->getUUID());
  8.   str += ", Value = ";
  9.   Serial.print(str.c_str());
  10.   for (size_t i = 0; i < length; i++) {
  11.     Serial.print(pData[i], HEX);
  12.     Serial.print(',');
  13.   }
  14.   Serial.println("");
  15.   if (pData[2] != 0) {
  16.     Serial.print(pData[0], HEX);
  17.     Serial.print(" Rev:");
  18.     Received = (char)ScanCode2Ascii(pData[0], pData[2]);
  19.     Serial.println(Received);
  20.   }
  21.   if (length == 6) {
  22.     // BLE Trackball Mouse from Amazon returns 6 bytes per HID report
  23.     Serial.printf("buttons: %02x, x: %d, y: %d, wheel: %d",
  24.                   pData[0], *(int16_t *)&pData[1], *(int16_t *)&pData[3], (int8_t)pData[5]);
  25.   }
  26.   else if (length == 5) {
  27.     // https://github.com/wakwak-koba/ESP32-NimBLE-Mouse
  28.     // returns 5 bytes per HID report
  29.     Serial.printf("buttons: %02x, x: %d, y: %d, wheel: %d hwheel: %d",
  30.                   pData[0], (int8_t)pData[1], (int8_t)pData[2], (int8_t)pData[3], (int8_t)pData[4]);
  31.   }
  32.   Serial.println();
  33. }
复制代码

收到的数据在pData[] 中,是 Scancode ,因此还需要用ScanCode2Ascii()函数将 ScanCode转为 ASCII,转化结果放在Received变量中。特别注意,这里只处理了每只有一个按键按下的情况,如果同时多个按键按下,第一个按下之外的会被忽略。
取得了按键信息,就可以继续进行处理。先介绍一下具体的摩尔斯编码方式,它的代码包括五种:
1.点( · ):1 (读 “滴” dit ,时间占据1t )
2.划(—):111 (读 “嗒”dah ,时间占据3t )
3.字符内部的停顿(在点和划之间):0 (时间占据1t )
4.字符间停顿:000 ( 时间占据3t )
5.单词间的停顿:0000000 ( 时间占据7t )
点的长度(也就是上面的时间长度t)决定了发报的速度,这里我们使用80ms。
字母
  
字符
  
电码符号
字符
电码符号
字符
电码符号
字符
电码符号
A
.━
B
━ ...
C
━ .━ .
D
━ ..
E
F
..━ .
G
━ ━ .
H
....
I
..
J
.━ ━ ━
K
━ .━
L
.━ ..
M
━ ━
N
━ .
O
━ ━ ━
P
.━ ━ .
Q
━ ━ .━
R
.━ .
S
...
T
U
..━
V
...━
W
.━ ━
X
━ ..━
Y
━ .━ ━
Z
━ ━ ..
 
 
 
 
数字
  
字符
  
电码符号
字符
电码符号
字符
电码符号
字符
电码符号
0
━ ━ ━ ━ ━
1
.━ ━ ━ ━
2
..━ ━ ━
3
...━ ━
4
....━
5
.....
6
━ ....
7
━ ━ ...
8
━ ━ ━ ..
9
━ ━ ━ ━ .
 
 
 
 
标点符号
  
字符
  
电码符号
字符
电码符号
字符
电码符号
字符
电码符号
.
.━ .━ .━
:
━ ━ ━ ...
,
━ ━ ..━ ━
;
━ .━ .━ .
?
..━ ━ ..
=
━ ...━
'
.━ ━ ━ ━ .
/
━ ..━ .
!
━ .━ .━ ━
━ ....━
_
..━ ━ .━
"
.━ ..━ .
(
━ .━ ━ .
)
━ .━ ━ .━
$
...━ ..━
&
.━ ...
@
.━ ━ .━ .
 
 
 
 
 

  
  
从编码上可以看出字母“E”和“T” 是最短的,这是因为最初在设计编码时,统计了英文中字母出现的频率,其中根据结果这两个字符出现的频率最高的,所以它们被赋予了最短的编码。
对应在代码中 uint8_t GetEncode(uint8_tcharacter) 函数负责将character转化为摩尔斯码,例如:GetEncode(‘!’)输出结果为0b1110101,对应着“━ .━ .━ ━”。可以看到1的对应”━”,0对应“.”。因为编码长度不同,所以最高位需要用1进行占位操作,比如:“5”编码是“. ....”,如果没有占位那就是0 无法得知正确的长度,而在有占位的情况下是0b100000,可以准确的知道有5个“.”。
用户输入的字符会被拼接在message这个字符串中,同时还会显示在 OLED上。当收到回车后,会对message进行编码,同时使用蜂鸣器进行播放。
  1.     if (Received == 1) { //处理回车
  2.       Serial.print("Message>"); Serial.print(message); Serial.println("<");
  3.       for (uint8_t i = 0; i < Index; i++) {
  4.         Encode = GetEncode(message.charAt(i));
  5.         Serial.print(message.charAt(i)); Serial.print(":"); Serial.print(Encode, HEX);
  6.         while (Encode != 0x1) {
  7.           if ((Encode & 0x1) == 0) { //短
  8.             digitalWrite(SENDPINT, HIGH);
  9.             delay(DELAYDI);
  10.             digitalWrite(SENDPINT, LOW);
  11.             Serial.print(".");
  12.           } else {               //长
  13.             digitalWrite(SENDPINT, HIGH);
  14.             delay(DELAYDAH);
  15.             digitalWrite(SENDPINT, LOW);
  16.             Serial.print("-");
  17.           }
  18.           Encode >>= 1;
  19.           delay(DELAYDIDAH);
  20.         }
  21.         delay(DELAYCHAREND);
  22.         Serial.println("");
  23.       }
复制代码

用流程图描述如下:
FireBeetle 声音摩尔斯图9
图9 工作流程图

普通人最容易接触的摩尔斯码恐怕是 SOS 信号。“SOS”本身并没有任何的意义,就是因为S,O这两个字母的摩斯密码是三个“·”,三个“—”,很容易与其他的字母区分,所以在1906年,第二届国际无线电会议,确定了SOS为遇难求救信号。但之前国际公海海难求救信号为CQD,虽然确定了新的求救信号了,但是英国的无线电操作员很少使用SOS信号,他们更喜欢老式的CQD遇难信号(英国马可尼无线电公司决定用CQD作为船舶遇难信号),但因 D(—··)易于其他字母混淆,周围船只并未意识到是求救信号,没有快速救援,在快沉没时才使用的新求救信号SOS(··· — — — ···)发报。泰坦尼克号沉没后,SOS才被广泛接受和使用。

zoologist  高级技匠
 楼主|

发表于 2022-11-22 19:44:23

本文电路图和 PCB 设计

下载附件电路图和PCB.zip

完整程序代码:
下载附件FireBeetleMorse.zip
回复

使用道具 举报

zoologist  高级技匠
 楼主|

发表于 2022-11-23 09:28:30

工作视频:


回复

使用道具 举报

赤星三春牛!  初级技神

发表于 2022-11-23 14:37:02

厉害厉害
回复

使用道具 举报

zoologist  高级技匠
 楼主|

发表于 2022-12-2 20:52:30

FireBeetle 声音摩尔斯图1
回复

使用道具 举报

陈玉玮  中级技师

发表于 2022-12-19 07:38:55

好厉害哟
回复

使用道具 举报

摸鱼的网民  中级技师

发表于 2022-12-22 08:49:24

看起来有点东西
回复

使用道具 举报

摸鱼的网民  中级技师

发表于 2023-1-17 11:53:26

涨知识了
回复

使用道具 举报

迟迟具体  见习技师

发表于 2023-4-7 16:45:48

太有趣了,厉害。想做一个完整电台,能收发电报
回复

使用道具 举报

Amos Young  中级技师

发表于 2023-8-7 14:11:16

好厉害,太专业了
回复

使用道具 举报

花生编程  中级技匠

发表于 2023-8-23 21:58:39

厉害厉害
回复

使用道具 举报

花生编程  中级技匠

发表于 2023-8-23 21:59:51

赞赞赞赞赞!
回复

使用道具 举报

三春牛-创客  初级技神

发表于 2023-8-24 14:12:47

作品好棒!!
回复

使用道具 举报

三春牛-创客  初级技神

发表于 2023-8-24 14:13:55

不错不错
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail