[Перевод] Собираем свой AM-передатчик кода Морзе

image-loader.svg


Это проект по сборке простого маломощного AM-передатчика кода Морзе, позволяющего передавать и принимать сообщения на любом транзисторном радиоприемнике в среднеполосном диапазоне. Этого диапазона вполне достаточно для передачи между комнатами в доме, и при этом нет риска пересечься с каналом радиовещания.

Передатчик можно использовать для ручной отправки сообщений, вводя их при помощи кнопки или ключа Морзе. Вторая кнопка автоматически отправляет предопределенное сообщение, что может пригодиться для отработки навыка понимания кода.

Введение


Сын моего друга недавно заинтересовался кодом Морзе, что подтолкнуло меня собрать это устройство в подспорье его изучению и экспериментированию с отправкой сообщений.
Возможности у передатчика получились следующие:

  • Он позволяет телеграфировать код Морзе вручную, используя нажимную кнопку. При этом можно отслеживать его на светодиодном дисплее или слышать через пьезодинамик.
  • Если подключить к нему метровый кабель в качестве антенны, он сможет передавать код находящемуся неподалеку транзисторному АМ-радиоприемнику, позволяя двум людям обмениваться секретными, находясь в разных комнатах одного дома.
  • Он также способен воспроизводить или передавать предопределенное сообщение, что можно использовать для лучшего понимания кода Морзе и наработки скорости его ввода.


Построено устройство на базе ATtiny85 с минимумом дополнительных компонентов и является простым как в настройке, так и в использовании.

Код Морзе уже не актуален для удаленной связи, но навык его использования может пригодиться для случаев, когда технологические решения окажутся недоступны. К примеру, используя этот код, вы можете просигнализировать с помощью факела или кусочка зеркала, находясь на вершине горы, где сотовая связь недоступна.

Код Морзе


В кодировке Морзе используется последовательность коротких и длинных сигналов, кодирующих буквы от A до Z, цифры от 0 до 9 и несколько знаков препинания. Таким образом сообщения могут посредством звука или света передаваться между двух людей, которые этот код знают. Чтобы придерживаться максимально коротких сообщений для самых распространенных букв английского алфавита определена краткая кодировка. Для редких же букв, наоборот:

image-loader.svg

Последовательности азбуки Морзе для букв и цифр

Продолжительность сигналов:


Опытным путем я понял, что проще всего заучить буквы с помощью визуализации приведенной ниже схемы, где каждая левая ветвь представляет точку, а каждая правая тире:

image-loader.svg

Схематичное представление последовательностей кода Морзе для букв от A до Z

Передача кода Морзе


Традиционно код Морзе передается при помощи техники, известной как «незатухающая волна», или CW. Точки и тире отправляются посредством подачи импульсов несущей частоты. На стандартном AM-передатчике присутствие несущей частоты можно обнаружить только путем настройки на эту частоту с последующей регистрацией провалов в фоновом шуме. Чтобы сделать код Морзе более отчетливым, радиолюбители встраивают в приемники генератор биений (BFO) с частотой близкой к несущей, в результате чего при ее присутствии возникает слышимый сигнал.

Поскольку домашние транзисторные AM-радиоприемники не имеют генератора биений, данный простой передатчик Морзе модулирует несущую частоту так, чтобы она генерировала слышимый тон. Вот образец графика такой амплитудно-модулированной несущей частоты1:

image-loader.svg


Схема


А вот схема самого передатчика:

image-loader.svg


Я взял ATtiny85, но программа также вполне подойдет и для ATtiny45 или ATtiny25.

Длина антенны должна совпадать с длиной кабеля и иметь длину до одного метра. Один конец подключаем к PB1, второй оставляем неподключенным. Кабель при этом вывешивается примерно вертикально.

Если передавать код на радиоприемник вы не планируете, то антенну можно не делать, а обойтись просто пьезодинамиком2.

Использование АМ-передатчика


Для ручной генерации кода нажмите кнопку Keyer. Если у вас есть профессиональный ключ Морзе, то можете подключить его параллельно с этой кнопкой. Я использовал NanoKey от Phoenix Kits3.

Для генерации предопределенного в программе сообщения нажмите Auto. Чтобы прервать сообщение и вернуться в ручной режим, нажмите Keyer.

Можете заменить это сообщение любым желаемым, лишь бы оно вмещалось в память. Хранится оно в программной памяти ATtiny85, значит всего вам доступно около 7000 символов.

Программа


