有没有办法在数组中实现摩尔斯电码?

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)