Pull to refresh

Знакомство с Arduino, часть 3. Морзе-клавиатура: бета-версия

Developing for Arduino *
В начале февраля я попробовала собрать морзе-клавиатуру на базе «радиоконструктора» Arduino. Получился вполне работоспособный прототип с единственной кнопкой, нажимая которую, можно «генерировать» точки и тире — из которых микроконтроллер будет собирать буквы и отправлять их на компьютер. Девайс (если можно назвать девайсом с полдюжины деталек на макетной плате) получился вполне работоспособный. Но для практического применения малопригодный, так что я собиралась усовершенствовать конструкцию. И вот, что у меня получилось.



Прежде всего, в новой версии морзе-клавиатуры стоило бы отказаться от ввода точек и тире одной кнопкой. Однокнопочный ввод — это необходимость подстраивать свой темп печати под временные интервалы, прописанные в программе, чтобы точки и тире пользователя «попадали» в точки и тире клавиатуры. Да и вводить точки-тире куда удобнее, не задумываясь над длительностью нажатия. К такому варианту давным-давно пришли радисты и телеграфисты, перейдя на подобные ключи:



Итак, мы будем использовать две кнопки — одну для точек, вторую для тире. Заодно заменим малоинформативный одноцветный светодиод на RGB-диод. Цветом можно будет информировать пользователя о текущей раскладке. Кроме того, стоило бы дополнить девайс обратной тактильной связью — например, через вибромотор. Правда, как выяснилось в процессе работы, вибромотор нужно подключать через специальную микросхему — драйвер управления моторами. Поэтому пока я заменила вибромотор пьезодинамиком-пищалкой, который можно подключить к Arduino напрямую, без дополнительных деталей.

Что мне потребовалось для работы:



1) Freeduino 2009 — полный аналог Arduino Duemilanove (впрочем, можно было обойтись куда более слабыми вариациями микроконтроллера)
2) Макетная плата
3) 2 кнопки
4) RGB-светодиод с общим анодом
5) 2 резистора 10 кОм
6) 3 резистора 330 Ом
7) Пьезо-динамик (на картинко по ссылке это Piezo Buzzer)
8) дюжина проводков для соединения деталей на макетной плате

Для создания альфа-версии мне дополнительно понадобились:
9) Полметра кабеля «витая пара». Как оказалось, проводки из «витой пары» вполне годятсяв качестве соединительных проводов для макетки.
10) Старый непишущий фломастер для надписей на компакт-дисках.
11) Паяльник, припой, изолента.

Как подключить RGB-светодиод.

В прошлой версии морзе-клавиатуры мы использовали простой одноцветный светодиод, с одним анодом и одним катодом. Его подключить было несложно: анод подключаем к выводу микроконтроллера, катод — через резистор к земле. Возможно, если бы у меня был RGB-диод с общим катодом и тремя анодами, я бы поступила аналогично. Но в набор Seeeduino Catalyst Pack входили RGB-диоды с общим анодом, так что пришлось немножко подумать над подключением (спасибо гуру Arduino, давшим мне правильные советы!). Суть решения оказалась в использовании инвертированной логики (возможно, термин не совсем правилен — буду благодарна за поправку). В прошлой версии светодиод горел, когда на вывод микроконтроллера (МК) подавалось напряжение, и гас, когда напряжение отсутствовало. В новой версии все будет наоборот. При отсутствии напряжения на выводе диод будет гореть, а при наличии — гаснуть. Для реализации этой хитроумной схемы подключим катоды диода через сопротивления к выводам процессора. А анод — подключим к +5В. Теперь при наличии +5В на выводе МК тока через диод не будет, а при отсутствии напряжения — ток потечет и зажжет светодиод. Естественно, при написании программы нам нужно помнить об инвертированной логике.

