Remote Sensing Morse Code

statch

New Member
I dont know if anyone has done anything similar but here is code that can be used to transmit a static message (callsign) along with three ADC values using morse code. It simply pulses an output using a binary representation for morse characters. It was written for a -08M and uses nearly all of the memory. It was used as a backup data system on a high altitude balloon and worked beautifully except our transmitter was too weak once we got to ~90,000 feet :). We also used it to do Directional Finding when recovering the balloon.

Code:
;Standard Register Structure
;******************************************
Symbol I1 = b0	'Index 1			*
Symbol I2 = b1	'Index 2			*
Symbol I3 = b2	'Index 3			*
Symbol T1 = b3	'Temp 1			*
Symbol T2 = b4	'Temp 2			*
Symbol T3 = b5	'Temp 3			*
Symbol P1 = b6	;Data Pointer 1(Input)	*
Symbol P2 = b7	;Data Pointer 2(Input)	*
Symbol P3 = b8	;Data Pointer 3(Input)	*
Symbol P4 = b9	;Data Pointer 4(Output)	*
Symbol P5 = b10	;Data Pointer 5(Output)	*
Symbol P6 = b11	;Data Pointer 6(Output)	*
Symbol R1 = b12	;Random Variable 1	*
Symbol R2 = b13	;Random Variable 2	*
;******************************************


'Note:  Binary representation of morse code
'uses the 3 LSB's to represent the number of
;Dits/Dahs in the morse character. The
'remaining MSB's represents the actual Dits/Dahs

;load the morse equivalent numbers 0-9 into eeprom
;addressed at their decimal ascii value
data 48,(253,125,61,29,13,5,133,197,229,245)
;        0   1  2  3  4  5  6   7   8   9

;load the morse equivalent alphabet into eeprom
;addressed at their decimal ascii equivalent
data 65,(66,132,164,131,1,36,195,4,2,116,163,68,194,130,227,100,212,67,3,129,35,20,99,148,180,196)
;        A   B   C   D  E F   G  H I  J   K  L   M   N   O   P   Q  R  S  T  U  V  W   X   Y   Z

'load static message note: only use capital letters
data 0,("K","J","4","H","V","J",0) '0 represents a space


Symbol Dit_length = 500		'set length of a dot in ms
Symbol Dah_length = Dit_length * 3
Symbol Wrd_length = Dit_length * 7     


Start:			
	low 0	;make sure output is off
	pause 1500	;pause 1.5 secs b/w transmissions
	readadc 1,T1 ;read ADC values and store in memory
	poke 80,T1
	readadc 2,T1
	poke 81,T1
	readadc 4,T1
	poke 82, T1
 

'Cycles through static message and ADC data and transmits
'Sends with P1,P2 recieves with P4,P5,P6
Main:
	for I1 = 0 to 6	'send static message from 
				;0 to end of msg
		read I1,P1  'get the character from the eeprom
		gosub Morse	'go to the ch. generation routine  
	next	'loop back to get next ch. and load it
      
      for P2= 80 to 82	;adc data is stored in location 80-82
		gosub convert ;convert adc data to three ascii char.
		for I1 = 0 to 3
			lookup I1, (P6,P5,P4,0),P1
			gosub morse	;transmit hundreds,tens,ones,space
		next
	next
	
	goto Start	'return to start to wait for next input



;toggles Pin 0 to send the Morse
;receives from P1, does not send
Morse:
	if P1 = 0 then  '0 represents a space
		pause Wrd_length
		return
	endif	

	read P1,T1	'get binary morse representation from eeprom
	let T2 = T1 & %00000111	'get the number of elements in morse character
	for I3 = 1 to T2	'loop through to get all elements
		if T1 >= 128 then 		'test MSB for a 1
			pulsout 0,Dah_length	'if so pulse long
		else 					'else pulse short
			pulsout 0,Dit_length
		endif
				
		pause Dit_length	'pause between morse elements
		let T1 = T1 * 2	'left shift morse character
	next				'loop back to get the next element
	
	pause Dah_length			'pause b/w letters
	return				


