有没有办法在数组中实现摩尔斯电码?
Is there a way to implement Morse code inside an array?
我正在使用 LED 使我的微控制器以摩尔斯电码显示字母表中的字母(点 == 短闪烁,破折号 == 长闪烁)。
我可以做一个 switch 语句,然后这样做 :
switch (input)
case "a | A"
....
case "b | B "
....
但是我有一个 27+ 长的 switch 语句,所以我想这不是很好?
我正在考虑制作一个包含所有摩尔斯电码的数组,但我如何实现这个概念,即数组的第一个条目等于 a 或 A,...?
如果我们假设您的平台使用字符编码系统,其中 26 个拉丁字母具有连续值(最常用的系统 ASCII 有,但不是 由 C 标准保证),那么我们可以为每个字母的摩尔斯电码定义一个字符串数组,并使用给定字母的值减去 'A'
的值对该数组进行索引。
我们也可以对数字做类似的事情(标准保证具有连续的代码)。
这是一个示例代码(我们在索引到 Morse 数组之前将所有字母转换为大写):
#include <stdio.h>
#include <ctype.h>
int main()
{
const char* Alpha[26] = {
".-", // 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
};
const char* Digit[10] = {
"-----",// 0
".----",// 1
"..---",// 2
"...--",// 3
"....-",// 4
".....",// 5
"-....",// 6
"--...",// 7
"---..",// 8
"----.",// 9
};
char input[256];
do {
printf("Enter text ($ to quit): ");
scanf("%255s", input);
printf("Morse code...\n");
for (char *c = input; *c; ++c) {
if (isalpha(*c)) printf("%s", Alpha[toupper(*c) - 'A']);
else if (isdigit(*c)) printf("%s", Digit[*c - '0']);
else if (*c != '$') printf("<error>");
printf("\n");
}
} while (input[0] != '$');
return 0;
}
如果我们不能依赖字母的连续代码(或者选择不依赖,以获得更稳健的实现),我们可以通过调用 strchr
函数来确定索引(然后我们必须 #include <string.h>
) 获取我们的字母在所有字母列表中的位置:
//...
const char* Letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
//...
if (isalpha(*c)) printf("%s", Alpha[strchr(Letters,toupper(*c)) - Letters]);
如有任何进一步的说明,请随时提出要求and/or。
@Adrian 的替代方案,只需对大部分 ASCII 字符集进行编码 - 从 space (32) 到大写 Z (91)。你会得到数字、字母、标点符号和亲号,有些我们不关心,但谁在乎,因为它简化了事情so。您使用的是 8 位微控制器,因此您不必担心字符编码和 OS 首选项以及所有这些垃圾。
此外,跳过字符串。它们只会占用您有限的 RAM 中的空间,除非您对 Arduino 使用 F("asd")
技巧将它们放入闪存中。不使用字符串,而是使用 1 和 0:0b0110000
从左到右读取以获得点、破折号、标记停止位,然后是填充零。看起来很讨厌,但实际上不是。
这是我的...
/*
* Bit packing: read left to right from MSB, 0=dit, 1=dah,
* with extra dah terminating sentinel, then zero filled on right.
* Example,
* letter D -.. "dahdidit"
* convert 100
* terminate 1001
* pad 10010000
* result 0b10010000
* To use, test the top bit, send dit or dah, shift left, end when result is .
*/
/*
* the character codes are in ASCII order,
* from space to underscore F or 32-95 decimal.
* lower-case alpha should be coverted to upper-case before lookup
*/
const charcodes[] PROGMEM = {
0, // space
0b10101110, // ! exclamation point /KW
0b01001010, // " double quote /AF
0, // # hash mark, octothorpe
0b00010011, // $ dollar sign /SX
0, // % percent sign or /KA ?
0b01000100, // & ampersand /AS
0b01111010, // ' single quote /WG
0b10110100, // ( left parenthesis /KN
0b10110110, // ) right parenthesis /KK EOW ? EOM
0b00010110, // * asterisk /SK
0b01010100, // + plus sign
0b11001110, // , comma
0b10000110, // - dash, hyphen /DU
0b01010110, // . period
0b10010100, // / slash, divide /DN
0b11111100, // 0
0b01111100, // 1
0b00111100, // 2
0b00011100, // 3
0b00001100, // 4
0b00000100, // 5
0b10000100, // 6
0b11000100, // 7
0b11100100, // 8
0b11110100, // 9
0b11100010, // : colon /OS
0b10101010, // ; semicolon /KR
0, // < less-than sign
0b10001100, // = equal sign /BT
0, // > greater-than sign
0b00110010, // ? question mark
0b01101010, // @ commercial 'at' sign /AC
0b01100000, // A
0b10001000, // B
0b10101000, // C
0b10010000, // D
0b01000000, // E
0b00101000, // F
0b11010000, // G
0b00001000, // H
0b00100000, // I
0b01111000, // J
0b10110000, // K
0b01001000, // L
0b11100000, // M
0b10100000, // N
0b11110000, // O
0b01101000, // P
0b11011000, // Q
0b01010000, // R
0b00010000, // S
0b11000000, // T
0b00110000, // U
0b00011000, // V
0b01110000, // W
0b10011000, // X
0b10111000, // Y
0b11001000, // Z
0, // [ left bracket
0, // \ back-slash
0, // ] right bracket
0, // ^
0b00110110, // F _ underscore /IQ
};
/*
* look up the code for an ASCII character
* return 0 for bad characters and characters out of range.
*/
byte getcode(char c)
{
// convert upper-case to lower-case
if ( c >= 'a' && c <= 'z' )
c -= 'a' - 'A';
// check for characters beyond our table
if ( c < ' ' || c > '_' )
return 0;
// else read the byte from flash
return pgm_read_byte(charcodes + c - ' ');
}
我相信聪明人会发现问题,我会向他们学习。玩得开心!
编辑:他们做到了! @Clifford 指出我没有展示如何使用编码字节。所以这里是...您必须定义滴、哒、元素间隙(滴和哒之间)、字符间隙(字符之间)和单词间隙(单词之间)的值:
#define TOPBIT 0x80
void key(byte c)
{
// while we're not done, start the tone, delay a bit, stop the tone
while ( c != TOPBIT && c != 0 ) {
tone(BUZZ, FREQ);
digitalWrite(LED, 1);
delay( (c & TOPBIT) ? dahLen : ditLen );
noTone(BUZZ);
digitalWrite(LED, 0);
delay(elemGap);
// shift left one place; test the next bit the next time around
c <<= 1;
}
// now generate a character space
delay(charGap - elemGap);
}
HTH! (感谢@Clifford)
我正在使用 LED 使我的微控制器以摩尔斯电码显示字母表中的字母(点 == 短闪烁,破折号 == 长闪烁)。
我可以做一个 switch 语句,然后这样做 :
switch (input)
case "a | A"
....
case "b | B "
....
但是我有一个 27+ 长的 switch 语句,所以我想这不是很好?
我正在考虑制作一个包含所有摩尔斯电码的数组,但我如何实现这个概念,即数组的第一个条目等于 a 或 A,...?
如果我们假设您的平台使用字符编码系统,其中 26 个拉丁字母具有连续值(最常用的系统 ASCII 有,但不是 由 C 标准保证),那么我们可以为每个字母的摩尔斯电码定义一个字符串数组,并使用给定字母的值减去 'A'
的值对该数组进行索引。
我们也可以对数字做类似的事情(标准保证具有连续的代码)。
这是一个示例代码(我们在索引到 Morse 数组之前将所有字母转换为大写):
#include <stdio.h>
#include <ctype.h>
int main()
{
const char* Alpha[26] = {
".-", // 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
};
const char* Digit[10] = {
"-----",// 0
".----",// 1
"..---",// 2
"...--",// 3
"....-",// 4
".....",// 5
"-....",// 6
"--...",// 7
"---..",// 8
"----.",// 9
};
char input[256];
do {
printf("Enter text ($ to quit): ");
scanf("%255s", input);
printf("Morse code...\n");
for (char *c = input; *c; ++c) {
if (isalpha(*c)) printf("%s", Alpha[toupper(*c) - 'A']);
else if (isdigit(*c)) printf("%s", Digit[*c - '0']);
else if (*c != '$') printf("<error>");
printf("\n");
}
} while (input[0] != '$');
return 0;
}
如果我们不能依赖字母的连续代码(或者选择不依赖,以获得更稳健的实现),我们可以通过调用 strchr
函数来确定索引(然后我们必须 #include <string.h>
) 获取我们的字母在所有字母列表中的位置:
//...
const char* Letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
//...
if (isalpha(*c)) printf("%s", Alpha[strchr(Letters,toupper(*c)) - Letters]);
如有任何进一步的说明,请随时提出要求and/or。
@Adrian 的替代方案,只需对大部分 ASCII 字符集进行编码 - 从 space (32) 到大写 Z (91)。你会得到数字、字母、标点符号和亲号,有些我们不关心,但谁在乎,因为它简化了事情so。您使用的是 8 位微控制器,因此您不必担心字符编码和 OS 首选项以及所有这些垃圾。
此外,跳过字符串。它们只会占用您有限的 RAM 中的空间,除非您对 Arduino 使用 F("asd")
技巧将它们放入闪存中。不使用字符串,而是使用 1 和 0:0b0110000
从左到右读取以获得点、破折号、标记停止位,然后是填充零。看起来很讨厌,但实际上不是。
这是我的...
/*
* Bit packing: read left to right from MSB, 0=dit, 1=dah,
* with extra dah terminating sentinel, then zero filled on right.
* Example,
* letter D -.. "dahdidit"
* convert 100
* terminate 1001
* pad 10010000
* result 0b10010000
* To use, test the top bit, send dit or dah, shift left, end when result is .
*/
/*
* the character codes are in ASCII order,
* from space to underscore F or 32-95 decimal.
* lower-case alpha should be coverted to upper-case before lookup
*/
const charcodes[] PROGMEM = {
0, // space
0b10101110, // ! exclamation point /KW
0b01001010, // " double quote /AF
0, // # hash mark, octothorpe
0b00010011, // $ dollar sign /SX
0, // % percent sign or /KA ?
0b01000100, // & ampersand /AS
0b01111010, // ' single quote /WG
0b10110100, // ( left parenthesis /KN
0b10110110, // ) right parenthesis /KK EOW ? EOM
0b00010110, // * asterisk /SK
0b01010100, // + plus sign
0b11001110, // , comma
0b10000110, // - dash, hyphen /DU
0b01010110, // . period
0b10010100, // / slash, divide /DN
0b11111100, // 0
0b01111100, // 1
0b00111100, // 2
0b00011100, // 3
0b00001100, // 4
0b00000100, // 5
0b10000100, // 6
0b11000100, // 7
0b11100100, // 8
0b11110100, // 9
0b11100010, // : colon /OS
0b10101010, // ; semicolon /KR
0, // < less-than sign
0b10001100, // = equal sign /BT
0, // > greater-than sign
0b00110010, // ? question mark
0b01101010, // @ commercial 'at' sign /AC
0b01100000, // A
0b10001000, // B
0b10101000, // C
0b10010000, // D
0b01000000, // E
0b00101000, // F
0b11010000, // G
0b00001000, // H
0b00100000, // I
0b01111000, // J
0b10110000, // K
0b01001000, // L
0b11100000, // M
0b10100000, // N
0b11110000, // O
0b01101000, // P
0b11011000, // Q
0b01010000, // R
0b00010000, // S
0b11000000, // T
0b00110000, // U
0b00011000, // V
0b01110000, // W
0b10011000, // X
0b10111000, // Y
0b11001000, // Z
0, // [ left bracket
0, // \ back-slash
0, // ] right bracket
0, // ^
0b00110110, // F _ underscore /IQ
};
/*
* look up the code for an ASCII character
* return 0 for bad characters and characters out of range.
*/
byte getcode(char c)
{
// convert upper-case to lower-case
if ( c >= 'a' && c <= 'z' )
c -= 'a' - 'A';
// check for characters beyond our table
if ( c < ' ' || c > '_' )
return 0;
// else read the byte from flash
return pgm_read_byte(charcodes + c - ' ');
}
我相信聪明人会发现问题,我会向他们学习。玩得开心!
编辑:他们做到了! @Clifford 指出我没有展示如何使用编码字节。所以这里是...您必须定义滴、哒、元素间隙(滴和哒之间)、字符间隙(字符之间)和单词间隙(单词之间)的值:
#define TOPBIT 0x80
void key(byte c)
{
// while we're not done, start the tone, delay a bit, stop the tone
while ( c != TOPBIT && c != 0 ) {
tone(BUZZ, FREQ);
digitalWrite(LED, 1);
delay( (c & TOPBIT) ? dahLen : ditLen );
noTone(BUZZ);
digitalWrite(LED, 0);
delay(elemGap);
// shift left one place; test the next bit the next time around
c <<= 1;
}
// now generate a character space
delay(charGap - elemGap);
}
HTH! (感谢@Clifford)