At my birthday I got a „special“ present from my friends. A screwdriver on which are two 1.5 volt batteries are taped on it. That symbolic „electrical screwdriver“ was decorated with some 5 euro banknotes from which I should buy an electrical screwdriver.
After thinking about the screwdriver with the two batteries an idea come into my mind. I can tape a led and a Atmel AVR microcontroller on this present and the led can blink a morse code message. I locked at the morse code wikipage and found how the morse code alphabet is coded. So I soldered an ATTiny85 with a 51 Ohm resistor and a red led together an wrote the following program.
/*
* MorseCode.c
*
* Created: 17.12.2014
* Author: Matthias Jentsch
*
* The program let a led blink on PB3 to form a morse code. The fixed message will be send.
*/
#include <avr/io.h>
#define F_CPU 1000000UL /* Internal 8MHz clock divided by 8 = 1MHz clock */
#ifndef DEBUG
#include <util/delay.h>
#endif
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
// The sending speed factor; above 1 means send slower; below 1 means send faster
#define FACTOR 1.5
// The SHORT signal period
#define SHORT 100 * FACTOR
// The LONG signal period
#define LONG 300 * FACTOR
// The period of silence between two SHORT/LONG signals
#define SYMBOL_SPACE 100 * FACTOR
// The period of silence between two characters
#define CHARACTER_SPACE 300 * FACTOR
// The period of silence between two words
#define WORD_SPACE 700 * FACTOR
// The period of silence after the complete sentence/message was sent
#define SENTENCE_SPACE 3000 * FACTOR
// That's the messsage that shoul be send
const char PROGMEM _message[] =
"First line of the message " \
"Next line of the message " \
"Last line of the message";
// The morse code alphabet
// The first byte in the line is the count of symbols that are needed to form a character
// The second byte forms the short/long symbols for each character
// Example: 0x04, 0x09 describes the symbols "long short short long" for the character 'X'
const uint8_t _symbols[40][2] =
{
{ 0x02, 0x02 }, // A
{ 0x04, 0x01 }, // B
{ 0x04, 0x05 }, // C
{ 0x03, 0x01 }, // D
{ 0x01, 0x00 }, // E
{ 0x04, 0x04 }, // F
{ 0x03, 0x03 }, // G
{ 0x04, 0x00 }, // H
{ 0x02, 0x00 }, // I
{ 0x04, 0x0E }, // J
{ 0x03, 0x05 }, // K
{ 0x04, 0x02 }, // L
{ 0x02, 0x03 }, // M
{ 0x02, 0x01 }, // N
{ 0x03, 0x07 }, // O
{ 0x04, 0x06 }, // P
{ 0x04, 0x0B }, // Q
{ 0x03, 0x02 }, // R
{ 0x03, 0x00 }, // S
{ 0x01, 0x01 }, // T
{ 0x03, 0x04 }, // U
{ 0x04, 0x08 }, // V
{ 0x03, 0x06 }, // W
{ 0x04, 0x09 }, // X
{ 0x04, 0x0D }, // Y
{ 0x04, 0x03 }, // Z
{ 0x05, 0x1F }, // 0
{ 0x05, 0x1E }, // 1
{ 0x05, 0x1C }, // 2
{ 0x05, 0x18 }, // 3
{ 0x05, 0x10 }, // 4
{ 0x05, 0x00 }, // 5
{ 0x05, 0x01 }, // 6
{ 0x05, 0x03 }, // 7
{ 0x05, 0x07 }, // 8
{ 0x05, 0x0F } // 9
};
// Send one SHORT signal
void BlinkShort()
{
PORTB &= ~(1 << PB3);
#ifndef DEBUG
_delay_ms(SHORT);
#endif
PORTB |= (1 << PB3);
}
// Send one LONG signal
void BlinkLong()
{
PORTB &= ~(1 << PB3);
#ifndef DEBUG
_delay_ms(LONG);
#endif
PORTB |= (1 << PB3);
}
// Wait the SYMBOL_SPACE period
void WaitSymbolSpace()
{
#ifndef DEBUG
_delay_ms(SYMBOL_SPACE);
#endif
}
// Wait the CHARACTER_SPACE period
void WaitCharacterSpace()
{
#ifndef DEBUG
_delay_ms(CHARACTER_SPACE);
#endif
}
// Wait the WORD_SPACE period
void WaitWordSpace()
{
#ifndef DEBUG
_delay_ms(WORD_SPACE);
#endif
}
// Wait the SENTENCE_SPACE period
void WaitSentenceSpace()
{
#ifndef DEBUG
_delay_ms(SENTENCE_SPACE);
#endif
}
// Output one character code; pIndex: Index in _symbols array
void OutputCode(uint8_t pIndex)
{
uint8_t symbolCount = _symbols[pIndex][0];
uint8_t symbols = _symbols[pIndex][1];
for (uint8_t i = 0; i < symbolCount; i++)
{
if ((symbols & (1 << i)) > 0)
{
BlinkLong();
}
else
{
BlinkShort();
}
if (i != symbolCount - 1)
{
WaitSymbolSpace();
}
}
WaitCharacterSpace();
}
// Output one character; pCharacter: The character to send
void OutputCharacter(char pCharacter)
{
// Upper case characters
if (pCharacter >= 'A' && pCharacter <= 'Z')
{
OutputCode(pCharacter - 'A');
}
// Lower case characters
else if (pCharacter >= 'a' && pCharacter <= 'z')
{
OutputCode(pCharacter - 'a');
}
// Decimals
else if (pCharacter >= '0' && pCharacter <= '9')
{
OutputCode(26 + pCharacter - '0');
}
// The german Ä
else if (pCharacter == 'Ä' || pCharacter == 'ä')
{
// will be splitted into AE
OutputCharacter('A');
OutputCharacter('E');
}
// The german Ö
else if (pCharacter == 'Ö' || pCharacter == 'ö')
{
// will be splitted into OE
OutputCharacter('O');
OutputCharacter('E');
}
// The german Ü
else if (pCharacter == 'Ü' || pCharacter == 'ü')
{
// will be splitted into UE
OutputCharacter('U');
OutputCharacter('E');
}
// The german ß
else if (pCharacter == 'ß')
{
// will be splitted into SS
OutputCharacter('S');
OutputCharacter('S');
}
// The space between two words
else if (pCharacter == ' ')
{
WaitWordSpace();
}
}
// The entry point
int main( void )
{
DDRB = ( 1 << PB3 ); // set PB3 at PORTB as output
PORTB |= (1 << PB3);
// read the save point
uint16_t savePoint = eeprom_read_word((const uint16_t*)0);
if (savePoint == 0xFFFF)
{
savePoint = 0;
}
while(1)
{
// output header (training for the receiving app)
OutputCharacter('x');
OutputCharacter('x');
OutputCharacter('x');
OutputCharacter(' ');
// output the message
int max = sizeof(_message) - savePoint;
for (uint16_t i = savePoint; i < max; i++)
{
uint8_t nextCharacter = pgm_read_byte(_message + i);
OutputCharacter(nextCharacter);
// a complete word sent? (current character was a space)
if (nextCharacter == ' ')
{
// write the save point to the last word
eeprom_write_word((uint16_t*)0, savePoint);
// the next save point is the start of the next word (current space + 1)
savePoint = i + 1;
}
}
// reset the save point
eeprom_write_word((uint16_t*)0, 0);
WaitSentenceSpace();
}
return 0;
}
In the _message variable I programmed a special greetings message for my friend. At christmas I gave this morse code blinkig led pen as a present back to my friend. They were really amazed about the present.