'converts binary numbers to their one,tens,hundreds representation then
'to their equivalent morse number
'receives on P2, sends on P4,P5,P6
Convert:
	
	peek P2,T1	'grab value to convert

	P4=T1//10+48	'get the ones place
	P5=T1/10//10+48'get the tens place
	P6=T1/100+48	;get the hundreds place
	'add 48 to get the ascii equivalent

	read P4,P4	;get the morse representations from eeprom
	read P5,P5
	read P6,P6

	return


Dont worry about the stuff at the top. It is my attempt at doing modular code and its still being evolved.

Any comments would be appreciated.

Thanks,
Daniel
 
Last edited:

lbenson

Senior Member
MPep (and others). If you can't view all of the code because you can't scroll down far enough in the code window, press refresh. That should fix it. This appears to be an IE7 bug. (If others have this problem with other browsers, please report.)
 

leftyretro

New Member
Interestingly, I used to have this problem (IE7 XP SP3) but after the last large "update" it seems to work OK now:)
(IE7 XP SP3), same problem here. But I found if you maximize the window to full screen then the whole code window is avalible with proper scroll bar.

Lefty
 

manuka

Senior Member
Bravo-inspired by a BASIC Stamp Morse idea, Australian Eric & I hacked together something similar for an 08 back in ~2003. See => www.picaxe.orcon.net.nz/morse.bas . Copyleft!

What sort of transmitter did you use? 90,000 feet (~20 miles) is quite a range if 433MHz LOS!
 
Last edited:

statch

New Member
Balloon Info

The transmitter was small. I dont remember the exact specs but it was driving a 1/2 wave dipole. We also had a more powerful transmitter that was spitting out GPS on APRS freqs so we could point a 10 element yagi at it. Still we only could decode the beacon to about 50,000 ft. We could hear it faintly higher. Here are some pics taken by some decent cameras from the balloon. There are some nice shots there.

http://ideasvn.ece.engr.uky.edu/pics/gallery2/main.php?g2_itemId=12645

Daniel
 

MPep

Senior Member
Hi Ibenson,

Thanks for that. Never knew of this trick before.
I have come across this problem before, but never bothered to mention it.

Cheers.
 

bfordfl

New Member
Morse Code

Daniel - I'm working on a project that takes input from a PS2 computer keyboard. converts it to morse code by keyboard input and then when the enter key is pressed, sends the morse code to a speaker. It uses a 28x1 PIC. The code was transcribed from another Intrepreted Basic to PICAXE Basic.
If you are interested, I would like to discuss some aspects of the code with you.
Bill
 

statch

New Member
Bill:

Sure I am interested. Let me know what you had in mind and I will see what I can do. I am fairly busy right now trying to finish up my masters thesis but am always interested in talking picaxe.

Daniel
 

bfordfl

New Member
Morse Code Output from Computer Keyboard

Daniel - The Morse Code emulator works very well. I'm using a piezo speaker for the output because of its small size. I am now working on the software to put the keystrokes on an LCD so that it can be seen as inputted.
Bill
 

bfordfl

New Member
Reading Morse Code

Has anyone built a Morse Code reader that would translate Morse Code audio into text and willing to share information?
Bill
 

hippy

Technical Support
Staff member
I haven't noticed any Morse code receivers and decoders done with a PICAXE but shouldn't be too hard to achieve.

The hardware would need to generate a digital stream indicating the presence of a dit or dah, or the absence of such. The software would simply time the lengths of presence and absence to determine dits, dahs and spaces between letter. Accumulate dits and dahs until the end of a letter, translate that dit-dah value into a letter ...

Code:
Symbol DIT = 0
Symbol DAH = 1
Symbol GAP = 2

Do
  Gosub Get_Dit_Dah_Or_Gap
  Select Case result
    case DIT : char = char * 2
    case DAH : char = char * 2 + 1
    case GAP : Read char, char
               SerTxd( char )
               char = 0
  End Select
Loop

