Доброго времени суток всем.
Не знаю, кто как, а я продолжаю заниматься этой темой, правда, без особого фанатизма. Потренировавшись на игрушке, что я описывал раньше, решил глубже изучить тему. В результате родилось вот это: Комнатная метеостанция с часами | Аппаратная платформа Arduino. После очередного перерыва в радиолюбительском творчестве решил продолжить тему CW Клавиатуры на Arduino, заодно поработать с периферией Arduino и воплотить в жизнь некоторые задумки. Дабы не забрасывать в долгий ящик реализацию задуманного, решил поделиться с общественностью, в надежде получить стимул в виде здоровой критики.
Задание на 1-й этап проект выглядит в виде изложенном ниже.
Разработать клавиатурный датчик кода Морзе со следующими требованиями:
1. жестко запрограммированный режим генерации кодов Морзе и функциональных клавиш без возможности настройки;
2. гибкая настройка кодов Морзе для произвольных клавиш с учетом желания конечного пользователя. Настройка выполняется при помощи настроечного файла записанного на SD – флеш-карту и редактируется пользователем на ПК;
3. гибкая настройка непечатных – функциональных клавиш для генерации Морзе -посылок по желанию конечного пользователя. Настройка выполняется при помощи настроечного файла записанного на SD – флеш-карту и редактируется пользователем на ПК;
4. режим воспроизведения произвольного текстового файла записанного пользователем на SD – флеш-карту;
5. текущая настройка с клавиатуры, скорости передачи ,громкости, тона и др.;
6. режим обучения оператора методом повтора на клавиатуре воспроизводимого учебного текста с формированием лог-файла содержащего информацию о количестве ошибок в разрезе символов;
7. генерируемые Морзе – посылки отображаются на экране LCD;
8. пользовательское меню по возможности отображается на экране LCD;
9. питание устройства должно обеспечиваться посредством штекера DC и min-USB разъема;
10. на первом этапе возможно воспроизведение звука при помощи микро излучателя, в дальнейшем генерация для наушников программным или аппаратным генератором;
11. вывести на лицевую панель кнопку «СБРОС»;
Как бы так. Реализую из того, что оказалось под рукой, хотя желательны дополнительные материалы, на как показывает практика надо исчерпать то, что имеется. А что же имеется? А имеется:
- Arduino Mega 2560;
- LCD 16x2 с последовательным однопроводным интерфейсом ZX-400P;
- Arduino-шилд –однополярное реле;
- SD модуль – LC Studio;
Для удобства монтажа и сокращения габаритов над и под платой ардуины я разместил платы периферии, изготовленные из монтажных плат. Такой способ удачно зарекомендовал себя при изготовлении метеостанции описанной выше. На нижней плате я разместил саму ардуину, SD и LCD модули, штыревой разъем для соединения с верхней платой и штыревой разъем для соединения с LCD. На верхней плате разместились разъем клавиатуры, разъем mini-USB для питания 5 вольт, шилд-реле, штыревой разъем для соединения с нижней платой. Монтаж проводной. Осталось допаять связь с исполнительным модулем, установить звуковой излучатель и разъемы для трансивера и звука. Работоспособность на сегодняшний день определяется световой индикацией системного светодиода, выводом на LCD и через программный интерфейс среды разработки. Необходимо отметить, что я выбрал среду разработки Arduino 1.0.5.-r2.
SD модуль подключен стандартно , т.е. как рекомендует производитель. Ничего здесь изобретать не пришлось в плане электроники, но зато в плане программирования пришлось повозиться со строковыми переменными и чтением с носителя.
Мне на этот раз крупно не повезло с LCD монитором. Я взял его из набора Robot POP-BOT. Этот LCD имеет однопроводной интерфейс и я, честно говоря, с ним очень помучался, и думаю, что и еще помучаюсь, т.к. в нем не прошита кириллица, а лично для меня это очень существенно по той причине, что я привык работать именно с кириллической клавиатурой и это осложнит разработку алгоритмов именно под это устройство. Так что кому интересно, то советую все-таки применять самый обычный LCD и желательно с кириллической прошивкой, примерно такой как я применил в указанном выше проекте метеостанции (правда там тоже без кириллицы, но она там и не нужна).
Шилд-реле я использую, чтобы не валялся без дела. Исполняющий блок можно с успехом сделать на реле SS1A05 т.е. как я делал и описывал раньше.
Итак, макет практически смонтирован и основные режимы работы проверены. Основная работа сводится к освоению языка разработки Arduino и периферией. Конечно, если опыта нет или маловато, то уходит много времени на доведение идеи до ума. На сегодняшний день практически 50% проекта реализовано. В жестком запрограммированном режиме генератор работает, учебный файл читается и воспроизводится, информация на дисплее отображается. Формат файла для настроек печатных клавиш мною утвержден, а именно файл состоит из трех столбцов
1. изображение символа на экране LCD- (литера);
2. ASCII код клавиши;
3. код Морзе.
Например, для символа «а» будет выглядеть так: а|97|.- .
Алгоритм чтения из файла настройки отработан для латиницы. С кириллицей еще надо подумать. Это снова отголоски недостатка знаний по LCD индикаторам. Будем бороться. Главное процесс. К сожалению пока все разбросано в виде отдельных программных решений и заготовок и предстоит самое сложное и интересное, а именно компоновка в единый программный модуль. В настоящий момент дорабатываю генератор на основе файла настроек печатных символов.
Сразу предупреждаю, что на замечания или вопросы типа, а зачем это надо, реагировать не буду. Проверки в эфире не проводилось и вряд ли будет проводиться, так как я телеграфист никакой. Просто эта тема мне очень интересна. Выкладываю фото получившегося устройства. Скетчи не выкладываю, кроме жесткого генератора, кому интересно остальное,то обсудим отдельно
Жду здоровой критики и предложений пока проект не реализован до конца.
Владимир.
[I]
Код:
// клавиатурный датчик кода Морзе
// версия 1.1
// !!!!без загрузки с SD кодов клавиш !!!!
// Проверено 14.01.14
// пробная без изысков и претензий на профи, по простому в лоб
// RN6LJK
// есть буфер - прописан в PS2Keyboard.cpp - #define BUFFER_SIZE 45
// есть пробел-задержка между словами- 7 точек !!! у других не видел, только на слух
// замеченные ошибки - ERROR -
// не прописана буква Ч
// проблемы с клавишами F
// проблемы с дополнительной клавиатурой
//
//
// PARIS - содержит 44 точки (9 точки, 4x3=12 тире (три точки),
// интервал между знаками 7, буквами 5х3 -> 9+12+7+15=43
// + 1 точка между словами ИТОГО 44 точки
// в минуте 60 000 милисекунд
// для dot=100 т.е. delay(100)-100 мс -> 44х100=4400, 60000/4400 = 13.6 (14) WPM
// 200 мс -> 44х200=8800, 60000/8800= 6.8 (7) WPM
//
//
//
//
//*******************************
// arduino_1.0.5-r2 *
//*******************************
// Описываем знаки
// цифры
char Letter_1[]=".----";
char Letter_2[]="..---";
char Letter_3[]="...--";
char Letter_4[]="....-";
char Letter_5[]=".....";
char Letter_6[]="-....";
char Letter_7[]="--...";
char Letter_8[]="---..";
char Letter_9[]="----.";
char Letter_0[]="-----";
// /*
// кириллица
// названия в Letter_символ не совпадают с названиями кнопок
// мне так удобней писать, чтобы не запутаться
// смотри ниже при распознавании в case
char Letter_A[]=".-"; // А
char Letter_B[]="-..."; // Б
char Letter_W[]=".--"; // В
char Letter_G[]="--."; // Г
char Letter_D[]="-.."; // Д
char Letter_E[]="."; // Е
char Letter_V[]="...-"; // Ж
char Letter_Z[]="--.."; // З
char Letter_I[]=".."; // И
char Letter_J[]=".---"; // Й
char Letter_K[]="-.-"; // К
char Letter_L[]=".-.."; // Л
char Letter_M[]="--"; // М
char Letter_N[]="-."; // Н
char Letter_O[]="---"; // О
char Letter_P[]=".--."; // П
char Letter_R[]=".-."; // Р
char Letter_S[]="..."; // С
char Letter_T[]="-"; // Т
char Letter_U[]="..-"; // У
char Letter_F[]="..-."; // Ф
char Letter_H[]="...."; // Х
char Letter_C[]="-.-."; // Ц
char Letter_SH[]="----"; // Ш
char Letter_Q[]="--.-"; // Щ
char Letter_x[]="-..-"; // Ъ
char Letter_Y[]="-.--"; // Ы
char Letter_X[]="-..-"; // Ь
char Letter_EE[]="..-.."; // Э
char Letter_YU[]="..--"; // Ю
char Letter_JA[]=".-.-"; // Я
// знаки препинания
char Letter_DOT[]=".-.-.-"; // точка
char Letter_COMMA[]="--..--"; // запятая
char Letter_QUESTION[]="..--.."; // вопрос
char Letter_SLASH[]="-..-."; // слэш
char Letter_PLUS[]=".-.-."; // плюс
char Letter_EQUALITY[]="-...-"; // равенство - раздел
// */
// переменные для настройки
// переменные dot и dash в дальнейшем необходимо вводить с клавиатуры
int dot =100; // длительность точки
int dash=dot*3; // длительность тире
int sign_delay = dot; // Задержка между элементами одного знака
int delay_between_signs = 2*dot; // задержка между знаками 3*dot-1
// (итого см. по тексту sign_delay+delay_between_signs)=3*dot
int delay_between_words =6*dot; // задержка между словами 7*dot-1
// (итого см. по тексту sign_delay+delay_between_words)=7*dot
int PinOut = 4; // исполнительный порт
// int ledPin = 13; // порт светодиода
// установки
#include <PS2Keyboard.h> // библиотека клавиатуры
const int DataPin = 2; // порт для клавиатуры - данные
const int IRQpin = 3; // порт для клавиатуры - синхросигнал
PS2Keyboard keyboard;
void setup() {
pinMode(PinOut, OUTPUT); // инициализируем исполнительный порт
// pinMode(ledPin, OUTPUT); // инициализируем порт светодиода
keyboard.begin(DataPin, IRQpin);
Serial.begin(9600);
Serial.println("Keyboard Test:");
for ( int i=0; i <= 2; i++){ // Моргнем три раза, что готовы
// digitalWrite(ledPin, HIGH);
delay(500);
// digitalWrite(ledPin, LOW);
delay(500);
digitalWrite(PinOut, HIGH);
}
}
// Главная
void loop() {
if (keyboard.available()) {
char c = keyboard.read(); // читаем состояние клавиатуры
switch (c){
case '1': Processing(Letter_1); delay(delay_between_signs); break; // 1
case '2': Processing(Letter_2); delay(delay_between_signs); break; // 2
case '3': Processing(Letter_3); delay(delay_between_signs); break; // 3
case '4': Processing(Letter_4); delay(delay_between_signs); break; // 4
case '5': Processing(Letter_5); delay(delay_between_signs); break; // 5
case '6': Processing(Letter_6); delay(delay_between_signs); break; // 6
case '7': Processing(Letter_7); delay(delay_between_signs); break; // 7
case '8': Processing(Letter_8); delay(delay_between_signs); break; // 8
case '9': Processing(Letter_9); delay(delay_between_signs); break; // 9
case '0': Processing(Letter_0); delay(delay_between_signs); break; // 0
case ' ': delay(delay_between_words); break; // пробел sign_delay+delay_between_words)=7*dot
case 'f': Processing(Letter_A); delay(delay_between_signs); break; //
case ',': Processing(Letter_B); delay(delay_between_signs); break; //
case 'd': Processing(Letter_W); delay(delay_between_signs); break; //
case 'u': Processing(Letter_G); delay(delay_between_signs); break; //
case 'l': Processing(Letter_D); delay(delay_between_signs); break; //
case 't': Processing(Letter_E); delay(delay_between_signs); break; //
case ';': Processing(Letter_V); delay(delay_between_signs); break; //
case 'p': Processing(Letter_Z); delay(delay_between_signs); break; //
case 'b': Processing(Letter_I); delay(delay_between_signs); break; //
case 'q': Processing(Letter_J); delay(delay_between_signs); break; //
case 'r': Processing(Letter_K); delay(delay_between_signs); break; //
case 'k': Processing(Letter_L); delay(delay_between_signs); break; //
case 'v': Processing(Letter_M); delay(delay_between_signs); break; //
case 'y': Processing(Letter_N); delay(delay_between_signs); break; //
case 'j': Processing(Letter_O); delay(delay_between_signs); break; //
case 'g': Processing(Letter_P); delay(delay_between_signs); break; //
case 'h': Processing(Letter_R); delay(delay_between_signs); break; //
case 'c': Processing(Letter_S); delay(delay_between_signs); break; //
case 'n': Processing(Letter_T); delay(delay_between_signs); break; //
case 'e': Processing(Letter_U); delay(delay_between_signs); break; //
// case 'a': Processing(Letter_F); delay(delay_between_signs); break; //
case 97 : Processing(Letter_F); delay(delay_between_signs); break; //
case '[': Processing(Letter_H); delay(delay_between_signs); break; //
case 'w': Processing(Letter_C); delay(delay_between_signs); break; //
case 'i': Processing(Letter_SH); delay(delay_between_signs); break; //
case 'o': Processing(Letter_Q); delay(delay_between_signs); break; //
case ']': Processing(Letter_x); delay(delay_between_signs); break; //
case 's': Processing(Letter_Y); delay(delay_between_signs); break; //
case 'm': Processing(Letter_X); delay(delay_between_signs); break; //
case 39 : Processing(Letter_EE); delay(delay_between_signs); break; //
case '.': Processing(Letter_YU); delay(delay_between_signs); break; //
case 'z': Processing(Letter_JA); delay(delay_between_signs); break; //
case '/': Processing(Letter_DOT); delay(delay_between_signs); break; //
case '?': Processing(Letter_COMMA); delay(delay_between_signs); break; //
case '&': Processing(Letter_QUESTION); delay(delay_between_signs); break; //
case PS2_ENTER : Processing(Letter_SLASH); delay(delay_between_signs); break; //
case '+': Processing(Letter_PLUS); delay(delay_between_signs); break; //
case '=': Processing(Letter_EQUALITY); delay(delay_between_signs); break; //
case 3: Processing(Letter_EQUALITY); delay(delay_between_signs); break; //
default: // непрописанная клавиша
// /* // спец символы
// это блок для отладки, после можно убрать
if (c == PS2_ENTER) {
Serial.println();
} else if (c == PS2_TAB) {
Serial.print("[Tab]");
} else if (c == PS2_END) {
Serial.print("[End]");
} else if (c == PS2_ESC) {
Serial.print("[ESC]");
} else if (c == PS2_PAGEDOWN) {
Serial.print("[PgDn]");
} else if (c == PS2_PAGEUP) {
Serial.print("[PgUp]");
} else if (c == PS2_LEFTARROW) {
Serial.print("[Left]");
} else if (c == PS2_RIGHTARROW) {
Serial.print("[Right]");
} else if (c == PS2_UPARROW) {
Serial.print("[Up]");
} else if (c == PS2_DOWNARROW) {
Serial.print("[Down]");
} else if (c == PS2_DELETE) {
Serial.print("[Del]");
} else if (c == PS2_F2) {
Serial.print("[F2]");
} else if (c == PS2_HOME) {
Serial.print("[HOME]");
} else if (c == PS2_SHIFT_F2) {
Serial.print("[SHIFT_F2]");
} else {
Serial.print(c); // вывести на монитор символ, который не прописан
}
// */
break;
}
}
}
// Исполнительная подпрограмма
void blink(int d) {
digitalWrite(PinOut,LOW);
// digitalWrite(ledPin, HIGH);
delay(d); // активируем на точку или тире
digitalWrite(PinOut, HIGH);
// digitalWrite(ledPin,LOW);
delay(sign_delay); // Задержка между элементами одного знака, по концу знака
// получится sign_delay+delay_between_signs==3*dot
// digitalWrite(PinOut, LOW);
}
// обработка нажатой клавиши
void Processing(char LL[]) {
int i;
i=0;
while (LL[i]!='\0'){
if (LL[i] == '.'){
blink(dot); } // посылаем на исполнение или dot или dash
else {blink(dash);}
// пока для отладки
Serial.print(LL); // печатаем сдержимое массива
i=i++;
}
}
Социальные закладки