;RETURN TO THE MORSE BEACON PAGE

;Copy and paste this into an assembler file. 

;WARNING: A JMP IS USED IN THIS FILE, ALTHOUGH THE ATMEGA8 DOES NOT HAVE A JMP INSTRUCTION.
;THE LINE READS:
"jmp    Atodonoff". ONE POSSIBLE SOLUTION IS TO CHANGE THIS TO AN RJMP AND SEE IF THAT WORKS.
;ANOTHER IS TO IGNORE IT FOR NOW. IF YOU ASSEMBLER DOESN'T COMPLAIN, YOU CAN LEAVE FIXING THIS UNTIL LATER.
;AS FAR AS I KNOW THIS PART OF THE CODE WAS FULLY TESTED. WHY THE ASSEMBLER DID NOT COMPLAIN AND WHY THE CODE
;RAN CORRECTLY IS A MYSTERY AT THIS MOMENT. Noted March, 2007.

;-start of document-


;Program: Morse beacon with 4 A/D channels


;Version:morbecon050219A

;Copyright 2004, 2005 by the Dick Cappels and Jeff Heidbrier.
;projects(at)cappels.org www.projects.cappels.org
 
 
.include "m8def.inc"        ;Include file is in the same directory as the project.
 
     ;Interrupt timer parameters
     .equ    a1wpmhigh    =$12    ;High byte of number of clocks between interrupts.
     .equ    a1wpmlow    =$43    ;Low byte of number of clocks between interrupts.
     .equ    a5wpmhigh    =$03    ;High byte of number of clocks between interrupts.
     .equ    a5wmplow    =$A9    ;Low byte of number of clocks between interrupts.
     .equ    a10wpmhigh    =$01    ;High byte of number of clocks between interrupts.
     .equ    a10wpmlow    =$D4    ;Low byte of number of clocks between interrupts.
     .equ    a25wpmhigh    =$00    ;High byte of number of clocks between interrupts.
     .equ    a25wpmlow    =$BB    ;Low byte of number of clocks between interrupts.
     .equ    timer0rel1khz    =254    ;Reload value for tone timer. 254 = 1 kHz.
     .equ    timer0rel500hz    =252    ;Reload value for tone timer. 252 = 500 Hz.
 
         ;UART baud rate calculation
     .equ    clock = 4000000    ;clock frequency
     .equ    baudrate = 9600    ;choose a baudrate
    .equ    baudconstant = (clock/(16*baudrate))-1        
 
      ;ALLOCATE BUFFER(S)
     .equ    rambot    =$60
     .equ    lbuffsize    = 80    ;Bytes allocated to line buffer
     .equ    lbufftop    = rambot+80
     .equ    lbuffbot    = rambot ;Top address (start of) line buffer
     
 
     .def    opsel        = r2    ;Option select bits
     .def    termsel    = r3    ;Options as selected by terminal
     .def    tim0rel    = r4    ;Timer 0 reload value
     .def    EEchecksum    = r5    ;Simple checksum of EEPROM from $60 to $FE
     .def    temp        = r16    ;General purpose scratch register.
     .def    a1        = r17    ;Three byte number
     .def    a2        = r18    ;Three byte number
     .def    a3        = r19    ;Three byte number
     .def    h        = r20    ;Binary to decimal conversion.
     .def    t        = r21   ;Binary to decmial conversion.
     .def    u        = r22    ;Binary to decimal conversion.
     .def    flagreg    = r23    ;Flags.
     .def    temp2        = r24    ;Intermediate results
 
 
 ;EEPROM Map
 ;$60 to $B0 Line Buffer
 ;$FE        termsel byte
 ;$FF        simple checksum
 
 ;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
 
 
 ;defintion of opsel O(ption Select) bits
 ;0    lsb of code speed select (corresponds to port pin C4)
 ;1    msb of code speed select (correspoinds to port pin C5)
 ;2    lsb of A/D channels select (corrseponds to port p[in D2)
 ;3    msb of A/D channels select (corrseponds to port p[in D3)
 ;4    Tone Hi/low. 1 = 1 kHz; 0 = 500 Hz (corrsponds to port pin D4)
 ;5    Deault operation if 1 (corresponds to port pin D5)
 ;6
 ;7
 
 ;definition of termsel (terminal selection) bits -parameters set by RS-232 interface
 ;and stored in EEPROM.
 ;0    Terminal selections override user I/O selections when set. Can be over-ridden by groudning pin 11.
 ;1    Analog channel A on when set.
 ;2    Analog channel B on when set.
 ;3    Analog channel C on when set.
 ;4    Analog channel D on when set.
 ;5    lsb of code speed (corresponds to obsel bit 0).
 ;6    msb of code speed (corresponds to obsel bit 1).
 ;7    Tone Hi/low (corresponds to obsel bit 4).
 
 
 ;definition of I/O
 ;B0    + comparitor input (Reserved)
 ;B1    - comparitor input (Reserved)
 ;B2    Tone (Morse code) output    
 ;B3    Morse code output    
 ;B4    A/D channels 0    - configure as INPUT with weak pullup
 ;B5    A/D channels 1    - configure as INPUT with weak pullu
 ;B6    (not assigned - configure as INPUT with weak pullup)    
 ;B7    (not assigned - configure as INPUT with weak pullup)    
 
     .equ    PORTBdata    =0b11110000    ;Initial data    
     .equ    DDRBdata    =0b00001100    ;Initial data    
     .equ    codeport     = PORTB
     .equ    codeout    = DDRB
     .equ    codebit     = 2        ;Tone output
     .equ    pulsebit    = 3        ;Morse code output
 
 
 ;C0    A/D A    configure as INPUT, with weak pullup when not used
 ;C1    A/D B    configure as INPUT, with weak pullup when not used
 ;C2    A/D C    configure as INPUT, with weak pullup when not used
 ;C3    A/D D    configure as INPUT, with weak pullup when not used
 ;C4    Code Speed 0    - configure as INPUT with weak pullup
 ;C5    Code speed 1    - configure as INPUT with weak pullup
 ;C6    Reset pin - configure as INPUT with weak pullup
 ;C7    (does not exist - configure as INPUT with weak pullup)
 
     .equ    PORTCdata    =0b11110000    ;Initial data    
     .equ    DDRCdata    =0b00000000    ;Initial data
 
 
 ;D0    UART RECEIVE - configured with weak pullup
 ;D1    UART TRANSMIT
 ;D2    (not assigned - configure as INPUT with weak pullup)
 ;D3    (not assigned - configure as INPUT with weak pullup)
 ;D4    Tone Select    - configure as INPUT with weak pullup)
 ;D5    Default Op    - configure as INPUT with weak pullup)
 ;D6    (not assigned - configure as INPUT with weak pullup)
 ;D7    (not assigned - configure as INPUT with weak pullup)
 
     .equ    PORTDdata    =0b11111101    ;Initial data    
     .equ    DDRDdata    =0b00000010    ;Initial data

 
 .cseg    
 .ORG $0000    