Eeprom %01   , ("A") ' .-
Eeprom %001  , ("U") ' ..- 
Eeprom %0001 , ("V") ' ...-
There's a flaw in that - it is not possible for the code to distinguish A from U from V - and the code won't even compile.

Two solutions; either left shift to add invisible dits ( or dahs ) so each Morse input becomes a unique 8-bit code, or include a count of how many dits or dahs are in the character. The first allows Morse codes which may have up to 8 dits or dahs which is better than the second which only allows 5 dits or dahs, and it's easy to implement ...

Code:
Symbol DIT = 0
Symbol DAH = 1
Symbol GAP = 2

Do
  Gosub Get_Dit_Dah_Or_Gap
  counter = counter + 1
  Select Case result
    case DIT : char = char * 2
    case DAH : char = char * 2 + 1
    case GAP : Do While counter < 9
                 char = char * 2
                 counter = counter + 1
               Loop    
               Read char, char
               SerTxd( char )
               char = 0
               counter = 0
  End Select
Loop

Eeprom %01000000 , ("A") ' .-
Eeprom %00100000 , ("U") ' ..- 
Eeprom %00010000 , ("V") ' ...-
 

manuka

Senior Member
Hippy et.al- well maybe with just machine morse?

As a reluctant "Morse man"for over 40 years, I should point out that human sent Morse varies considerably with operator "fist". A "brass ponding" sender may vary his style even within a simple transmission, and on air CW decoding is further complicated by static/key clicks & interference! The experienced human ear can compensate, but simple machine decoding may be VERY tricky.

Any number of PC sound card based decoding programs abound now anyway. Stan-ZL2APS ( since 1966!)
 

mrburnette

Senior Member
Just to add a little info for any searchers...
The decoding and demodulation of Morse Code can be accomplished with a 08M2@32MHz to 10-WPM straight key. The algorithm permits a significant amount of "fist" and is not overly sensitive to the BFO tone... the algorithm is written for 700-800Hz, but usually works OK from 600-1K. On a 20X2 uC, up to 25+WPM straight keyed code can be decoded and the BFO can run from 500Hz to 1200Hz at lower speeds of around 15WPM.
http://www.picaxeforum.co.uk/showthread.php?19123-Morse-Code-Decoding-8WPM-with-a-PICAXE-08M2
http://www.picaxeforum.co.uk/showthread.php?19088-Morse-Code-Decoder-for-Cheap-using-a-20X2
http://www.picaxeforum.co.uk/entry.php?30-Notes-behind-Magic-Morse

The algorithm that underpins to/fro conversion from ASCII to Magic-Morse is very light-weight. The demodulation of the audio signal is the only uC intensive task but does eliminate the need for the tone decoder IC... a significant savings in co$t and adds to a more simplistic approach although one that is not directly suited to using a RF rig since circuits with a tone decoder IC provide the benefits of noise rejection and bandpass filtering as well as signal conditioning. Since MM was designed as a training aid and not an RF decoder, this was not a concern in my project requirements... the circuit works perfectly on a PC with ARRL MP3 files from 05WPM to 25WPM using the earphone jack on my Dell notebook.

-Ray
 

srnet

Senior Member
I can see that these routines are designed to decode morse with very little additional circuitry.

So if you wanted to do some audio front end filtering and use a NE567 PLL to detect the tone, could your code read the logic outpurt of the NE567 ?
 
Last edited:

MFB

Senior Member
There was a high altitude balloon project undertaken in the 60's to measure long-term air circulation around the South Pacific. The idea being that ham operators would be able to decode and log instrumentation data that was transmitted in Morse code. These special super pressure balloons used low power discrete transistor circuitry (no IC's in those days!) that even enabled a rough fix to be obtained, based on the time of sunset and sun rise. However, as Manuka points out, the human ear is pretty good at extracting Morse data from weal signals and I can't therefore see much advantage of using this form of coding now that PC sound cards and modem chips are available. Why not just base the balloons telemetry design on the wealth of modern ham communications technology?
 

srnet

