;RETURN TO THE MORSE CODE ALARM CLOCK PAGE.
;Copy and paste into your assemble.
;Copyright 2004 Richard Cappels, projects@cappels.org
;Program Name: Send Morse

;Version morclk041204A Corrected reversed code for the letter "D".



;Mores code message for alarm clock
;Pin 20 + 5V.
;Pin 15 High Z speaker return. Anti-phase of signal on pin 14
;Pin 14 High Z speaker output. Tone with message.
;Pin 13 Normally high, goes low during message.
;Pin 12 Normally low, goes high during message.
;Pin 10 Ground.
;Pin 6 - Message starts on negative edge on this pin.
;Pins 4 and 5 - crystal oscialltor per datasheet.
;Pin 1 may be grounded to terminate message.


;Key subroutines:


; dottime - set of delay loops to set basic dot time. Interacts with interupt routine.
;The dot time is set by adjusting the value loaded into temp at the start of the routine.
;Loading 100 into temp gives 1 wpm. Loading 1 into temp gives 100 wmp. Loadign 20 gets 5 wpm.

   
;sendromstring -send a string from Flash ROM. See TypeGreeting for example of use.


;sendSerialMorse - sends ASCII Data via serial port and as Morse Code.
;    ldi    temp,'A'
;    rcall    sendSerialMorse

;sendnumberMorseASCII -Sends binary nummber in temp as a 3 digit number via serial port and as Morse Code.   
;    ldi    temp,123        ;Send the nummber, 123
;    rcall    sendnumberMorseASCII
       
;interword - Delays one inter-word delay period   
;    rcall    interword
   
   

.include "2313def.inc"        ;Include file in same directory as project.

;03e7
        ;Interrupt timer parameters
.equ    intcountlow    =$E7    ;Low byte of number of clocks between interrupts.
.equ    intcounthigh    =$03    ;High byte of number of clocks between interrupts.


        ;UART baud rate calculation
.equ    clock = 4000000    ;clock frequency
.equ    baudrate = 9600        ;choose a baudrate
.equ    baudconstant = (clock/(16*baudrate))-1

.def    delaycount    = r2    ;Counter for delay generation
.def    dotlength    = r3    ;Number of 1/100 seconds for dot time.
.def    temp        = r16    ;General purpose scratch register.
.def    temp2        = r17    ;General purpose scratch register.
.def    h        = r22    ;Binary to decimal conversion.
.def    t        = r23   ;Binary to decmial conversion.
.def    u        = r24    ;Binary to decimal conversion.
.def    flagreg        = r25    ;Flags.


;definiton of flagreg bit assignments
;0    Status of code out bit last sent (memory used to toggle)
;1    True enables toggling of code output
;2
;3
;4
;5
;6
;7

.equ    codeport     = PORTB
.equ    codeout        = DDRB
.equ    codebit     = 2
.equ    pulsebit    = 3

;definition of I/O
;B0    + comparitor input (Reserved)
;B1    - comparitor input (Reserved)
;B2    Tone (code) output   
;B3    Anti-phase of signal on B2.   
;B4    (not assigned - configure as INPUT with weak pullup)   
;B5    (not assigned - configure as INPUT with weak pullup)   
;B6    (not assigned - configure as INPUT with weak pullup)   
;B7    (not assigned - configure as INPUT with weak pullup)   


;D0    Reserved FOR UART RECEIVE
;D1    Reserved FOR UART TRANSMIT -input has weak pullup.
;D2    (not assigned - configure as INPUT with weak pullup)
;D3    (not assigned - configure as INPUT with weak pullup)
;D4    (not assigned - configure as INPUT with weak pullup)
;D5    (not assigned - configure as INPUT with weak pullup)
;D6    (not assigned - configure as INPUT with weak pullup)
;D7    (not assigned - configure as INPUT with weak pullup)



.cseg   
.ORG $0000            ;Initializaton code
    rjmp    start
.ORG $0001
    rjmp    int0service
.ORG $0004
    rjmp    timerservice    ;Timer/counter compare interrupt handler