rjmp     start
 .org $0009    
rjmp    timer0service    
                         ;Initializaton code

 start:                    ;Entry point after reset -initialize everything
 warm:                    ;Warm is actually a reset.
     ldi    temp,DDRBdata        ;Set PORTB.    
     out    DDRB,temp
     ldi    temp,PORTBdata
     out    PORTB,temp        
     ldi    temp,DDRCdata        ;Set PORTC
     out    DDRC,temp
     ldi    temp,PORTcdata
     out    PORTc,temp    
     ldi    temp,DDRDdata        ;Set PORTD.    
     out    DDRD,temp
     ldi    temp,PORTDdata
     out    PORTD,temp
     ldi    temp,high(ramend)     ;Initialize 16 bit Stack Pointer
     out    sph,temp    
     ldi     temp,low(ramend)    
     out     spl,temp
     clr    flagreg            ;Clear firmware flagreg (flag register).
 
                         ;SET UP USART
     clr    temp                ; Set baud rate
     out     UBRRH, temp
     ldi    temp,baudconstant        ;load computed value for baud rate
     out     UBRRL, temp            ;Enable Receiver and Transmitter
     ldi     temp, (1<<RXEN)|(1<<TXEN)
     out     UCSRB,temp            ;Set frame format: 8data, 2stop bit
     ldi     temp, (1<<URSEL)|(1<<USBS)|(3<<UCSZ0)
     out     UCSRC,temp
                         ;8 BIT TIMER 0 SETUP
     ldi    temp,5            ;Set prescaler for clk/8
     out    TCCR0,temp
     ldi    temp,timer0rel1khz    ;Set number of pulses to count up after division by prescaler
     mov    tim0rel,temp        ;Default is for 1 kHz (4 MHz clock).
     out    TCNT0,temp
     in    temp,TIMSK
     ori    temp,0b00000001        ;Enable timer 0 oveflow interrupt.
     out    TIMSK,temp
                         ;ITINITALIZE A TO D CONVERTER
     ldi    temp,0b00010101        ;Set control and status register. 4 MHz clock.Clear int flag.
     out    ADCSR,temp
     sei                    ;Enable interrupts.
                         ;Now that interrups are on and there is a tone, send the greeting.
 
     ldi    temp,0b11111100        ;25 words per minute
     mov    opsel,temp    
     rcall    setdottime            ;Set the dot period as a function of opsel bit 0,1
     rcall    crlf
     rcall    crlf
     rcall    crlf
     rcall    crlf
     rcall    Typeheader            ;Type the header at 25 WPM.
     rcall    Loadcommand            ;Load EEPROM contents into RAM $60 to $FF
     rcall    typestatus            ;Type terminal control setup.
     rcall    DumpLineBuffer        ;Display line buffer contents
     rcall    GetOptionBits        ;Get jumper selectable options to opsel register
                         ;Switch flow to Programmed Main if bit o in termsel is set,
                          ;EEPROM checksum is valid, and opsel bit 5 is set.
     ldi    temp,0b00100000        ;Check for jumper pin override.
     and    temp,opsel    
     breq    DefaultMain
     ldi    temp,0b00000001        ;Check for terminal program control bit set in termsel
     and    temp,termsel
     breq    DefaultMain    
     clr    YH                ;Check EEProm checksum
     ldi    YL,$FF
     ld    temp,Y
     cp    temp,EEChecksum
     brne    DefaultMain
     rjmp    ProgrammedMain
         
     
 DefaultMain:                ;Main Loop
     rcall    GetOptionBits        ;Get jumper selectable options to opsel register
     rcall    setdottime            ;Set the dot period as a function of opsel bit 0,1
     rcall    ToggleTonepitch        ;Set tone pitch based on opsel bit 4
     rcall    MeasureAndSendVolts
     rcall    interword
     rcall    OptionsEditor        ;Check to see if Operator requested Options Editor.
     rjmp    DefaultMain    
     

     
 ToggleTonepitch:                ;Set the interrupt period to 500 Hz or 1 Khz
     push    temp                ;based on opsel bit 4.
     mov    temp,opsel
     andi    temp,0b00010000
     breq    x22
     ldi    temp,timer0rel1khz
     rjmp    x23
 x22:    ldi    temp,timer0rel500hz    
 x23:
     mov    tim0rel,temp        ;Set interrupt time for chosen tone frequ.
     pop    temp
     ret
     
 
 
     
 GetOptionBits:                ;Get jumper selectable options to opsel register
     push    temp
     in    temp,PINC            ;Get Port C bits 4,5.
     andi    temp,0b00110000
     lsr    temp
     lsr    temp
     lsr    temp
     lsr    temp
     mov    opsel,temp
     in    temp,PIND            ;Get Port D bits 2,3,4, and 5.
     andi    temp,0b00111100
     or    opsel,temp
     pop    temp
     ret
 
 
 crlf:                    ;Send Carrige return and line feed ($0D, $0A)
     push    temp
     ldi    temp,$0D
     rcall    emitchar
     ldi    temp,$0A
     rcall    emitchar
     pop    temp
     ret
 
 emitchar0D:                ;Send outchar to terminal. Add line feed to carriage return.
     push    temp
     rcall    emitchar
     cpi    temp,$0D            ;Its a carraiage return, send a linefeed also
     brne    notareturn
     ldi    temp,$0A
     rcall    emitchar    
 notareturn:   
     pop    temp
     ret
 
 
 emitchar:    ;Send character contained in temp.
     sbis    UCSRA,UDRE            ;Test for TX register empty
     rjmp    emitchar            ;Loop until TX empty
     out    UDR,temp            ;Send the byte
     ret
     
 getchar:    
     sbis    UCSRA,RXC            ;Wait until a character has been received
     rjmp    getchar
     in    temp,UDR            ;Read byte from the UART
     ret
 
 
 Typeheader:                ;Type header
     push    ZL
     push    ZH
     ldi    ZH,high(2*hellomessage)    ;Load high part of byte address into ZH
     ldi    ZL,low(2*hellomessage)    ;Load low part of byte address into ZL
     rcall    typeromstring        ;Send it
     pop    ZH
     pop    ZL
     ret
     
     
     
 hellomessage:
     .db    $0A,$0D
     .db    $0A,$0D
     .db   "morbecon050219A "
     .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    SendMorseAscii     ;Send upper case ASCII Char as Morse Code.
          adiw    ZL,1        ;Increment Z registers
          rjmp    srs1
 finishsendstering:
     pop    ZH            ;Pop Z from stack.
     pop    ZL
      rcall    interword
          ret
 

 
 MeasureAndSendVolts:        ;Measure 1 to 4 A/D channels and send the values as Morse Code
                     ;and via RS-232 accoding to obsel bits 2 and 3.
                     ;Bit 3        Bit 2    Measure
                     ;1        1    Channel A only (ADC  0)
                     ;0        1    Channels A & B (ADC 0,1)
                     ;1        0    Channels A,B & C (ADC 0,1,2)
                     ;0        0    Channels A,B,C & D (ADC 0,1,2,3)
     push    temp
    ldi    temp,'A'
     rcall    SendMorseAscii
 
     ldi    temp,0            ;Channel A always sent, so do that first.
     rcall    measure            ;Measure it.
     rcall    SendVolts            ;Send out as Morse Code
     mov    temp,opsel
     andi    temp,0b00001100
     cpi    temp,0b00001100        ;If bit 2 and 3 are set, we're done.
     breq    donemeas
     push    temp
      ldi    temp,$20
     rcall    SendMorseAscii
     ldi    temp,'B'
     rcall    SendMorseAscii
     ldi    temp,1            ;Do Channel B.
     rcall    measure            ;Measure it.
     rcall    SendVolts            ;Send out as Morse Code
     pop    temp
     cpi    temp,0b00000100        
     breq    donemeas            ;If only bit 2 is set, we're done.    
     push    temp
     ldi    temp,$20
     rcall    SendMorseAscii
     ldi    temp,'C'
     rcall    SendMorseAscii
     ldi    temp,2            ;Do Channel C..
     rcall    measure            ;Measure it.
     rcall    SendVolts            ;Send out as Morse Code
     pop    temp
     cpi    temp,0b00001000        
     breq    donemeas            ;If only bit 3 is set, we're done.    
     ldi    temp,$20
     rcall    SendMorseAscii
     ldi    temp,'D'
     rcall    SendMorseAscii
     ldi    temp,3            ;Do Channel D..
     rcall    measure            ;Measure it.
     rcall    SendVolts            ;Send out as Morse Code
