Радиолюбительский Маяк на arduino nano

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

ua6em, кста, если убрать автоповтор, можно получить автоматический ключ.  Набрал в сериале то, что хочешь передать, нажимаешь ентер да наливаешь себе, пока оно там само отстукиваеца. 

Green
Offline
Зарегистрирован: 01.10.2015

Только не ключ, а клавиатурный датчик кода Морзе.)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Green пишет:

ua6em, а я всё хотел спросить. Вот ваш маяк, подключили вы его к своему ТХ. Как я понимаю, сами при этом работать не можете - ведь маяк за вас работает... Или есть какие то иные правила?

маяк работает на своих частотах, я на общепринятых

Samid777
Offline
Зарегистрирован: 24.04.2019

Хорошо работает такой маяк, на 8 мГц проверил, правда частота на 20 килогерц ниже. За 20 км можно принять на трансивер с хорошей антенной, на Sметре ничего, на слух принимается. При том что антенна 2 метра провода. Через пару комнат ловил 3 гармонику на SDR приемник, на кусок провода. У меня трансивер есть только на 2м, не попадает его диапазон ни в одну из гармоник, частоту кварца бы на 20 КГц больше, поймал думаю бы. Усилитель к нему бы еще, для КВ маяк на 10 ватт это норма, для УКВ и ватта за глаза хватит. 
Одно но получается... Не получится с ардуино задавать любую частоту. Максимум 16 мегагерц, следующая будет 8.. но чем ниже, тем больше возможных делителей. 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Samid777 пишет:

Хорошо работает такой маяк, на 8 мГц проверил, правда частота на 20 килогерц ниже. За 20 км можно принять на трансивер с хорошей антенной, на Sметре ничего, на слух принимается. При том что антенна 2 метра провода. Через пару комнат ловил 3 гармонику на SDR приемник, на кусок провода. У меня трансивер есть только на 2м, не попадает его диапазон ни в одну из гармоник, частоту кварца бы на 20 КГц больше, поймал думаю бы. Усилитель к нему бы еще, для КВ маяк на 10 ватт это норма, для УКВ и ватта за глаза хватит. 
Одно но получается... Не получится с ардуино задавать любую частоту. Максимум 16 мегагерц, следующая будет 8.. но чем ниже, тем больше возможных делителей. 

у меня на нано от рободина нормальный кварц, 144 слышно на ура, а вот 430 уже нет
Задавать получится, я жеж всё это дело к SI модулю прикручивать далее буду, у него три выхода частоты, так что маячок на 144/430/1200 должен получится

Samid777
Offline
Зарегистрирован: 24.04.2019

С сишкой конечно получится. Но ардуинко перестанет быть генератором, она будет управлять сишкой. 
У меня не слышно на двойке потому, что начальная частота трансивера 144 ровно, а частота моего генератора будет на 360 килогерц ниже. Следующая частота примерно 152, но я уже не слышу на трансивере выше 149. Так услышал бы. 
На 430 можно было бы услышать, несколько укоротив импульс. Думаю получилось бы, если выход ардуино подключить к входу элементу ксор, к одному напрямую, к другому через 4 инвертора. А потом это все на умножитель. Но думаю не стоит такой огород городить.
На свой трансивер я ловил гармоники, кварц на 3.5 мгц примерно, гормоники в районе сороковой, с уровнем 5/9!! Чем понлавилось, очень чистый сигнал. 

negavoid
Offline
Зарегистрирован: 09.07.2016

А, смотрю, понравилось :) Вот вам ещё, простой св-кв маячок.

/*
The 16 MHz clock is divided by 10 (that is, 1.6 MHz) and that is used to toggle pin 9 at that rate,
giving a frequency of 800 KHz, since one toggle turns the output on, and second toggle turns it off.

If you hold the Arduino near an AM radio tuned to around 800 KHz you should hear a hissing toggling on
and off (like Morse code) as the carrier is turned on and off for 0.5 / 0.3 second intervals.
*/

const byte ANTENNA = 9;

void setup()
{
  // set up Timer 1
  TCCR1A = bit (COM1A0);               // toggle OC1A on Compare Match
  TCCR1B = bit (WGM12) | bit (CS10);   // CTC, no prescaler
  OCR1A =  9;                          // compare A register value to 10 (zero relative)
}