Мне посоветовали применить инвертированную же логику и при подключении кнопок — потому, что с учетом возможности короткого замыкания безопаснее тянуть провод с землей, чем с напряжением. Честно говоря, логика мне не совсем понятна — ведь электроны-то «текут» не с положительного, а с отрицательного вывода. Решив разобраться с этим позже, я подключила кнопки немного иначе, чем в предыдущей версии. Теперь при отпущенной кнопке с подключенного к ней вывода МК будет считывать HIGH, а при нажатой кнопке — LOW.

Зачем нам нужна пьезо-пищалка. При наборе точек и тире хотелось бы, не глядя на экран, получать подтверждение, что набранная буква принята и отправлена на компьтер. Иначе при быстром наборе, сделав недостаточную паузу между буквами, мы можем, например, вместо символов АЕ (*- *) отправить на компьютер бкуву Р (*-*). Если пользователь будет получать сигнал при отправке каждой буквы, он наделает меньше ошибок. Конечно, вместо «пищалки» стоило бы использовать вибро-моторчик, но пищалку подключить проще. А с виброй я разберусь в следующей части морзе-эпопеи. Так что пока вместо вибрации каждый отправленный клавиатурой символ будет сопровождаться коротким звуком.

Соберем схему:





Схему я рисовала в программе Fritzing, но мне нигде не удалось найти для нее RGB-светодиода. Поэтому я самостоятельно собрала эту «детальку», склеив красный, зеленый и синий светодиоды. При подключении диода стоит посмотреть на его спецификацию, чтобы понять, где какая ножка. Нелишним будет и протестировать диод, подключив общий анод к плюсу батарейки, а каждый из катодов — поочередно к его минусу. Для тестирования своего светодиода я использовала два подключенных последовательно полуторавольтовых (итого 3 вольта) AA-аккумулятора от фотоаппарата.

Откомпилируем и загрузим код (он довльно подробно откомментирован, так что просто приведу листинг):

//================================================================================================================
// Настройки кнопок.
//================================================================================================================

// Кнопка-точка будет слева.
#define BUTTON_DOT   6
// Кнопка-тире - справа.
#define BUTTON_TIRE  7

int buttons, buttonsPrev; // Здесь будем в виде битовых масок хранить нынешнее и предыдущее состояние клавиш.
#define BUTTON_DOT_MASK   1
#define BUTTON_TIRE_MASK  2

// С помощью этих переменных мы засекаем, когда в последний раз была нажата и отпущена кнопка. Любая. По этому
//  времени мы определяем, завершен ли ввод текущего символа и не пора ли переходить в спящий режим.
unsigned long int timeRelease, timePress;

// Смену состояния кнопки на время менее 0.03с будем считать дребезгом и игнорировать.
#define DEBOUNCING_TIME  30
// В эти переменные будем сохранять время для отфильтровывания дребезга контактов.
unsigned long int timeDotDebouncing;
unsigned long int timeTireDebouncing;

// Максимальная пауза между точками и тире в букве - 0.4 секунды.
//  Если пауза больше - считаем ввод буквы завершенным и переходим к вводу следующей буквы.
#define DELIMITER_TIME  500
// Если кнопка не нажималась более минуты - переходим в спящий режим.
#define SLEEP_TIME  60000
// Выйти из спящего режима можно, удерживая нажатой любую кнопку в течение 1 секунды.
#define WAKEUP_TIME  2000

// Для переключения раскладки на кириллицу нажимаем кнопку-точку и, не отпуская ее, нажимаем кнопку-тире. 
// Для переключения раскладки на латынь нажимаем правую кнопку-тире и, не отпуская ее, нажимаем кнопку-точку. 

//================================================================================================================
// Настройки RGB-светодиода.
//================================================================================================================

// Для обратной связи будем использовать RGB-светодиод:
#define LED_R  11
#define LED_G  10
#define LED_B  9

// Цвета диода будем задавать в виде числа-битовой маски: 00000RGB, вспомним цвета в старых добрых EGA и Yamaha MSX.
//  Семи цветов (черный не в счет) нам более, чем хватит.
#define COLOR_BLACK    0
#define COLOR_BLUE     1
#define COLOR_GREEN    2
#define COLOR_CYAN     3
#define COLOR_RED      4
#define COLOR_MAGENTA  5
#define COLOR_YELLOW   6
#define COLOR_WHITE    7

