With just 8 pins, if you use the internal oscillator, you get 6 available pins for input and output which is really quite a lot for many simple tasks like this.
In the code below, pin 5 is the keyer output, pin 6 is an inverted version and pin 7 is an audio side tone output.
My code is a simplification and an extension (to include the full alphabet and make a side tone) of the code that is "© 1997-2006 by AWC, 310 Ivy Glen, League City, TX 77573" so I hope it's ok to present it here:
/*
Morse ident, based on code from:
http://www.awce.com/cbasic.htm
*/
#include
#include
#define F_CPU 800000UL // Sets up the default speed for delay.h
#include
#include
/* dit delay for morse code */
#define DITDELAY 50 /* mS */
#define OUTPORT PORTB
#define OUTPORTDIRECTION DDRB
// the normal output bit
#define OUTBIT 0
// inverted version out bit
#define INVERTED_OUTBIT 1
// tone output bit
#define TONE_OUTBIT 2
void sendchar(int c);
void tone(int length);
int main (void)
{
// Put beacon message in program memory
PGM_P *message=PSTR("cq cq cq cq de vk2tpm ");
OUTPORTDIRECTION = _BV(OUTBIT) | _BV(INVERTED_OUTBIT) | _BV(TONE_OUTBIT);
while (1)
{
int c;
// Send each character in message
PGM_P ptr=message;
for (c=pgm_read_byte(ptr); c; c=pgm_read_byte(++ptr))
{
sendchar(c);
}
_delay_ms(30000); // wait 30 seconds
}
return 0;
}
/* Send a Morse code element (.- or space) */
void send(char c)
{
switch (c)
{
case '-':
OUTPORT = _BV(OUTBIT);
tone(3*DITDELAY);
OUTPORT = _BV(INVERTED_OUTBIT);
break;
case '.':
OUTPORT = _BV(OUTBIT);
tone(DITDELAY);
OUTPORT = _BV(INVERTED_OUTBIT);
break;
case ' ':
_delay_ms(4*DITDELAY);
break;
}
_delay_ms(DITDELAY); /* inter element space */
}
// play a tone for the given length
void tone(int length)
{
int i;
for(i = 0; i < length; i++)
{
// leave the other bits in place
OUTPORT ^= _BV(TONE_OUTBIT);
_delay_ms(2);
}
}
// Send a character (made from dots/dashes) from program memory
void sendc(PGM_P s)
{
int c;
for (c=pgm_read_byte(s);c;c=pgm_read_byte(++s))
{
send(c);
}
}
// Send an ASCII character
void sendchar(int c)
{
switch (toupper(c))
{
case ' ': sendc(PSTR(" ")); break;
case 'A': sendc(PSTR(".-")); break;
case 'B': sendc(PSTR("-...")); break;
case 'C': sendc(PSTR("-.-.")); break;
case 'D': sendc(PSTR("-..")); break;
case 'E': sendc(PSTR(".")); break;
case 'F': sendc(PSTR("..-.")); break;
case 'G': sendc(PSTR("--.")); break;
case 'H': sendc(PSTR("....")); break;
case 'I': sendc(PSTR("..")); break;
case 'J': sendc(PSTR(".---")); break;
case 'K': sendc(PSTR("-.-")); break;
case 'L': sendc(PSTR(".-..")); break;
case 'M': sendc(PSTR("--")); break;
case 'N': sendc(PSTR("-.")); break;
case 'O': sendc(PSTR("---")); break;
case 'P': sendc(PSTR(".--.")); break;
case 'Q': sendc(PSTR("--.-")); break;
case 'R': sendc(PSTR(".-.")); break;
case 'S': sendc(PSTR("...")); break;
case 'T': sendc(PSTR("-")); break;
case 'U': sendc(PSTR("..-")); break;
case 'V': sendc(PSTR("...-")); break;
case 'W': sendc(PSTR(".--")); break;
case 'X': sendc(PSTR("-..-")); break;
case 'Y': sendc(PSTR("-.--")); break;
case 'Z': sendc(PSTR("--..")); break;
case '1': sendc(PSTR(".----")); break;
case '2': sendc(PSTR("..---")); break;
case '3': sendc(PSTR("...--")); break;
case '4': sendc(PSTR("....-")); break;
case '5': sendc(PSTR(".....")); break;
case '6': sendc(PSTR("-....")); break;
case '7': sendc(PSTR("--...")); break;
case '8': sendc(PSTR("---..")); break;
case '9': sendc(PSTR("----.")); break;
case '0': sendc(PSTR("-----")); break;
}
send(' ');
}
When I burn it with the fabulous AVRDUDE I get:
Writing | ################################################## | 100% 34.10s
avrdude: 1026 bytes of flash written
avrdude: safemode: lfuse reads as 62
avrdude: safemode: hfuse reads as DF
avrdude: safemode: efuse reads as FF
avrdude: safemode: Fuses OK
avrdude done. Thank you.
So the code uses just 1026 bytes out of the available 8k which means a lot more can be done on one of these chips.
Excellent Peter!
ReplyDeleteWhere are you going to setup the beacon? I'm thinking 20 or 15 metres for mine (mainly because I have crystals for those bands). I've got a solar panel doing nothing, so I might power it off that to make it free to run. Figure I'll use a transmitting loop to keep the size down. If the sun was more active I'd put it on 10 metres, but that will have to wait for a few years.
I got my tool chain working yesterday, and got this compiled and turned into a hex file for the ATTiny13V.
Haven't got to programming it into a chip yet, I've been feeling *really* crook, I think I have that weird flu going around and I just want to stay in bed and sleep.
BTW, can you include the code as a file, it is getting interpreted as markup.
20 metres is my band of choice at the moment.
ReplyDeleteI'll have to figure out the best way to publish the source file, blogger won't let me upload it as it is for some reason.
I hope you got the updated version of this source where I've added the inverted output and audio pin.. both good improvements.
Sorry to hear you are not feeling well. Take care.
Peter
Yep fine to post it here. 73 de WD5GNR
ReplyDeleteThanks Al.
ReplyDeleteThought you might be interested in my ATTINY85 keyer! http://projectmf.homelinux.com/keyer/ and https://www.youtube.com/watch?v=Ol6krttaOy0
ReplyDelete73,
Don
WD9DMP