esp8266 点灯与摩斯密码

概述

这篇文章介绍了使用 Arduino 开发 esp8266 的基础功能——点灯,用程序点亮 esp8266 板载 LED,另外还使用到了串口通信功能,实现电脑、手机与 esp8266 的通信功能,最后实现了使用 esp8266 输出摩斯密码信号的小应用。

Esp8266

乐鑫公司推出的低成本 wifi 模块,这里用到的是 esp8266 开发板,可以使用 Arduino 开发,是体验 Arduino 和硬件开发的好东西。

原料

硬件

  • esp8266 开发板:用于烧录程序、板载 LED 输出光电信号
  • 安卓手机:用串口通信给 esp8266 发送文本数据,需要支持 OTG 功能
  • USB 连接线:用于 esp8266 连接电脑下载程序,连接手机串口通信
  • OTG 转接线:用于手机连接 USB 线

软件

  • Arduino IDE:PC 软件,用于开发 Arduino 程序,给 esp8266 烧录程序,串口监视器发送文本内容

  • 串口调试工具:Android 软件,用于手机通过串口给 esp8266 发送文本数据

硬件开发的第一节课——点灯。

开发环境配置这里就不再赘述,可以参考:ESP8266初体验 hello world

将 esp8266 接到电脑上,在 Arduino IDE 中选择 示例 - ESP8266 - Blink ,打开官方的点灯示例代码,上传到开发板后即可看到开发板上 LED 闪烁效果。

以下程序将使 esp8266 开发板上的 LED 循环闪烁,亮 1 秒,熄灭 2 秒,一直循环。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void setup() {
// 设置内嵌 LED 的引脚(LED_BUILTIN)为输出模式
pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
// 输出低电平,低电平将点亮 esp8266 板载 LED,因为实际上是 ESP-01 的低电平
digitalWrite(LED_BUILTIN, LOW);
// 等待 1s
delay(1000);
// 输出高电平,高电平将熄灭 esp8266 板载 LED
digitalWrite(LED_BUILTIN, HIGH);
// 等待 2s
delay(2000);
}

整个程序理解起来比较容易,但需要注意的一点是,在 esp8266 开发板上,板载 LED 引脚 (LED_BUILTIN) 输出低电平时,LED 将会点亮;输出高电平时,LED 将会熄灭。

另外一个问题是 LED_BUILTIN 这个引脚是几号引脚呢?这是一个定义好常量,在每一种开发板中,对应的引脚编号都不同,我们怎么才能知道具体是几号呢?一种方法是上网查资料,第二种是用串口打印输出,这个方法最直接。还有一种方法是去看开发板 SDK 的源码,这里以我们选择的 Generic ESP8266 Module 开发板为例,我们需要先找到 esp8266 SDK 的目录,一般是在 ~/AppData/Local/Arduino15/packages ,这里放的是解压出来的 SDK 源码,最后我们可以在 ~/AppData/Local/Arduino15/packages/esp8266/hardware/esp8266/2.5.0/variants 目录下,可以找到不同开发板定义引脚的头文件 pins_arduino.h

摩斯密码

定义

莫斯密码 (Morse code),又称摩尔斯电码,是一种时通时断的信号代码,通过不同的排列顺序表达不同的英文字母、数字和标点符号。莫斯密码是早期的数字化通信形式,但它和现代的 0 和 1 的二进制码不同,它有 5 种形式:点、划、点和划直接的停顿、每个字符之间的停顿、每个词之间中等的停顿以及句子之间长的停顿。

莫斯电码部分规则:短促的点信号 . ,读 “滴”,保持一定时间的长信号 - ,读 “嗒”。点的时间长度为一个单位,一个线是点的 3 倍长度,每个线或者点之间的时间等于一个点的持续时间,两个字母之间的间隔时间与一个线的长度相同,两个单词之间的间隔等于7个点的持续时间。

字母数字的莫斯密码

原文 编码 原文 编码 原文 编码
a .- m y -.–
b -… n -. z –…
c -.-. o 0 -----
d -… p .–. 1 .----
e . q –.- 2 …—
f …-. r .-. 3 …–
g –. s 4 …-
h t - 5
i u …- 6 -…
j .— v …- 7 –…
k -.- w .– 8 —…
l .-… x -…- 9 ----.

