/ / ===================================== ==================================== === ============== // Button settings. // =============================================== ==================================== === ============== // The button-point will be on the left. #define BUTTON_DOT 6 // The dash button is on the right. #define BUTTON_TIRE 7 int buttons, buttonsPrev; // Here we will keep the current and previous state of the keys in the form of bit masks. #define BUTTON_DOT_MASK 1 #define BUTTON_TIRE_MASK 2 // With these variables, we detect when the button was last pressed and released. Any. From this // time, we determine whether the input of the current character is complete and whether it is time to go into sleep mode. unsigned long int timeRelease, timePress; // Change the state of the button to a time less than 0.03s will be considered bounce and ignored. #define DEBOUNCING_TIME 30 // In these variables we will save time to filter out contact bounce. unsigned long int timeDotDebouncing; unsigned long int timeTireDebouncing; // Maximum pause between points and a dash in a letter - 0.4 seconds. // If the pause is longer, we consider the input of the letter completed and proceed to the next letter. #define DELIMITER_TIME 500 // If the button is not pressed for more than a minute, go to sleep mode. #define SLEEP_TIME 60000 // Exit from sleep mode by holding down any button for 1 second. #define WAKEUP_TIME 2000 // To switch the layout to Cyrillic, press the button-point and, without releasing it, press the button-dash. // To switch the layout to Latin, press the right button-dash and, without releasing it, press the button-point. // =============================================== ================================================= ============== // RGB-LED settings. // =============================================== ================================================= ============== // For feedback, we will use the RGB-LED: # define LED_R 11 # define LED_G 10 # define LED_B 9 // The diode colors will be specified as a number-bit mask: 00000RGB, remember the colors in the good old EGA and Yamaha MSX. // Seven colors (black does not count) are more than enough for us. #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 Cyrillic 7 // - green, Latin - Yellow sleeping mode indicator - purple flashing. #define COLOR_CYRILLIC_LAYOUT COLOR_GREEN #define COLOR_LATIN_LAYOUT COLOR_YELLOW #define COLOR_SLEEP_MODE COLOR_MAGENTA // Flashing brightness for print mode and sleep mode. Do not forget that our logic is inverted // and 0 means the maximum brightness, and 255 is an off LED. #define BRIGHTNESS_TYPING_LOW (255-1) #define BRIGHTNESS_TYPING_aaaaaaaa (255-7) #define BRIGHTNESS_TYPING_TIRE (255-15) #define BRIGHTNESS_SLEEP_LOW (255-0) #define BRIGHTNESS_SLEEP_HEktha of the Waktha (575) deptineLive_LOW (255-0) #define BRIGHTNESS_TYPING_DOT (255-128) #define BRIGHTNESS_TYPING_TIRE (255-255) #define BRIGHTNESS_SLEEP_LOW (255-8) #define BRIGHTNESS_SLEEP_HIGH (255-128) * / // ========== ================================================= ================================================ // Piezo dynamics settings. // =============================================== ================================================= ============== #define PIEZO 12 byte piezoData; unsigned long int piezoShutUpTime; // =============================================== ================================================= ============== // Morse Code. // =============================================== ================================================= ============== // These symbols will denote dots and dashes. #define MORSE_DOT '*' #define MORSE_TIRE '-' // A point or a dash has not been entered yet. #define MORSE_EMPTY 0 // This is for blocking the entry of points / dashes when changing the layout or resuming from sleep mode. #define MORSE_LOCKED '!' // Maximum length of Morse code symbol (in dots and dashes) #define MAX_MORSE_SYMBOL_LENGTH 8 // Buffer for recording Morse character. byte morseSymbol [MAX_MORSE_SYMBOL_LENGTH]; unsigned int morseSymbolLen; byte newMorseSignal; // New signal entered - point or dash. // Morse code table. The nth element of the code corresponds to the nth character of the layout. char * code [] = {"* -", "- ***", "* -", "- *", "- **", "*", "*** -", "- - ** "," ** "," * --- "," - * - "," * - ** "," - "," - * "," --- "," * - * "," * - * "," *** "," - "," ** - "," ** - * "," **** "," - * - * "," --- * "," ---- "," - * - "," - * - "," - ** - "," ** - ** "," ** - "," * - * - "," * ---- "," ** --- "," *** - "," **** - "," ***** "," - **** " , "- ***", "--- **", "---- *", "-----", "......", "* - * - * -" , "--- ***", "- * - * -", "- * - * -", "* ---- *", "* - ** - *", "- *** * - "," - ** - * "," ** - ** "," - ** - "," - *** - "," ******** "," * - * - * "," ** - * - "," "}; // Cyrillic layout. char * layoutCyrillic [] = {"a", "b", "c", "g", "d", "e", "g", "g", "u", "d", "k" , "l", "m", "n", "o", "p", "p", "s", "t", "y", "f", "x", "c", " h "," sh "," u "," s "," "," e "," yu "," i "," 1 "," 2 "," 3 "," 4 "," 5 " , "6", "7", "8", "9", "0", ".", ",", ":", ";", "(", "\ '", "\" " , "-", "/", "?", "!", "* DELIMITER *", "* ERR *", "@", "* END *", "" "; // Latin layout. 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 ; // ============================================== ================================================= =============== // Modes of operation. // ============================ ================================================= ================================== #define TYPING_MODE 0 #define SLEEP_MODE 1 in t mode; boolean flagWakeUp; // This flag will be used to exit sleep mode. byte ledLevelSleepCounter; // Brightness switch for flashing diode in sleep mode. // =============================================== ================================================= ============== void setup () {Serial.begin (9600); pinMode (LED_R, OUTPUT); pinMode (LED_G, OUTPUT); pinMode (LED_B, OUTPUT); // Both the buttons and the LED work with inverted logic: the button is pressed = LOW, released = HIGH, // the LED is on full brightness = LOW, turned off = HIGH. Extinguish the LEDs: 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; } // ============================================== ================================================= =============== // Light the LED with the desired color and brightness. Do not forget that our logic is inverted and 0 is the brightest // light, and 255 is the extinguished LED. 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); }} // ============================================= ================================================= ================ // Working with void doPiezo piezo speaker (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; } // ============================================== ================================================= =============== // Read the state of the button, taking into account the possible bounce of contacts. 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) {// Mark the time that the button will be pressed - so as not to confuse the bounce of contacts with pressing. * timeDebouncing = currentTime; // While we do not perceive pressing, considering it as a bounce of contacts. btnState = LOW; } else {if ((currentTime - * timeDebouncing) <DEBOUNCING_TIME) {// While we do not perceive the click, considering it as a contact bounce. btnState = LOW; } else {// This is not the bounce of contacts, this is the real button click. btnState = HIGH; * timeDebouncing = 0; }}} else {* timeDebouncing = 0; }} else {if (btnPrevState == HIGH) {if (* timeDebouncing == 0) {// Mark the time that the button will be pressed - so as not to confuse the bounce of contacts with pressing. * timeDebouncing = currentTime; // While we do not perceive the release, considering it as a bounce of contacts. btnState = HIGH; } else {if ((currentTime - * timeDebouncing) <DEBOUNCING_TIME) {// While we do not perceive release, considering it as a bounce of contacts. btnState = HIGH; } else {// This is not a bounce of contacts, this is a real button out. btnState = LOW; * timeDebouncing = 0; }}} else {* timeDebouncing = 0; }} return btnState; } // ============================================== ================================================= =============== // Send the entered character to the computer. void sendMorseSymbol () {int i, j; if (morseSymbolLen <1) {return; } playPiezo (50, millis ()); for (i = 0; code [i] [0]! = '\ 0'; i ++) {// Compare the entered character with the characters from the Morse code table. for (j = 0; (j <morseSymbolLen) && (code [i] [j]! = '\ 0'); j ++) {if (code [i] [j]! = morseSymbol [j]) {j = -one; break; }} if ((j! = -1) && (j == morseSymbolLen) && (code [i] [j] == '\ 0')) {// The symbol from the Morse code table corresponds to the entered character. // Send the character to the computer. Serial.print (currentLayout [i]); morseSymbolLen = 0; return; }} // Character not found in the table. Print the unrecognized symbol. Serial.print ("["); for (i = 0; i <morseSymbolLen; i ++) {Serial.print (morseSymbol [i]); } Serial.print ("]"); morseSymbolLen = 0; } // ============================================== ================================================= =============== // Print mode void typingLoop () {unsigned long int t, dt; // These variables will be used for time measurements. int btnDotState, btnTireState; // In these variables, count the states of the buttons. In principle, they could immediately be entered into the buttons variable, but the code will be clearer. int ledLevel; // Diode brightness int ledColor; // Color of the diode, the bit mask - 00000RGB. // analogWrite (PIEZO, 0); t = millis (); // Do not forget that our logic is inverted, and the pressed button is 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) {// Both buttons are released, you can add the entered point, a dash or switch the layout. // If the pause is longer than SLEEP_TIME - go to sleep mode. // If the pause is longer DELIMITER_TIME - send the symbol. 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) {// Pressed point. newMorseSignal = MORSE_DOT; timePress = t; } break; // BUTTON_DOT_MASK case BUTTON_TIRE_MASK: if (newMorseSignal == MORSE_EMPTY) {// Press the "dash". newMorseSignal = MORSE_TIRE; timePress = t; } break; // BUTTON_DOT_MASK case BUTTON_DOT_MASK | BUTTON_TIRE_MASK: // Both buttons are pressed. Change the layout. switch (buttonsPrev) {case 0: // It is unlikely that both buttons are pressed simultaneously, but in this case we will switch to Cyrillic. 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}} // Let's do the LED. 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); } // ============================================== ================================================= =============== // Hibernate void sleepLoop () {unsigned long int t, dt; // These variables will be used for time measurements. int btnDotState, btnTireState; // In these variables, count the states of the buttons. In principle, they could immediately be entered into the buttons variable, but the code will be clearer. int ledLevel; // Diode brightness int ledColor; // Color of the diode, the bit mask - 00000RGB. // We are sleeping - so we will rarely check the status of the buttons - once every 0.3 s. delay (300); t = millis (); // Do not forget that our logic is inverted, and the pressed button is 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; } // Determine whether the button was pressed long enough to exit hibernation. if (! flagWakeUp && ((t - timePress)> = WAKEUP_TIME)) {flagWakeUp = true; }} else {if (buttonsPrev! = 0) {timeRelease = t; } if (flagWakeUp) {// Wake up. flagWakeUp = false; mode = TYPING_MODE; Serial.println ("\ nTYPING_MODE \ n"); return; }} // We blink the LED. if (flagWakeUp) {// Light the color corresponding to the current layout. 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; } // ============================================== ================================================= =============== // The main loop. void loop () {switch (mode) {case TYPING_MODE: typingLoop (); break; case SLEEP_MODE: sleepLoop (); break; }}
Source: https://habr.com/ru/post/85530/
All Articles