void loop()
{
  pinMode (ANTENNA, OUTPUT);
  delay (500);
  pinMode (ANTENNA, INPUT);
  delay (300);
}

/*
The OCR1A variable is related to the frequency.
The OCR1A variable is one less than the actual divisor.
OCR1A - Frequency
15 - 500 khz
14 - ~530 khz
13 - ~570 khz
12 - ~610 khz
11 - ~670 khz
10 - ~730 khz
9 - 800 khz
8 - ~890 khz
7 - 1000 khz
6 - ~1140 khz
5 - ~1330 khz
4 - 1600 khz
3 - 2000 khz
2 - ~2670 khz
1 - 4000 khz
0 - 8000 khz *would not recommend this setting

The formula is (16÷(OCR1A+1)÷2)×1000 = frequency in khz
*/

 

Samid777
Offline
Зарегистрирован: 24.04.2019

Сейчас на 8 мегагерц оставил работать, а после выходных попробую. 

Green
Offline
Зарегистрирован: 01.10.2015

ua6em пишет:

Green пишет:

ua6em, а я всё хотел спросить. Вот ваш маяк, подключили вы его к своему ТХ. Как я понимаю, сами при этом работать не можете - ведь маяк за вас работает... Или есть какие то иные правила?

маяк работает на своих частотах, я на общепринятых

И что? Вы можете членораздельно людям объяснить что к чему? И не так, что бы было понятно только вам самому.

Samid777
Offline
Зарегистрирован: 24.04.2019

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

Green
Offline
Зарегистрирован: 01.10.2015

ОК, допустим есть разделение по диапазонам. Но ведь маяк это передатчик. А передатчик должен быть за кем то зарегистрирован, кому то принадлежать. И если он принадлежит мне, то как я могу работать параллельно на другой частоте с этим же позывным? Вот на это я хотел получить объяснение. Я 100 лет не связан с КВ, поэтому не знаю сегодняшней ситуации, поэтому и вопросы.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Green пишет:

ОК, допустим есть разделение по диапазонам. Но ведь маяк это передатчик. А передатчик должен быть за кем то зарегистрирован, кому то принадлежать. И если он принадлежит мне, то как я могу работать параллельно на другой частоте с этим же позывным? Вот на это я хотел получить объяснение. Я 100 лет не связан с КВ, поэтому не знаю сегодняшней ситуации, поэтому и вопросы.

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

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

Green
Offline
Зарегистрирован: 01.10.2015

Во блин, всё течёт, всё меняется! Могли и раньше, и на всех диапазонах.)) Примерно идея понятна. Спасибо.)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

DetSimen пишет:

ua6em, кста, если убрать автоповтор, можно получить автоматический ключ.  Набрал в сериале то, что хочешь передать, нажимаешь ентер да наливаешь себе, пока оно там само отстукиваеца. 

а самопрослушивание? )))
 

#define toneFreq (800) //частота звука (выбирайте между 600 - 1000Гц)
static uint8_t TXPin = 13;  // пин передаччика
int tonePin = A4;    // выход звука на радиостанцию

void TXOnOff(const bool On) {  // передаччик вкл/выкл
	digitalWrite(TXPin, On);
  if(On) {tone(tonePin, toneFreq);}else{ noTone(tonePin);}
}

 

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

Активный бузер весьма пригодица для самопрослушивания

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

DetSimen пишет:

Активный бузер весьма пригодица для самопрослушивания

выдернул с компьютера, там пассивный

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

 DOT_TIME = от 25 до 100 будет достаточно, резистора тут под руками нет, попытать )))

Samid777
Offline
Зарегистрирован: 24.04.2019

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

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

ua6em пишет:

выдернул с компьютера, там пассивный

100р за 10 шт у китайцев.  ссылку дать?

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Samid777 пишет:

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

в кварце...тем более что в дуине у тебя и не кварц вовсе )))
Кварцы они в дуинах от рободына... у меня в WAVGAT такой же, и тоже частота ниже получается...
Я о вводе регулировки скорости в скетч от DetSimen, задумка есть куда применить его код и, это не Маяк

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

DetSimen пишет:

ua6em пишет:

выдернул с компьютера, там пассивный