start:
  
    ldi    r16,RAMEND        ;Initialize Stack Pointer.
    out    spl,r16
                    ;Set PORTD.
    ldi    temp,0b00000000       
    out    DDRD,temp
    ldi    temp,0b10111111
    out    PORTD,temp
   
                    ;Set PORTB.
    ldi    temp,0b00001111       
    out    DDRB,temp
    ldi    temp,0b11110010
    out    PORTB,temp       
   
    ldi    temp,$40
    out    GIMSK,temp

    sei   
    ldi    temp,$38
    out    MCUCR,temp
   
   
    sleep
waithere:
    rjmp    start        ;Added so it would repeat if interrupt repeated.
   
   
int0service:    ;Alarm has gone off, so wake up
   
    clr    temp
    out    GIMSK,temp
    out    MCUCR,temp   
   
    clr    flagreg            ;Clear flagreg (flag register).

                    ;TIMER 1 SETUP.
    ldi    temp,$09        ;Set timer 1 to reset 0000 after compare match. Prescaler = 1X.
    out    TCCR1B,temp
    ldi    temp,intcounthigh    ;Set compare register to establish interrupt frequency.
    out    OCR1AH,temp
    ldi    temp,intcountlow
    out    OCR1AL,temp   
    ldi    temp,$40        ;Enable interrupt on compare match.
    out    TIMSK,temp
   
   
    sbi    PORTB,0
    cbi    PORTB,1
   
    sei                ;Enable interrupts.




    ldi    temp,20            ;Set for 10 words per minute
    mov    dotlength,temp
    rcall    TypeMessage        ;Send  message three times

    rjmp    start            ;added so it would repeat message each time interrupted.
   
    rcall    TypeMessage        ;Send  message three times
    rcall    TypeMessage        ;Send  message three times
    rcall    TypeMessage        ;Send  message three times
    rcall    TypeMessage        ;Send  message three times
    rcall    TypeMessage        ;Send  message three times
    rcall    TypeMessage        ;Send  message three times
    rcall    TypeMessage        ;Send  message three times
    rcall    TypeMessage        ;Send  message three times
    rcall    TypeMessage        ;Send  message three times
    rcall    TypeMessage        ;Send  message three times
    rcall    TypeMessage        ;Send  message three times
    rcall    TypeMessage        ;Send  message three times
    rcall    TypeMessage        ;Send  message three times
    rcall    TypeMessage        ;Send  message three times
    rcall    TypeMessage        ;Send  message three times
    rcall    TypeMessage        ;Send  message three times
    rcall    TypeMessage        ;Send  message three times
    rcall    TypeMessage        ;Send  message three times
    rcall    TypeMessage        ;Send  message three times

    rjmp    start            ;Go back to sleep
   


   




TypeMessage:                ;Type greeting
    push    ZL
    push    ZH
    ldi    ZH,high(2*Message)    ;Load high part of byte address into ZH
    ldi    ZL,low(2*Message)    ;Load low part of byte address into ZL
    rcall    sendromstring        ;Send it
    pop    ZH
    pop    ZL
    ret
   
   
   
Message:
    .db     "WAKE UP " "
    .db    $0A,$0D
    .db     $00,$00



sendromstring:            ;call with location of string in Z.
    push    ZL        ;Save Z on stack.
    push    ZH
srs1:
         lpm            ;Load byte from program memory into r0.
        tst    r0        ;Check if we've reached the end of the message.
        breq    finishsendstering;If so, return.
         mov    temp,r0
    rcall    sendSerialMorse ;Send via serial link and as Morse Code.
         adiw    ZL,1        ;Increment Z registers
         rjmp    srs1
finishsendstering:
    pop    ZH        ;Pop Z from stack.
    pop    ZL
     rcall    interword
         ret




sendcodedcode:    ;Send Coded Morse Code
        ;Shift out morse code from coded character.
        ;Enter with code for character in temp.
   
