Video
# Lab: Morse Code Sending System
## **Objective**
Create a Morse code sending system using the TK04 push button to control the TK01 LED and TK36 buzzer. Press and hold the button to send dots and dashes, with proper Morse code timing and visual/audio feedback.
## **Required Components**

1. **Lonely Binary UNO R3** - Main Arduino board
2. **TinkerBlock UNO R3 Shield** - Expansion shield that plugs onto the UNO R3
3. **TinkerBlock TK01** - LED Module
4. **TinkerBlock TK04** - Push Button Module
5. **TinkerBlock TK36** - Active Buzzer Module
## **Theory**
### **Morse Code Basics**
- **Dot (.)**: Short signal (1 unit duration)
- **Dash (-)**: Long signal (3 units duration)
- **Space between elements**: 1 unit duration
- **Space between letters**: 3 units duration
- **Space between words**: 7 units duration
### **Timing Standards**
- **Unit Duration**: Typically 100-200ms (adjustable)
- **Dot**: 1 unit (100-200ms)
- **Dash**: 3 units (300-600ms)
- **Element Space**: 1 unit (100-200ms)
- **Letter Space**: 3 units (300-600ms)
- **Word Space**: 7 units (700-1400ms)
### **Button Control Logic**
- **Press and Hold**: Send continuous signal (dash)
- **Quick Press**: Send short signal (dot)
- **Release**: Stop signal and add spacing
- **Timing Detection**: Automatic dot/dash determination
- **Pull-down Configuration**: Button uses internal pull-down resistor (LOW when pressed, HIGH when released)
## **Wiring Instructions**
### **TK01 LED Module Pinout**
- **GND** → Arduino GND
- **VCC** → Arduino 5V
- **NC** → No Connection
- **Signal** → Arduino Digital Pin D3
### **TK04 Push Button Pinout**
- **GND** → Arduino GND
- **VCC** → Arduino 5V
- **NC** → No Connection
- **Signal** → Arduino Digital Pin D5
### **TK36 Active Buzzer Pinout**
- **GND** → Arduino GND
- **VCC** → Arduino 5V
- **NC** → No Connection
- **Signal** → Arduino Digital Pin D9
### **Connection Diagram**