// Кириллица - зеленый, латынь - желтый, спящий режм - мигание фиолетовым.
#define COLOR_CYRILLIC_LAYOUT  COLOR_GREEN
#define COLOR_LATIN_LAYOUT     COLOR_YELLOW
#define COLOR_SLEEP_MODE       COLOR_MAGENTA

// Яркость мигания для режима печати и спящего режима. Не забывваем, что у нас логика инвертирована
//  и 0 означает максимальную яркость, а 255 - погашенный светодиод.

#define BRIGHTNESS_TYPING_LOW   (255-1)
#define BRIGHTNESS_TYPING_DOT   (255-7)
#define BRIGHTNESS_TYPING_TIRE  (255-15)
#define BRIGHTNESS_SLEEP_LOW    (255-0)
#define BRIGHTNESS_SLEEP_HIGH   (255-1)
/*
#define BRIGHTNESS_TYPING_LOW   (255-7)
#define BRIGHTNESS_TYPING_DOT   (255-128)
#define BRIGHTNESS_TYPING_TIRE  (255-255)
#define BRIGHTNESS_SLEEP_LOW    (255-8)
#define BRIGHTNESS_SLEEP_HIGH   (255-128)
*/
//================================================================================================================
// Настройки пьезо-динамика.
//================================================================================================================

#define PIEZO  12
byte piezoData;
unsigned long int piezoShutUpTime;

//================================================================================================================
// Азбука Морзе.
//================================================================================================================

// Этими символами мы будем обозначать точки и тире.
#define MORSE_DOT     '*'
#define MORSE_TIRE    '-'
// Точка или тире пока не введены. 
#define MORSE_EMPTY   0
// Это - для блокировки ввода точек/тире при смене раскладки или выходе из спящего режима.
#define MORSE_LOCKED  '!'

// Максимальная длина символа азбуки Морзе (в точках и тире)
#define MAX_MORSE_SYMBOL_LENGTH  8
// Буфер для записи морзе-символа.
byte morseSymbol[MAX_MORSE_SYMBOL_LENGTH];
unsigned int morseSymbolLen;
byte newMorseSignal; // Новый введенный сигнал - точка или тире.

// Таблица кодов Морзе. N-ный элемент кода соответствует n-ному символу раскладки.
char* code[] = {
  "*-","-***","*--","--*","-**","*","***-","--**","**","*---",
  "-*-","*-**","--","-*","---","*--*","*-*","***","-","**-",
  "**-*","****","-*-*","---*","----","--*-","-*--","-**-","**-**","**--",
  "*-*-",
  "*----","**---","***--","****-","*****","-****","--***","---**","----*","-----",
  "......","*-*-*-","---***","-*-*-","-*--*-","*----*","*-**-*","-****-","-**-*","**--**","--**--",
  "-***-","********","*--*-*","**-*-",
  ""
};

// Кириллическая раскладка.
char* layoutCyrillic[] = {
  "а","б","в","г","д","е","ж","з","и","й",
  "к","л","м","н","о","п","р","с","т","у",
  "ф","х","ц","ч","ш","щ","ы","ь","э","ю",
  "я",
  "1","2","3","4","5","6","7","8","9","0",
  ".",",",":",";","(","\'","\"","-","/","?","!",
  " *DELIMITER* "," *ERR* ","@"," *END* ",
  ""
  };
// Латинская раскладка.
char* layoutLatin[] = {
  "a","b","w","g","d","e","v","z","i","j",
  "k","l","m","n","o","p","r","s","t","u",
  "f","h","c","ö","ch","q","y","x","é","ü",
  "ä",
  "1","2","3","4","5","6","7","8","9","0",
  ".",",",":",";","(","\'","\"","-","/","?","!",
  " *DELIMITER* "," *ERR* ","@"," *END* ",
  ""
};