donemeas:                    ;We are done.
     ldi    temp,$20
     rcall    SendMorseAscii    
     ldi    temp,$0A
     rcall    SendMorseAscii
     ldi    temp,$0D
     rcall    SendMorseAscii
     pop    temp
     ret
 
 
 
 Measure:    ;Measure A/D channel. Enter with channel number in temp. Exit with data in YH:YL
         ;Allowed range is 0..5
     push    temp
     sbi    ADCSR,ADEN            ;Enable A/D converter.
     andi    temp,0b00000011        ;Mask off upper bits to restrict range of channel selction.
     ori    temp,0b01000000        ;Set reference voltage bit.
     out    ADMUX,temp            ;Select channel.
     sbi    ADCSR,ADSC            ;Start conversion.
 wfc:
     sbis    ADCSR,ADIF            ;Wait for bit to be set, indicating conversion complete.
     rjmp    wfc
     sbi    ADCSR,ADIF            ;Clear interrupt flag.
     in    YL,ADCL            ;Get data into Y register.
     in    YH,ADCH
     pop    temp
     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. " The code that follows is based on this technique.
 
 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.

     rcall    OptionsEditor        ;Check to see if Operator requested Options Editor.        
     push    ZL                ;Save registers
     push    ZH
    push    temp                ;Save contents of temp.
     rcall    emitchar0D            ;Emit the char via UART.
     pop    temp                ;Restore value of temp.
     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                ;Restore registers
     pop    ZL
     ret                    ;Return
 
 
 dot:        ;Send dot, wait one dot time.
     sbr    flagreg,0b00000010        ;Set flag to send tone.
     sbi    codeport,pulsebit        ;Set on-off key pulse high.
     rcall    dottime
     cbr    flagreg,0b00000010    ;Clear flag to send tone.
     cbi    codeport,pulsebit        ;Set on-off key pulse low.
     rcall    dottime
     ret
 
 
 dash:    ;Send dash, wait one dot time.
     sbr    flagreg,0b00000010    ;Set flag to send tone.
     sbi    codeport,pulsebit        ;Set on-off key pulse high.
     rcall    dottime
     rcall    dottime
     rcall    dottime
     cbr    flagreg,0b00000010    ;Clear flag to send tone.
     cbi    codeport,pulsebit        ;Set on-off key pulse low.
     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
 
 
 setdottime:                
     push    temp
     
                     ;Load compare registers, OCR1AH,OCR1AL with values for
                     ;dot rate as a function of opsel bits 0 and 1.
                     ;
                     ;    bit1    bit0    Code Speed    OCR1AH    ORC1Al
                     ;    1        1        10 WPM
                     ;    1        0        1  WPM
                     ;    0        1        5  WPM
                     ;    0        0        25 WPM
                     ;
                     ;Note Code speed is calcualted using PARIS (50 spaces)
                     ;send in 1 minute = 1 WPM.
 
 
     mov    temp,opsel              ;Get option select bits into temp.
     andi    temp,0b00000011        ;Mask off all but two lsb.
     cpi    temp,0                  ;Test if 0.
     brne    not0                   ;If not 0 skip to next test.
     ldi    temp,a25wpmhigh         ;If 0 load parameters for 25 WPM.
     out    OCR1AH,temp
     ldi    temp,a25wpmlow
     out    OCR1AL,temp    
     rjmp    speedset
 not0:    
    cpi    temp,1                ;Test for value = 1.
     brne    not1
     ldi    temp,a5wpmhigh
     out    OCR1AH,temp
     ldi    temp,a5wmplow
     out    OCR1AL,temp    
     rjmp    speedset
 not1:    cpi    temp,2        ;Test for value = 2
     brne    not2
     ldi    temp,a1wpmhigh
     out    OCR1AH,temp
     ldi    temp,a1wpmlow
     out    OCR1AL,temp    
     rjmp    speedset
 not2:    
    ldi    temp,a10wpmhigh    ;Its not 0,1, or 2, so it must be 3.
     out    OCR1AH,temp
     ldi    temp,a10wpmlow
     out    OCR1AL,temp    
 speedset:                    ;Come to here when speed has been set.
     pop    temp
     ret
 
 
 
 dottime:                    ;Delay one dot time.
 
     push    temp                    
     ldi    temp,0b00001101        ;Set timer 1 to reset 0000 after compare match. Prescaler = 1X.    out    TCCR1B,temp
     out    TCCR1B,temp
 
 
 
 wd1:    in    temp,TIFR
     sbrs    temp,OCF1A             ;Wait for flagreg bit two to go high (timer to time out)
     rjmp    wd1
     out    TIFR,temp            ;Clear the flag
 
     ldi    temp,0b00000000        ;Set timer 1 to "normal" mode, prescale output stopped.
     out    TCCR1B,temp
     pop    temp
 
     ret
 
    
 SendVolts:
                         ;Enter with input value in YH:YL. YH,YL,a1,a2,a3,temp,H,T,U modified.
                        ;Scale input with range of 0 to 1023 to d digit expression of range
                         ;from 0 to 5. This is for a 5 volt full scale input 10 bit ADC.
                         ;Multiply input by 489 and divide by 1,000 to get answer in tens of
                         ;millivolts.
 
     push    temp    
     clr    a1                ;Clear the 3 byte number
     clr    a2
     clr    a3
     
         
 mloop:    
         
     tst    YL        
     brne    notzero
     tst    YH
     brne    notzero
     rjmp    countdone
 notzero:
     sbiw    YL,1                ;Decrement the 10 bit value and add 489 to each time
     ldi    temp,$E9
     add    a1,temp            ;To multiply number in Y by 489
     ldi    temp,$01
     adc    a2,temp
     clr    temp
     adc    a3,temp
     rjmp    mloop
 countdone:                    ;At this point, the product is in a1,2,3
                         ;Test values come out of 489000 here.
     clr    H
     clr    T
     clr    U
 MoreH:    
     inc    H    
     subi    a1,$A0            ;Find out how many 100,000's
     sbci    a2,$86
     sbci    a3,1
     brcc    MoreH    
     ldi    temp,$A0            ;Subtracted one too many, add back on.
     add    a1,temp
     ldi    temp,$86
     adc    a2,temp
     ldi    temp,1
     adc    a3,temp
     dec    H                ;VALUE EXITING THIS ROUTINE IS 23112. SHOULD BE 89000.
 MoreT:
     inc    T    
     subi    a1,$10            ;Find out how many 10.000's
     sbci    a2,$27
     sbci    a3,$00
     brcc    moreT        
     ldi    temp,$10            ;Subtracted one too many, add back on.
     add    a1,temp
     ldi    temp,$27
     adc    a2,temp
     ldi    temp,0
     adc    a3,temp
     dec    T
 MoreU:
     inc    U    
     subi    a1,$E8            ;Find out how many 10.000's
     sbci    a2,$03
     sbci    a3,$00
     brcc    moreT    
     ldi    temp,$E8            ;Subtracted one too many, add back on.
     add    a1,temp
     ldi    temp,$03
     adc    a2,temp
     ldi    temp,0
     adc    a3,temp
     dec    U                
     subi    H,-48                ;Convert to ASCII and send. Send H
      mov    temp,H
     rcall    SendMorseAscii
     subi    T,-48
      mov    temp,T
     rcall    SendMorseAscii
     subi    U,-48                ;Send U
      mov    temp,U
      rcall    SendMorseAscii
     rcall    interword
     rcall    interword
     rcall    interword
     pop    temp
     ret
 
 
 
 ;/////////////////////////////Morse Code Chart\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
 
 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
   
&nbs