100р за 10 шт у китайцев.  ссылку дать?

не, у меня этих системников )))
В генераторе для катушки Мишина как раз пассивный используется, у приятеля их есть, но это паяться надо, а тут прям с проводками и пецалками для подключения

Да, собрал твой скетч всё с библиотеками в одну папку, так понимать проще... кое-что поправить правда пришлось, чтобы компилировалось

Да! на таймерах скорость регулируется правильно, строго пропорционально от константы...

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

negavoid пишет:

А, смотрю, понравилось :) Вот вам ещё, простой св-кв маячок.

/*
The 16 MHz clock is divided by 10 (that is, 1.6 MHz) and that is used to toggle pin 9 at that rate,
giving a frequency of 800 KHz, since one toggle turns the output on, and second toggle turns it off.

If you hold the Arduino near an AM radio tuned to around 800 KHz you should hear a hissing toggling on
and off (like Morse code) as the carrier is turned on and off for 0.5 / 0.3 second intervals.
*/

const byte ANTENNA = 9;

void setup()
{
  // set up Timer 1
  TCCR1A = bit (COM1A0);               // toggle OC1A on Compare Match
  TCCR1B = bit (WGM12) | bit (CS10);   // CTC, no prescaler
  OCR1A =  9;                          // compare A register value to 10 (zero relative)
}

void loop()
{
  pinMode (ANTENNA, OUTPUT);
  delay (500);
  pinMode (ANTENNA, INPUT);
  delay (300);
}

/*
The OCR1A variable is related to the frequency.
The OCR1A variable is one less than the actual divisor.
OCR1A - Frequency
15 - 500 khz
14 - ~530 khz
13 - ~570 khz
12 - ~610 khz
11 - ~670 khz
10 - ~730 khz
9 - 800 khz
8 - ~890 khz
7 - 1000 khz
6 - ~1140 khz
5 - ~1330 khz
4 - 1600 khz
3 - 2000 khz
2 - ~2670 khz
1 - 4000 khz
0 - 8000 khz *would not recommend this setting

The formula is (16÷(OCR1A+1)÷2)×1000 = frequency in khz
*/

 

выставить 1 мегагерц поставить каскад умножения с катушечкой на 7 мегагерц м как раз в любительскои диапазоне

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

ua6em пишет:

кое-что поправить правда пришлось, чтобы компилировалось

Абисни

ua6em пишет:

Да! на таймерах скорость регулируется правильно, строго пропорционально от константы...

Хто бы мог подумать, ага? 

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

Хотя, нет.  Я до понедельника сиравно в синей яме, боюсь, что на полноценный диалог меня не хватит.  Лучше в понедельник

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

DetSimen пишет:

ua6em пишет:

кое-что поправить правда пришлось, чтобы компилировалось

Абисни

ua6em пишет:

Да! на таймерах скорость регулируется правильно, строго пропорционально от константы...

Хто бы мог подумать, ага? 

я точно так думал, когда ты предложил сделать на таймерах и я не отказался )))

да всё не помню, мелкие огрехи типа <> такие кавычки на "" такие и еще что-то по мелочи, теперь твой скетч смотрится так

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

странна, а у меня компилируеца и нигде таких "<>" кавычков нет.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

DetSimen пишет:

странна, а у меня компилируеца и нигде таких "<>" кавычков нет.

 и даже в файле Messages.cpp? )))
видимо у меня барабашка IDE изучает

зы я то в чистой IDE всё пробую, без библиотек

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

А. Понял, ты про #include <>.  Да, есть, поправил

Green
Offline
Зарегистрирован: 01.10.2015

ua6em пишет:

выставить 1 мегагерц поставить каскад умножения с катушечкой на 7 мегагерц м как раз в любительскои диапазоне


Делается проще - в саму Ардуину ставим кварц на 14 и получаем частоты кратные любительским диапазонам.

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

DetSimen пишет:

А. Понял, ты про #include <>.  Да, есть, поправил

каоче, пофиг, главна, чтоб работало.  Если спросишь, расскажу как другие операции, например, опрос даччиков или верчение моторами или реле встроить в эту карикатуру, ничего не сломав.   Или ты сам мальчик башой, догадаешьса? 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

DetSimen пишет:

DetSimen пишет:

А. Понял, ты про #include <>.  Да, есть, поправил

каоче, пофиг, главна, чтоб работало.  Если спросишь, расскажу как другие операции, например, опрос даччиков или верчение моторами или реле встроить в эту карикатуру, ничего не сломав.   Или ты сам мальчик башой, догадаешьса? 

для начала может энкодер прикрутим?

Сам, это наврядли )))

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

ua6em пишет:

для начала может энкодер прикрутим?

Нахуа тама энкодер?  Если скорость менять - простой потанцометр справица. 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

DetSimen пишет:

ua6em пишет:

для начала может энкодер прикрутим?

Нахуа тама энкодер?  Если скорость менять - простой потанцометр справица. 

да некошерно, энкодером же скорость можно наращивать кратно 5, с потенциометром, плавно

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

тебе рассказать, как из плавного интервала сделать дискретный с шагом 5? 

Samid777
Offline
Зарегистрирован: 24.04.2019

А энкодер идея хорошоя, но шаг то может быть любой, хоть 1*10^-15, да и нажатием на кнопку (самого же энкодера) можно поменять будет. В ардуино если не ошибаюсь керамический резонатор. Лежит у меня плата от старого кенвуда, на 430, вот в нем вроде или ГУН, или образцовый генератор на 14 мегагерц. Еще лучше чем у обычного кварца дочность должна быть... Если на выходе логика, то можно внешнее тактирование делать. Но по идее мы должны фузы поменять, иначе все делей или мились будут работать медленнее. 
Если это ГУН, то конечно им ничего не потактирвоать, или получится плата с плавно изменяемой частотой. 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

DetSimen пишет:

тебе рассказать, как из плавного интервала сделать дискретный с шагом 5? 

подскажи, я не сталкивался с такой задачей

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

от скольки до скольки скорость меняется?

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

DetSimen пишет:

от скольки до скольки скорость меняется?

в твоих тугриках от 100 до 20 будет за глаза

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

Миллисекунд? С интервалом 5?

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

DetSimen пишет:

Миллисекунд? С интервалом 5?

да, я так понял процедуру инициализации таймеров эти данными надо делать?

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

вот матри.  В диапаносе 20-100 интервалов по 5 укладываеца 15

(100-20)/5 - 1 = 15

для расчета лучше взять 16 интервалов.  

читаем потенциометр (аналоговый порт), получаем значения от 0 до 1023.  Теперь простым делением на 64 (сдвигом на 6)  мы проецируем интервал 0-1023 на 0-15 (пусь это будет L), прикинь, да? 

при 0 у нас задержка будет 100, а при 15 - 25  если написать так: 100-(5*L) 

втуляешь полученное значение в таймер и радуешься.  При выкрученном влево резисторе, задершка будет максимальна (скорость передачи самая ниская), при полностью вкрученном, задержка самая маинькая - 25, сотвецтвенно скорость передачи самая высокая.  пропробуй.

Samid777
Offline
Зарегистрирован: 24.04.2019

Не, только все начинается. Теперь нужно вводить гистерезис, чтобы на крайних положениях не было дрожания скорости, которая может происходить слишком часто) Вот терь будет интереснее!

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

она и не будет дрожать (именно в крайних значениях). угадаешь почему?

а вот МЕЖДУ значениями - может дрожать. Решается доворотом чучуть потацометра. 

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

Вопщем, сами чонить поделайте, у мня там уже мидихлориан в морозилке застыл меня ждать.  Пора наполнить им кроффь. :)  До понедельника. 

Samid777
Offline
Зарегистрирован: 24.04.2019

DetSimen пишет:

она и не будет дрожать (именно в крайних значениях). угадаешь почему?

а вот МЕЖДУ значениями - может дрожать. Решается доворотом чучуть потацометра. 

Ну это немногоо я костноязычен. Имел ввиду на краях значений, написал на крайних, изменив смысл. Не, ну без гистерезиса все равно не очень Потому нужны небольшие участки, гне изменения бы не происходили, как раз на границе участков значений. Так что, чтобы все было попроще, надо писать свою библиотеку, под аналоговой энкодер, гистререзис в которой задавался бы при подключении библиотеки. 

Samid777
Offline
Зарегистрирован: 24.04.2019