char** currentLayout;
char** newLayout;

//================================================================================================================
// Режимы работы.
//================================================================================================================

#define TYPING_MODE  0
#define SLEEP_MODE   1
int mode;
boolean flagWakeUp; // Этот флаг будем использовать для выхода из спящего режима.
byte ledLevelSleepCounter; // Переключатель яркости для мигания диода в спящеь режиме.

//================================================================================================================

void setup() {
  Serial.begin(9600);
  pinMode(LED_R, OUTPUT);
  pinMode(LED_G, OUTPUT);
  pinMode(LED_B, OUTPUT);
  // И кнопки, и светодиод у нас работают с инвертированной логикой: кнопка нажата = LOW, отпущена = HIGH,
  //  светодиод горит на полную яркость = LOW, погашен = HIGH. Погасим светодиоды:
  analogWrite(LED_R, 255);
  analogWrite(LED_G, 255);
  analogWrite(LED_B, 255);

  pinMode(PIEZO, OUTPUT);
  digitalWrite(PIEZO, LOW);

  pinMode(BUTTON_DOT, INPUT);
  pinMode(BUTTON_TIRE, INPUT);
  buttons = 0;
  buttonsPrev = 0;
  
  mode = TYPING_MODE;
  flagWakeUp = false;

  morseSymbolLen = 0;

  currentLayout = layoutLatin;
  newLayout = 0;
  newMorseSignal = MORSE_EMPTY;
  ledLevelSleepCounter = 0;
}

//================================================================================================================
// Зажжем светодиод нужными цветом и яркостью. Не забываем, что у нас инвертирована логика и 0 - это самый яркий
//  свет, а 255 - погашенный светодиод.
void setLed(int ledColor, int ledBrightness) {
  if (ledColor & COLOR_RED) {
    analogWrite(LED_R, ledBrightness);
  } else {
    analogWrite(LED_R, 255);
  }
  if (ledColor & COLOR_GREEN) {
    analogWrite(LED_G, ledBrightness);
  } else {
    analogWrite(LED_G, 255);
  }
  if (ledColor & COLOR_BLUE) {
    analogWrite(LED_B, ledBrightness);
  } else {
    analogWrite(LED_B, 255);
  }
}

//================================================================================================================
// Работа с пьезо-динамиком
void doPiezo(unsigned long int currentTime) {
  if (currentTime >= piezoShutUpTime) {
    if (piezoShutUpTime > 0) {
      piezoShutUpTime = 0;
      digitalWrite(PIEZO, LOW);
    }
    return;
  }
  piezoData = (piezoData == LOW) ? HIGH : LOW;
  digitalWrite(PIEZO, piezoData);
}

void playPiezo(unsigned long int t, unsigned long int currentTime) {
  piezoShutUpTime = currentTime + t;
}

//================================================================================================================
// Считывание состояния кнопки с учетом возможного дребезга контактов.
int getButtonState(int btnPrevState, int BUTTON_PIN, unsigned long int* timeDebouncing, unsigned long int currentTime) {
  int btnState = digitalRead(BUTTON_PIN);
  
  if (btnState == HIGH) {
    if (btnPrevState == LOW) {
      if (*timeDebouncing == 0) {
        // Засечем время, которое кнопка будет нажата - чтобы не спутать дребезг контактов с нажатием.
        *timeDebouncing = currentTime;
        // Пока не воспринимаем нажатие, считая его дребезгом контактов.
        btnState = LOW;
      } else {
        if ((currentTime - *timeDebouncing) < DEBOUNCING_TIME) {
          // Пока не воспринимаем нажатие, считая его дребезгом контактов.
          btnState = LOW;
        } else {
          // Это не дребезг контактов, это реальное нажатие кнопки.
          btnState = HIGH;
          *timeDebouncing = 0;
        }
      }
    } else {
      *timeDebouncing = 0;
    }
  } else {
    if (btnPrevState == HIGH) {
      if (*timeDebouncing == 0) {
        // Засечем время, которое кнопка будет нажата - чтобы не спутать дребезг контактов с нажатием.
        *timeDebouncing = currentTime;
        // Пока не воспринимаем отпускание, считая его дребезгом контактов.
        btnState = HIGH;
      } else {
        if ((currentTime - *timeDebouncing) < DEBOUNCING_TIME) {
          // Пока не воспринимаем отпускание, считая его дребезгом контактов.
          btnState = HIGH;
        } else {
          // Это не дребезг контактов, это реальное отпукание кнопки.
          btnState = LOW;
          *timeDebouncing = 0;
        }
      }
    } else {
      *timeDebouncing = 0;
    }
  }
  
  return btnState;
}