注:不区分大小写

esp8266 输出摩斯密码信号

在明白了摩斯密码的含义后,我们可以修改一下点灯程序代码,以灯光持续时间表示摩斯密码信号,输出国际通用的求救信号 SOS ,将其装换成摩斯密码信号为 ...---... ,通过程序控制 LED 灯亮和灭的时间间隔,输出信号。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// 定义单位时间 200ms
#define t 200
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
// S ...,每个 . 持续时间为 1t
digitalWrite(LED_BUILTIN, LOW);
delay(t);
digitalWrite(LED_BUILTIN, HIGH);
delay(t); // 两个 . 之间 1t
digitalWrite(LED_BUILTIN, LOW);
delay(t);
digitalWrite(LED_BUILTIN, HIGH);
delay(t);
digitalWrite(LED_BUILTIN, LOW);
delay(t);
digitalWrite(LED_BUILTIN, HIGH);
delay(t*3); // 字母之间间隔 3t

// O ---,每个 - 持续 3t
digitalWrite(LED_BUILTIN, LOW);
delay(t*3);
digitalWrite(LED_BUILTIN, HIGH);
delay(t); // 每个 - 之间 1t
digitalWrite(LED_BUILTIN, LOW);
delay(t*3);
digitalWrite(LED_BUILTIN, HIGH);
delay(t);
digitalWrite(LED_BUILTIN, LOW);
delay(t*3);
digitalWrite(LED_BUILTIN, HIGH);
delay(t*3);

// S ...
digitalWrite(LED_BUILTIN, LOW);
delay(t);
digitalWrite(LED_BUILTIN, HIGH);
delay(t);
digitalWrite(LED_BUILTIN, LOW);
delay(t);
digitalWrite(LED_BUILTIN, HIGH);
delay(t);
digitalWrite(LED_BUILTIN, LOW);
delay(t);
digitalWrite(LED_BUILTIN, HIGH);

// 一轮完成,间隔 1s 分隔
delay(1000);
}

我们看了上面的代码之后,发现其中有太多重复代码了,我们可以利用函数将重复的功能封装起来,让我们的代码更加简洁。

优化后的代码

我们将灯闪烁的代码封装成一个函数,参数指定闪烁时间长度;将每个字符的摩斯代码对应的闪烁时间存入一个数组,使用 for 循环遍历输出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// 使用板载的 led 模拟发出 摩斯电码的 SOS 信号
// SOS, 原文 Save Our Souls,拯救我们的灵魂,是国际通用的求救信号
// 在莫斯电码中,S 为 ... ,O 为 ---
// ESP8266 中板载LED,低电平点亮,高电平熄灭

// 我们把每个字母信号的闪烁时间提取出来,存入数组,用循环方式输出
int durations[] = {200,200,200,500,500,500,200,200,200};

void setup() {
pinMode(LED_BUILTIN, OUTPUT);

}

void loop() {
showSOS();
}

/**
* 用循环的方式输出信号
* 将每个信号闪烁时间写到数组里,for循环逐个输出
* 这种方式字母之间间隔没控制好,用 showSOS 方法效果比较好
*/
void showSOSByLoop(){
for(int i = 0; i < 9; i++){
flash(durations[i]);
}
delay(1000);
}

/**
* 按字母一个一个的输出
*/
void showSOS(){
// S
flash(200);
flash(200);
flash(200);

// 字母之间增加延迟,否则前 4 个信号感觉是连起来的
delay(300);

// O
flash(500);
flash(500);
flash(500);

// S
flash(200);
flash(200);
flash(200);

delay(1000);
}

/**
* LED闪烁
* 参数:
* duration 闪烁间隔
*/
void flash(int duration){
digitalWrite(LED_BUILTIN,LOW);
delay(duration);
digitalWrite(LED_BUILTIN,HIGH);
delay(duration);
}

手机电报机

串口发送原文