Senior Member
However, as Manuka points out, the human ear is pretty good at extracting Morse data from weal signals
Indeed it is, and I have very specific reasons for using morse. The main one being that the transmitted data (GPS Distance, Direction and location data) can be read by ear when the signals are very weak with no other equipment apart from a small & cheap UHF receiver.

I can read the morse data by ear, I taught myself the numbers only (all I need) at 12WPM, working my way up to 20WPM.

But not everybody can read morse and carrying a PC\Netbook across hill and dale is not ideal. Although MRP40 does a reasonable job of decoding morse on a netbook, its weak signal performance is not great, so I would like to experiment with a small cheap handheld PICAXE device that can do the job.
 

MFB

Senior Member
OK, so you want to use Morse for human decoding whilst retaining the option of automatic decoding by a very portable device. Therefore your suggestion of using a PLL decoder front-end for the PICAXE is a good approach. I have used the NE567 for successfully detecting telemetry tones, from oceanographic drift buoys, that not even the human ear could extract from radio noise.
 

srnet

Senior Member
OK, so you want to use Morse for human decoding whilst retaining the option of automatic decoding by a very portable device. Therefore your suggestion of using a PLL decoder front-end for the PICAXE is a good approach. I have used the NE567 for successfully detecting telemetry tones, from oceanographic drift buoys, that not even the human ear could extract from radio noise.
Ah, that sounds promising.

Just about to hook up a NE567 to get an idea of how it performs.
 

MFB

Senior Member
From what I remember of the NE567, when selecting component values the main trade-off is between response time and noise rejection. Therefore, the slower the Morse rate the batter the PLL is able to pull out the signal from the noise (as theory suggests). I found a useful technique for bench testing this kind of set-up is to mix noise from a reverse biased base/emitter junction (2N3904 seems to work well) with the Morse tone. Saves having to play around with rf attenuators etc.
 

srnet

Senior Member
Was not difficult to make it work, although it will take a bit of twiddling to get it decoding down to background noise level.

Need to sort a problem problem with my PC Scope the output is reading all over the place, looks like a typical ground loop type issue.

I dont have a problem bench testing, the transmitter in this case is the Lost Model Locator posted in this forum, when the transmitter output is set at 1mW and the transmiter in a tin, you just need to place it from 2 - 10M away and the signal goes from S9 to S0. Open up the receiver squelch and you have heaps of continuous noise and a bit of tone.

Looks promising so far.
 

MFB

Senior Member
Your test set-up sounds good as long as the signal does not change when you wave your arms around (I tend to do that a lot whilst testing). The oceanographic buoys used 500mW VHF transmitters feeding a 1/4 wave antenna, or dummy load for lab tests.
 

srnet

Senior Member
Your test set-up sounds good as long as the signal does not change when you wave your arms around (I tend to do that a lot whilst testing). The oceanographic buoys used 500mW VHF transmitters feeding a 1/4 wave antenna, or dummy load for lab tests.
No change I can detect, the receiver is a small handheld UHF tranciever, it can be placed out of the way with a 3.5mm audio extension lead going to the breadboard setup.

If I really want to kill the signal, I put the transmitter in the tin and the tin in the kettle BBQ at the other end of the garden. A crude but very effective attenuator setup.

No risk of a BBQ in the current weather ........
 

srnet

Senior Member
The NE567 is working well, by playing with the feedback the jitter is removed and I have a nice clean pulse in a ratio of dit:dah of 1:3.

Sometime later I might try some audio limiting and a bandpass filter.
 

MFB

Senior Member
I seem to remember that the NE567 pass-band increases for signals above about 200mV p-to-p. It would therefore be worth using a diodes/attenuator circuit to limit the input to the NE567 below that level. Adding an input bandpass filter may also help but the rf receiver is probably already providing this function.

It's amazing that this Signetics (then National Semi) chip has been around since the early 70's and yet is still pretty useful for this type of application.

This sounds like an interesting project, so please let us know how it progresses.
 

srnet