//================================================================================================================
// Отправим на компьютер введенный символ.
void sendMorseSymbol() {
  int i, j;
  if (morseSymbolLen < 1) {
    return;
  }
  playPiezo(50, millis());
  for (i = 0; code[i][0] != '\0'; i++) {
    // Сравним введенный символ с символами из таблицы кодов Морзе.
    for (j = 0; (j < morseSymbolLen) && (code[i][j] != '\0'); j++) {
      if (code[i][j] != morseSymbol[j]) {
        j = -1;
        break;
      }
    }
    if ((j != -1) && (j == morseSymbolLen) && (code[i][j]=='\0')) {
      // Символ из таблицы кодов Морзе соответствует введенному символу.
      //  Отправим символ на компьютер.
      Serial.print(currentLayout[i]);
      morseSymbolLen = 0;
      return;
    }
  }
  // Символ в таблице не найден. Напечатаем нераспознанный символ.
  Serial.print(" [");
  for (i = 0; i < morseSymbolLen; i++) {
    Serial.print(morseSymbol[i]);
  }
  Serial.print("] ");
  morseSymbolLen = 0;
}

//================================================================================================================
// Режим печати

void typingLoop() {
  unsigned long int t, dt; // Эти пременные будем использовать для замеров времени.
  int btnDotState, btnTireState;  // В эти переменные считаем состояния кнопок. В принципе, их можно было бы сразу
                                  //  занести в переменную buttons, но так код будет понятнее.
  int ledLevel; // Яркость диода
  int ledColor; // Цвет диода, битовая маска - 00000RGB.

//  analogWrite(PIEZO, 0);

  t = millis();
  // Не забываем, что у нас логика инвертирована, и нажатая кнопка - это LOW.
  btnDotState = getButtonState((buttonsPrev & BUTTON_DOT_MASK) ? LOW : HIGH, BUTTON_DOT, &timeDotDebouncing, t);
  btnTireState = getButtonState((buttonsPrev & BUTTON_TIRE_MASK) ? LOW : HIGH, BUTTON_TIRE, &timeTireDebouncing, t);
  buttons = ((btnDotState == LOW) ? BUTTON_DOT_MASK : 0) | ((btnTireState == LOW) ? BUTTON_TIRE_MASK : 0);
  
  if (buttons == 0) {
    // Обе кнопки отпущены, можно добавить введенную точку, тире или переключить раскладку.
    // Если пауза дольше SLEEP_TIME - перейдем в спящий режим.
    // Если пауза дольше DELIMITER_TIME - отправим символ.
    if (buttonsPrev != 0) {
      timeRelease = t;
    }
    if (newLayout) {
      currentLayout = newLayout;
      newLayout = 0;
    } else switch (newMorseSignal) {
    case MORSE_DOT:
    case MORSE_TIRE:
      morseSymbol[morseSymbolLen++] = newMorseSignal;
      break; // MORSE_DOT, MORSE_TIRE
    }
    newMorseSignal = MORSE_EMPTY;
    dt = t - timeRelease;
    if ((morseSymbolLen > 0) && (dt > DELIMITER_TIME)) {
      sendMorseSymbol();
    } else if (dt > SLEEP_TIME) {
      mode = SLEEP_MODE;
Serial.println("\nSleep mode\n");
    }
  } else if (newMorseSignal != MORSE_LOCKED) {
    switch (buttons) {
    case BUTTON_DOT_MASK:
      if (newMorseSignal == MORSE_EMPTY) {
        // Нажата "точка".
        newMorseSignal = MORSE_DOT;
        timePress = t;
      }
      break; // BUTTON_DOT_MASK
    case BUTTON_TIRE_MASK:
      if (newMorseSignal == MORSE_EMPTY) {
        // Нажато "тире".
        newMorseSignal = MORSE_TIRE;
        timePress = t;
      }
      break; // BUTTON_DOT_MASK
    case BUTTON_DOT_MASK | BUTTON_TIRE_MASK:
      // Нажаты обе кнопки. Сменим раскладку.
      switch (buttonsPrev ) {
      case 0: // Маловероятно, что обе кнопки нажаты одновременно, но в этом случае переключимся на кириллицу.
      case BUTTON_DOT_MASK:
        if (newLayout == 0) {
          sendMorseSymbol();
          newLayout = layoutCyrillic;
Serial.println("\nLayout: cyrillic\n");
        }
        break; // 0, BUTTON_DOT_MASK
      case BUTTON_TIRE_MASK:
        if (newLayout == 0) {
          sendMorseSymbol();
          newLayout = layoutLatin;
Serial.println("\nLayout: latin\n");
        }
        break; // BUTTON_TIRE_MASK
      }
      timePress = t;
      newMorseSignal = MORSE_LOCKED;
      break; // BUTTON_DOT_MASK | BUTTON_TIRE_MASK
    }
  }
  
  // Займемся светодиодом.
  if (currentLayout == layoutCyrillic) {
    ledColor = COLOR_CYRILLIC_LAYOUT;
  } else {
    ledColor = COLOR_LATIN_LAYOUT;
  }
  setLed(ledColor, (buttons == 0) ? BRIGHTNESS_TYPING_LOW : ((buttons == BUTTON_DOT_MASK) ? BRIGHTNESS_TYPING_DOT : BRIGHTNESS_TYPING_TIRE));
  
  doPiezo(t);
  
  buttonsPrev = buttons;
  delay(10);
}