```
UNO R3 + Shield
├── Digital Pin D3 ──→ TK01 Signal
├── Digital Pin D5 ──→ TK04 Signal
└── Digital Pin D9 ──→ TK36 Signal
```
## **Basic Morse Code Sending Code**
```cpp
// Basic Morse Code Sending System
// Pin definitions
#define LED_PIN 3 // TK01 LED on D3
#define BUTTON_PIN 5 // TK04 Button on D5
#define BUZZER_PIN 9 // TK36 Buzzer on D9
// Morse code timing (milliseconds)
#define UNIT_TIME 150 // Base unit time (150ms)
#define DOT_TIME UNIT_TIME
#define DASH_TIME (UNIT_TIME * 3)
#define ELEMENT_SPACE UNIT_TIME
#define LETTER_SPACE (UNIT_TIME * 3)
#define WORD_SPACE (UNIT_TIME * 7)
// Button timing
#define DOT_THRESHOLD 300 // Press time threshold for dot vs dash (ms)
#define DEBOUNCE_TIME 50 // Button debounce time (ms)
// Variables
bool buttonPressed = false; // Current button state
bool lastButtonState = false; // Previous button state
unsigned long buttonPressTime = 0; // When button was pressed
unsigned long buttonReleaseTime = 0; // When button was released
bool signalActive = false; // Whether signal is currently being sent
int signalCount = 0; // Count of signals sent
void setup() {
// Initialize serial communication
Serial.begin(9600);
Serial.println("Morse Code Sending System");
Serial.println("=========================");
// Initialize pins
pinMode(LED_PIN, OUTPUT);
pinMode(BUTTON_PIN, INPUT); // Button uses internal pull-down resistor
pinMode(BUZZER_PIN, OUTPUT);
// Start with everything off
digitalWrite(LED_PIN, LOW);
digitalWrite(BUZZER_PIN, LOW);
delay(1000);
Serial.println("System ready! Press and hold TK04 to send Morse code.");
Serial.println("Quick press = Dot (.) | Hold = Dash (-)");
Serial.println("Timing: Dot=");
Serial.print(DOT_TIME);
Serial.print("ms, Dash=");
Serial.print(DASH_TIME);
Serial.println("ms");
Serial.println();
}
void loop() {
// Read button state
bool currentButtonState = digitalRead(BUTTON_PIN); // Direct reading for pull-down
// Handle button press (rising edge for pull-down)
if (currentButtonState && !lastButtonState) {
buttonPressTime = millis();
startSignal();
}
// Handle button release (falling edge for pull-down)
if (!currentButtonState && lastButtonState) {
buttonReleaseTime = millis();
stopSignal();
processSignal();
}
// Update button state
lastButtonState = currentButtonState;
// Small delay for stability
delay(10);
}
// Function to start signal (LED and buzzer on)
void startSignal() {
if (!signalActive) {
signalActive = true;
digitalWrite(LED_PIN, HIGH);
digitalWrite(BUZZER_PIN, HIGH);
Serial.println("Signal START");
}
}
// Function to stop signal (LED and buzzer off)
void stopSignal() {
if (signalActive) {
signalActive = false;
digitalWrite(LED_PIN, LOW);
digitalWrite(BUZZER_PIN, LOW);
Serial.println("Signal STOP");
}
}
// Function to process the signal and determine if it's a dot or dash
void processSignal() {
unsigned long signalDuration = buttonReleaseTime - buttonPressTime;
// Determine if it's a dot or dash based on duration
if (signalDuration < DOT_THRESHOLD) {
// Short press = dot
Serial.print("DOT (.) - Duration: ");
Serial.print(signalDuration);
Serial.println("ms");
signalCount++;
} else {
// Long press = dash
Serial.print("DASH (-) - Duration: ");
Serial.print(signalDuration);
Serial.println("ms");
signalCount++;
}
Serial.print("Total signals: ");
Serial.println(signalCount);
Serial.println();
}
```
## **Advanced Morse Code with Character Recognition**
```cpp
// Advanced Morse Code with Character Recognition
// Pin definitions
#define LED_PIN 3
#define BUTTON_PIN 5
#define BUZZER_PIN 9
// Timing
#define UNIT_TIME 150
#define DOT_TIME UNIT_TIME
#define DASH_TIME (UNIT_TIME * 3)
#define ELEMENT_SPACE UNIT_TIME
#define LETTER_SPACE (UNIT_TIME * 3)
#define WORD_SPACE (UNIT_TIME * 7)
#define DOT_THRESHOLD 300
#define DEBOUNCE_TIME 50
// Morse code alphabet (dots and dashes)
const char* morseAlphabet[] = {
".-", // 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
};
// Variables
bool buttonPressed = false;
bool lastButtonState = false;
unsigned long buttonPressTime = 0;
unsigned long buttonReleaseTime = 0;
bool signalActive = false;
String currentCharacter = ""; // Current character being built
unsigned long lastSignalTime = 0;
bool characterComplete = false;
void setup() {
Serial.begin(9600);
pinMode(LED_PIN, OUTPUT);
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(BUZZER_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
digitalWrite(BUZZER_PIN, LOW);
delay(1000);
Serial.println("Advanced Morse Code System");
Serial.println("==========================");
Serial.println("Send Morse code to build characters and words.");
Serial.println("Quick press = Dot (.) | Hold = Dash (-)");
Serial.println("Wait 3+ units after last signal to complete character.");
Serial.println();
}
void loop() {
bool currentButtonState = digitalRead(BUTTON_PIN);
// Handle button press (falling edge for pull-up)
if (!currentButtonState && lastButtonState) {
buttonPressTime = millis();
startSignal();
}
// Handle button release (rising edge for pull-up)
if (currentButtonState && !lastButtonState) {
buttonReleaseTime = millis();
stopSignal();
processSignal();
}
// Check for character completion
checkCharacterCompletion();
lastButtonState = currentButtonState;
delay(10);
}
void startSignal() {
if (!signalActive) {
signalActive = true;
digitalWrite(LED_PIN, HIGH);
digitalWrite(BUZZER_PIN, HIGH);
}
}
void stopSignal() {
if (signalActive) {
signalActive = false;
digitalWrite(LED_PIN, LOW);
digitalWrite(BUZZER_PIN, LOW);
}
}
void processSignal() {
unsigned long signalDuration = buttonReleaseTime - buttonPressTime;
lastSignalTime = millis();
if (signalDuration < DOT_THRESHOLD) {
currentCharacter += ".";
Serial.print("DOT (.) - Duration: ");
Serial.print(signalDuration);
Serial.println("ms");
} else {
currentCharacter += "-";
Serial.print("DASH (-) - Duration: ");
Serial.print(signalDuration);
Serial.println("ms");
}
Serial.print("Current character: ");
Serial.println(currentCharacter);
}
void checkCharacterCompletion() {
if (currentCharacter.length() > 0) {
unsigned long timeSinceLastSignal = millis() - lastSignalTime;
if (timeSinceLastSignal > LETTER_SPACE) {
// Character is complete, decode it
decodeCharacter();
currentCharacter = "";
lastSignalTime = 0;
}
}
}
void decodeCharacter() {
Serial.print("Character complete: ");
Serial.print(currentCharacter);
Serial.print(" = ");
// Find the character in the alphabet
char decodedChar = '?';
for (int i = 0; i < 26; i++) {
if (currentCharacter == morseAlphabet[i]) {
decodedChar = 'A' + i;
break;
}
}
Serial.println(decodedChar);
Serial.println();
}
// Function to send a specific Morse code character
void sendMorseCharacter(char character) {
character = toupper(character);
if (character >= 'A' && character <= 'Z') {
const char* morseCode = morseAlphabet[character - 'A'];
Serial.print("Sending ");
Serial.print(character);
Serial.print(": ");
Serial.println(morseCode);
for (int i = 0; morseCode[i] != '\0'; i++) {
if (morseCode[i] == '.') {
sendDot();
} else if (morseCode[i] == '-') {
sendDash();
}
delay(ELEMENT_SPACE);
}
delay(LETTER_SPACE);
}
}
void sendDot() {
digitalWrite(LED_PIN, HIGH);
digitalWrite(BUZZER_PIN, HIGH);
delay(DOT_TIME);
digitalWrite(LED_PIN, LOW);
digitalWrite(BUZZER_PIN, LOW);
}
void sendDash() {
digitalWrite(LED_PIN, HIGH);
digitalWrite(BUZZER_PIN, HIGH);
delay(DASH_TIME);
digitalWrite(LED_PIN, LOW);
digitalWrite(BUZZER_PIN, LOW);
}
```
## **Interactive Morse Code Training System**
```cpp
// Interactive Morse Code Training System
// Pin definitions
#define LED_PIN 3
#define BUTTON_PIN 5
#define BUZZER_PIN 9
// Timing
#define UNIT_TIME 150
#define DOT_TIME UNIT_TIME
#define DASH_TIME (UNIT_TIME * 3)
#define ELEMENT_SPACE UNIT_TIME
#define LETTER_SPACE (UNIT_TIME * 3)
#define WORD_SPACE (UNIT_TIME * 7)
#define DOT_THRESHOLD 300
#define DEBOUNCE_TIME 50
// Morse code alphabet
const char* morseAlphabet[] = {
".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---",
"-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-",
"..-", "...-", ".--", "-..-", "-.--", "--.."
};
// Training modes
#define MODE_SEND 1
#define MODE_RECEIVE 2
#define MODE_PRACTICE 3
// Variables
bool buttonPressed = false;
bool lastButtonState = false;
unsigned long buttonPressTime = 0;
unsigned long buttonReleaseTime = 0;
bool signalActive = false;
String currentCharacter = "";
unsigned long lastSignalTime = 0;
int currentMode = MODE_SEND;
int practiceLevel = 1;
int score = 0;
int totalAttempts = 0;
void setup() {
Serial.begin(9600);
pinMode(LED_PIN, OUTPUT);
pinMode(BUTTON_PIN, INPUT); // Button uses internal pull-down resistor
pinMode(BUZZER_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
digitalWrite(BUZZER_PIN, LOW);
delay(1000);
Serial.println("Interactive Morse Code Training System");
Serial.println("=====================================");
Serial.println("Commands:");
Serial.println("s: Send mode (send your own messages)");
Serial.println("r: Receive mode (practice receiving)");
Serial.println("p: Practice mode (send and receive)");
Serial.println("t: Adjust timing");
Serial.println("h: Show help");
Serial.println("v: View statistics");
Serial.println();
displayMenu();
}
void loop() {
// Check for serial commands
if (Serial.available()) {
handleCommand(Serial.read());
}
// Handle button input
bool currentButtonState = digitalRead(BUTTON_PIN);
if (currentButtonState && !lastButtonState) {
buttonPressTime = millis();
startSignal();
}
if (!currentButtonState && lastButtonState) {
buttonReleaseTime = millis();
stopSignal();
processSignal();
}
checkCharacterCompletion();
lastButtonState = currentButtonState;
delay(10);
}
void handleCommand(char command) {
switch (command) {
case 's':
setMode(MODE_SEND);
break;
case 'r':
setMode(MODE_RECEIVE);
break;
case 'p':
setMode(MODE_PRACTICE);
break;
case 't':
adjustTiming();
break;
case 'h':
showHelp();
break;
case 'v':
showStatistics();
break;
}
}
void setMode(int mode) {
currentMode = mode;
currentCharacter = "";
lastSignalTime = 0;
switch (mode) {
case MODE_SEND:
Serial.println("Mode: SEND - Send your own Morse code messages");
break;
case MODE_RECEIVE:
Serial.println("Mode: RECEIVE - Practice receiving Morse code");
startReceiveMode();
break;
case MODE_PRACTICE:
Serial.println("Mode: PRACTICE - Send and receive practice");
startPracticeMode();
break;
}
}
void startReceiveMode() {
Serial.println("I will send a random letter. Try to decode it!");
delay(1000);
sendRandomLetter();
}
void startPracticeMode() {
Serial.println("I will send a letter. Send it back to me!");
delay(1000);
sendRandomLetter();
}
void sendRandomLetter() {
int randomIndex = random(26);
char letter = 'A' + randomIndex;
Serial.print("Sending letter: ");
Serial.println(letter);
delay(1000);
sendMorseCharacter(letter);
Serial.println("What letter was that? Type your answer:");
}
void sendMorseCharacter(char character) {
character = toupper(character);
if (character >= 'A' && character <= 'Z') {
const char* morseCode = morseAlphabet[character - 'A'];
for (int i = 0; morseCode[i] != '\0'; i++) {
if (morseCode[i] == '.') {
sendDot();
} else if (morseCode[i] == '-') {
sendDash();
}
delay(ELEMENT_SPACE);
}
}
}
void sendDot() {
digitalWrite(LED_PIN, HIGH);
digitalWrite(BUZZER_PIN, HIGH);
delay(DOT_TIME);
digitalWrite(LED_PIN, LOW);
digitalWrite(BUZZER_PIN, LOW);
}
void sendDash() {
digitalWrite(LED_PIN, HIGH);
digitalWrite(BUZZER_PIN, HIGH);
delay(DASH_TIME);
digitalWrite(LED_PIN, LOW);
digitalWrite(BUZZER_PIN, LOW);
}
void startSignal() {
if (!signalActive) {
signalActive = true;
digitalWrite(LED_PIN, HIGH);
digitalWrite(BUZZER_PIN, HIGH);
}
}
void stopSignal() {
if (signalActive) {
signalActive = false;
digitalWrite(LED_PIN, LOW);
digitalWrite(BUZZER_PIN, LOW);
}
}
void processSignal() {
unsigned long signalDuration = buttonReleaseTime - buttonPressTime;
lastSignalTime = millis();
if (signalDuration < DOT_THRESHOLD) {
currentCharacter += ".";
} else {
currentCharacter += "-";
}
if (currentMode == MODE_SEND) {
Serial.print("Signal: ");
Serial.println(signalDuration < DOT_THRESHOLD ? "DOT" : "DASH");
}
}
void checkCharacterCompletion() {
if (currentCharacter.length() > 0) {
unsigned long timeSinceLastSignal = millis() - lastSignalTime;
if (timeSinceLastSignal > LETTER_SPACE) {
decodeCharacter();
currentCharacter = "";
lastSignalTime = 0;
}
}
}
void decodeCharacter() {
char decodedChar = '?';
for (int i = 0; i < 26; i++) {
if (currentCharacter == morseAlphabet[i]) {
decodedChar = 'A' + i;
break;
}
}
if (currentMode == MODE_SEND) {
Serial.print("Character: ");
Serial.print(currentCharacter);
Serial.print(" = ");
Serial.println(decodedChar);
} else if (currentMode == MODE_PRACTICE) {
// Check if it matches the expected character
totalAttempts++;
if (decodedChar != '?') {
score++;
Serial.println("Correct! Well done!");
} else {
Serial.println("Incorrect. Try again!");
}
}
}
void adjustTiming() {
Serial.println("Current timing:");
Serial.print("Unit time: ");
Serial.print(UNIT_TIME);
Serial.println("ms");
Serial.print("Dot threshold: ");
Serial.print(DOT_THRESHOLD);
Serial.println("ms");
Serial.println("Enter new unit time (50-500ms):");
while (!Serial.available()) {
delay(100);
}
int newTime = Serial.parseInt();
if (newTime >= 50 && newTime <= 500) {
// Note: In a real implementation, you'd update the timing constants
Serial.print("New unit time: ");
Serial.print(newTime);
Serial.println("ms");
}
}
void showHelp() {
Serial.println("Morse Code Help:");
Serial.println("Quick press = Dot (.)");
Serial.println("Hold press = Dash (-)");
Serial.println("Wait 3+ units after last signal to complete character");
Serial.println("Common letters:");
Serial.println("E = . | T = - | A = .- | I = .. | N = -.");
Serial.println("S = ... | O = --- | H = .... | R = .-.");
Serial.println();
}
void showStatistics() {
Serial.println("Statistics:");
Serial.print("Total attempts: ");
Serial.println(totalAttempts);
Serial.print("Correct answers: ");
Serial.println(score);
if (totalAttempts > 0) {
float accuracy = (float)score / totalAttempts * 100;
Serial.print("Accuracy: ");
Serial.print(accuracy);
Serial.println("%");
}
Serial.println();
}
void displayMenu() {
Serial.println("Current Mode: SEND");
Serial.println("Press button to send Morse code signals");
Serial.println("Use serial commands to change modes");
Serial.println();
}
```
## **Code Explanation**
### **Basic System**
- **Button Control**: Press and hold TK04 to send signals (uses internal pull-down resistor)
- **Visual Feedback**: TK01 LED indicates signal transmission
- **Audio Feedback**: TK36 buzzer provides audio confirmation
- **Timing Detection**: Automatic dot/dash determination based on press duration
- **Button Logic**: HIGH when pressed, LOW when released (pull-down configuration)
### **Advanced Features**
- **Character Recognition**: Decodes complete Morse code characters
- **Alphabet Support**: Full A-Z Morse code alphabet
- **Timing Standards**: Proper Morse code timing intervals
- **Interactive Training**: Multiple practice modes
### **Training Modes**
- **Send Mode**: Send your own Morse code messages
- **Receive Mode**: Practice receiving and decoding
- **Practice Mode**: Two-way communication practice
- **Statistics Tracking**: Monitor learning progress
## **Troubleshooting**
### **Button not responding:**
- Check TK04 wiring (D5 pin)
- Verify pull-down resistor configuration (internal)
- Test button with simple digitalRead
- Check for loose connections
### **LED not lighting:**
- Check TK01 wiring (D3 pin)
- Verify power connections (5V, GND)
- Test LED with simple digitalWrite
- Check for pin conflicts
### **Buzzer not working:**
- Check TK36 wiring (D9 pin)
- Verify power supply (5V required)
- Test buzzer with simple tone
- Check for proper grounding
### **Timing issues:**
- Adjust UNIT_TIME constant
- Modify DOT_THRESHOLD for sensitivity
- Check for delays in other code
- Verify button debouncing
## **Customization Ideas**
### **Add More Features:**
- **Numbers**: Add 0-9 Morse code support
- **Punctuation**: Add common punctuation marks
- **Words**: Pre-programmed word transmission
- **Speed Control**: Adjustable transmission speed
### **Add Sensors:**
- **Light Sensor**: Automatic transmission in darkness
- **Sound Sensor**: Voice-activated transmission
- **Motion Sensor**: Gesture-based control
- **Potentiometer**: Manual speed adjustment
### **Advanced Features:**
- **Memory**: Store and replay messages
- **Wireless**: Bluetooth or WiFi transmission
- **Display**: LCD screen for message display
- **Recording**: Save transmission history
## **Next Steps**
- Practice with common letters and words
- Experiment with different timing settings
- Create custom Morse code patterns
- Build complete communication systems
## **Resources**
- **Morse Code Standards**: International Morse code specifications
- **Timing Guidelines**: Proper Morse code timing intervals
- **Learning Resources**: Morse code practice materials
- **Communication Theory**: Signal transmission principles