;Description of data format from David Robinson's web page:
;"At this point I was reminded of the N1KDO NHRC-2 repeater controller published
;in February 97 QST that had Morse ID. Investigation of the assembler listing (1)
;revealed a simple conversion scheme, where all morse characters are encoded in a
;single Byte, bitwise, LSB to MSB.; ì0î = dit, ì1î = dah. The Byte is shifted out
;to the right, until only a ì1î remains. As an example 3 is encoded as binary 00111000,
;which translates to 38 in hexadecimal. "



morecode:
    cpi    temp,0b00000001
    breq    codedcodesent
    clc
    ror    temp
    brcs    senddash        ;Send a dash if lsb was a one
    rcall    dot            ;Send a dot if lsb was not a one
    rjmp    morecode
senddash:
    rcall    dash
    rjmp    morecode

codedcodesent:                ;Finished sending the coded code.
    ret



SendMorseAscii:    ;Look up coded Morse code and send, followed by rcall to interchar.
        ;Enter with ASCII character in temp. Upper-case, don't process
        ;control characters.
   
    push    ZL
    push    ZH
       
    cpi    temp,$20        ;If space character, do interword delay.
    brne    SMA1
    rcall    interword
    rjmp    lookupdone
SMA1:
    cpi    temp,$5B
    brmi    upperacse   
    andi    temp,$5F        ;Make upper-case
upperacse:
    cpi    temp,$2A   
    brmi    lookupdone

   
                ;Set up pointer into codechart.
    ldi    ZH,high(2*codechart)    ;Load high part of byte address into ZH.
    ldi    ZL,low(2*codechart)    ;Load low part of byte address into ZL.

    subi    temp,$2A        ;Removed offset from ASCII value in temp.
    add    ZL,temp            ;Add the value to the index.
    clr    temp
    adc    ZH,temp
    lpm            ;Fetch the value from the table.
    mov    temp,r0
    rcall    sendcodedcode        ;Send as Morse Code
    rcall    interchar        ;Dealy one interchar time
lookupdone:

    pop    ZH
    pop    ZL
    ret                ;Return




dot:        ;Send dot, wait one dot time.
    sbr    flagreg,0b00000010    ;Set flag to send tone.
    rcall    dottime
    cbr    flagreg,0b00000010    ;Clear flag to send tone.
    rcall    dottime
    ret
   


dash:        ;Send dash, wait one dot time.
    sbr    flagreg,0b00000010    ;Set flag to send tone.
    rcall    dottime
    rcall    dottime
    rcall    dottime
    cbr    flagreg,0b00000010    ;Clear flag to send tone.
    rcall    dottime
    ret

interchar:    ;Wait interchear period with output off -3 dot times
    rcall    dottime
    rcall    dottime
    rcall    dottime
    ret
   
interword:    ;Wait interword period with output off-6 dot times
    rcall    dottime
    rcall    dottime
    rcall    dottime
    rcall    dottime
    rcall    dottime
    rcall    dottime
    rcall    dottime
    ret



dottime:            ;Delay one dot time.
;reload values for 100 wmp with 4 MHz Crystal:
;temp = 1
;temp2 = 20
;dealycount = 0 (cleared)
;With these interrupt reload values:
;.equ    intcountlow    =$E7
;.equ    intcounthigh    =$03

;Using dotlength = 20 (decmimal), dot time is 83.37 milliseconds.
;Using dotlength = 200 (decimal), dot time is 833.64 milliseconds

    push    temp
    push    temp2
   
    mov    temp,dotlength      ;<= vary this from 1 to 100 to get 100 to 1 wpm. 20 = 5 wpm; 100 = 1
moretime3:   
    clr    delaycount
moretime2:
    ldi    temp2,20
moretime1:
    dec    temp2
    brne    moretime1
    dec    delaycount
    brne    moretime2
    dec    temp
    brne    moretime3
   
    pop    temp2
    pop    temp

    ret

            ;go back


sendSerialMorse:    ;Send ASCII Character via serial port and via Morse Code.
            ;Enter with char in temp.
           
    push    temp
     pop    temp
     rcall    SendMorseAscii
     ret           