上面的程序可以输出预先定义好的字符的摩斯密码信号,我们可以使用串口通信功能,通过串口将原文发送给 esp8266 ,由 esp8266 将其转换成莫斯密码信号,然后通过 LED 闪烁形式发出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
// 莫斯电码翻译机
// 可以通过串口(115200)向 ESP8266 发信息(英文字母、数字、空格),ESP8266 将输出对应的莫斯电码信号
// 莫斯电码部分规则:一个线是点的 3 倍长度,每个线或者点之间的时间等于一个点的持续时间,两个字母之间的间隔时间与一个线的长度相同,两个单词之间的间隔等于7个点的持续时间

// 字母数组
char* letters[] = {
".-","-...","-.-.","-..", // 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
};

// 数字数组
char* numbers[] = {
"-----",".----","..---","...--","....-", // 0,1,2,3,4
".....","-....","--...","---..","----." // 5,6,7,8,9
};

// 点的闪烁时间,用于调节速度
int dotDelay = 200;

void setup() {
pinMode(LED_BUILTIN,OUTPUT);
Serial.begin(115200);

// 初始时让灯不亮
digitalWrite(LED_BUILTIN,HIGH);
}

void loop() {
char ch;
if(Serial.available()){
ch = Serial.read();
Serial.print(ch);
if(ch != '\n'){
Serial.print(": ");
}
if(ch >= 'a' && ch <= 'z'){
flashSequence(letters[ch - 'a']);
}else if(ch >= 'A' && ch <= 'Z'){
flashSequence(letters[ch - 'A']);
}else if(ch >= '0' && ch <= '9'){
flashSequence(numbers[ch - '0']);
}else if(ch == ' '){
delay(dotDelay * 4);
}
Serial.println();
}
}

/**
* 通过LED输出语句信号
*/
void flashSequence(char* sequence){
int i = 0;
while(sequence[i] != NULL){
Serial.print(sequence[i]);
flashDotOrDash(sequence[i]);
i++;
}
delay(dotDelay);
}

/**
* 通过LED输出 . 或 - 的信号
*/
void flashDotOrDash(char dotOrDash){
digitalWrite(LED_BUILTIN,LOW);
if(dotOrDash == '.'){
// 如果是 . 延迟一倍的 dotDelay 时长
delay(dotDelay);
}else{
// 如果是 - 延迟三倍的 dotDelay 时长
delay(dotDelay * 3);
}
digitalWrite(LED_BUILTIN,HIGH);
delay(dotDelay);
}

烧录上面程序后,可以打开 Arduino IDE 的串口监视器,设置波特率为 115200,通过串口给 esp8266 发送字符串,然后可以看到 esp8266 开发板上 LED 输出了对应摩斯密码信号。

手机发送原文

上面是使用 Arduino IDE 的串口监视器给 ESP8266 发送数据,这样就离不开电脑,使用场景收到了限制。我们可以在手机上下载一个串口调试工具,然后通过 OTG 功能线将 esp8266 连接到手机上,这样就可以用手机的串口调试工具给 esp8266 发送数据,随时都可以发出想要的摩斯密码信号了。

串口调试工具可以在手机的应用中心搜索下载,我用的是华为的手机, Android 系统,测试没问题。其它手机和苹果系统没有测试,应该也没啥问题吧。

将 esp8266 连接上手机后,通过串口发出 SOS 数据,esp8266 板载 LED 正确输出了摩斯密码信号。

在串口调试工具的 设置 菜单中,可以修改通信波特率等参数。

参考资料

  • 余静; DFRobot. Arduino入门基础教程. 人民邮电出版社

总结

通过官方提供的一个 blink 示例程序,加上之前学过的串口通信知识,我们就可以扩展做出串口电报机,可以通过手机连接 esp8266 向外界发出摩斯电。这里只是通过 esp8266 的板载 LED 输出,我们还可以把它改成其他引脚,外接大功率的 LED 灯珠输出,或者直接以电平信号输出,这样就完成了一个非常实用的串口电报机。所以,不要小看这些最基本的功能和示例代码,学会了它们,再加上我们的一点点思考,就做很酷的应用。此外,我们在学习的时候,一定要多思考,发散思维,发掘一个简单程序的深层应用价值。