В коде Морзе наиболее часто применяются символы длиной 1-6 знаков.
; . Ee Ее Ёё
; - Tt Тт
; .. Ii Ии
; .- Aa Аа
; -. Nn Нн
; -- Mm Мм
; ... Ss Сс
; ..- Uu Уу
; .-. Rr Рр
; .-- Ww Вв
; -.. Dd Дд
; -.- Kk Кк
; --. Gg Гг
; --- Oo Оо
; .... Hh Хх
; ...- Vv Жж
; ..-. Ff Фф
; ..-- Юю
; .-.. Ll Лл
; .-.- Яя [AA] digraph UNKNOWN STATION
; .--. Pp Пп
; .--- Jj Йй
; -... Bb Бб
; -..- Xx Ьь Ъъ
; -.-. Cc Цц
; -.-- Yy Ыы
; --.. Zz Зз
; --.- Qq Щщ
; ---. Чч
; ---- Шш
; .---- 1
; ..--- 2
; ...-- 3
; ....- 4
; ..... 5
; -.... 6
; --... 7
; ---.. 8
; ----. 9
; ----- 0
; ..-.. Ээ
; ..-.- [INT] trigraph - military network question marker
; -..-. Slash/Fraction Bar [/]
; -.--. Parenthesis (Open)
; .-... [AS] digraph - Ampersand (or "Wait") [&]
; -...- [BT] digraph - Double Dash = or --
; .-.-. Plus sign [+]
; .-.-. [AR] digraph - New Page Signal
; -.-.- Starting Signal
; ...-. Understood
; .--.-. Ъъ
; .-.-.- Period [.]
; --..-- Comma [,]
; ..--.. [UD] digraph Question Mark [?]
; .----. Apostrophe [']
; -.-.-- [KW] digraph - Exclamation Point [!]
; -.--.- Parenthesis (Close)
; ---... Colon [:]
; -.-.-. Semicolon [;]
; -....- Hyphen, Minus Sign [-]
; ..--.- Underscore [_]
; .-..-. Quotation mark ["]
; .--.-. [AC] digraph - At Sign [@]
; ...-.- End of work
; ...-..- [SX] digraph - Dollar sign [$]
; ........ [HH] digraph - Error/correction
; ...---... [SOS] trigraph
Эти символы будем помещать в 8-разрядный аргумент. Байт должен содержать последовательность знаков (от 1 до 6) и их количество (также от 1 до 6). Последовательность знаков должна быть выровнена по младшему или старшему биту для удобства проталкивания во флаг переноса (Carry) командами сдвига. Получаем два варианта расположения счетчика ( c ) и последовательности ( s ) знаков:
; arg[s, x, x, x, x, c, c, c] – 1 знак
; arg[s, s, x, x, x, c, c, c] – 2 знака
; arg[s, s, s, x, x, c, c, c] – 3 знака
; arg[s, s, s, s, x, c, c, c] – 4 знака
; arg[s, s, s, s, s, c, c, c] – 5 знаков
; arg[s, s, s, s, s, s/c, c, c] – 6 знаков
; arg[c, c, c, x, x, x, x, s] – 1 знак
; arg[c, c, c, x, x, x, s, s] – 2 знака
; arg[c, c, c, x, x, s, s, s] – 3 знака
; arg[c, c, c, x, s, s, s, s] – 4 знака
; arg[c, c, c, s, s, s, s, s] – 5 знаков
; arg[c, c, c/s, s, s, s, s, s] – 6 знаков
В первом варианте при максимальной длине последовательности 6-й знак накладывается на старший бит счетчика.
Во втором варианте при максимальной длине последовательности 1-й знак накладывается на младший бит счетчика. В данном случае младший бит счетчика можно считать незначащим, так как за максимальное значение счетчика (6) можно принять обе комбинации 110 и 111. При значении счетчика 5 и меньше значащие знаки не накладывается на разряды счетчика.
Выбираем второй вариант. Называем точки нулями, тире – единицами. Так как последовательность знаков выровнена по младшему биту аргумента последовательность знаков располагаем в обратном порядке для проталкивания сдвигом вправо. Получаем кодировку аргумента:
; arg[c2, c1, c0/s6, s5, s4, s3, s2, s1]
В коде Морзе за единичный временной интервал принята длительность точки. Длительность тире – 3 интервала. Пауза между знаками внутри символа – 1 интервал. Пауза между символами – 4 интервала. Пауза между словами – 7 интервалов. Для сообщения функции, что не надо отрабатывать знаки, а только паузу введем комбинацию:
; arg[0, 0, 0, 0, 0, 0, 0, 0]
Приняв аргумент arg[c2, c1, c0/s6, s5, s4, s3, s2, s1] функция должна извлечь из него счетчик и последовательность, «отпиликать» символ и завершить его паузой длительностью 3 интервала.
Для формирования паузы между словами передаем функции аргумент arg[0, 0, 0, 0, 0, 0, 0, 0]. Функция должна в дополнение к постпаузе длительностью 3 интервала от предыдущего символа отработать паузу длительностью 4 интервала (итого 7 интервалов).
Для извлечения счетчика функция должна сдвинуть копию содержимого arg вправо на 5 битов, применить маску И(00000111), приравнять счетчик к 6 если равен 7. Далее пошаговыми сдвигами вправо извлечь знаки из оригинала arg. Если “0” – точка: 1 интервал beep, 1 интервал пауза. Если ”1” – тире: 3 интервала beep, 1 интервал пауза. После отработки последнего знака – 2 интервала пауза. Если arg=0: только пауза длительностью 4 интервала.
Даная 8-разрядная кодировка покрывает все символы и диграфы Морзе длиной от 1 до 6 знаков. Рассмотрим примеры:
; . Ee Ее Ёё arg[0, 0, 1, x, x, x, x, 0]
; - Tt Тт arg[0, 0, 1, x, x, x, x, 1]
; .. Ii Ии arg[0, 1, 0, x, x, x, 0, 0]
; .- Aa Аа arg[0, 1, 0, x, x, x, 1, 0]
; -. Nn Нн arg[0, 1, 0, x, x, x, 0, 1]
; -- Mm Мм arg[0, 1, 0, x, x, x, 1, 1]
; ... Ss Сс arg[0, 1, 1, x, x, 0, 0, 0]
; ..- Uu Уу arg[0, 1, 1, x, x, 1, 0, 0]
; .-. Rr Рр arg[0, 1, 1, x, x, 0, 1, 0]
; .-- Ww Вв arg[0, 1, 1, x, x, 1, 1, 0]
; -.. Dd Дд arg[0, 1, 1, x, x, 0, 0, 1]
; -.- Kk Кк arg[0, 1, 1, x, x, 1, 0, 1]
; --. Gg Гг arg[0, 1, 1, x, x, 0, 1, 1]
; --- Oo Оо arg[0, 1, 1, x, x, 1, 1, 1]
; .... Hh Хх arg[1, 0, 0, x, 0, 0, 0, 0]
; ...- Vv Жж arg[1, 0, 0, x, 1, 0, 0, 0]
; ..-. Ff Фф arg[1, 0, 0, x, 0, 1, 0, 0]
; ..-- Юю arg[1, 0, 0, x, 1, 1, 0, 0]
; .-.. Ll Лл arg[1, 0, 0, x, 0, 0, 1, 0]
; .-.- Яя arg[1, 0, 0, x, 1, 0, 1, 0]
; .--. Pp Пп arg[1, 0, 0, x, 0, 1, 1, 1]
; .--- Jj Йй arg[1, 0, 0, x, 1, 1, 1, 0]
; -... Bb Бб arg[1, 0, 0, x, 0, 0, 0, 1]
; -..- Xx Ьь Ъъ arg[1, 0, 0, x, 1, 0, 0, 1]
; -.-. Cc Цц arg[1, 0, 0, x, 0, 1, 0, 1]
; -.-- Yy Ыы arg[1, 0, 0, x, 1, 1, 0, 1]
; --.. Zz Зз arg[1, 0, 0, x, 0, 0, 1, 1]
; --.- Qq Щщ arg[1, 0, 0, x, 1, 0, 1, 1]
; ---. Чч arg[1, 0, 0, x, 0, 1, 1, 1]
; ---- Шш arg[1, 0, 0, x, 1, 1, 1, 1]
; .---- 1 arg[1, 0, 1, 1, 1, 1, 1, 0]
; ..--- 2 arg[1, 0, 1, 1, 1, 1, 0, 0]
; ...-- 3 arg[1, 0, 1, 1, 1, 0, 0, 0]
; ....- 4 arg[1, 0, 1, 1, 0, 0, 0, 0]
; ..... 5 arg[1, 0, 1, 0, 0, 0, 0, 0]
; -.... 6 arg[1, 0, 1, 0, 0, 0, 0, 1]
; --... 7 arg[1, 0, 1, 0, 0, 0, 1, 1]
; ---.. 8 arg[1, 0, 1, 0, 0, 1, 1, 1]
; ----. 9 arg[1, 0, 1, 0, 1, 1, 1, 1]
; ----- 0 arg[1, 0, 1, 1, 1, 1, 1, 1]
; ..-.. Ээ arg[1, 0, 1, 0, 0, 1, 0, 0]
; ..-.- [INT] arg[1, 0, 1, 1, 0, 1, 0, 0]
; -..-. [/] arg[1, 0, 1, 0, 1, 0, 0, 1]
; -.--. Parenthesis arg[1, 0, 1, 1, 0, 1, 1, 0]
; .-... [&] arg[1, 0, 1, 0, 0, 0, 1, 0]
; -...- [=] arg[1, 0, 1, 1, 0, 0, 0, 1]
; .-.-. [+] arg[1, 0, 1, 0, 1, 0, 1, 0]
; -.-.- Starting Signal arg[1, 0, 1, 1, 0, 1, 0, 1]
; ...-. Understood arg[1, 0, 1, 0, 1, 0, 0, 0]
; .--.-. Ъъ arg[1, 1, 0, 1, 0, 1, 1, 0]
; .-.-.- [.] arg[1, 1, 1, 0, 1, 0, 1, 0]
; --..-- [,] arg[1, 1, 1, 1, 0, 0, 1, 1]
; ..--.. [?] arg[1, 1, 0, 0, 1, 1, 0, 0]
; .----. ['] arg[1, 1, 0, 1, 1, 1, 1, 0]
; -.-.-- [!] arg[1, 1, 1, 1, 0, 1, 0, 1]
; -.--.- Parenthesis arg[1, 1, 1, 0, 1, 1, 0, 1]
; ---... [:] arg[1, 1, 0, 0, 0, 1, 1, 1]
; -.-.-. [;] arg[1, 1, 0, 1, 0, 1, 0, 1]
; -....- [-] arg[1, 1, 1, 0, 0, 0, 0, 1]
; ..--.- [_] arg[1, 1, 1, 0, 1, 1, 0, 0]
; .-..-. ["] arg[1, 1, 0, 1, 0, 0, 1, 0]
; .--.-. [@] arg[1, 1, 0, 1, 0, 1, 1, 0]
; ...-.- End of work arg[1, 1, 1, 0, 1, 0, 0, 0]
Если присмотреться к тому, что осталось в сухом остатке:
; ...-..- Dollar sign [$] [SX] digraph
; ........ Error/correction [HH] digraph or [EEEEEEEE]
; ...---... [SOS]
логично было бы внести дополнительную функцию void dot3woPostPause() после которой отработать [X](-..-), [5](.....) или [:](---...).
Для полноты картины рассмотрим «сложный» путь. Для отработки диграфов и триграфов Морзе длиной более 6 знаков необходимо внести дополнение в кодировку с целью отработки «лишних» знаков без межсимвольной паузы (без постпаузы длительностью 2 интервала после «лишних» знаков).
Количество «лишних» знаков от 1 до 3. Разрядность счетчика 2. Расположим счетчик в разрядах arg[4,3], а последовательность в разрядах arg[2,1,0]:
; arg[0, 0, 0, c1, c0, s3, s2, s1]
При arg[7,6,5]=000 для извлечения счетчика функция должна сдвинуть копию содержимого arg вправо на 3 бита, применить маску И(00000011). Далее пошаговыми сдвигами вправо извлечь знаки из оригинала arg. Если “0” – точка: 1 интервал beep, 1 интервал пауза. Если ”1” – тире: 3 интервала beep, 1 интервал пауза. После отработки последнего знака не добавляются какие либо дополнительные паузы.
Теперь чтобы отработать «длинный» символ надо сначала обработать знаки без постпаузы потом знаки с постпаузой. Для этого нужны два 8-разрядных аргумента. Суммарное количество знаков в аргументах должно соответствовать длине символа:
; ...-..- Dollar sign [$] [SX] digraph
; arg1[0, 0, 0, 0, 1, x, x, 0] arg2[1, 1, 1, 0, 0, 1, 0, 0]
; arg1[0, 0, 0, 1, 0, x, 0, 0] arg2[1, 0, 1, 1, 0, 0, 1, 0]
; arg1[0, 0, 0, 1, 1, 0, 0, 0] arg2[1, 0, 0, x, 1, 0, 0, 1]
;
; ........ Error/correction [HH] digraph or [EEEEEEEE]
; arg1[0, 0, 0, 1, 0, x, 0, 0] arg2[1, 1, 0, 0, 0, 0, 0, 0]
; arg1[0, 0, 0, 1, 1, 0, 0, 0] arg2[1, 0, 1, 0, 0, 0, 0, 0]
;
; ...---... [SOS]
; arg1[0, 0, 0, 1, 1, 0, 0, 0] arg2[1, 1, 0, 0, 0, 1, 1, 1]
Упаковка символов кода Морзе в 8-разрядный код может быть реализована на разных языках программирования и на разных платформах. Для Макса (любителя Щ-кодов) приготовил исходный код «рыбы» на STM8 asm.
Альтернативная 8-разрядная кодировка от пользователя «Akon32», позволяющая избавиться от второго аргумента:
; arg[0, 0, 0, 0, 0, 0, 0, 0] — [HH] + пауза длительностью 2 интервала
; arg[0, 0, 0, 0, 1, 0, 0, 1] — [$] + пауза длительностью 2 интервала
; arg[1, 0, s1, s2, s3, s4, s5, s6] — [6 знаков] + пауза длительностью 2 интервала
; arg[1, 1, 0, s1, s2, s3, s4, s5] — [5 знаков] + пауза длительностью 2 интервала
; arg[1, 1, 1, 0, s1, s2, s3, s4] — [4 знака] + пауза длительностью 2 интервала
; arg[1, 1, 1, 1, 0, s1, s2, s3] — [3 знака] + пауза длительностью 2 интервала
; arg[1, 1, 1, 1, 1, 0, s1, s2] — [2 знака] + пауза длительностью 2 интервала
; arg[1, 1, 1, 1, 1, 1, 0, s1] — [1 знак] + пауза длительностью 2 интервала
; arg[1, 1, 1, 1, 1, 1, 1, 0] — только пауза длительностью 4 интервала
; arg[1, 1, 1, 1, 1, 1, 1, 1] — [SOS] + пауза длительностью 2 интервала
; начальный счетчик цикла равен 8
; далее пошаговый сдвиг влево через Carry флаг
; старшие единицы ('1') незначащие
; наличие нуля ('0') во флаге переноса (Carry) - условие для передачи последующих знаков
; комбинации 0b00000000, 0b11111111, 0b11111110 обрабатываются вне основного цикла
В отличие от последовательности букв (напр. [S], [O], [S]) диграфы и триграфы (напр. [SOS]) отрабатываются без межбуквенных пауз.
Комментарии (15)
saboteur_kiev
25.10.2019 12:16Не очень понятен смысл такой сложности.
Вы придумали свой алгоритм, как в байте указать точки и тире в виде единиц и нулей, но из-за разного количества знаков, вам в тот же байт нужно также прописать это длину. В результате выходит сложный и неудобный алгоритм, который может не сработать на всех имеющихся знаках.
При этом всего, у вас 67 различных сигналов, а в байт можно запихнуть 256 без вообще каких-либо алгоритмов, банальной таблицей соответствий.
Какая стоит цель данного алгоритма? Сэкономить 100 байт кода? Но он получается не универсален для разных языков.
И да, выше привели алгоритм попроще, за исключением что нужно сделать отдельный сигнал для девятисимвольного SOSAstroscope
26.10.2019 20:08Тем более, что SOS это три отдельных буквы: S, O и, неожиданно, снова S. Нет никакой объективной необходимости создавать отдельный сигнал вместо последовательной передачи составляющих его отдельных букв.
AndreyHenneberg
28.10.2019 01:58+1SOS — не три буквы, а триграф: между «буквами» нет пауз, они передаются такой длинной «буквой». То же самое и с другими ди- и триграфами.
saboteur_kiev
28.10.2019 18:48Смысл есть в ускорении передачи. Не забывайте, что морзянка использовалась, когда скорость была даже не 300 бод, а гораздо, гораздо медленнее — 1-2 символа в секунду.
Также в морзянке были отдельные «буквы» для «конец связи» и «ошибка передачи»Astroscope
28.10.2019 19:19Конец связи — SK, часто действительно передаваемые слитно, а не как положено отдельными буквами.
trapwalker
25.10.2019 12:21А тут неуникальные строчки — это так задумано?
".-.-." : "+", # Plus sign [+] ".-.-." : ("[AR]", "digraph - New Page Signal"), ".--.-." : " Ъъ", ".--.-." : "@", # [AC] digraph - At Sign [@]
Astroscope
26.10.2019 20:15+1У меня, наверное, профдеформация, но в реальной практике использования телеграфа нужны только буквы стандартной латиницы, цифры, дробь и единственный знак вопроса. Даже точка и запятая редкость. Это не значит, что они не нужны в принципе, но значит, что с поправкой на специфику использования (которая мне не вполне понятна из статьи) малоиспользуемые знаки может быть можно исключить, если этим достигается упрощение программы или устройства, на котором эта программа будет работать.
AndreyHenneberg
28.10.2019 02:18+1trapwalker, похоже прав: коды не совпадают с "эталоном". На сам принцип не влияет, но… Царапает, в общем.
Akon32
А почему для записи длины не использовали унарный код? Так можно вместить от 0 до 7 знаков.
trapwalker
А если учесть, что 7-знаковый код всего один, можно один бит вообще зарезервировать под индикатор служебного кода. Так все 6-знаки кодируются вашим способом, а если служебный бит "1", то все остальные кодируют 7-битовый служебный код.
Среди них можно разместить много полезного:
Rsa97
Ещё один вариант — кодировать необходимость паузы в последнем бите. Тогда получим
111110X1 - 1 знак
...
0XXXXXX1 - 6 знаков
0XXXXXX0 111110X1 - 7 знаков
...
0XXXXXX0 0XXXXXX1 - 12 знаков
trapwalker
О, да, так ещё лучше. Если не нужны служебные управляющие коды, то вообще идеально
Rsa97
Признаком начала служебного кода может быть байт, в котором только единицы. При таком кодировании он как обычный символ возникнуть не может.
Или же можно использовать комбинацию 111111YY, если хватит четырёх служебных кодов.
Или даже так, с двумя специальными комбинацияами:
1111110X - 1 знак
...
0XXXXXXX - 7 знаков
11111110 - Error/correction [HH]
11111111 - [SOS]
Служебных кодов не будет, но все стандартные символы умещаются в один байт, требуется только обработка двух специальных случаев.
ovsp Автор
Благодарю за комментарий. Разрешите развить:
00000000 — [HH] + пауза длительностью 2 интервала
00001001 — [$] + пауза длительностью 2 интервала
10XXXXXX — [6 знаков] + пауза длительностью 2 интервала
…
111110XX — [2 знака] + пауза длительностью 2 интервала
1111110X — [1 знак] + пауза длительностью 2 интервала
11111110 — только пауза длительностью 4 интервала
11111111 — [SOS] + пауза длительностью 2 интервала
начальный счетчик цикла равен 8
далее пошаговый сдвиг влево через Carry флаг
комбинации 00000000, 11111111, 11111110 обрабатываются вне основного цикла
AndreyHenneberg
Мне кажется, что, просто ради систематизации, лучше вынести все «неформатные» символы, которые обрабатываются отдельно, в группу, начинающуюся с 0. Тогда первые три будут [SOS], [$] и [HH], а остальное… Ну да, можно использовать для управления «терминалом», как предложили выше. Не уверен, зачем такое может понадобиться, но всё таки.