Выполнение всего тайминга и генерацию сигналов программа реализует через два таймера/счетчика ATtiny85 и сторожевой таймер, которые настраиваются в setup() следующим образом:

Таймер/Счетчик1


На ATtiny85 вы можете тактировать Таймер/Счетчик1 из системы ФАПЧ, которая из внутренних 8МГц генерирует 32МГц. Эта величина в OCR1C делится на 28, генерируя сигнал, используемый для активации вывода на антенну, PB1:

  // Настройка Таймера/Счетчика1 на генерацию 552кГц
  PLLCSR = 1<


Несущая частота:

f = 
 
320000002 × (28 + 1)
 
 = 552kHz


Эта частота находится в среднеполосном диапазоне АМ, который простирается от 530кГц до 1600кГц, значит для получения кода Морзе приемник нужно просто настроить на эту частоту.

Точность тактов процессора ATtiny85 колеблется на ±10%, поэтому по факту несущая частота может оказаться несколько смещенной относительно указанной, и вам придется подстроить радио, пока в эфире не раздадутся гудки. Приведенная далее таблица показывает номинальные частоты, которые получатся для заданных значений OCR1C:


Выбирайте такую, которая соответствует свободному сегменту диапазона без транслирующих станций.

Таймер/Счетчик0


Таймер/Счетчик0 используется для генерации слышимой частоты в районе 644Гц4:

  // Настройка Таймера/Счетчика0 на 644Гц
  TCCR0A = 1<


Таймер/Счетчик0 активирует вывод PB0 для управления пьезодинамиком. Помимо этого, он служит для генерации прерываний. Процедура обработки прерываний включает/отключает тактирование Таймера/Счетчика1. Это ведет к появлению/исчезновению несущей частоты, что в качестве простой формы амплитудной модуляции делает точки и тире слышимыми на радиоприемнике в виде гудков:

// Прерывание модулирует несущую частоту 644Гц
ISR (TIMER0_COMPA_vect) {
  TCCR1 = TCCR1 ^ 1<


В периоды тишины передается чистая несущая частота.

Сторожевой таймер


При автоматической генерации кода Морзе программа использует сторожевой таймер, генерируя прерывание 32Гц, которое служит для отсчета продолжительности точек, тире и интервалов:

  // Устанавливаем сторожевой таймер на прерывание 32Гц для таймера тиков
  WDTCR = 1<


Обработчик прерываний просто инкрементирует глобальный счетчик тиков, Ticks:

// Прерывание, генерируемое сторожевым таймером, отсчитывает тики (1/32сек)
ISR (WDT_vect) {
  WDTCR |= 1<


Прерывание автоматически восстанавливает сторожевой таймер, приводя к сбросу перед очередным прерыванием. Чтобы избежать этого, обработчик устанавливает бит прерывания до его следующего срабатывания:

  WDTCR |= 1<


Сторожевой таймер используется процедурой Wait(), которая ожидает заданное число тиков:

// Таймер тиков
void Wait (int units) {
  NextTick = NextTick + units * Dot;
  unsigned int t;
  do {
    cli(); t = Ticks; sei();
  } while (t < NextTick);
}


Обратите внимание, что на время считывания переменной Ticks прерывания отключены, чтобы исключить ее возможное обновление ими.

Общая скорость определяется константой Dot, которая указывает длительность точки в 1/32-х долях секунды. Изначально Dot установлена на 6, определяя скорость около 5 слов в минуту (WPM). Такая скорость достаточно невелика, чтобы можно было записывать буквы после их считывания. К тому же, именно такое ее значение использовалось на квалификационном экзамене радиолюбителей5. Для увеличения скорости уменьшите значение переменной Dot.

Генерация гудка


Процедура Beep() активирует/отключает генерацию гудка:

void Beep (bool on) {
  if (on) {
    digitalWrite(Lamp, HIGH);             // светодиод включен
    TCCR0B = 0<


Если параметр истинен, светодиод загорается и активируется тактирование Таймера/Счетчика0.

Если параметр ложен, светодиод тухнет и тактирование Таймера/Счетчика0 прекращается. Процедура также активирует тактирование Таймера/Счетчика1, потому что обработчик прерываний Таймера/Счетчика0 может оставить его отключенным.

Автоматическая генерация кода Морзе


Нажатие кнопки Auto приводит к генерации кода для строки Message[]:

const char Message[] PROGMEM = "The quick brown fox jumps over the lazy dog.  ";


Директива PROGMEM сохраняет сообщение во флэш памяти.

Кодирование букв от A до Z, цифр от 0 до 9 и выбор знаков препинания в программе реализуется с помощью таблицы соответствий Chars[], где представлены коды для точек и тире:

uint8_t Chars[42] = {
//A           B           C           D           E           F
  0b01100000, 0b10001000, 0b10101000, 0b10010000, 0b01000000, 0b00101000,
//G           H           I           J           K           L
  0b11010000, 0b00001000, 0b00100000, 0b01111000, 0b10110000, 0b01001000,
//M           N           O           P           Q           R
  0b11100000, 0b10100000, 0b11110000, 0b01101000, 0b11011000, 0b01010000,
//S           T           U           V           W           X
  0b00010000, 0b11000000, 0b00110000, 0b00011000, 0b01110000, 0b10011000,
//Y           Z           0           1           2           3
  0b10111000, 0b11001000, 0b11111100, 0b01111100, 0b00111100, 0b00011100,
//4           5           6           7           8           9
  0b00001100, 0b00000100, 0b10000100, 0b11000100, 0b11100100, 0b11110100,
//+           ,           -           .           ?           !
  0b01010100, 0b11001110, 0b10001100, 0b01010110, 0b00110010, 0b10101110,
};


Каждый восьмибитный код состоит из 0-й для точки и 1-ц для тире, которые сопровождаются завершающей 1, указывающей конец последовательности. Оставшиеся биты заполняются нулями.

Процедура Letter() получает символ ASCII, преобразует его в верный индекс из таблицы соответствий Chars[], после чего через вызов DotDash() выводит результат в виде последовательности точек и тире :

void Letter (char letter) {
  uint8_t index;
  letter = letter | 0x20;                 // Преобразует буквы в нижний регистр
  if (letter == ' ') { Wait(4); return; }
  if (letter >= '0' && letter <= '9') index = letter - '0' + 26;
  else if (letter >= 'a' && letter <= 'z') index = letter - 'a';
  else if (letter >= '+' && letter <= '.') index = letter - '+' + 36;
  else if (letter = '?') index = 38;
  else if (letter = '!') index = 39;
  else return;
  uint8_t code = Chars[index];
  while (code != 0x80) {
    DotDash(code & 0x80);
    code = code<<1;
  }
  Wait(2);
}


Процедура DotDash():

void DotDash (bool dash) {
  Beep(true);
  if (dash) Wait(3); else Wait(1);
  Beep(false);
  Wait(1);
}


DotDash() добавляет пробел продолжительностью в одну единицу времени после каждой точки или тире. Letter() при определении разрыва между символами и словами этот пробел учитывает.

Основная программа


Основная программа циклически проверяет нажатие любой из кнопок:

void loop() {
  // Manual mode
  if (digitalRead(Keyer) == 0) Beep(true);
  else Beep(false);
  // Auto mode
  if (digitalRead(Auto) == 0) {
    int p = 0; char c;
    do {
      char c = pgm_read_byte(&Message[p++]);
      if (c == 0 || digitalRead(Keyer) == 0) break;
      Letter(c);
    } while (true);
  } 
}


Кнопка Keyer при отжатии отправляет гудок. Кнопка Auto передает предопределенное сообщение. При этом также можно нажать Keyer, чтобы прервать отправку сообщения и вернуться к ручному вводу.

Компиляция программы


Для компиляции используйте ATTiny Core от Spence Konde6. Во вкладке ATtinyCore выберите опцию ATtiny25/45/85 (No bootloader), ведущую в меню Board. Убедитесь, что опции выставлены как указано ниже (прочие игнорируйте):

Chip: «ATtiny85»
Clock:»8 MHz (internal)»

Выберите Burn Bootloader для установки фьюз-битов в соответствии с этим вариантом частоты. Затем загрузите программу, используя ISP (внутрисхемное программирование). Я использовал программатор Tiny AVR от Sparkfun. Подробнее о нем можете почитать в статье ATtiny-Based Beginner’s Kit.

Листинг программы


Вся программа для AM-передатчика кода Морзе лежит здесь: AM Morse-Code Transmitter Program.

Сноски


1. Этот график был сделан при помощи BitScope Micro BS05 Oscilloscope, который можно заказать на Pimoroni в UK.
2. Piezo Buzzer на сайте Adafruit.
3. The NanoKey на сайте PhoenixKitsonline.co.uk.
4. Это близко к 641Гц, частоте, используемой армией США для обучения работе с азбукой Морзе.
5. Традиционно величина WPM измеряется таймингом слов PARIS CODEX.
6. ATTinyCore на GitHub.

image-loader.svg

© Habrahabr.ru