Дубль получился.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Samid777 пишет:

DetSimen пишет:

она и не будет дрожать (именно в крайних значениях). угадаешь почему?

а вот МЕЖДУ значениями - может дрожать. Решается доворотом чучуть потацометра. 

Ну это немногоо я костноязычен. Имел ввиду на краях значений, написал на крайних, изменив смысл. Не, ну без гистерезиса все равно не очень Потому нужны небольшие участки, гне изменения бы не происходили, как раз на границе участков значений. Так что, чтобы все было попроще, надо писать свою библиотеку, под аналоговой энкодер, гистререзис в которой задавался бы при подключении библиотеки. 

ну так я это давно понял, когда только подумал про потенциометр, потому и сказал, что энкодер будет попроще

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

negavoid пишет:

А, смотрю, понравилось :) Вот вам ещё, простой св-кв маячок.

/*
The 16 MHz clock is divided by 10 (that is, 1.6 MHz) and that is used to toggle pin 9 at that rate,
giving a frequency of 800 KHz, since one toggle turns the output on, and second toggle turns it off.

If you hold the Arduino near an AM radio tuned to around 800 KHz you should hear a hissing toggling on
and off (like Morse code) as the carrier is turned on and off for 0.5 / 0.3 second intervals.
*/

const byte ANTENNA = 9;

void setup()
{
  // set up Timer 1
  TCCR1A = bit (COM1A0);               // toggle OC1A on Compare Match
  TCCR1B = bit (WGM12) | bit (CS10);   // CTC, no prescaler
  OCR1A =  9;                          // compare A register value to 10 (zero relative)
}

void loop()
{
  pinMode (ANTENNA, OUTPUT);
  delay (500);
  pinMode (ANTENNA, INPUT);
  delay (300);
}

/*
The OCR1A variable is related to the frequency.
The OCR1A variable is one less than the actual divisor.
OCR1A - Frequency
15 - 500 khz
14 - ~530 khz
13 - ~570 khz
12 - ~610 khz
11 - ~670 khz
10 - ~730 khz
9 - 800 khz
8 - ~890 khz
7 - 1000 khz
6 - ~1140 khz
5 - ~1330 khz
4 - 1600 khz
3 - 2000 khz
2 - ~2670 khz
1 - 4000 khz
0 - 8000 khz *would not recommend this setting

The formula is (16÷(OCR1A+1)÷2)×1000 = frequency in khz
*/

 

при загрузке таймеров этим кодом почему-то уровень сигнала поменьше, до S-5

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

госспади, проградуируй шкалу потанцометра на середину каждого диапаноса значений и забудь про дребезг. не будут с него значения по +-32 гулять

да как ты с такой математикой замуш то вышел? 

Samid777
Offline
Зарегистрирован: 24.04.2019

Ну как это забудь...
1- случайно попал на границу между значениями
2- ручка потенциометра прокрутилась, и все значения сместились на пол значения
3-При передаче трансивера уровень, наведенный на аналоговый пин оказался достаточным, чтобы изменить его значение.
4- При передаче изменилось напряжение питания микроконтроллера, по причине просадки напряжения, изменив значение напряжения на нужную величину.
5- На не очень новых потенциометров при вращении возможен некоторый дребезг, потому необходимо производить накопление за некоторый, относительно короткий перид вращения, являющийся делением колличества материальных точек на одно положение аналогового энкодера, т.е. резистора, на время прохождение материальной точки. Т.е. делением бесконечно малой величины на бесконечно малую.
6- Вижу еще необходимость предсказать ожидаемую величину по ускорению поворота энкодера, т.к. оно прямо пропорционально рассктоянию, на которое мы хотим повернуть ручку. Пример реализации, комьютерная мышка. 
Остальные проблемы думаю будут вытекать из этих, как раз можно решить за выходные.
 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Samid777 пишет:

 как раз можно решить за выходные.
 

Пасха на носу ...

Но для хорошо выполненной программы пяток минут и, всё пучком )))

/*
    Name:       Morze.ino
    Created:  21.04.2019 4:16:26
    Author:     DetSimen
*/

#include <EEPROM.h>
#include "Arduino.h"
#include "MorzeTable.h"
#include "TimerList.h"
#include "Messages.h"

