Sunday, September 28, 2014
Sunday, September 21, 2014
220 MHz Ground Plane II
Sunday, September 14, 2014
220 Mhz Ground Plane Antenna
I will be needing a dedicated 220 MHz antenna for an upcoming project and needed it to be small. I had built a nice 220 Mhz J-pole that turned out being to large and the "home congress" rejected it's installation. A quarter wave ground plane is nice and small so it can be made "stealth". I had build other SO-239 connector antennas before, in fact one of my first antenna for 2 meters was one of this type and I soldered all of it and just used 12 AWG bare solid wire. It worked out great, but one drawback of the solid copper wire it that it not that stiff and if the wind blows hard for several days your antenna will get deformed and you will need to straighten it. I had always heard of people building them with welding rods (much stiffer than copper wire). A quick search on the internet yielded that basic dimensions AI4JI's website for a 220 Mhz antenna and I began work.
I had these BernzOmatic rods that I got with a little torch years ago and there were 5 rods in the package. This is the perfect number however each rod is only 12 inches long. Before using these rods the flux was removed. The easiest way is to just take a hammer and gently pound on the rod until it crumbles off, then sand it clean with sand paper.
The solution to the short rods was solved by using 2 inch lengths of 1/4 inch copper pipe. This is the soft copper tubing you use for connecting a ice maker to your frig. As you can see, I flatten part if it so I can make the radials 13.4 inches long.
The flatten section also allows an easy way to bend the radials at the required 45 degree angle.
For the radiator or vertical element, I just used a ring lug to extend it's length and it add safety by not being so pointed.
Here is the completed antenna before being painted. The antenna drops into a 3/4 inch PVC pipe that has been split on the ends so a house clamp will hold the antenna firmly in place. After the paint dries I will post more pictures and the mounting arrangement. The SWR was below 1.3:1 across the whole band.
I had these BernzOmatic rods that I got with a little torch years ago and there were 5 rods in the package. This is the perfect number however each rod is only 12 inches long. Before using these rods the flux was removed. The easiest way is to just take a hammer and gently pound on the rod until it crumbles off, then sand it clean with sand paper.
The solution to the short rods was solved by using 2 inch lengths of 1/4 inch copper pipe. This is the soft copper tubing you use for connecting a ice maker to your frig. As you can see, I flatten part if it so I can make the radials 13.4 inches long.
The flatten section also allows an easy way to bend the radials at the required 45 degree angle.
For the radiator or vertical element, I just used a ring lug to extend it's length and it add safety by not being so pointed.
Here is the completed antenna before being painted. The antenna drops into a 3/4 inch PVC pipe that has been split on the ends so a house clamp will hold the antenna firmly in place. After the paint dries I will post more pictures and the mounting arrangement. The SWR was below 1.3:1 across the whole band.
Saturday, September 6, 2014
Ferrite Core Memory
I read Mark's blog posting on Brainwagon about rope core memory and it's relation to the Apollo program with great interest, I have always been a fan if this tech. I also found another great posting on Wayne's blog HERE searching for other core memory stuff.
I set out to duplicate Wayne's work but tried to do it with only off the shelf modules and really no circuit building. I did want to step it up a little so I did build a 4-bit core memory unit.
I obtained my cores just as Wayne did, from eBay. It took a few weeks for the cores to ship but they came in a very small package from Bulgaria. The extra URLs that Mark provided in his posting gave me the pattern for my 4-bit core array. I used a proto board PCB to make a tiny breakout assembly with header pins to allow me to plug it into a standard breadboard. My idea is to use a standard L298N motor controller board instead of building a driver circuit from scratch like Wayne.
I set out to duplicate Wayne's work but tried to do it with only off the shelf modules and really no circuit building. I did want to step it up a little so I did build a 4-bit core memory unit.
I obtained my cores just as Wayne did, from eBay. It took a few weeks for the cores to ship but they came in a very small package from Bulgaria. The extra URLs that Mark provided in his posting gave me the pattern for my 4-bit core array. I used a proto board PCB to make a tiny breakout assembly with header pins to allow me to plug it into a standard breadboard. My idea is to use a standard L298N motor controller board instead of building a driver circuit from scratch like Wayne.
The L298N boards are very available and I use them to drive both relays and motors. For the 4-bit array you would just need two of these boards. Here is the basic hook-up with two boards. Note; You will need a load resistor in each motor line (4 total) to limit the current, I use a 10 ohm resistor with 5 volts just like Wayne.
I lashed up a single L298N board to one core initially to see if it would work and I pretty much duplicated Wayne's results.
I am pulsing to the core three times just as Wayne did, first to set it to a "1" then followed by two pulses writing it to "0". On the scope I am displaying the three sync pulses (top trace) and the output of the sense wire (bottom trace), note the noise too. The sync pulse line is separate from the drive lines to be used with the scope, in the code this is PIN 12. The sync is just for the scope to use since the drive lines change polarity making the display not as clean.
You can see I get the "kickback" on the "0" to "1" transition (first pulse) and then the "1" to "0" (second pulse), but not the "0" to "0" transition. My sense signal had an amplitude of about 50 mV with a 1 microsecond pulse length. The X/Y core pulses are about 8 microseconds long and the "kickback" occurs at about 6 microseconds from the leading edge, this would be the window to look for the read data to avoid the noise that you can see on trace two.
So with just a basic Arduino UNO and a L298N motor control board you can build Wayne's 1-bit wonder. You do also need a 10 ohm resistor in each motor line and a separate 5 volt power supply that can deliver at least 1 Amp but that is it!
I am not sure if I will expand mine to use the full 4-bits of the array and/or build a sense amplifier to read the data but it was fun to experiment with this piece of computer history. Here is my code for my 1-bit wonder, enjoy!
/* Core Memory Experiment
Core Memory experiment using a L298N H-Bridge motor interface
Single Bit Core
Set the Core to "1" state then "0" state then "0" and repeat at the cycleDelay rate
*/
int pin8 = 8;
int pin9 = 9;
int pin10 = 10;
int pin11 = 11;
int pin12 = 12;
int cycleDelay = 150;
// the setup routine runs once when you press reset:
void setup() {
// initialize the digital pin as an output for motor controler
pinMode(pin8, OUTPUT);
pinMode(pin9, OUTPUT);
pinMode(pin10, OUTPUT);
pinMode(pin11, OUTPUT);
pinMode(pin12, OUTPUT);
}
// Loop the single core with 1-0-0 repeat
void loop() {
delayMicroseconds(cycleDelay); // cycle delay time
// Set Core to "1" state
digitalWrite(pin12, HIGH);
digitalWrite(pin11, HIGH);
digitalWrite(pin9, HIGH);
//onDelay ~8 microseconds
__asm__("nop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop\n\t");
__asm__("nop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop\n\t");
__asm__("nop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop\n\t");
__asm__("nop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop\n\t");
__asm__("nop\n\t");
digitalWrite(pin12, LOW);
digitalWrite(pin11, LOW);
digitalWrite(pin9, LOW);
//offDelay ~8 microseconds
__asm__("nop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop\n\t");
__asm__("nop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop\n\t");
__asm__("nop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop\n\t");
__asm__("nop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop\n\t");
__asm__("nop\n\t");
// Set Core to "0" state
digitalWrite(pin12, HIGH);
digitalWrite(pin10, HIGH);
digitalWrite(pin8, HIGH);
//onDelay ~8 microseconds
__asm__("nop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop\n\t");
__asm__("nop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop\n\t");
__asm__("nop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop\n\t");
__asm__("nop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop\n\t");
__asm__("nop\n\t");
digitalWrite(pin12, LOW);
digitalWrite(pin10, LOW);
digitalWrite(pin8, LOW);
//offDelay ~8 microseconds
__asm__("nop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop\n\t");
__asm__("nop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop\n\t");
__asm__("nop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop\n\t");
__asm__("nop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop\n\t");
__asm__("nop\n\t");
//Set Core to "0" state
digitalWrite(pin12, HIGH);
digitalWrite(pin10, HIGH);
digitalWrite(pin8, HIGH);
//onDelay ~8 microseconds
__asm__("nop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop\n\t");
__asm__("nop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop\n\t");
__asm__("nop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop\n\t");
__asm__("nop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop\n\t");
__asm__("nop\n\t");
digitalWrite(pin12, LOW);
digitalWrite(pin10, LOW);
digitalWrite(pin8, LOW);
//offDelay ~8 microseconds
__asm__("nop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop\n\t");
__asm__("nop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop\n\t");
__asm__("nop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop\n\t");
__asm__("nop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop\n\t");
__asm__("nop\n\t");
}
Monday, September 1, 2014
Arduino Morse Code Decoder
I came across this Arduino Morse Code Decoder Sketch by Budd WB7FHC HERE and it look interesting and very well documented so I thought I would try it out and run some tests on it because I may have an application for such a decoder.
Using a straight key with it was a little tough but I was able to get it to copy me fine as long as I was sending perfectly at about 10 WPM. I tried increasing the speed but it seems to get easily confused requiring a reset.
I then decided to connect a keyer to it so it was receiving perfect machine generated Morse. I used my WINKEYER USB. I started at 10 WPM and was able to increase the speed in 2-3 WPM increments and it was able to copy 100% all the way to 99 WPM!
I still need to do more testing but the way the code is built, it seems to needs to start at a slow speed before handling higher speed code. I did find that from a reset it will copy perfectly at 10 WPM every time with virtually no training. It seems the training part of the code is more useful when dealing with a straight key and the variation that a human may cause.
I came across some minor issues in the code while I was running it regarding decoding punctuation. The fix required a change to the "mySet" array and also the punctuation code. If you look at the printPunctuation code on Budds original sketch and compare to my code below I just did a direct print instead of assigning it to "pMark". I also made it so when it decodes a "@" sign it sends a newline to the terminal.
There are some other changes I would like to make that would enable this code to work in an application I am pondering... a CW transponder. The idea would be to send it my call-sign and a command, it would decode it and if correct would respond with an appropriate CW response back (transpond). For example, if I send it... WA6PZB WA6PZB CMD WX CMD WX it would respond back with WA6PZB WA6PZB RESP 72F RESP 72F. Here I am requesting the temperature or weather (WX) and it is responding with 72 degrees F. I am expecting to send everything twice in and attempt to get the signal through under varying conditions since Morse has no error correction.
Using a straight key with it was a little tough but I was able to get it to copy me fine as long as I was sending perfectly at about 10 WPM. I tried increasing the speed but it seems to get easily confused requiring a reset.
I then decided to connect a keyer to it so it was receiving perfect machine generated Morse. I used my WINKEYER USB. I started at 10 WPM and was able to increase the speed in 2-3 WPM increments and it was able to copy 100% all the way to 99 WPM!
I still need to do more testing but the way the code is built, it seems to needs to start at a slow speed before handling higher speed code. I did find that from a reset it will copy perfectly at 10 WPM every time with virtually no training. It seems the training part of the code is more useful when dealing with a straight key and the variation that a human may cause.
I came across some minor issues in the code while I was running it regarding decoding punctuation. The fix required a change to the "mySet" array and also the punctuation code. If you look at the printPunctuation code on Budds original sketch and compare to my code below I just did a direct print instead of assigning it to "pMark". I also made it so when it decodes a "@" sign it sends a newline to the terminal.
There are some other changes I would like to make that would enable this code to work in an application I am pondering... a CW transponder. The idea would be to send it my call-sign and a command, it would decode it and if correct would respond with an appropriate CW response back (transpond). For example, if I send it... WA6PZB WA6PZB CMD WX CMD WX it would respond back with WA6PZB WA6PZB RESP 72F RESP 72F. Here I am requesting the temperature or weather (WX) and it is responding with 72 degrees F. I am expecting to send everything twice in and attempt to get the signal through under varying conditions since Morse has no error correction.
/* Barnacle Budd's Morse Code Decoder v. 0.1
(c) 2011, Budd Churchward - WB7FHC
Minor modification by WA6PZB 8/30/2014
Hook a button or telegraph key up to your Arduino
and this program will copy your Morse Code and display
the characters in your Monitor window.
The program will automatically adjust to the speed of code that
you are sending. The first few characters may come out wrong.
The software tracks the speed of the sender's dahs to make
its adjustments. The more dahs you send at the beginning
the sooner it locks into solid copy.
After a reset, the following text is very difficult to lock in on:
'SHE IS HIS SISTER' because there are only two dahs in the whole
phrase and they come near the end. However, if you reset and then
send 'CALL ME WOODY' it will match your speed quite quickly.
*/
int myKey=14; // We are borrowing Analog Pin 0 and using it as digital
int speaker=11; // Speaker will be hooked between pin 11 and ground
int val=0; // A value for key up and down
int myTone=640; // Frequency of our tone
boolean ditOrDah=true; // We have a full dit or a full dah
int dit=100; // If we loop less than this with keydown it's a dit else a dah
int averageDah=150; // Start with this value we will adjusted it each time he sends a dah
boolean characterDone=true; // A full character has been sent
int myBounce=2; // Handles normal keybounce but we needed to do more later
int downTime=0; // We are going to count the cycles we loop while key is down
long FullWait=10000; // This value will be set by the sender's speed - the gap between letters
long WaitWait=FullWait; // WaitWait is for the gap between dits and dahs
long newWord=0; // For the gap between words
int nearLineEnd=40; // How far do you want to type across your monitor window?
int letterCount=0; // To keep track of how many characters have been printed on the line
int myNum=0; // We will turn the dits and dahs into a data stream and parse
// a value that we will store here
// The place a letter appears here matches the value we parse out of the code
char mySet[] ="##TEMNAIOGKDWRUS##QZYCXBJP#L#FVH09#8###7#:###/#61#######2###3#45";
void setup() {
pinMode(myKey, INPUT);
pinMode(speaker,OUTPUT);
// initialize the serial communication:
Serial.begin(9600);
}
void loop() {
val=digitalRead(myKey); // Is it up or is it down?
if (val) keyIsDown(); // Any value here means it is down.
if (!val) keyIsUp(); // Should be 0 when it is up.
}
void keyIsDown() {
tone(speaker,myTone); // Turn on the sound
WaitWait=FullWait; // Reset our Key Up countdown
downTime++; //Count how long the key is down
if (myNum==0) { // myNum will equal zero at the beginning of a character
myNum=1; // This is our start bit - it only does this once per letter
}
characterDone=false; // we aren't finished with the character yet, there could be more
ditOrDah=false; // we don't know what it is yet - key is still down
delay(myBounce); // short delay to keep the real world in synch with Arduino
}
void keyIsUp() {
noTone(speaker); // Turn off the sound
if (newWord>0) newWord--; // Counting down to spot gap between words
if (newWord==1) printSpace(); // Found the gap, print a space but only once next time it will be 0
if (!ditOrDah) { // We don't know if it was a dit or a dah yet, so ...
shiftBits(); // let's go find out! And do our Magic with the bits
}
if (!characterDone) {
WaitWait--; // We are counting down
if (WaitWait==0) { // Bingo, keyUp just timed out! A full letter has been sent
WaitWait=FullWait; // Reset our keyUp counter
printCharacter(); // Go figure out what character it was and print it
characterDone=true; // We got him, we're done here
myNum=0; // This sets us up for getting the next start bit
}
downTime=0; // Reset our keyDown counter
}
}
void printSpace() {
letterCount++; // we're counting the number of characters on the line
if (letterCount>nearLineEnd) { // when we get past our threshold we do this:
Serial.println(); // jump down to a new line
letterCount=0; // reset our character counter
return; // Go back to loop(), we're done here.
}
Serial.print(' '); // print a space on the monitor window
}
void printCharacter() {
FullWait=averageDah*100; // the keyUp counter gets reset based on sender's speed
newWord=FullWait*5; // word gap counter is also adjusted by sender's speed
letterCount++; // we're counting the number of characters on the line
if (myNum>63) {
printPunctuation(); // The value we parsed is bigger than our character array
// It is probably a punctuation mark so go figure it out.
return; // Go back to the main loop(), we're done here.
}
Serial.print(mySet[myNum]); // Print the letter that is in this spot in our character set
}
void printPunctuation() {
byte pMark='#'; // Just in case nothing matches
if (myNum==71) Serial.print(":");
if (myNum==76) Serial.print(",");
if (myNum==84) Serial.print("!");
if (myNum==94) Serial.print("-");
if (myNum==101) Serial.println(); // the @ sign used for newline
if (myNum==106) Serial.print(".");
if (myNum==115) Serial.print("?");
}
void shiftBits() {
ditOrDah=true; // we will know which one in two lines
if (downTime<dit/3) return; // ignore my keybounce
if (downTime<dit) {
// We got a dit
myNum = myNum << 1; // shift bits left
myNum++; // add one because it is a dit
}
else {
// We got a dah
myNum = myNum << 1; // shift bits left
// The next three lines handle the automatic speed adjustment:
averageDah=(downTime+averageDah)/2; // running average of dahs
dit=averageDah/3; // normal dit would be this
dit=dit*2; // double it to get the threshold between dits and dahs
}
}