//================================================================================================================
// Спящий режим
void sleepLoop() {
  unsigned long int t, dt; // Эти пременные будем использовать для замеров времени.
  int btnDotState, btnTireState;  // В эти переменные считаем состояния кнопок. В принципе, их можно было бы сразу
                                  //  занести в переменную buttons, но так код будет понятнее.
  int ledLevel; // Яркость диода
  int ledColor; // Цвет диода, битовая маска - 00000RGB.

  // Мы же  спим - поэтому будем проверять статус кнопок редко - раз в 0.3 с.
  delay(300);

  t = millis();
  // Не забываем, что у нас логика инвертирована, и нажатая кнопка - это LOW.
  btnDotState = getButtonState((buttonsPrev & BUTTON_DOT_MASK) ? LOW : HIGH, BUTTON_DOT, &timeDotDebouncing, t);
  btnTireState = getButtonState((buttonsPrev & BUTTON_TIRE_MASK) ? LOW : HIGH, BUTTON_TIRE, &timeTireDebouncing, t);
  buttons = ((btnDotState == LOW) ? BUTTON_DOT_MASK : 0) | ((btnTireState == LOW) ? BUTTON_TIRE_MASK : 0);

  if (buttons != 0) {
    if (buttonsPrev == 0) {
      timePress = t;
    }
    // Определим, достаточно ли долго была нажата кнопка для выхода из спячки.
    if (!flagWakeUp && ((t - timePress) >= WAKEUP_TIME)) {
      flagWakeUp = true;
    }
  } else {
    if (buttonsPrev != 0) {
      timeRelease = t;
    }
    if (flagWakeUp) {
      // Просыпаемся.
      flagWakeUp = false;
      mode = TYPING_MODE;
Serial.println("\nTYPING_MODE\n");
      return;
    }
  }

  // Помигаем светодиодом.
  if (flagWakeUp) {
    // Зажжем цвет, соответствующий текущей раскладке.
    if (currentLayout == layoutCyrillic) {
      ledColor = COLOR_CYRILLIC_LAYOUT;
    } else {
      ledColor = COLOR_LATIN_LAYOUT;
    }
    ledLevel = BRIGHTNESS_TYPING_TIRE;
  } else {
    ledColor = COLOR_SLEEP_MODE;
    ledLevel = (ledLevelSleepCounter == 0) ? BRIGHTNESS_SLEEP_LOW : BRIGHTNESS_SLEEP_HIGH;
    ledLevelSleepCounter = 1-ledLevelSleepCounter;
  }
  setLed(ledColor, ledLevel);

  buttonsPrev = buttons;
}

