A simple beacon keyer for the ATtiny13

February 18, 2012 | Arduino | By: Mark VandeWettering

Roger, G3XBM built a simple beacon for light communication using a K1EL beacon keyer chip and a handful of other components. I didn’t have any of those chips around, but I did have some Atmel ATtiny13s lying around. I hacked this simple program together to send Morse code in two different ways: on pin PB1 (pin six) there is a simple on/off keying signal. On pin PB0 (pin five) there is the same signal, modulated with an 800 hz signal. Roger used a similar output to send a modulated version of his call. I hardcoded this program to transmit slow Morse with three second dits (QRSS3). I loaded this onto an ATtiny13 tonight, and hooked a small white led the PWM output pin through a current limiting resistor. Using a primitive receiver I built before, a solar cell hooked into a Radio Shack powered speaker, I tested it out, and it seemed to work rather well: the 800hz tone was clear and audible. I’ll be playing with this some more, but for now, here’s the code:

[sourcecode lang=”cpp”]
/*
* beaker.c
*
* A simple beacon beeper for the ATtiny13
*/

// #define F_CPU 1200000UL
#define F_CPU 9600000UL

#include <inttypes.h>
#include <avr/io.h>
#include <avr/sleep.h>
#include <util/delay.h>

#define FREQ (800)
#define DIT_MS (3000)

#define OUTPUT PB0 /* 800 Hz PWM signal, OC0A */
#define KEY PB1 /* Just a keying output */
#define SWITCH PB4 /* a switch between 12 WPM and QRSS3 */

void
dit()
{
/* on */
TCCR0A |= _BV(COM0A0) ; /* enable OC0A */
PORTB |= _BV(KEY) ;
_delay_ms(DIT_MS) ;

/* off */
TCCR0A &= ~_BV(COM0A0) ; /* disable… */
PORTB &= ~_BV(KEY) ;
_delay_ms(DIT_MS) ;
}

void
dah()
{
/* on */
TCCR0A |= _BV(COM0A0) ;
PORTB |= _BV(KEY) ;
_delay_ms(3*DIT_MS) ;

/* off */
TCCR0A &= ~_BV(COM0A0) ;
PORTB &= ~_BV(KEY) ;
_delay_ms(DIT_MS) ;
}

void
space()
{
_delay_ms(2*DIT_MS) ;
}

void
ioinit()
{
DDRB = _BV(KEY) | _BV(OUTPUT) | _BV(SWITCH) ;
PORTB &= ~_BV(OUTPUT) ;

TCCR0A = _BV(COM0A0) | _BV(WGM01) ;
TCCR0B = _BV(CS01) | _BV(CS00) ;
OCR0A = 93 ;
}

int
main(void)
{
ioinit() ;

for (;;) {
dah() ; dit() ; dah() ; space() ;
dah() ; dit() ; dit() ; dit() ; dit() ; space() ;
dit() ; dit() ; dit() ; dit() ; space() ;
dah() ; dit() ; dit() ; dah() ; space() ;
space() ; space() ;
}

return 0 ;
}
[/sourcecode]

Comments

Comment from MikeK
Time 2/18/2012 at 9:36 am

I always enjoy reading your posts, Mark. Is this version of the code missing the PWM? I don’t see the “FREQ” value being used anywhere.

Comment from Mark VandeWettering
Time 2/18/2012 at 3:04 pm

Nope, it works, and thanks for calling to mind that I didn’t document it very well. The final version will be more copiously documented. But here’s the basic idea. You need to define F_CPU before including the util/delay.h to get them to work. I’ve defined the clock to be 9.6Mhz, to match the internal oscillator on the ATtiny13. In ioinit, I set two bits (CS01 and CS00) to divide this clock by 64. I then set the chip up to do CTC mode (it toggles the output when the counter matches the value of OCR0A). That gets set to 93, which generates an alternating tone of around 800 Hz (9600000 / (2 * 64 * 800), 64 is the division ratio, and 800 is the desired frequency). The output is only hooked to the output pin when the COM0A0 pin is set, so we just let the PWM modulator run, and toggle that bit to turn it on and off.

Comment from Jan
Time 4/22/2012 at 12:58 am

I do not recognize how “sleep.h” is used. No interrupt / watchdog-timer implemented.
Is there any “powersaving”?

Comment from Mark VandeWettering
Time 4/22/2012 at 7:38 am

Good eyes. I didn’t implement any watchdog stuff in this program, but I copied the basic framework from one that did. And of course, it’s got no power saving at all. I was really just trying to get a basic keyer going to toggle my LED beacon. I’m no expert on the AVR power saving modes, and that would have taken me beyond the hour or so I had to make this project work. Still, a great suggestion for a more advanced version.