Senior Member
I seem to remember that the NE567 pass-band increases for signals above about 200mV p-to-p. It would therefore be worth using a diodes/attenuator circuit to limit the input to the NE567 below that level. Adding an input bandpass filter may also help but the rf receiver is probably already providing this function.

It's amazing that this Signetics (then National Semi) chip has been around since the early 70's and yet is still pretty useful for this type of application.

This sounds like an interesting project, so please let us know how it progresses.
I would concur with that. I have noticed that setting the volume level just so, arround the 200mV level does make a differance when the wanted signal in relation to the noise is weak.
 

mrburnette

Senior Member
I can see that these routines are designed to decode morse with very little additional circuitry.

So if you wanted to do some audio front end filtering and use a NE567 PLL to detect the tone, could your code read the logic outpurt of the NE567 ?
Yes, but the pulsin routine would need a complete rewrite. Since the 567 gives the 1:3 ratio, I suspect the best approach would be to just separate dits and dahs on width and the apply the algotithm directly to the results.... dits & dahs are summed into bits 0, 1, 2 and dahs are weighted by position receive in bits 3, 4, 5, 6, 7. The result is a pointer into EEPROM for the decoded character or pro sign.

You are correct that I did specifically engineer around the need for the 567, but I was designing a device to decode a very clean signal from a code practice oscillator or the ARRL mp3 files, specifically for training.

-Rayy
 

srnet

Senior Member
I think I can see where to mod the code.

I will try it as intended first, with the transmitter nearby the UHF tranciever the audio output is fairly clean.
 

mrburnette

Senior Member
I think I can see where to mod the code.

I will try it as intended first, with the transmitter nearby the UHF tranciever the audio output is fairly clean.
The affected area of code to target is the inner loop where I count the transition of Pulsin (essentially the frequency) and use that to determine a dot/dash based upon a statistical number I generated from analysis of 05-WPM to 25-WPM code samples from the ARRL. Therefore, if this test is true: IF Duration > DIT then the element is a DAH, conversely it is a DIT if false. The pointer is adjusted through simple math to keep this section of code low-weight and the loop is repeated until multiple timeouts exists with no incoming data. I add the two sub-pointers, #elements and the dah-weights to create a single pointer into EEPROM and return the ASCII character.

One can muck around with the code to actually clump characters into words, etc. but the more manipulation, the more time taken before returning to the inner DO loop and the lower the overall top-end decoding. The very nice part of this algorithm is that the brute-force MM-number is very easily converted in one pass back to Morse Code, 5-bit Dits and Dahs... examples in my blog.

- Ray

Do ' Initialize TOP-Level variables, flags, and pointers
Flag = 0 : Pflag = 0 : Point = 0 : DitDah = 0
LOW RLED : LOW GLED ' Turn off LEDs

Do ' loop converts individual Morse elements into a Character
Duration = 0
Do ' INPUT-loop counts DITs or DAHs carrier (BFO) frequency
' 64MHz = 0.625us unit 41mS timeout: Manual2 page 160
PULSIN PulseInput, Hi2Lo, InputPulse ' =0 if timeout
IF InputPulse = 0 then EXIT
INC Duration : Flag = 0
Loop ' Loop while signal is on port PulseInput (active low)


' InputPulse = 0 Therefore we know that the input has returned HIGH
' Set a Flag: dah/dit OR one of the space conditions: element,character,word
' Only want to detect DIT / DAH when Flag = 1, Conclude when Flag = 5 (default =5, 4-3-2 is progressively more aggressive)
INC Flag ' Count number of consecutive (timeouts)
 
Last edited:

srnet

Senior Member
I changed the inner routine to this;