//================================================================================================================
// Главный цикл.
void loop() {
  switch(mode) {
    case TYPING_MODE:
      typingLoop();
      break;
    case SLEEP_MODE:
      sleepLoop();
      break;
  }
}


Voila! Что умеет наш девайс? Левая кнопка выдает точку. Правая — тире. При этом диод вспыхивает в такт нажимаемым кнопкам (для тире — ярче, чем для точки). Если нажать левую и, не отпуская ее, правую — переключимся на кириллицу (зеленый цвет диода). А нажав правую и, не отпуская ее, левую — на латынь (желтый цвет). Если в течение минуты ни одна кнопка не нажималась, девайс передет в спящий режим, а диод начнет мигать фиолетовым.

Теоретически клавиатура готова. Но на практике не слишком-то удобно щелкать кнопками, расположенными на макетной плате. Попробуем придать нашей конструкции более функциональный вид.

В качестве корпуса я взяла старый высохший фломастер для надписей на компакт-дисках. В следующий раз я выберу более вместительный корпус — очень уж неудобно в такой узкой трубочке протягивать кучу проводов. А у нас их получится целых 10: 4 от светодиода и по 3 от каждой кнопки. Припаяем к каждой кнопке и диоду необходимые провода и резисторы:


(кажется, на этой фотографии я перепутала провода для напряжения и провода для земли — к счастью, ничего не сгорело, но пришлось все перепаять)

Можно, конечно, было соптимизировать, спаяв внутри вместе 3 «напряжения» и 2 «земли», но тогда смонтировать все это внутри фломастера стало бы сложнее. Кроме того, спаяв вместе кнопки и диод, я бы не смогла экспериментировать с различными вариантами корпусов и размещением кнопок и диода. Поэтому я припала к катодам светодиода по 330-омному резистору и проводок соответствующего цвета (R — оранжевый, G — зеленый, B — синий), а к аноду — оранжево-белый. Так же поступила и с кнопками, припаяв к каждой по 10-килоомному сопротивлению и по 3 провода — для земли (коричневый), питания (рыже-белый) и для подключения к выводам Arduino. Припаивая провода, стоит уделить внимание, какой цвет куда должен быть подсоединен, чтобы, глядя на выходящий из корпуса десяток проводов, не гадать, какой — к чему. Оголенные места проводов я обмотала скотчем. Хотя, видимо, грамотнее было бы изолировать их с помощью термоусадочной трубочки, входящей в набор «Seeeduino Catalyst Pack». Нужно будет расспросить об этом знающих людей :)

Перед тем, как поместить кнопки и диод в корпус, я убедилась, что спаянные детали работают:



Все в сборе:



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

Для следующей версии морзе-клавиатуры я собираюсь подобрать более удобный корпус, в котором уместится вся электроника (нужно будет перейти на более компактную версию Arduino), заменить пищалку вибро-моторчиком и, возможно, дополнить клавиатуру жк-экранчиком, на который можно будет выводить подсказки.
Tags:
Hubs:
Total votes 51: ↑45 and ↓6 +39
Views 7.7K
Comments Comments 32