A few months ago, I wrote some code for my Arduino board, to act as a Amateur Radio Fox Hunt Beacon. It is made to act as the hidden transmitter setup. Last week I was contacted by Dennis, N8ERF, asking if he could use the setup I had. He was doing a Fox Hunt for the school radio class that he teaches. I loaned him my Arduino board and a Yaesu VX-1, micro sized HT. It was set on low power with 200mw.
Today he held the Fox Hunt at the school. Unfortunately I couldn’t make it, since me kids get off the bus at the time he does the class. He Emailed me today and said it went well. They had 4 teams searching for the “Fox”. They want to do another hunt next week, with 2 hidden transmitters.
I have been asked by some other Hams to provide the code I used. Below is the Arduino sketch I have written.
/*
Foxhunt IDer
Written by
Mark Rodgers - KC8GRQ
http://Mark-Rodgers.com
http://Mark-Rodgers.com/fox-hunt-beacon
Morse blinker/sounder
Written By KB3VCQ
*/
// Global variables
boolean done = false; // initialize a Boolean flag if we don't want to endlessly loop
#define PTT_Low 2 // Transmitter PTT. If PTT goes LOW, use PIN 2
#define PTT_High 3 // Transmitter PTT. If PTT goes HIGH, use PIN 3
#define FOUND 4 // This is the IM FOUND button. Keep LOW for off. Switch HIGH for FOUND Tone Activation.
#define LED 13
#define SPEAKER 6 // Audio out to radio
#define TONE 600.0 // Tone of CWID
#define USESPEAKER true
#define intracharacter 3 // delay between characters
#define dot 1 // length of a dit -- 1 unit
#define dash 3 // length of a dah
#define eow 7 // length at end of word
#define fiveWPM 240 // milliseconds for 5 wpm (based on sending PARIS 5 times for a total of 250 units)
#define wpm 15 // *** SET THIS TO YOUR DESIRED SPEED ***
#define speed fiveWPM / (wpm / 5) // multiplier to apply to 5 wpm rate. 2 = 10wpm, 2.5 = 15wmp, etc.
// CHANGE THESE SETTINGS
// CHANGE THESE SETTINGS
char send[] = "KC8GRQ FOXHUNT TRANSMITTER"; // SET THIS TO THE CW STRING YOU WANT TO SEND -- MUST BE UPPRCASE ***
int timer = 10; // Set the time between transmissions in SECONDS
char PTT_Setting = LOW; // Set how your radio transmits. Low = PTT goes LOW. High = PTT goes HIGH
// CHANGE THESE SETTINGS
// CHANGE THESE SETTINGS
int tx_hold = timer*1000;
// Morse code tokens. 0 = dit, 1 = dah any other character will generate 8 dit error.
// NOTE: These need to be in ASCII code sequence to work
char tokens [][7] = { "110011","100001", // ,,-
"010101","10010", // .,/
"11111","01111","00111","00011","00001","00000", // 0,1,2,3,4,5
"10000","11000","11100","11110", // 6,7,8,9
"111000","10101","<", // :,;,<
"=",">","001100", // =,>,?
"@", // @,
"01","1000","1010", // A,B,C
"100","0","0010", // D,E,F
"110","0000","00", // G,H,I
"0111","101","0100", // J,K,L
"11","10","111", // M,N,O
"0110","1101","010", // P,Q,R
"000","1","001", // S,T,U
"0001","011","1001", // V,W,X
"1011","1100"}; // Y,Z }
;
// Arduino setup routine
void setup()
{
pinMode(SPEAKER,OUTPUT);
pinMode(PTT_Low, OUTPUT);
pinMode(PTT_High, OUTPUT);
pinMode(FOUND, INPUT);
digitalWrite(PTT_Low, HIGH); // Sets the PTT to OFF when its not supposed to TX
digitalWrite(PTT_High, LOW); // Sets the PTT to OFF when its not supposed to TX
}
// Routine to output a dit
void dit()
{
if (USESPEAKER)
{
tone(SPEAKER,TONE, dot * speed);
delay(dot * speed); }
else
{
digitalWrite(LED, HIGH); // set the LED on
delay(dot * speed); // wait for a dot's worth
digitalWrite(LED, LOW); // set the LED off
}
delay(speed);
}
// Routine to output a dah
void dah()
{
if (USESPEAKER)
{
tone(SPEAKER,TONE, dash * speed);
delay(dash * speed);
}
else
{
digitalWrite(LED, HIGH); // set the LED on
delay(dash * speed); // wait for a dah's worth
digitalWrite(LED, LOW); // set the LED off
}
delay(speed);
}
// Intracharacter delay
void ic()
{
digitalWrite(LED, LOW); // set the LED off
delay (intracharacter * speed); // wait for a half second
}
// a space is 7 units of off based on speed
void spaceCharacter()
{
digitalWrite(LED, LOW); // set the LED off
delay((eow * speed) + (intracharacter * speed)); // wait for 7 units
}
// Send a CW error for unknown characters
void error()
{
for (int i = 0; i < 8; i++)
{
dit();
}
ic();
}
// Look up a character in the tokens array and send it
void send_element(int c)
{
char token_to_send[7]; // allocate space for the token
strcpy(token_to_send,tokens[c]); // copy the token from the table into our variable
int len = strlen(token_to_send); // figure out how many dit dahs are in it
for (int i = 0; i < len; i++) // for each item in the token
{
if (token_to_send[i] == '0') // if its a 0
{
dit(); // send a dit
}
else if (token_to_send[i] == '1')
{
dah(); // otherwise we send a dah
}
else
{
error(); // we don't have a valid morse token
}
}
ic(); // after each character there is an intercharacter delay
}
// The main send routine. Pull each character apart and determine its corresponding token.
void send_code()
{
int len = strlen(send); // get the length of the string to send
int c;
for (int i = 0; i < len; i++) // loop thru each character in the string to send
{
c = send[i]; // get the ASCII integer value of the character
if (c == ' ') // see if we are between words
{
spaceCharacter(); // send a space
}
else
{
c -= ','; // offset it by the lowest ASCII character in the tokens table (a comma)
send_element(c); // send that element from the token array
}
}
}
void startup_tones()
{
tone(SPEAKER,300,500);
delay(1000);
tone(SPEAKER,350,500);
delay(1000);
tone(SPEAKER,400,500);
delay(1000);
tone(SPEAKER,450,500);
delay(1000);
tone(SPEAKER,500,500);
delay(1000);
tone(SPEAKER,550,500);
delay(1000);
tone(SPEAKER,600,500);
delay(1000);
tone(SPEAKER,650,500);
delay(1000);
tone(SPEAKER,700,500);
delay(1000);
tone(SPEAKER,750,500);
delay(1000);
tone(SPEAKER,800,500);
};
void found_tones()
{
tone(SPEAKER,400,500);
delay(130);
tone(SPEAKER,600,500);
delay(130);
tone(SPEAKER,800,500);
delay(800);
tone(SPEAKER,400,500);
delay(130);
tone(SPEAKER,600,500);
delay(130);
tone(SPEAKER,800,500);
delay(800);
tone(SPEAKER,400,500);
delay(130);
tone(SPEAKER,600,500);
delay(130);
tone(SPEAKER,800,500);
delay(3000);
};
// The Arduino main run loop
void loop()
{
if (!done) // see if we are done the loop
{
digitalWrite(PTT_Low, LOW); // Enable PTT for "Low" type radios
digitalWrite(PTT_High, HIGH); // Enable PTT for "High" type radios
delay(2000); // Wait 2 seconds to allow radio to Key Up
startup_tones(); // Play the startup tones
delay(3000); // Wait 3 seconds
if (digitalRead(FOUND) == HIGH) { found_tones(); }; // Check to see if FOUND button was pressed, if YES, then play tones
send_code(); // send the string
spaceCharacter(); // make sure we have a space if we loop around to the beginning
delay(1000); // Wait 1 second to allow radio to UnKey
digitalWrite(PTT_Low, HIGH); // Disable PTT for "Low" type radios
digitalWrite(PTT_High, LOW); // Disable PTT for "High" type radios
// Multiple delays are used below, since the code doesnt like to run long delays. Use multiples for more time.
delay(tx_hold); // Delay between transmissions, set above in config area
delay(tx_hold); // Delay between transmissions, set above in config area
//delay(tx_hold); // Delay between transmissions, set above in config area
//delay(tx_hold); // Delay between transmissions, set above in config area
//delay(tx_hold); // Delay between transmissions, set above in config area
done = false; // Uncomment to set our flag to finish sending
}
}