mrburnette
Senior Member
When one asks a question, even rhetorical, sometimes an answer is required to put the thought to rest. Such is the case with a recent blog post, Command-and-Control-via-Morse-Code and so I set about seeing if I could prototype something quickly and simple enough that others could play with the concept without pulling out their hair. On the first part, I have something simple but I will not be responsible for hair lost since the POC is pretty brute-force in implementation.
On a PICAXE 08M2+, I implemented the Magic Morse algorithm, stripped bare. I then implemented a master Do-Loop and a quasi-control structure build pitifully from IF-Then-ELSE statements... mainly because it is easy to follow the logic here.
The Morse Code is generated by a 650Hz sine wave from my function generator at about 2Vp-p and is clipped by a 2N3904 with a 1K ohm resistor in the base circuit from the Morse Key and a 10K to +5 in the collector-PIC C.3 connection. This gives a very decent square wave to C.3 when viewing with a scope and the signal is active HIGH due to the pullup.
I implemented 3 control channels, but fell back for the POC to just using 2 due to the desire to have a serial link to my PC via serout which I dedicated to C.1. In use, this link would not be necessary and C.1, C.2, and C.4 could be used for control output.
I implemented only 2 verbs: High and Low. This could be expanded to include Input and Output, etc.
I implemented a crude 3-byte input queue such that all commands to the PICAXE must begin with the Morse decoded letter "C" and if not, the queue would flush. Once the first element is "C" the second element must be either "1", "2", or "4" to represent the port number... in the POC port C.1 is used for serial and is only implemented as a skeleton.
The third parameter is the method invocation, a "0" for LOW or a "1" for HIGH. Any other value is not processed and the queue is automatically cleared and returned to the Do-Loop to be provisioned with Morse received characters.
Here is the code: note that a significant amount of size can be reduced by eliminating the serout statements.
Here is a terminal session being echoed to the console as the command "C20" and "C21" come in via Morse Code.
This low speed signaling approach (approximately 5 - 8 WPM) is very slow, but should be reasonably reliable over some distances. Using simple filtering, low frequency hum and high frequency noise should be relatively easy to eliminate. The command queue is continuous recycling, so a distant PICAXE master unit can simply continue to send over and over to the receiver and only change state as required. Or, if the distant master unit does not check in, the remote PICAXE stays in-state until communication is re-established.
- Ray
Basic clipper circuit... do NOT pay attention to the PICAXE connection... on an 08M2, use PIN C.3 which is physical PIN#4
- Up to 36+ devices chould share a single audio line if the first character were the "node address"
- Since Audio can be superimposed on DC, a 2-wire network could be created
- Works like UDP over TCP - no guarantee
On a PICAXE 08M2+, I implemented the Magic Morse algorithm, stripped bare. I then implemented a master Do-Loop and a quasi-control structure build pitifully from IF-Then-ELSE statements... mainly because it is easy to follow the logic here.
The Morse Code is generated by a 650Hz sine wave from my function generator at about 2Vp-p and is clipped by a 2N3904 with a 1K ohm resistor in the base circuit from the Morse Key and a 10K to +5 in the collector-PIC C.3 connection. This gives a very decent square wave to C.3 when viewing with a scope and the signal is active HIGH due to the pullup.
I implemented 3 control channels, but fell back for the POC to just using 2 due to the desire to have a serial link to my PC via serout which I dedicated to C.1. In use, this link would not be necessary and C.1, C.2, and C.4 could be used for control output.
I implemented only 2 verbs: High and Low. This could be expanded to include Input and Output, etc.
I implemented a crude 3-byte input queue such that all commands to the PICAXE must begin with the Morse decoded letter "C" and if not, the queue would flush. Once the first element is "C" the second element must be either "1", "2", or "4" to represent the port number... in the POC port C.1 is used for serial and is only implemented as a skeleton.
The third parameter is the method invocation, a "0" for LOW or a "1" for HIGH. Any other value is not processed and the queue is automatically cleared and returned to the Do-Loop to be provisioned with Morse received characters.
Here is the code: note that a significant amount of size can be reduced by eliminating the serout statements.
Code:
' Morse Test Command & Control.BAS
' 572 Bytes / 2048
' NOTE: 9600 BAUD is sent to RS232 PortC.1 Physical Pin #6
' Test program by Ray Burnette
' Magic Morse is (c) 2011 by M. Ray Burnette, all commercial rights retained
#picaxe 08m2
#Terminal 9600
#NO_DATA ' REMARK THIS LINE DURING INITIAL PICAXE PROGRAMMING!!!
' SYMBOL table - aliases for byte and word variables
{
SYMBOL DitDah = B0
SYMBOL CharCount = B1
SYMBOL DIT = B2
SYMBOL Point = B3
SYMBOL Flag = B4
SYMBOL Pflag = B5
SYMBOL InputPulse = W3
SYMBOL Temp = B8
SYMBOL Duration = W5
; Command variables
SYMBOL W = B24
SYMBOL X = B25
SYMBOL Y = B26
SYMBOL Z = B27
; Command structure = 3 bytes: x= Primary_Key, y= Secondary_Key, z= action/state
; x y z
; C 1 0|1
; C 2 0|1
; C 4 0|1
' Valid 08m2 SetFreq: k31, k250, k500, m1, m2, m4, m8,m16,m32
SYMBOL CLOCK = m32
SYMBOL BAUD = N9600_32 ' For use with Windows XP HyperTerminal
SYMBOL MONITOR = C.1 ' RS232 output on this pin
SYMBOL PulseInput = C.3 ' The 'conditioned' Morse Code signal on this pin
' The Input pulses on pin C.3 can be latched on high to low OR low to high
SYMBOL Hi2Lo = 0
SYMBOL Lo2Hi = 1
}
' Initialize program state
{
SetFreq CLOCK
' Set DITDAH discrimination factor
LET DIT = 100
' Wait to ensure all is stable
Pause 4000
serout MONITOR,BAUD,("08M2+ 32MHz Morse Control Test",LF,CR)
' DISCONNECT ' Do Not Inspect C.5 for New Download
GoSub Flush
;HIGH 1 :
HIGH 2 : HIGH 4 ; default state is HIGH
}
' Main Code Block____________________________________
{
Do ; Main Program
MAIN:
Gosub Morse
' Variable Temp contains the ASCII character value received
INC w ' instruction length counter
; serout MONITOR,BAUD,(Temp) ' Send to Monitor
; Not intended to be elegant, kind of brute-force for demo
If w = 1 then
x = Temp : serout MONITOR,BAUD,(x," ")
If x = "C" then MAIN
GoTo FAIL
Elseif w = 2 then
y = Temp : serout MONITOR,BAUD,(y," ")
If y = "2" or y = "4" then MAIN
GOTO FAIL
Elseif w = 3 then
z = Temp : serout MONITOR,BAUD,(z," ")
; Fall throught to subroutine selection
endif
; Subroutines must perform their own validation on "z"
if x = "C" and y = "1" then ; Port C.1 z= 0|1 = low | HIGH
serout MONITOR,BAUD,("Gosub C1:")
gosub C1
Elseif x = "C" and y = "2" then ; Port C.2 z= 0|1 = low | HIGH
serout MONITOR,BAUD,("Gosub C2:")
gosub C2
Elseif x = "C" and y = "4" then ; Port C.4 z= 0|1 = low | HIGH
serout MONITOR,BAUD,("Gosub C4:")
gosub C4
endif
FAIL:
Gosub Flush ; Prepare for next instruction sequence
serout MONITOR,BAUD,("flush", CR, LF)
Loop ' Gather more characters
}
Morse:' Differentiates between DITs and DAHs on the PulseInput PIN
{
' Initialize TOP-Level variables, flags, and pointers
Flag = 0 : Pflag = 0 : Point = 0 : DitDah = 0
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
INC Flag ' Count number of consecutive (timeouts)
If Flag = 1 AND Duration != 0 THEN
INC Point : INC Pflag
IF Duration > DIT then ' DAHS are in the 180's @ 13WPM
' DAHs are weighted by received position but DITs are only counted
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
EndIf
If Flag = 5 AND PFlag > 0 then' Morse Code in buffer
EXIT ' Shortcircuit - we are done with this character
EndIf
Loop ' Gather more elements
' The decoded ASCII character is found by creating a pointer into EEPROM
DitDah = DitDah + Point ' Complete the pointer algorithm
READ DitDah, Temp ' Read mapped Morse character from EEPROM
' Return to main loop with Temp carrying the decoded Morse Code character
RETURN
}
Flush:' Clear control variables
{
W = 0 : X = 0 : Y = 0 : Z = 0
Return
}
; Actions / Methods
; Routines here are responsible for validating (ignoring) "bad" z-values
{
C1:
Return ; serial console in use... just abort
IF z = "0" then
LOW 1
else if z = "1" then
HIGH 1
EndIf
Return
C2:
IF z = "0" then
LOW 2
serout MONITOR,BAUD,("C2 LOW ")
elseif z = "1" then
HIGH 2
serout MONITOR,BAUD,("C2 HIGH ")
else
serout MONITOR,BAUD,(z," invalid parameter")
EndIf
Return
C4:
IF z = "0" then
LOW 4
serout MONITOR,BAUD,("C4 LOW ")
elseif z = "1" then
HIGH 4
serout MONITOR,BAUD,("C4 HIGH ")
else
serout MONITOR,BAUD,(z," invalid parameter")
EndIf
Return
}
' Magic Morse Numbers and Algorithm are (c) 2011 by M. Ray Burnette, Atlanta GA
' DATA for Magic Morse translation
{
' Morse Object: ASCII 5-bit subset mapped into 8-bit eeprom space
' Mappings ", . ? @" which are 6-bit wide but these are
' forced into the 5-bit space by dropping the 6th bit
EEPROM 0, (0,"E","I","S","H","5",0,0,"e") ' e = ERROR = di di di di di di di di
EEPROM 9, ("T","N","D","B","6","-")
EEPROM 18,("A","R","L","w") ' w = wait
EEPROM 26,("M","G","Z","7")
EEPROM 35,("U","F")
EEPROM 41,("i") 'i == INVITE
EEPROM 43,("K","C")
EEPROM 51,("W","P")
EEPROM 59,("O")
EEPROM 61,("8",":")
EEPROM 68,("V","u","]","$") 'u == UNDERSTOOD ]== EndOfWork
EEPROM 76,("X","/",0,0,0,0,0,0,0,"+",".") 'SLASH=77 PERIOD=86
EEPROM 92,("Q",0,".")
EEPROM 101,("!","?") 'QUESTION MARK=102
EEPROM 108,("Y","(",")")
EEPROM 116,("J")
EEPROM 125, ("9")
EEPROM 133, ("4")
EEPROM 158, (",") ' COMMA
EEPROM 161, (0,0,0,0,0,0,0,0,0,0,0,0,"[",";") ' > == STARTING
EEPROM 182, ("@") ' @ ==182
EEPROM 197, ("3")
EEPROM 200, ("A","B")
EEPROM 202, ("C","D","E","F")
EEPROM 206, ("G","H","I","J")
EEPROM 210, ("K","L","M","N")
EEPROM 214, ("O","P","Q","R")
EEPROM 218, ("S","T","U","V")
EEPROM 222, ("W","X","Y","Z")
EEPROM 226, (0,0,0,"2")
EEPROM 245, ("1","'")
EEPROM 253, ("0","'")
}
End
In the POC, I tied the C.2 port to a LED-resistor as a visual that the port did properly respond and would light the led (LOW) or extinguish the LED (HIGH).08M2+ 32MHz Morse Control Test«0A»
C 2 0 Gosub C2:C2 LOW flush
C 2 1 Gosub C2:C2 HIGH flush
This low speed signaling approach (approximately 5 - 8 WPM) is very slow, but should be reasonably reliable over some distances. Using simple filtering, low frequency hum and high frequency noise should be relatively easy to eliminate. The command queue is continuous recycling, so a distant PICAXE master unit can simply continue to send over and over to the receiver and only change state as required. Or, if the distant master unit does not check in, the remote PICAXE stays in-state until communication is re-established.
- Ray
Basic clipper circuit... do NOT pay attention to the PICAXE connection... on an 08M2, use PIN C.3 which is physical PIN#4
- Up to 36+ devices chould share a single audio line if the first character were the "node address"
- Since Audio can be superimposed on DC, a 2-wire network could be created
- Works like UDP over TCP - no guarantee
Last edited: