Радиолюбительский Маяк на arduino nano
- Войдите на сайт для отправки комментариев
Чт, 18/04/2019 - 21:53
В разработке конструкция простого радиолюбительского маяка на три диапазона, планируется 144/430/1200Mhz/
За основу скетча планировался проект выполненный радиолюбителем из Италии Nicola Salsotto IN3GJH
Так как скетч был сильно раскритикован здешним сообществом с их помощью и попытаюсь реализовать.
Начиналось с этого скетча:
#define SPEED (20) //скорость в WPM #define DOTLEN (1200/SPEED) #define DASHLEN (4*(1200/SPEED)) //#define PAUSE (180000) //пауза между передачами маяка в милисекундах #define PAUSE (10000) //пауза между передачами маяка в милисекундах int txPin=10; //управление PTT int ledPin=13; //мигать встроенным светодиодом или подключить внешний на пин 13 int tonePin=5; //выход звука int toneFreq=800; //Частота звука (выбирайте между 800 - 1500Гц) unsigned long old_millis; char thePhrase[] = "UA6EM UA6EM BEACON QRA IS LN14AG LN14AG"; typedef struct { char letter; uint8_t sequence; } morseCode_t; // B11101000 // ...-S <- S - start bit morseCode_t morseCode[]= { {'A', B01100000}, {'B', B11101000}, {'C', B10101000}, {'D', B11010000}, {'E', B11000000}, {'F', B10111000}, {'G', B10010000}, {'H', B11111000}, {'I', B11100000}, {'J', B00011000}, {'K', B01010000}, {'L', B11011000}, {'M', B00100000}, {'N', B10100000}, {'O', B00010000}, {'P', B10011000}, {'Q', B01001000}, {'R', B10110000}, {'S', B11110000}, {'T', B01000000}, {'U', B01110000}, {'V', B01111000}, {'W', B00110000}, {'X', B01101000}, {'Y', B00101000}, {'Z', B11001000}, {'0', B00000100}, {'1', B00001100}, {'2', B00011100}, {'3', B00111100}, {'4', B01111100}, {'5', B11111100}, {'6', B11110100}, {'7', B11100100}, {'8', B11000100}, {'9', B10000100}, {' ', B10000000}, }; void setup() { pinMode(ledPin, OUTPUT); pinMode(txPin, OUTPUT); Serial.begin(115200); old_millis = millis(); } //*** передаём тире *** void dash() { digitalWrite(ledPin, HIGH); tone(tonePin, toneFreq); delay(DASHLEN); digitalWrite(ledPin, LOW); noTone(tonePin); delay(DOTLEN); } //*** передаём точку *** void dot() { digitalWrite(ledPin, HIGH) ; tone(tonePin, toneFreq); delay(DOTLEN); digitalWrite(ledPin, LOW); noTone(tonePin); delay(DOTLEN); } //(c) sadman41 www.arduino.ru void sendBeacon(char* _thePhrase) { while (*_thePhrase) { for(int8_t i=0; i<sizeof(thePhrase); i++) {//Serial.println(sizeof(thePhrase)); // длина определилась верно, проверить при изменении данных if (toupper(*_thePhrase) == morseCode[i].letter) { uint8_t sequenceStarted = false; for (uint8_t l = 0; l < 8; l++) { uint8_t currentBit = bitRead(morseCode[i].sequence, l); if (!sequenceStarted) { sequenceStarted = currentBit; continue; } currentBit ? dot() : dash() ; } } } if(toupper(*_thePhrase) == ' ') {Serial.println("Пробел"); delay(3*DOTLEN);} _thePhrase++; delay(2*DOTLEN); } } void loop() { if(millis() - old_millis >= PAUSE){ sendBeacon(thePhrase); old_millis = millis(); } }Далее:
Вариант 1. (с изменениями от 20.04.2019 - введен режим программирования с консольного порта, вход в режим программирования отправка с консоли "P", далее следуем инструкциям выводимым в консоль, сначала позывной, далее локатор, изменения вступают в силу сразу же, так как функция передачи маяка блокирующая, вход в режим после окончания текущего сеанса
#include <EEPROM.h> int eeAddress = 0; //EEPROM address to start reading from int eeFlag = 73; // в ячейке 73 сохраняем флаг ==73, что структура сохранялась int eeData; // сюда читаем байт из ячейки флага #define DataFlag 73 struct MyBeacon { char call_sign[20]; char loc[7]; }; MyBeacon mb = {"UA6EM", "LN14AG"}; String my_call; String my_loc; String my_null; #define SPEED (20) //скорость в WPM #define DOTLEN (1200/SPEED) #define DASHLEN (4*(1200/SPEED)) //#define PAUSE (180000) //пауза между передачами маяка в милисекундах #define PAUSE (10000) //пауза между передачами маяка в милисекундах unsigned long old_millis; unsigned long modeTime; int txPin=10; //управление PTT int ledPin=13; //мигать встроенным светодиодом или подключить внешний на пин 13 int tonePin=5; //выход звука int toneFreq=800; //Частота звука (выбирайте между 800 - 1500Гц) //char thePhrase[] = "ABCDEF GHIJK LMNOP QRSTU VWXYZ 01234 56789 .,:?\/ -()@="; const int8_t strSize; volatile char str[50]; //char thePhrase[strSize]; // B11101000 // ...-S <- S - start bit // (c) sadman41 дописал UA6EM www.arduino.ru typedef struct { char letter; uint8_t sequence; } morseCode_t; // И само наполнение структуры morseCode_t morseCode[]= { {'A', B01100000}, {'B', B11101000}, {'C', B10101000}, {'D', B11010000}, {'E', B11000000}, {'F', B10111000}, {'G', B10010000}, {'H', B11111000}, {'I', B11100000}, {'J', B00011000}, {'K', B01010000}, {'L', B11011000}, {'M', B00100000}, {'N', B10100000}, {'O', B00010000}, {'P', B10011000}, {'Q', B01001000}, {'R', B10110000}, {'S', B11110000}, {'T', B01000000}, {'U', B01110000}, {'V', B01111000}, {'W', B00110000}, {'X', B01101000}, {'Y', B00101000}, {'Z', B11001000}, {'0', B00000100}, {'1', B00001100}, {'2', B00011100}, {'3', B00111100}, {'4', B01111100}, {'5', B11111100}, {'6', B11110100}, {'7', B11100100}, {'8', B11000100}, {'9', B10000100}, {'.', B01010110}, {',', B00110010}, {':', B11000100}, {'?', B11001110}, {'-', B01111010}, {'\\', B10000110}, {'/', B10110100}, {'(', B01001010}, {')', B01001010}, {'@', B10100110}, {'=', B01110100}, {'"', B10110110}, }; //*** передаём тире *** // (c) Nicola Salsotto IN3GJH void dash() { digitalWrite(ledPin, HIGH); tone(tonePin, toneFreq); delay(DASHLEN); digitalWrite(ledPin, LOW); noTone(tonePin); delay(DOTLEN); } //*** передаём точку *** // (c) Nicola Salsotto IN3GJH void dot() { digitalWrite(ledPin, HIGH) ; tone(tonePin, toneFreq); delay(DOTLEN); digitalWrite(ledPin, LOW); noTone(tonePin); delay(DOTLEN); } // *** функция разбора и передачи строки *** // (c) ЕвгенийП www.arduino.ru // void sendMsg(char *str){ // Строка для отправки сформируется внутри, // а при выходе будет освобождена, (если не объявить глобально) // void sendMsg(MyBeacon & mbStr) { static const char middle[] = "BEACON QRA is"; // серёдка сообщения static const int8_t sizeMiddle = strlen(middle); // длина серёдки сообщения static const int8_t repeatCounter = 2; // сколько раз повторять позывной и ... тот хвост // // strSize - длина строки для отправки по sms, включая терминальный ноль. const int8_t strSize = sizeMiddle + (strlen(mbStr.call_sign) + strlen(mbStr.loc) + 2) * repeatCounter + 1; // volatile char str[strSize]; // // Заполняем строку str[0] = '\0'; for (int8_t i = 0; i < repeatCounter; i++) { strcat(str, mbStr.call_sign); strcat(str, " "); } strcat(str, middle); for (int8_t i = 0; i < repeatCounter; i++) { strcat(str, " "); strcat(str, mbStr.loc); // Собрали строку текста Маяка } } // ***** (c) brokly arduino.ru ***** void sendBeacon(char* _thePhrase) { while (*_thePhrase) { if (toupper(*_thePhrase)==' '){ delay(3*DOTLEN); } else { for(int8_t i=0;i<sizeof(morseCode)/sizeof(morseCode[0]);i++){ if (toupper(*_thePhrase) == morseCode[i].letter) { uint8_t mask=1; while(!(morseCode[i].sequence & mask)){ mask<<=1; } mask<<=1; while(mask){ (morseCode[i].sequence & mask) ? dot() : dash(); mask<<=1; } break; } } } _thePhrase++; delay(2*DOTLEN); } } // Процедура инициализации текста Маяка (с) UA6EM void initBeacon(){ // MyBeacon mb = {"UA6EaM", "LN14Ae"}; // Данные для Маяка при первом включении eeData = EEPROM.read(eeFlag); if (eeData == 73){ Serial.println(eeData); EEPROM.get(eeAddress, mb); // получить данные из EEPROM }else{ // первая запись в EEPROM EEPROM.put(eeAddress,mb); EEPROM.write(eeFlag, DataFlag); } } void setBeacon_Data(){ my_null=Serial.readString(); // Очистим буфер порта modeTime = millis(); Serial.println("Введите ваш позывной сигнал"); while(!Serial.available()> 0 && millis() - modeTime <= 10000) { } if(Serial.available()>0) { my_call = Serial.readString(); my_call.toCharArray(mb.call_sign,20); } my_call = mb.call_sign; Serial.print("Использую ваш позывной сигнал - "); Serial.println(my_call); my_null=Serial.readString(); // Очистим буфер порта modeTime = millis(); Serial.println("Введите ваш QRA локатор"); while(!Serial.available()> 0 && millis() - modeTime <= 10000) { } if(Serial.available()>0) { my_loc = Serial.readString(); my_loc.toCharArray(mb.loc,7); } my_loc = mb.loc; Serial.print("Использую QRA локатор - "); Serial.println(my_loc); EEPROM.put(eeAddress,mb); // сохраним новые данные в EEPROM EEPROM.write(eeFlag, DataFlag); initBeacon(); sendMsg(mb); } // выход из режима программирования void setup() { pinMode(ledPin, OUTPUT); pinMode(txPin, OUTPUT); Serial.begin(115200); initBeacon(); sendMsg(mb); old_millis = millis(); Serial.println("Для входа в режим программирования введите P"); } void loop() { if(millis() - old_millis >= PAUSE){ digitalWrite(txPin, HIGH); delay(900); //txdelay - задержка после нажатия PTT // sendMsg(mb); //текст маяка - проба delay(20); // sendBeacon(thePhrase); sendBeacon(str); old_millis = millis(); digitalWrite(txPin, LOW); } // Serial.println("Для входа в режим программирования введите P"); if (Serial.available()) { int inByte = Serial.read(); if(inByte == 'P'){ setBeacon_Data(); } } }Вариант 2
#include <EEPROM.h> int eeAddress = 0; //EEPROM address to start reading from int eeFlag = 73; // в ячейке 73 сохраняем флаг ==73, что структура сохранялась int eeData; // сюда читаем байт из ячейки флага #define DataFlag 73 struct MyBeacon { char call_sign[20]; char loc[7]; }; MyBeacon mb = {"UA6EM", "LN14AG"}; String my_call; String my_loc; #define SPEED (20) //скорость в WPM #define DOTLEN (1200/SPEED) #define DASHLEN (4*(1200/SPEED)) //#define PAUSE (180000) //пауза между передачами маяка в милисекундах #define PAUSE (10000) //пауза между передачами маяка в милисекундах unsigned long old_millis; int txPin=10; //управление PTT int ledPin=13; //мигать встроенным светодиодом или подключить внешний на пин 13 int tonePin=5; //выход звука int toneFreq=800; //Частота звука (выбирайте между 800 - 1500Гц) const int8_t strSize; volatile char str[50]; //ТАБЛИЦА ГЕНЕРАЦИИ БУКВЫ АЗБУКИ МОРЗЕ // '' // 0 1 2 3 4 5 6 7 8 9 // 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 // описание буквы 0-точка, 1 -тире const PROGMEM uint8_t morseCode[]={B00000000, B00000100,B00001100,B00011100,B00111100,B01111100,B11111100,B11110100,B11100100,B11000100,B10000100, B01100000,B11101000,B10101000,B11010000,B11000000,B10111000,B10010000,B11111000,B11100000,B00011000, B01010000,B11011000,B00100000,B10100000,B00010000,B10011000,B01001000,B10110000,B11110000,B01000000, B01110000,B01111000,B00110000,B01101000,B00101000,B11001000}; // секвенция по символу uint8_t getMorzeSeq(char in) { uint8_t till = 0; if (in < '0') { return 0; } else if (in <= '9') { till = in - 0x2F; // если цифра , то корректируем на 0x2F; } else if (in < 'A') { return 0; } else if (in <= 'Z') { till = in - 0x36; // заглавные буквы до Z, в нашей таблице с 11 до 37 } else if (in < 'a') { return 0; } else if (in <= 'z') { till = in - 0x56; // маленькие, передаем как заглавные буквы до z, в нашей таблице с 11 до 37 } if (till>=sizeof(morseCode)) { return 0; } return pgm_read_byte_near(morseCode+till); } //*** передаём тире *** // (c) Nicola Salsotto IN3GJH void dash() { digitalWrite(ledPin, HIGH); tone(tonePin, toneFreq); delay(DASHLEN); digitalWrite(ledPin, LOW); noTone(tonePin); delay(DOTLEN); } //*** передаём точку *** // (c) Nicola Salsotto IN3GJH void dot() { digitalWrite(ledPin, HIGH) ; tone(tonePin, toneFreq); delay(DOTLEN); digitalWrite(ledPin, LOW); noTone(tonePin); delay(DOTLEN); } // *** функция разбора и передачи строки *** // void sendMsg(char *str){ // Строка для отправки сформируется внутри, // а при выходе будет освобождена // void sendMsg(MyBeacon & mbStr) { static const char middle[] = "BEACON QRA is"; // серёдка сообщения static const int8_t sizeMiddle = strlen(middle); // длина серёдки сообщения static const int8_t repeatCounter = 2; // сколько раз повторять позывной и ... тот хвост // // strSize - длина строки для отправки по sms, включая терминальный ноль. const int8_t strSize = sizeMiddle + (strlen(mbStr.call_sign) + strlen(mbStr.loc) + 2) * repeatCounter + 1; // // Заполняем строку str[0] = '\0'; for (int8_t i = 0; i < repeatCounter; i++) { strcat(str, mbStr.call_sign); strcat(str, " "); } strcat(str, middle); for (int8_t i = 0; i < repeatCounter; i++) { strcat(str, " "); strcat(str, mbStr.loc); // Собрали строку текста Маяка } } // ***** (c) brokly www.arduino.ru ***** void sendBeacon(char* _thePhrase) { while (*_thePhrase) { if (*_thePhrase==' '){ delay(5*DOTLEN); } else { uint8_t buff=getMorzeSeq(*_thePhrase); if(buff){ uint8_t mask=1; while(!(buff & mask)){ mask<<=1; } mask<<=1; while(mask){ (buff & mask) ? dot() : dash(); mask<<=1; } delay(2*DOTLEN); } } _thePhrase++; } } // Процедура инициализации текста Маяка (с) UA6EM void initBeacon(){ eeData = EEPROM.read(eeFlag); if (eeData == 73){ // если надо перешить данные в EEPROM из IDE изменить на 74 ))) Serial.println(eeData); EEPROM.get(eeAddress, mb); // получить данные из EEPROM }else{ EEPROM.put(eeAddress, mb); // сохраним позывной и локатор в EEPROM EEPROM.write(eeFlag, eeFlag); }// в ячейку с адресом 73 шьём адрес 73 ))) } void setBeacon_Data(){ Serial.readString(); // Очистим буфер порта unsigned long modeTime = millis(); Serial.println("Введите ваш позывной сигнал"); while(!Serial.available() && millis() - modeTime < 10000) { } if(Serial.available()>0) { my_call = Serial.readString(); my_call.toCharArray(mb.call_sign,20); } my_call = mb.call_sign; Serial.print("Использую ваш позывной сигнал - "); Serial.println(my_call); Serial.readString(); // Очистим буфер порта modeTime = millis(); Serial.println("Введите ваш QRA локатор"); while(!Serial.available() && millis() - modeTime < 10000) { } if(Serial.available()>0) { my_loc = Serial.readString(); my_loc.toCharArray(mb.loc,7); } my_loc = mb.loc; Serial.print("Использую QRA локатор - "); Serial.println(my_loc); EEPROM.put(eeAddress,mb); // сохраним новые данные в EEPROM EEPROM.write(eeFlag, DataFlag); initBeacon(); sendMsg(mb); } // выход из режима программирования void setup() { pinMode(ledPin, OUTPUT); pinMode(txPin, OUTPUT); Serial.begin(115200); initBeacon(); sendMsg(mb); old_millis = millis(); Serial.println("Для входа в режим программирования введите P"); } void loop() { if(millis() - old_millis >= PAUSE){ digitalWrite(txPin, HIGH); delay(900); //txdelay - задержка после нажатия PTT // sendMsg(mb); //текст маяка - проба delay(20); // sendBeacon(thePhrase); sendBeacon(str); old_millis = millis(); digitalWrite(txPin, LOW); } // Serial.println("Для входа в режим программирования введите P"); if (Serial.available()) { int inByte = Serial.read(); if(inByte == 'P'){ setBeacon_Data(); } } }Для варианта 2 можно конечно реализовать и обработку знаков, но код разрастется и экономия в 30 байт в таблице варианта 1 совсем потеряется

Деда Витя, это ж не маяк, это ж ключ :)
Вот маяк на 8 МГц:
А вот маяк на 1337 кГц:
long millisAtStart = 0; long millisAtEnd = 0; //period of shortest broadcast (256 port changes) const long period_broadcast = 8; // number of period_broadcasts in one 'dit', // all other lengths are scaled from this #define LENGTH_DIT 64 const int length_dit = LENGTH_DIT; //number of periods for dit const int pause_dit = LENGTH_DIT; //pause after dit const int length_dah = 3 * LENGTH_DIT; //number of persots for dah const int pause_dah = LENGTH_DIT; //pause after dah const int length_pause = 7 * LENGTH_DIT; //pause between words void dit(void); void dah(void); void pause(void); void broadcast(int N_cycles); void dontbroadcast(int N_cycles); // ### INC ### Increment Register (reg = reg + 1) #define ASM_INC(reg) asm volatile ("inc %0" : "=r" (reg) : "0" (reg)) void setup() { Serial.begin(9600); DDRB = 0xFF; //Port B all outputs // Do one dit to determine approximate frequency millisAtStart = millis(); dit(); millisAtEnd = millis(); Serial.print(millisAtEnd - millisAtStart); Serial.print(" ms/dit, freq: "); Serial.print( (length_dit + pause_dit) * period_broadcast * 256 / (millisAtEnd - millisAtStart) / 2 ); Serial.print("kHz "); Serial.println(); } void loop() { dah(); dit(); dah(); dah(); pause(); dah(); dit(); dah(); dah(); pause(); dah(); dah(); dit(); dit(); pause(); pause(); } void dit(void) { for (int i = 0; i < length_dit; i++) { broadcast(period_broadcast); } for (int i = 0; i < pause_dit; i++) { dontbroadcast(period_broadcast); } } void dah(void) { for (int i = 0; i < length_dah; i++) { broadcast(period_broadcast); } for (int i = 0; i < pause_dah; i++) { dontbroadcast(period_broadcast); } } void pause(void) { for (int i = 0; i < length_pause; i++) { dontbroadcast(period_broadcast); } } void broadcast(int N_cycles) { unsigned int portvalue; for (int i = 0; i < N_cycles; i++) { portvalue = 0; do { PORTB = portvalue; ASM_INC(portvalue); } while (portvalue < 255); } } void dontbroadcast(int N_cycles) { unsigned int portvalue; PORTB = 0x00; for (int i = 0; i < N_cycles; i++) { portvalue = 0; do { ASM_INC(portvalue); //add some assembly No OPerations to keep timing the same asm volatile ("NOP"); } while (portvalue < 255); } }Оба полноценные, никакого больше оборудования, кроме ардуины и куска провода к пину, не требуется.
Деда Витя, это ж не маяк, это ж ключ :)
ай да Клименко! А, что, красивое решение, это по нашему )))
будет Маяк, а ключ у меня тока разводной и пару-тройку трубных (есть номер 4-ре) )))
Мда. Похоже скоро китайцы будут говорить, что все что Сделано в России можно сразу на помойку.
Несколько Маяков от UA6HJQ:
1.Простой телеграфный маяк на Arduino
2. Телеграфный маяк с автоответчиком
CW-BEACON-R7HJ
Config.h
/* * UA6HJQ 25.11.2018 * ОСНОВНЫЕ НАСТРОЙКИ * UA6EM 22.04.2019 отсчет времени от начала/конца передачи */ #define MYCALL "UA6EM/B" // ваш позывной #define QTHLOC "LN14AE"// ваш локатор #define SPEED (20) //скорость передачи телеграфа в WPM #define toneFreq (800) //частота звука (выбирайте между 600 - 1000Гц) #define interval (60) // интервал передачи маяка в секундах // 180=3мин 300=5мин 600=10мин 900=15мин // 1200=20мин 1800=30мин 3600=60мин #define PAUSE_GO YES // если надо временные отрезки считать от конца // передачи Маяка закомментируйте эту строку // // уровень модуляции регулируйте подстроечным резистором на плате! //DTMF.cpp
DTMF.h
cw.ino
func.ino
/* * UA6HJQ 25.11.2018 * ФУНКЦИИ НЕОБХОДИМЫЕ ДЛЯ РАБОТЫ ВСЕХ РЕЖИМОВ ПРОГРАММЫ */ void ring() { txON(); tone(tonePin, 1000);delay(400); tone(tonePin, 800);delay(400); tone(tonePin, 600);delay(400); tone(tonePin, 400);delay(600); noTone(tonePin); txOFF(); } void ton() { txON(); tone(tonePin, 1000); delay(15000); noTone(tonePin); txOFF(); } void beacon() { txON(); sendMsg(MYCALL); sendMsg(MYCALL); sendMsg("BEACON"); sendMsg(QTHLOC); txOFF(); } void txON() { delay(1000); pinMode(ptt, OUTPUT); digitalWrite(ptt, LOW); delay(600); } void txOFF() { pinMode(ptt, INPUT); digitalWrite(ptt, LOW); } void text1() { txON(); for (int i=0; i <= 9; i++){ int randNumber = random(10000, 30000); char rcw[1]; itoa(randNumber, rcw, 10); Serial.print(rcw); Serial.print(" "); sendMsg(rcw); } Serial.println(); txOFF(); } void text2() { txON(); char Str1[ ] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; for (int i=0; i <= 9; i++){ for (int s = 1; s <= 5; s++){ int randNumber = random(0, 26); Serial.print(Str1[randNumber]); switch (Str1[randNumber]) { case 'A': dot();dash();break; case 'B': dash();dot();dot();dot();break; case 'C': dash();dot();dash();dot();break; case 'D': dash();dot();dot();break; case 'E': dot();break; case 'F': dot();dot();dash();dot();break; case 'G': dash();dash();dot();break; case 'H': dot();dot();dot();dot();break; case 'I': dot();dot();break; case 'J': dot();dash();dash();dash();break; case 'K': dash();dot();dash();break; case 'L': dot();dash();dot();dot();break; case 'M': dash();dash();break; case 'N': dash();dot();break; case 'O': dash();dash();dash();break; case 'P': dot();dash();dash();dot();break; case 'Q': dash();dash();dot();dash();break; case 'R': dot();dash();dot();break; case 'S': dot();dot();dot();break; case 'T': dash();break; case 'U': dot();dot();dash();break; case 'V': dot();dot();dot();dash();break; case 'W': dot();dash();dash();break; case 'X': dash();dot();dot();dash();break; case 'Y': dash();dot();dash();dash();break; case 'Z': dash();dash();dot();dot();break; case ' ': delay(DOTLEN*5);break; } delay(3*DOTLEN); } Serial.print(" "); delay(500); } Serial.println(); txOFF(); } void text3() { txON(); char Str1[ ] = "ABCDEFGHIJ0123456789KLMNOPQRST0123456789UVWXYZ"; for (int i=0; i <= 9; i++){ for (int s = 1; s <= 5; s++){ int randNumber = random(0, 46); Serial.print(Str1[randNumber]); switch (Str1[randNumber]) { case 'A': dot();dash();break; case 'B': dash();dot();dot();dot();break; case 'C': dash();dot();dash();dot();break; case 'D': dash();dot();dot();break; case 'E': dot();break; case 'F': dot();dot();dash();dot();break; case 'G': dash();dash();dot();break; case 'H': dot();dot();dot();dot();break; case 'I': dot();dot();break; case 'J': dot();dash();dash();dash();break; case 'K': dash();dot();dash();break; case 'L': dot();dash();dot();dot();break; case 'M': dash();dash();break; case 'N': dash();dot();break; case 'O': dash();dash();dash();break; case 'P': dot();dash();dash();dot();break; case 'Q': dash();dash();dot();dash();break; case 'R': dot();dash();dot();break; case 'S': dot();dot();dot();break; case 'T': dash();break; case 'U': dot();dot();dash();break; case 'V': dot();dot();dot();dash();break; case 'W': dot();dash();dash();break; case 'X': dash();dot();dot();dash();break; case 'Y': dash();dot();dash();dash();break; case 'Z': dash();dash();dot();dot();break; case ' ': delay(DOTLEN*5);break; case '0': dash();dash();dash();dash();dash();break; case '1': dot();dash();dash();dash();dash();break; case '2': dot();dot();dash();dash();dash();break; case '3': dot();dot();dot();dash();dash();break; case '4': dot();dot();dot();dot();dash();break; case '5': dot();dot();dot();dot();dot();break; case '6': dash();dot();dot();dot();dot();break; case '7': dash();dash();dot();dot();dot();break; case '8': dash();dash();dash();dot();dot();break; case '9': dash();dash();dash();dash();dot();break; } delay(3*DOTLEN); } Serial.print(" "); delay(500); } Serial.println(); txOFF(); } void smetr() { smetrReading = analogRead(smetrPin); Serial.print("S-metr "); Serial.print(smetrReading); txON(); if (smetrReading < 80) { Serial.println(" = S2"); sendMsg("S 2 2"); } // калибровка уровня S-метра else if (smetrReading < 90) { Serial.println(" = S3"); sendMsg("S 3 3"); } // 55-182 для GM-340 UHF else if (smetrReading < 100) { Serial.println(" = S4"); sendMsg("S 4 4"); } else if (smetrReading < 110) { Serial.println(" = S5"); sendMsg("S 5 5"); } else if (smetrReading < 120) { Serial.println(" = S6"); sendMsg("S 6 6"); } else if (smetrReading < 130) { Serial.println(" = S7"); sendMsg("S 7 7"); } else if (smetrReading < 140) { Serial.println(" = S8"); sendMsg("S 8 8"); } else { Serial.println(" = S9"); sendMsg("S 9 9"); } txOFF(); } //вольтметр калибруем в зависимости от резисторов (у меня 15к и 1к) // питаем он 5В и проверяем сколько на пине RAW/VCC должно быть примерно столько и в показаниях // затем включаем внешнее питание через RAW/VCC должно быть сколько подано void voltemeter() { //вольтметр на основе делителя из резисторов float U1; float U2; float Rs = 1000.0; float Rd = 15000.0; float Vo = 5.00; U2 = Vo * analogRead(A3) / Rs; U1 = U2 / ( Rs / ( Rd + Rs )); Serial.print(U1); Serial.println(" V"); int volt1 = U1; char volt[1]; itoa(volt1, volt, 10); txON(); sendMsg(volt); sendMsg(volt); sendMsg("V"); txOFF(); } void temp1() { sensors.requestTemperatures(); char temp[1]; itoa(sensors.getTempCByIndex(0), temp, 10); Serial.print(temp); Serial.println(" C"); txON(); sendMsg(temp); sendMsg(temp); sendMsg("C"); txOFF(); }3.Простой маяк от K6HX (весьма оригинальный математический метод перевода в знаки морзе)
PS для тех, кто дружен с математикой
Вот маяк на 8 МГц:
Оба полноценные, никакого больше оборудования, кроме ардуины и куска провода к пину, не требуется.
проверил первый, что на 8 мегагерц, CW сигнал просто великолепный!!!
Слышен на гармониках, на чётных похуже, на нечетных S9++ )))
Вплоть до 144mHz, на 432 нет даже присутствия
То-есть, можно просто поставить умножители, выделить нужные частоты и получить очень простой маячок ...
во. плод похмельной ночи, отоматический неблокирующий морзе-маяк с таймерами, очередью и блэкджэком.
https://youtu.be/5O44eD7DJaA
чо скормишь ему, то и будет передавать. Ннада?
во. плод похмельной ночи, отоматический неблокирующий морзе-маяк с таймерами, очередью и блэкджэком.
https://youtu.be/5O44eD7DJaA
чо скормишь ему, то и будет передавать. Ннада?
надо
ок. код причешу, описание набью и выкладу. В этой теме, или отдельную создать? тама код абъемный, аж 179 строк. Я помню, ты говорил, что код больше 200 строк ниасилишь, поэтому старался укласца в рамки.
ок. код причешу, описание набью и выкладу. В этой теме, или отдельную создать? тама код абъемный, аж 179 строк. Я помню, ты говорил, что код больше 200 строк ниасилишь, поэтому старался укласца в рамки.
В этой, я буду тут собирать все коды Маяков, что найду
Вы бы сам принцип работы ещё объяснили... И для чего/кого они нужны. Глядишь, люди и потянуться.)
Вы бы сам принцип работы ещё объяснили... И для чего/кого они нужны. Глядишь, люди и потянуться.)
Маяк, устройство подключаемое к радиопередатчику, работающему в автономном режиме, используется радиолюбителями при выезде в полевые условия, служит для точного определения азимута на корреспондента.
Частоты маяков перед выедом как правило озвучиваются на соответствующих сайтах. Так как маяк работает автономно, позволяет оценить прохождение радиоволн в конкретное время суток, отметить точные азимуты на корреспондентов, для последующего использования, в частности в соревнованиях.
Очень помогает при работе на высокочастотных диапазонах (5 - 10 Гигагерц и выше), где угол лепестка диаграммы антенны порядка 1-2 градуса.
Постоянно работающие маяки позволяют оценить прохождение радиосигнала на конкретных корреспондентов.
Попробовал маяк Клименко на WAVGAT nano, от внутреннего генератора сигнал просто ужасен, от внешнего кварца, а он на плате 12 мегацерцовый сигнал приемлемый, на атмеге ардуино нано всё же получше, там он кристально чистый.
Хочу попробовать сменить кварц на 28 мгц, тогда маяк будет работать на частоте 14 мегагерц и кратные этой частоте.
Да, уровень сигнала значительно ниже, сказывается питание камня от 3.3 вольта )))
Скетч здесь, аддоны брал из этой ветки форума
У Вас там в Черкесске ещё радиогубители осталися???
ок. код причешу, описание набью и выкладу.
Ан нет, быстро не выкладу. Там, аказываеца, думать надо. Крепко думать надо, и даже трезвым, а то хрень с налёту получица.
У Вас там в Черкесске ещё радиогубители осталися???
а то )))
ua6em, ты мне, кста, можешь существенно помочь, если набьешь пока недостающее.
const TMorze MorzeArray[] PROGMEM = { {'A',0b101}, {'B',0b11000}, {'C',0b11010}, {'D',0b1100}, {'E',0b10}, // . {'K',0b1101}, // . {'S',0b1000}, // . // . {'Q',0b11101}, // . {'Z',0b11100}, {'1',0b101111}, {'2',0b100111}, {'3',0b100011 }, // . {'9',0b111110}, {'0',0b111111}, // . // . {'?',0b1001100} };символ и код морзе в бинарном виде (0bxxxx), для кода морзе правило простое, ведущая единица (мы ее пропустим потом), а потом сам код морзя, 1-тире, 0- точка
например 'Щ' ('Q') ..--.. = 0b1 001100 - пробелом я отделил ведущую единицу от собственно кода Морзе, в реальном коде пробел ставить не нужно
символ и код морзе в бинарном виде (0bxxxx), для кода морзе правило простое, ведущая единица (мы ее пропустим потом), а потом сам код морзя, 1-тире, 0- точка
например 'Щ' ('Q') ..--.. = 0b1 001100 - пробелом я отделил ведущую единицу от собственно кода Морзе, в реальном коде пробел ставить не нужно
сейчас на работу доеду и набью, точнее в течении часа сделаю
дак я не тороплю же, у мня часть есть, отлаживать можно и на этом. Потом, как сделаешь, подставим, и решение будет полным. С кириллицей потом чонить придумаем, мошт таблицу перекодировки какую.
const TMorze MorzeArray[] PROGMEM = { {'A',0b101}, {'B',0b11000}, {'C',0b11010}, {'D',0b1100}, {'E',0b10}, {'F',0b10010}, {'G',0b1110}, {'H',0b10000}, {'I',0b100}, {'J',0b10111}, {'K',0b1101}, {'L',0b10100}, {'M',0b111}, {'N',0b110}, {'O',0b1111}, {'P',0b10110}, {'Q',0b11101}, {'R',0b1010}, {'S',0b1000}, {'T',0b11}, {'U',0b1001}, {'V',0b10001}, {'W',0b1011}, {'X',0b11001}, {'Y',0b11011}, {'Z',0b11100}, {'1',0b101111}, {'2',0b100111}, {'3',0b100011}, {'4',0b100001}, {'5',0b100000}, {'6',0b110000}, {'7',0b111000}, {'8',0b111100}, {'9',0b111110}, {'0',0b111111}, {'.',0b1010101}, {',',0b1110011}, {':',0b1111000}, {'\\',0b1011110}, {'-',0b1100001}, {'/',0b110010}, {'(',0b1101101}, {')',0b1101101}, {'@',0b1011010}, {'=',0b110001}, {'"',0b1010010}, {''',0b1011110}, {'?',0b1001100} {'!',0b1110011} {';',0b1101010} };Если ничего не пропустил )))
Спасибо, забрал
Восклецательный знак { '!',0b1110011 } забыл.
Как там с причёсыванием?
Жди. Или вдумчиво и надежно, или быстро. Хочешь, завтра выложу?
не думаю, что еслиф ты без маяка жил 50 лет, то не проживёшь еще 3-4 дня.
Жди. я же кроме писания программ от нечего делать, еще и таки немношко пью. :)
не думаю, что еслиф ты без маяка жил 50 лет, то не проживёшь еще 3-4 дня.
Жди. я же кроме писания программ от нечего делать, еще и таки немношко пью. :)
это другое дело ... да маяк в принципе работает, вот тут скетчик от UA6HJQ немного поправил, у него интересная задумка...
Гы. Очень сильно немношко. :-)
Именно поэтому я не беру заказов. Сегодня я здесь, а завтра в запое, и чем закащик виноват в такой ситуации? А такак у мня остались еще жалкие фрагменты совести, то мне неудобно подставлять непричастных людей. Тебе я ничего, сопсно, и не обещал, мне стала интересна задача, сиравно заняца нечем пока, я попробую сделать. Но уж, как смогу. Не получица - не обессудь, голова моя уже как в децтве работать не в состояньи. :-)
Можешь кидать в мня тапками, я ниабижусь. :-)
Моя задумка готова пока на 60%.
Я очень сильно сожалею, если вдруг обидел каво.
Тебе строку откуда брать? Из сериала или жоска заданную в тексте?
Пока сделал чтение из Сериала, что туда напишешь, то и будет по кругу передавать. Напишешь другое - через 2 секунды будет другое передавать.
В принципе, в АТМега8 код влазиит, даже, наерна, тиньку приспособить можно будет
мне интересен сам твой алгоритм, лучше из сериала, тогда можно клавиатуру притарачить, да я сам всё делаю из интереса )))
Ок. Сериал оставлю. Набираешь в сериале нужный текст. Отправляешь. когда прошло 2 секунды с момента приема последнего символа - передаваемая строка заменяется принятой из сериала и сразу начинает передаваца
Алгоритм простой, на таймерах и флагах. К вечеру выложу на гитхаб. Наерна.
К вечеру выложу на гитхаб. Наерна.
Хорошо!
А я тут небольшой тренер (по мотивам R7HJ) за это время насобирал, пока не оптимизировал, компилируется )))
/* * 24.04.2019 (с) UA6EM <a href="mailto:ua6em@yandex.ru">ua6em@yandex.ru</a>, cтарт проекта * * Предлагается скетч простого телеграфного датчика кода Морзе. * Для соревнований тексты формируются в трёх режимах: Цифры, Буквы, * Смешанные тексты, время передачи радиограммы составляет 1 минуту * с выравниваем текста до полной группы. * Скорость передачи регулируется с шагом 10 знаков в минуту. * * */ #define DOTLEN (1200/SPEED) #define DASHLEN (3*(1200/SPEED)) #define SEC 1000UL #define SPEED (60) //скорость передачи телеграфа в WPM #define toneFreq (800) //частота звука (выбирайте между 600 - 1000Гц) byte test_go = 1; byte test_mode = 1; int ledPin=13; int tonePin = A4; // выход звука unsigned long previousMillis; unsigned long test_time = 60; // время теста одна минута void setup() { Serial.begin(115200); previousMillis = millis(); } void loop() { if(test_go){ while(millis() - previousMillis <= test_time * SEC){ if(test_mode == 1) { Serial.println();cw_digi();} if(test_mode == 2) { Serial.println();cw_char();} if(test_mode == 3) { Serial.println();cw_chdg();} } delay(10000); previousMillis = millis(); test_mode++; if(test_mode == 4) test_mode=1; } }И ...при нём
/* * Библиотеки для CW */ // // *** Генерация цифровых кодов *** void cw_digi() { for (int i=0; i <= 9; i++){ int randNumber = random(10000, 30000); char rcw[1]; itoa(randNumber, rcw, 10); Serial.print(rcw); Serial.print(" "); sendMsg(rcw); } Serial.println(); } // // *** Генерация символьных кодов *** void cw_char() { char Str1[ ] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; for (int i=0; i <= 9; i++){ for (int s = 1; s <= 5; s++){ int randNumber = random(0, 26); Serial.print(Str1[randNumber]); switch (Str1[randNumber]) { case 'A': dot();dash();break; case 'B': dash();dot();dot();dot();break; case 'C': dash();dot();dash();dot();break; case 'D': dash();dot();dot();break; case 'E': dot();break; case 'F': dot();dot();dash();dot();break; case 'G': dash();dash();dot();break; case 'H': dot();dot();dot();dot();break; case 'I': dot();dot();break; case 'J': dot();dash();dash();dash();break; case 'K': dash();dot();dash();break; case 'L': dot();dash();dot();dot();break; case 'M': dash();dash();break; case 'N': dash();dot();break; case 'O': dash();dash();dash();break; case 'P': dot();dash();dash();dot();break; case 'Q': dash();dash();dot();dash();break; case 'R': dot();dash();dot();break; case 'S': dot();dot();dot();break; case 'T': dash();break; case 'U': dot();dot();dash();break; case 'V': dot();dot();dot();dash();break; case 'W': dot();dash();dash();break; case 'X': dash();dot();dot();dash();break; case 'Y': dash();dot();dash();dash();break; case 'Z': dash();dash();dot();dot();break; case ' ': delay(DOTLEN*5);break; } delay(3*DOTLEN); } Serial.print(" "); delay(500); } Serial.println(); } // // *** Генерация смешанного текста *** void cw_chdg() { char Str1[ ] = "ABCDEFGHIJ0123456789KLMNOPQRST0123456789UVWXYZ"; for (int i=0; i <= 9; i++){ for (int s = 1; s <= 5; s++){ int randNumber = random(0, 46); Serial.print(Str1[randNumber]); switch (Str1[randNumber]) { case 'A': dot();dash();break; case 'B': dash();dot();dot();dot();break; case 'C': dash();dot();dash();dot();break; case 'D': dash();dot();dot();break; case 'E': dot();break; case 'F': dot();dot();dash();dot();break; case 'G': dash();dash();dot();break; case 'H': dot();dot();dot();dot();break; case 'I': dot();dot();break; case 'J': dot();dash();dash();dash();break; case 'K': dash();dot();dash();break; case 'L': dot();dash();dot();dot();break; case 'M': dash();dash();break; case 'N': dash();dot();break; case 'O': dash();dash();dash();break; case 'P': dot();dash();dash();dot();break; case 'Q': dash();dash();dot();dash();break; case 'R': dot();dash();dot();break; case 'S': dot();dot();dot();break; case 'T': dash();break; case 'U': dot();dot();dash();break; case 'V': dot();dot();dot();dash();break; case 'W': dot();dash();dash();break; case 'X': dash();dot();dot();dash();break; case 'Y': dash();dot();dash();dash();break; case 'Z': dash();dash();dot();dot();break; case ' ': delay(DOTLEN*5);break; case '0': dash();dash();dash();dash();dash();break; case '1': dot();dash();dash();dash();dash();break; case '2': dot();dot();dash();dash();dash();break; case '3': dot();dot();dot();dash();dash();break; case '4': dot();dot();dot();dot();dash();break; case '5': dot();dot();dot();dot();dot();break; case '6': dash();dot();dot();dot();dot();break; case '7': dash();dash();dot();dot();dot();break; case '8': dash();dash();dash();dot();dot();break; case '9': dash();dash();dash();dash();dot();break; } delay(3*DOTLEN); } Serial.print(" "); delay(500); } Serial.println(); } void dash() { digitalWrite(ledPin, HIGH); tone(tonePin, toneFreq); delay(DASHLEN); digitalWrite(ledPin, LOW); noTone(tonePin); delay(DOTLEN); } void dot() { digitalWrite(ledPin, HIGH) ; tone(tonePin, toneFreq); delay(DOTLEN); digitalWrite(ledPin, LOW); noTone(tonePin); delay(DOTLEN); } void sendMsg(char *str) { int i; delay(500); for(i=0;i<strlen(str);i++) { switch (toupper(str[i])) { case 'A': dot();dash();break; case 'B': dash();dot();dot();dot();break; case 'C': dash();dot();dash();dot();break; case 'D': dash();dot();dot();break; case 'E': dot();break; case 'F': dot();dot();dash();dot();break; case 'G': dash();dash();dot();break; case 'H': dot();dot();dot();dot();break; case 'I': dot();dot();break; case 'J': dot();dash();dash();dash();break; case 'K': dash();dot();dash();break; case 'L': dot();dash();dot();dot();break; case 'M': dash();dash();break; case 'N': dash();dot();break; case 'O': dash();dash();dash();break; case 'P': dot();dash();dash();dot();break; case 'Q': dash();dash();dot();dash();break; case 'R': dot();dash();dot();break; case 'S': dot();dot();dot();break; case 'T': dash();break; case 'U': dot();dot();dash();break; case 'V': dot();dot();dot();dash();break; case 'W': dot();dash();dash();break; case 'X': dash();dot();dot();dash();break; case 'Y': dash();dot();dash();dash();break; case 'Z': dash();dash();dot();dot();break; case ' ': delay(DOTLEN*5);break; case '.': dot();dash();dot();dash();dot();dash();break; case ',': dash();dash();dot();dot();dash();dash();break; case ':': dash();dash();dash();dot();dot();break; case '?': dot();dot();dash();dash();dot();dot();break; case '\'': dot();dash();dash();dash();dash();dot();break; case '-': dash();dot();dot();dot();dot();dash();break; case '/': dash();dot();dot();dash();dot();break; case '(': case ')': dash();dot();dash();dash();dot();dash();break; case '\"': dot();dash();dot();dot();dash();dot();break; case '@': dot();dash();dash();dot();dash();dot();break; case '=': dash();dot();dot();dot();dash();break; case '0': dash();dash();dash();dash();dash();break; case '1': dot();dash();dash();dash();dash();break; case '2': dot();dot();dash();dash();dash();break; case '3': dot();dot();dot();dash();dash();break; case '4': dot();dot();dot();dot();dash();break; case '5': dot();dot();dot();dot();dot();break; case '6': dash();dot();dot();dot();dot();break; case '7': dash();dash();dot();dot();dot();break; case '8': dash();dash();dash();dot();dot();break; case '9': dash();dash();dash();dash();dot();break; } delay(2*DOTLEN); } }тваюштымать. ну как не надоест то ватэтовотвсё
291case'?':292dot();dot();dash();dash();dot();dot();break;293case'\'':294dot();dash();dash();dash();dash();dot();break;295case'-':296dash();dot();dot();dot();dot();dash();break;Нет. Сегодня вряд ли успею. Жучков много.
Нет. Сегодня вряд ли успею. Жучков много.
Да не торопись! Я дед только вникать в твой код неделю буду...PS Скидывал там скетч вверху, две ошибки на 50 строк, лохматость уже совсем не та ...ЗЫ и это не синтаксис, можно было сослаться на незнание языка, а логика...)))
здоброй ночей.
Значить, берешь, лезешь вот сюда.
https://github.com/DetSimen/MorzeRepeater
скачиваешь оттудова Zip файл
В Zip файле есть директория DtS, просто скопируй всё ее содержимое к себе в %Arduino%\libraries\DtS. ПОСЛЕ ЭТОГО только запускай IDE и открывай Morze.ino. Канпилируй, матерись, спрашивай, наливай.
Для вопросов и обсуждения, воть файл Morze.ino (осторожна!!! Dead-o-code):
#include "Arduino.h" #include "MorzeTable.h" #include "TimerList.h" #include "Messages.h" static uint8_t TXPin = 10; // пин передаччика 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 = 75; // основное время, длительность точки 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); } 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; } 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; } default: Serial.print(F("Unknown message code: 0x")); Serial.println(msg.Message, HEX); break; } }К 10 пину подключи светлодиот/бузер/ключ на полевике/Братскую ГЭС, всё чо хочешь, короче.
При старте начинает "передавать" фразу по умолчанию. Чтоб сменить, надо в Сериал отправить всё, что надо передавать. Через 2 секунды после приема ПОСЛЕДНЕГО символа, принятая фраза начинает передаваца. После окочания передачи всей фразы - пауза 5 секунд и передача сначала. Все тайминги настраиваюца в самом начале. Комментарии тоже есть. Разбирайся. Матерись. Спрашивай.
код морзе берется из таблицы в прогмем. Как получается код в бинарном виде:
Допустим, закодируем знак вопроса ..--..
ставим 1, это флаг, что после нее до конца байта будут значащие биты, 0-точка, 1-тире
0b1001100
из этого кода, пропусканием всех нулевых бит от начала байта и флага получаем маску символа
0b1001100 символ
0b0100000 - его маска, единичка стоит в первом значащем разряде
делаем маске и коду битовый AND, получаем 0 (точка) или не ноль (тире)
передаем этот бит
маску сдвигаем вправо на бит
пока маска не 0, т.е не сдвинулась до конца, передаем очередной бит.
символ 0b1001100
маски 0b0100000
0b0010000
0b0001000
.
0b0000001
и всё, символ кончился.
хорошо!
СКОМПИЛИРОВАЛ - ИЗУЧАЮ
И чо? скомпилировалось намайна?
у мня для Уно
ВСЁ НОРМАЛЬНО! у нас еще рано, хочу зуммер подключить послушать, разбужу тут всех )))
Работает!!!
Перезалил, уклался в 200 строк. Выкинул лишние сучности
теперь карикатура занимает 5272 байта PROGMEM и 280 АЗУ
Ой. Забыл про саафтара. Подтверждаю, понужал меня не спать изо всех сил.
ua6em, а я всё хотел спросить. Вот ваш маяк, подключили вы его к своему ТХ. Как я понимаю, сами при этом работать не можете - ведь маяк за вас работает... Или есть какие то иные правила?
Это ж как на рыбалке: приехал, удочки поставил, налил... Ну, иногда можно и дёрнуть, когда закусывать надоело ))
Нет, для своего позывного нужно же иметь разрешение с соответствующей категорией и пр. А так получается что вместо тебя работает робот и возможна ситуация когда твоих экземпляров класса может быть несколько.) С одинаковыми позывными! Что как то странненько.)
синглтон, аднака, нужен
Нет, для своего позывного нужно же иметь разрешение с соответствующей категорией и пр. А так получается что вместо тебя работает робот и возможна ситуация когда твоих экземпляров класса может быть несколько.) С одинаковыми позывными! Что как то странненько.)
РосЭфирЗапрет поймает роботов и разберётся, как полагается. Около робота же человек сидит обумаженный - следит, стало быть, за бездушной железякой. А этак ведь и обычный алко... партизан в тылу врага может отстучать под чужой фамилией - разницы нет ведь.
Не, ну это понятно. Хулиганить может каждый, только всё это ведь не законно. А мы же ж законопослушные граждане.)
Хотя раньше что бы выполнить норматив приходилось идти на обман. ЕМНИП, была категория один передатчик - несколько операторов, а категории несколько передатчиков - несколько опрераторов небыло. Однако, многие работали именно так, потому как конкуренция была большая.)
Законопослушные граждане по десять роботов не пускают в эфир под одним аккаунтом. Пока рука стакан держит - робот стучит. Освободилась рука - батарейку у робота отобрал и сам трели выдаёшь. Так что суть вопроса до сих пор неясна.
Ну вот и я о том же. Можно ли десяток роботов пускать под одним аккаунтом? Та даже одного робота и себя?