#define toneFreq (800) //частота звука (выбирайте между 600 - 1000Гц)
static uint8_t TXPin = 13;  // пин передаччика
int tonePin = A4;    // выход звука на радиостанцию
int mySpeedPin = A0; // потенциометр скорости
int mySpeed;         // переменная для потенциометра

extern TTimerList TimerList;  // списой таймеров (до 10) паумолчанью

TMessageList MessageList(12);  // очереть на 12 сапщений

static const int msg_ReadSerial = 0x100;   // сообщение "Читать Сериал"
static const int msg_SendChar = 0x101;    // сообщение "Передать символ (букву)"
static const int msg_SendNextBit = 0x102; // сообщение "Передать следующий бит в букве"

static /*const*/ uint32_t DOT_TIME = 35;  // основное время, длительность точки 75 мс, остальные производные
static /*const*/ uint32_t DASH_TIME = 3 * DOT_TIME; // длительность тире

static const uint16_t REPEAT_TIME = 5000;  // Задержка в мс между повторениями текста, по умолчанию 5 сек. 
static const uint16_t SERIAL_TIMEOUT = 2000; // если в течение 2000 мс не было данных с сериала, значит приняли всю строку

static const uint8_t MAX_STRING_LENGTH = 128; // макс длина передаваемой строки

enum class enumTXState : bool { Pause = false, Bit = true };  

enumTXState TXState = enumTXState::Pause;  // что передаем в данный момент: или бит (точка/тире) или паузу

THandle hTXTimer = INVALID_HANDLE;       // таймер передаччика
THandle hSerialTimer = INVALID_HANDLE;  // таймер таймаута приема из Serial
THandle hRepeatTimer = INVALID_HANDLE;  // таймер повтора фразы

uint8_t TXCurrentMask = 0;   // маска текущего символа
uint8_t TXCurrentCode = 0;   // битовый код Морзе текущего символа
bool  TXBusy = false;   //  идет передача бита или паузы
bool  TXStopped = false;  //  передаччик остановлен нахрен. ничего не передаеца


String StringToTransmit;            // строка, которую будем слать 
uint16_t TransmitCharIndex = 0;   // индекс текущего символа, в этой строке


void TXOnOff(const bool On) {  // передаччик вкл/выкл
  digitalWrite(TXPin, On);
  if(On) {tone(tonePin, toneFreq);}else{ noTone(tonePin);}
}

void tmrTXTimer(void) {     // здесь кончился таймер передачи бита/паузы
  SendMessage(msg_TimerEnd, hTXTimer);
  TimerList.Stop(hTXTimer); // остановим этот таймер 
}

void tmrSerialTimer(void) {  // строку приняли до конца
  SendMessage(msg_TimerEnd, hSerialTimer);
  TimerList.Stop(hSerialTimer); // таймер больше не нужен
}

void tmrRepeat(void) {     // таймер повтора кончился, начинаем передавать сначала
  TransmitCharIndex = 0;
  TXStopped = false;          
  TimerList.Stop(hRepeatTimer);
}

void sendBit(const bool aBit) {  // передать один бит (точку == false или тире == true)

  TXState = enumTXState::Bit;  // признак: передаем бит

  TXOnOff(true);        // ключ на старт!  

  TXBusy = true;        // передаччик теперя занят

  TimerList.setNewInterval(hTXTimer, aBit ? DASH_TIME : DOT_TIME);  // длительность таймера разная для точки и тире
  TimerList.Reset(hTXTimer);  // перезапустим его сначала интервала

}

void sendPause(const uint8_t kf = 1) {  // передаем паузу длиной в 1 точку по умолчанию
  TXState = enumTXState::Pause;
  
  TXBusy = true; // передаччик занят
  
  TimerList.setNewInterval(hTXTimer, kf*DOT_TIME);  // либо длительность паузы кратна точке в kf раз
  TimerList.Reset(hTXTimer);  // перезапустим таймер сначала
}

; void setup()
{
  Serial.begin(115200);

  delay(1000); // чтоб всё устаканилось к старту

  pinMode(TXPin, OUTPUT);

  TXOnOff(false); // ключ выключен

  // все таймеры создаюца по умолчанию остановленными
  //
  hTXTimer = TimerList.AddStopped(DOT_TIME, tmrTXTimer);  // таймер передаччика бит 
  hSerialTimer = TimerList.AddStopped(SERIAL_TIMEOUT, tmrSerialTimer);  // таймер таймаута чтения из Serial  
  hRepeatTimer = TimerList.AddStopped(REPEAT_TIME, tmrRepeat);  // таймер повтора передачи строки 

  StringToTransmit.reserve(MAX_STRING_LENGTH); // хапнем сразу место под строку, чтоб не перераспределять потом
  StringToTransmit = "CQ DX UA6EM CQ DX UA6EM QSA? 73! 73! 73! K";  // строка для передачи по умолчанию
  TransmitCharIndex = 0;  
}

void loop()
{
  if (Serial.available()) {        // если в сериал чота припрыгало
    SendMessage(msg_ReadSerial);  // пошлем команду прочесть сериал
    TXStopped = true;       // передачу остановим
    TransmitCharIndex = 0;    // и все индексы и маски обнулим, 
    TXCurrentCode = 0;      // так как после приема будем передавать уже новую строку
    TXCurrentMask = 0;
  }
  // тут читаем потенциометр скорости
  mySpeed = map(analogRead(mySpeedPin), 0,1023,0,15);
  DOT_TIME = 100-mySpeed*5;
  DASH_TIME = 3 * DOT_TIME; 

  if ((not TXBusy) and (not TXStopped)) {  // если передаччик не остановлен и не занят передачей бита

    if (TXCurrentMask > 0)  // если маска еще до конца не сдвинулась
    {
      SendMessage(msg_SendNextBit); // передать следующий бит знака
    }
    else 
    {
      SendMessage(msg_SendChar); // знак кончился, начать передавать след. символ
    }
  }


  if ( not MessageList.Available()) return;   // если сапщений в очереди нет, выходим

  TMessage msg = MessageList.GetMessage();

  switch (msg.Message)
  {

  case msg_TimerEnd: {
    if (msg.LoParam == hSerialTimer) {  // кончился таймер приёма по сериал
      TXStopped = false;    // можно стартовать передаччик, есличо
      break;
    }
    if (msg.LoParam == hTXTimer) { // кончился таймер передачи бита/паузы
      TXBusy = false;     // можно передавать следующий

      if (TXState == enumTXState::Bit) { // если передавали бит, передадим 1 паузу
        TXOnOff(false);         // выключим ключ
        TXCurrentMask >>= 1;
        if (TXCurrentMask>0) sendPause(); else sendPause(3); // а если знак кончился, то 3 паузы
      }

      break;
    }

    break;
  }

  case msg_SendNextBit: {   // передаем след. бит  (точка/тире) 
    sendBit(TXCurrentCode & TXCurrentMask);
    break;
  }

  case msg_ReadSerial: {   // чтение из сериала
    if (!TimerList.isActive(hSerialTimer)) {  // если таймер таймаута остановлен 
      StringToTransmit = "";          // значить читаем новую строку
      TransmitCharIndex = 0;
    }
    StringToTransmit += char(Serial.read()); // берем символ из сериал и вклеиваем в строку
    TimerList.Reset(hSerialTimer);      // перезапускаем таймер таймаута (помнишь? 2 секунды после ПОСЛЕДНЕГО символа) 
    break;
  }

  case msg_SendChar: {    // послать знак
    if (TransmitCharIndex < StringToTransmit.length()) { // если строка еще не кончиилась
      char c = StringToTransmit[TransmitCharIndex++]; // взять символ 
      if (c != ' ') {  // если не пробел, то
        TXCurrentCode = getMorzeCode(c);        // по нему взять код Морзя  см. MorzeTable.cpp
        TXCurrentMask = getSymbolMask(getMorzeCode(c)); // и маску    см. MorzeTable.cpp
      }
      else sendPause(7);  // пробел между словами - передаем паузу в 7 точек
    }
    else {    // если строка кончилась
      TXStopped = true;     // остановим передачу
      TransmitCharIndex = 0;      // вернем указатель на 0 символ строки
      TimerList.Reset(hRepeatTimer);  // и запустим таймер для REPEAT
    }
    break;
  }
    Serial.print("Unknown message code: 0x"); Serial.println(msg.Message, HEX);
    break;
  }

}