Code:
Do	' Initialize TOP-Level variables, flags, and pointers
	Flag = 0 :  Point = 0 : DitDah = 0 ':Pflag = 0 :
   Do	
   		SetFreq m4  'switch down to 4Mhz, so gap between characters causes a timeout 
		PULSIN PulseInput, 1, duration
		SetFreq Clock
			
		inc point  'increment the number of elements, dits or dahs
			
		IF Duration > 15000 then	'This is a DAH, these are weighted by received position but DITs are only counted
							'so for each position (point) encode the DAH position 
			Select Case Point
				Case 1 : DitDah = DitDah OR %00001000
				Case 2 : DitDah = DitDah OR %00010000
				Case 3 : DitDah = DitDah OR %00100000
				Case 4 : DitDah = DitDah OR %01000000
				Case 5 : DitDah = DitDah OR %10000000
			End Select 
		EndIf
		
	'check for timeout, i.e. end of character
	If duration = 0 then 'AND PFlag > 0 then' 5-Bit Morse except for ",.@?"
		DitDah = DitDah + Point	' Complete the two-part pointer algorithm
		dec ditdah  
		READ DitDah, Temp	' Read mapped character from EEPROM
		sertxd(Temp,"  ")
		EXIT	
	EndIf
   
   Loop	' Gather more elements for character	

Loop		' Gather more characters to display
I had some initial problems with the NE567, although it looked like a clean pulse on the logger output of my scope, there was a fair bit of jitter which I needed to get rid of. The routine above steps the frequency down to 4Mhz to read the pulse, at this speed the timeout of pulsin is just beyond the width of a DAH, so the intercharacter gap gives a timeout. I then swap to a higher frequency to give plenty of time to do sums during the inter element gap.

Pulsin is not ideal here. If there is a jitter pulse at the start of the actual DIT or DAH, its not enough to just throwout the 'short' pulse as the next pulsin has to wait for the signal to go low then high before it can read again, net result is too miss a DIT or DAH. I will do some manual loop counts to see if the pulse can be measured in this way, it would then be possible to cope with some noise in the pulse.

But anyway it does work.
 
Last edited:

srnet

Senior Member
And this little routine gives a duration count approximating to the width in ms of the pulse from the NE567;

setfreq m32

duration = 0

do
loop while pinc.4 = 0

do
inc duration
pause 7
loop while pinc.4 = 1


A DIT is about 110ms at 15WPM, so there is scope to time the pulse manually with the possibility of glitch removal.
 

srnet

Senior Member
It needs some changes, though.

The detection of the end of a character depends on a tone gap (a pulsin timeout) of just a little more than the length of a DAH.

Which is not a particular problem with machine generated Farnsworth spaced code, the inter character gap is long enough.

Be nice to check the tone gaps and detect end of character when the gap between elements just exceeds a DIT length, which is what happens with standard spaced code.

I will see if the manual pulse timing, not using pulsin that is, will work quick enough.

And the code is not rate adaptive either.

Final intention is to use a 28X2, I want enough pins to send the decoded morse to a single segment LED display and use a reasonator for more accuracy, although so far the 08M2 is doing an acceptable job at 32Mhz.
 
Last edited:

mrburnette

Senior Member
It needs some changes, though.
In my original code using pulsin, I assume any pulse shorter than a DAH is a DIT; of course, I'm presuming clean input from the code practice oscillator or the ARRL MP3 being played on a PC since I use a NPN transistor inverter in saturation mode... this approach on an 08M2 peters out around 10-12 WPM. At 64MHz with the same clipper and algorithm on a 20X2 and using a value of 100 as the differentiation (arrived at by repeated testing) between DIT and DAH, the 20X2 has a dynamic range of 05-WPM to 25+WPM using the ARRL recordings. Working with a TTL input from the 567 tone decoder, the challenges are vastly different.
My desire to eliminate the 567 PLL was from an expense point since I wanted to provide a very inexpensive decoder for training purposes. It may be that a possible solution would be to use the 567 output to switch a fixed frequency oscillator (simulate the BFO) and feed the 750-850Hz switched frequency into pulsin running the algorithm in pretty much the same fashion as I had originally written it... this also gives you an opportunity to clean-up the jitter on the 567, which I might add, does surprise me somewhat. With this approach, you keep the 567 in circuit to pull-out the signal from the noise and then use some R/C timing on the downstream switch to filter the jitter and use the "switch" (FET, Transistor, 555, etc.) to provide the PICAXE with a clean signal.

- Ray
 
Top