codechart:    ;Coded Morse Code look up table. Use ASCII value -$30, so zero = 0, "A" = $11, etc.
;Note: Some ASCII characters are silent, and are coded as 0b00000001
;Also note: BT (pause) is coded for ASCII "<" and SK (end of contanct) is coded for ASCII "*",
;and End of Message is coded for ASCII "+".


;    * (SK)        + (End of Message)
.db    0b01101000,    0b00101010


;    ,(comma)    -          .          /
.db    0b01110011,0b1011110,0b01111010,0b00101001


;    0          1          2          3
.db    0b00111111,0b00111110,0b00111100,0b00111000

;    4          5          6          7
.db    0b00110000,0b00100000,0b00100001,0b00100011
    
 
;    8          9          :          ;
.db    0b00100111,0b00101111,0b01000111,0b01010101
     
    
;    <  (BT)        =          >          ?
.db    0b000110001,0b00000001,0b00000001,0b01001100
         
 ;    @          A          B          C
.db    0b00000001,0b00000110,0b00010001,0b00010101
 
 
 ;    D          E          F          G
.db    0b00001001,0b00000010,0b00010100,0b00001011
 
  ;    H          I          J          K
.db    0b00010000,0b00000100,0b00011110,0b00001101
 
 
  ;    L          M          N          0
.db    0b00010010,0b00000111,0b00000101,0b00001111
 
 
   ;    P          Q          R          S
.db    0b00010110,0b00011011,0b00001010,0b0001000
  
 
    ;    T          U          V          W
.db    0b00000011,0b00001100,0b00011000,0b00001110
  

    ;    X          Y          Z          [
.db    0b00011001,0b00011101,0b00010011,0b00000001
  
   
          
    
timerservice:    ;Service Timer 1
    push    temp   
    in    temp,sreg
    push    temp
   
   
   
    sbrs    flagreg,1
    rjmp    notoggle
   
        ;Toggle tone output
    sbi    codeout,codebit        ;Enable code output pin.
    mov    temp,flagreg        ;Toggle it, using flagreg 0 as memory of last one.
    andi    temp,0b00000001
    inc    temp
    andi    temp,0b00000001
    brne    codehigh
    cbi    codeport,codebit
    sbi    codeport,pulsebit
    andi    flagreg,0b11111110
    rjmp    toggledone
codehigh:
    sbi    codeport,codebit
    cbi    codeport,pulsebit
    ori    flagreg,0b00000001
toggledone:
    pop    temp
    out    sreg,temp
    pop    temp

    reti            ;Return from interrupt.
   
notoggle:    ;Don't toggle port, but delay to equalize interrupt time toggling and not toggling.
    cbi    codeout,codebit        ;Disable code out pin.
    nop
    nop
    nop
    nop
    nop
    nop
    rjmp    toggledone


.exit

Liability Disclaimer and intellectual property notice

(Summary: No warranties, use these pages at your own risk. You may use the information provided here for personal and educational purposes but you may not republish or use this information for any commercial purpose without explicit permission.) I neither express nor imply any warranty for the quality, fitness for any particular purpose or use,or freedom from patents or other restrictions on the rights of use of any software, firmware, hardware, design, service,information, or advice provided, mentioned,or made reference to in these pages. By utilizing or relying on software, firmware, hardware, design, service,information, or advice provided, mentioned, or made reference to in these pages, the user takes responsibility to assume all risk and associated with said activity and hold Richard Cappels harmless in the event of any loss or expense associated with said activity. The contents of this web site, unless otherwise noted, is copyrighted by Richard Cappels. Use of information presented on this site for personal, nonprofit educational and noncommercial use is encouraged, but unless explicitly stated with respect to particular material, the material itself may not be republished or used directly for commercial purposes. For the purposes of this notice, copying binary data resulting from program files, including assembly source code and object (hex) files into semiconductor memories for personal, nonprofit educational or other noncommercial use is not considered republishing. Entities desiring to use any material published in this pages for commercial purposes should contact the respective copyright holder(s).





;RETURN TO THE MORSE CODE ALARM CLOCK PAGE.