Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

convert from 16c84 to 16f628a need help

upand_at_them

Active Member
OP can verify that the device is running with a well-placed "turn on LED" code. I'm curious of his results after the EEADR changes.
 

Pommie

Well-Known Member
Most Helpful Member
Terry,
I note that EEProg resets the bank to zero before returning. And is called assuming bank 1 is selected. Note also the increments of EEADR.
I.E.
Code:
InitISD
        movlw   d'1'            ;0.1 sec message length default
        movwf   EEDATA          ;put into EEPROM data register
        movlw   EEM0LEN         ;address of message 0 length
        movwf   EEADR           ;set EEPROM address to program 
        call    EEProg          ;program byte
        incf    EEADR,f         ;increment address of byte to init
        call    EEProg          ;program byte EEM1LEN
        incf    EEADR,f         ;increment address of byte to init
        call    EEProg          ;program byte EEM2LEN
        incf    EEADR,f         ;increment address of byte to init
        call    EEProg          ;program byte EEM3LEN
It may be safer to not switch back to bank 0 in EEProg and to move all Variables into common area (0x70-0x7f).

Mike.
 

Pommie

Well-Known Member
Most Helpful Member
There seems to be lots of places that EEADR is modified throughout the code.
I.E.
Code:
PNorm
        movf    msgNum,w        ;get message number
        andlw   b'00000011'     ;mask out bits 2-7
        addlw   EEM0LEN         ;add the base of the message lengths
        movwf   EEADR           ;save address
        call    ReadEE          ;read EEPROM, w will have message length after
        movwf   isdTmr          ;preset message timer
        btfsc   STATUS,Z        ;is the length 0
        return                  ;yes, don't play.
        bsf     PORTB,ptt       ;turn transmitter on
And here,
Code:
RecEnd
        movf    msgNum,w        ;get message number
        andlw   b'00000011'     ;mask out bit 2-7
        addlw   EEM0LEN         ;add address of message 0 length
        movwf   EEADR           ;set EEPROM address
        decf    isdRTmr,w       ;get timer - 1 (less 100 ms)
        movwf   EEDATA          ;put into EEPROM data register...
        call    EEProg          ;save message length
BTW, well done on doing this, I'm sure the OP is very pleased.

Mike.
Edit, and EEDATA.
 

augustinetez

Active Member
There seems to be lots of places that EEADR is modified throughout the code.
Thanks Mike, I'm doing this in between other things so having other pairs of eyes is most welcome.

I did think about moving various registers to the common area but decided there was too much chance of fouling things up even more, although it may come to it.

Jaison, OK, it will get there eventually. Just a few odd things to make sure are correct as Mike has picked up above.
 

Pommie

Well-Known Member
Most Helpful Member
As there's 16 SFRs used (0x20 to 0x2f) then they'll all fit in the common area which will make it more like the 84 as all SFRs were common. They could be accessing SFRs from bank 1 as it would have worked fine on an 84.

Actually, just counted and there are more than 16 - comment is wrong.
However, w_copy and s_copy definitely need to be in the common area.

Mike.
 

Ian Rogers

User Extraordinaire
Forum Supporter
Most Helpful Member
Here you go.

Code:
; PIC 16C84 Based Repeater Controller.
; Copyright (C) 1996, Jeffrey B. Otterson, N1KDO.  
; This software may be freely reproduced for use by amateur radio operators
; in their personally owned or club owned radio systems. 
; 21 August 1996
;
; '__CONFIG' especifica os parâmetros codificados no processador no momento de
; programação do processador. As definições estão no arquivo de inclusão.
; Seguem os valores e suas definições:
; _CP_ON Código de proteção ON: não pode ler novamente
; _CP_OFF ??Proteção de código OFF
; _PWRTE_ON Reset do temporizador ao ligar em serviço
; _PWRTE_OFF Temporizador fora de serviço
; _WDT_ON Watchdog em operação
; _WDT_OFF Watchdog desligado
; _LP_OSC Oscilador de cristal de baixa velocidade
; _XT_OSC Oscilador de cristal de velocidade média
; _HS_OSC oscilador de cristal de alta velocidade
; _RC_OSC RC oscilador de rede
       __config _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC
        LIST    p=16F628        ;    *************************ALTEREI
        #include "p16F628a.inc" ;    *************************ALTEREI  

;
;        LIST P=16C84, F=INHX8M, R=HEX
;        include "p16c84.inc"
;        __FUSES _CP_OFF & _XT_OSC & _WDT_OFF
        ERRORLEVEL 0, -302      ;suppress Argument out of range errors
;
VERSION EQU D'027'
;
DEBUG   EQU     0
;
; Message Addressing Scheme:
;   Stored Audio:
;     0 - Initial ID, "Welcome to N1KDO repeater"
;     1 - Normal ID, "N1KDO repeater"
;     2 - Timeout message, "Repeater Timeout"
;     3 - Tail message, "Club meeting tonight"
;   CW messages:
;     0 - CW ID, "de n1kdo/r"
;     1 - CW timeout message, "to"
;     2 - CW confirm message, "ok"
;     3 - CW bad message, "ng"
;

CW_ID   equ     h'00'
CW_TO   equ     h'01'
CW_OK   equ     h'02'
CW_NG   equ     h'03'
ISD_IID equ     h'10'
ISD_ID  equ     h'11'
ISD_TO  equ     h'12'
ISD_TM  equ     h'13'
ISD_SM  equ     h'14'   ;simplex repeater message 

ISDSIM  equ     2       ;indicates simplex message
ISDMSG  equ     4       ;indicates message is for ISD
MSGREC  equ     7       ;set high bit to indicate record mode

;
; The main program spins in Loop as fast as it can.  
; Timing is accomplished by the interrupt routine that sets 3 bits that
; are used inside the main loop: TENTH, ONESEC, and TENSEC.  When these
; bits are set, the corresponding timer(s) should be decremented.
;
; Port A has the DTMF data, and one bit that is used for muting and init
; A.0 (in ) = DTMF bit 0
; A.1 (in ) = DTMF bit 1
; A.2 (in ) = DTMF bit 2
; A.3 (in ) = DTMF bit 3
; A.4 (in ) = init input at start up, mute output after
;
;Port A
TMASK   equ     0f
INITBIT equ     4
MUTE    equ     4       ;mute and init share A.4
;
; Port B has the following
; B.0 (in ) = DTMF digit valid
; B.1 (out) = PTT
; B.2 (out) = ISD playl\
; B.3 (out) = ISD A0
; B.4 (out) = ISD A1
; B.5 (out) = ISD record\
; B.6 (out) = beep tone output
; B.7 (in ) = COR
;
;PortB
dv      equ     0       ;DTMF digit valid
ptt     equ     1       ;PTT key
isdPlay equ     2       ;ISD run
isdRec  equ     3       ;ISD record (0) / play (1) select
isdA0   equ     4       ;ISD message select bit 0 
isdA1   equ     5       ;ISD message select bit 1
beepBit equ     6       ;beep generator
cor     equ     7       ;unsquelched (0) / squelched (1)

CTL0    equ     2       ;output lead zero when no ISD
CTL1    equ     3       ;output lead one  when no ISD

;TFlags                 ;timer flags        
TICK    equ     0       ;100 ms tick flag
TENTH   equ     1       ;tenth second decrementer flag
ONESEC  equ     2       ;one second decrementer flag
TENSEC  equ     3       ;ten second decrementer flag
CWTICK  equ     4       ;cw clock bit
TFLCOR  equ     7       ;debounced cor

;flags
initID  equ     0       ;need to ID now
sentID  equ     1       ;recently sent ID
lastDV  equ     2       ;last pass digit valid
init    equ     3       ;initialize
lastCor equ     4       ;last COR flag
isdRecF equ     5       ;ISD record flag
cwOn    equ     6       ;cw sender is active...
beepOn  equ     7       ;beep tone on

;cfgFlag
NOISD   equ     0       ;ISD 1420 is not present
SIMPLEX equ     1       ;simplex repeater mode
;NIY    equ     2       ;NIY
;NIY    equ     3       ;NIY
NOCTSY  equ     4       ;suppress courtesy tone
NOMUTE  equ     5       ;don't mute touch-tones
ISDCTSY equ     6       ;play ISD message 3 for courtesy tone
;NIY    equ     7       ;NIY


;state, bit 0 set indicates transmitter should be on...
SQUIET  equ     0
SRPT    equ     1
STIMOUT equ     2
SHANG   equ     3
SDISABL equ     4

SACTIVE equ     b'00000001'     ;active mask, don't turn off PTT when ISD done

;debounce count complete Bit 
        IF DEBUG == 1
CDBBIT  equ     1               ; debounce counts to 2, about 1.143 ms?
        ELSE
CDBBIT  equ     5               ; debounce counts to 32, about 18.2 ms
        ENDIF

;
; EEPROM locations for data...
;
EEENAB  equ     h'00'
EECONF  equ     h'01'
EEHANG  equ     h'02'
EETOUT  equ     h'03'
EEID    equ     h'04'
EETMSG  equ     h'05'
EECWOK  equ     h'06'
EECWNG  equ     h'09'
EECWTO  equ     h'0c'
EECWID  equ     h'0f'
EEIEND  equ     h'1a'           ;last EEPROM to program with data at init time
EELAST  equ     h'37'           ;last EEPROM address to init

EEM0LEN equ     h'38'
EEM1LEN equ     h'39'
EEM2LEN equ     h'3a'
EEM3LEN equ     h'3b'
EETTPRE equ     h'3c'

;
;DTMF remote control constants
;
TONES   EQU     4               ;number of digits in received touch tone command
MAXCMD  EQU     4               ;maximum number of digits in command

;
; CW sender constants
;
CWDIT   equ     1               ;dit = 100 ms
CWDAH   equ     CWDIT * 3       ;dah = 300 ms
CWIESP  equ     CWDIT           ;inter-element space = 100 ms
CWILSP  equ     CWDAH           ;inter-letter space = 300 ms
CWIWSP  equ     7               ;inter-word space = 700 ms

ISDSMAX EQU     D'198'          ;preset max ISD record time 19.8 sec (simplex)
ISDMAX  EQU     D'48'           ;preset max ISD record time 4.8 sec
ISDBKOF EQU     D'3'            ;preset simplex ISD backoff time .3 sec

        IF DEBUG == 1
OFBASE  equ     D'2'            ;overflow counts fast!
TEN     equ     D'2'
        ELSE
OFBASE  equ     D'175'          ;overflow counts in 100.12 ms
TEN     equ     D'10'
        ENDIF

CWCNT   equ     D'105'          ;approximately 60 ms for 20 wpm

IDSOON  equ     D'6'            ;ID soon, polite IDer threshold, 60 sec
MUTEDLY equ     D'20'           ;DTMF muting timer

;macro definitions
push    macro
        movwf   w_copy          ;save w reg in Buffer
        swapf   w_copy,f        ;swap it
        swapf   STATUS,w        ;get status
        movwf   s_copy          ;save it
        endm
;
pop     macro
        swapf   s_copy,w        ;restore status
        movwf   STATUS          ;       /
        swapf   w_copy,w        ;restore W reg
        endm

;variables
        cblock   0x20           ;**************ALTEREI 0c  PARA 0x20
        w_copy                  ;saved W register for interrupt handler
        s_copy                  ;saved status register for int handler
        cfgFlag                 ;Configuration Flags
        tFlags                  ;Timer Flags
        flags                   ;operating Flags
        ofCnt                   ;100 ms timebase counter
        cwCntr                  ;cw timebase counter
        secCnt                  ;one second count
        tenCnt                  ;ten second count
        state                   ;CAS state
        hangDly                 ;hang timer preset, in tenths
        tOutDly                 ;timeout timer preset, in 1 seconds
        idDly                   ;id timer preset, in 10 seconds
        hangTmr                 ;hang timer, in tenths
        tOutTmr                 ;timeout timer, in 1 seconds
        idTmr                   ;id timer, in 10 seconds
        isdTmr                  ;ISD1240 playback timer, in tenths
        isdRTmr                 ;ISD1240 record timer, in tenths (up-counter)
        sISDTmr                 ;simplex ISD back-off timer
        muteTmr                 ;DTMF muting timer, in tenths
        cwTmr                   ;CW element timer
        msgNum                  ;message number to play
        tone                    ;touch tone digit received
        toneCnt                 ;digits received down counter
        cmdCnt                  ;command digists received
        tBuf1                   ;tones received buffer
        tBuf2                   ;tones received buffer
        tBuf3                   ;tones received buffer
        tBuf4                   ;tones received buffer
        cwBuff                  ;CW message buffer offset
        cwByte                  ;CW current byte (bitmap)                 
        tMsgCtr                 ;tail message counter
        dBounce                 ;cor debounce counter
        endc

;last RAM address is at 2f

;;;;;;;;;;;;;;;;;;
;; MAIN PROGRAM ;;
;;;;;;;;;;;;;;;;;;

        org     0
        goto    Start

        ;
        ; interrupt handler
        ;
        org     b'0100'            ; **********************  ALTEREI 4 para 0100
        push                    ;preserve W and STATUS

        btfsc   INTCON,T0IF
        goto    TimrInt
        goto    IntExit

TimrInt
        btfss   flags,beepOn    ;is beep turned on?
        goto    TimrTst         ;no, continue
        btfss   PORTB,beepBit   ;is beepBit set?
        goto    Beep0           ;no
        bcf     PORTB,beepBit   ;yes, turn it off
        goto    TimrTst         ;continue
Beep0
        bsf     PORTB,beepBit   ;beep bit is off, turn it on...

TimrTst
        decfsz  ofCnt,f         ;decrement the overflow counter
        goto    TimrDone        ;if not 0, then 
        bsf     tFlags,TICK     ;set tick indicator flag
        movlw   OFBASE          ;preset overflow counter
        movwf   ofCnt           

TimrDone                        
        decfsz  cwCntr,f        ;decrement the cw timebase counter
        goto    DBounce
        bsf     tFlags,CWTICK   ;set tick indicator
        movlw   CWCNT           ;get preset value
        movwf   cwCntr          ;preset cw timebase counter

DBounce                         ;COR debounce
        btfss   PORTB,cor       ;check cor
        goto    ICorOn          ;it's low...
                                ;squelch is closed; receiver is inactive
        movf    dBounce,f       ;check debounce counter for zero
        btfsc   STATUS,Z        ;is it zero?
        goto    TIntDone        ;yes
        decf    dBounce,f       ;no, decrement it
        btfss   STATUS,Z        ;is it zero?
        goto    TIntDone        ;no, continue
        bsf     tFlags,TFLCOR   ;yes, turn COR off
        goto    TIntDone        ;done with COR debouncing...        

ICorOn  
                                ;squelch is open; receiver is active
        btfsc   dBounce,CDBBIT  ;check debounce counter
        goto    TIntDone        ;already maxed out
        incf    dBounce,f       ;increment 
        btfss   dBounce,CDBBIT  ;is it maxed now?
        goto    TIntDone        ;no
        bcf     tFlags,TFLCOR   ;yes, turn COR on

TIntDone
        bcf     INTCON,T0IF     ;clear RTCC int mask

IntExit
        pop                     ;restore W and STATUS
        retfie

Start    
        BANKSEL CMCON
        movlw    0x07        ;************ADICIONADO turn off comparators
        movwf    CMCON       ; ***********ADICIONADO 

        bsf     STATUS,RP0      ;select bank 1
        movlw   b'00011111'     ;low 5 bits are input
        movwf   TRISA           ;set port a as outputs
        movlw   b'10000001'     ;RB0&RB7 inputs
        movwf   TRISB

        IF DEBUG == 1
        movlw   b'10001000'     ;DEBUG! no pull up, timer 0 gets no prescale
        ELSE
        movlw   b'10000000'     ;no pull up, timer 0 gets prescale 2
        ENDIF

       
        movwf   OPTION_REG      ;

        bcf     STATUS,RP0      ;select page 0
        clrf    PORTB           ;init port B
        clrf    PORTA           ;make port a all low
        clrf    state           ;clear state (quiet)
        clrf    tFlags          ;clear timer flags
        bsf     tFlags,TFLCOR   ;set debouced cor off
        clrf    flags           ;clear status flags
        clrf    msgNum          ;clear message number
        movlw   OFBASE          ;preset overflow counter
        movwf   ofCnt           
        movlw   CWCNT           ;get preset value
        movwf   cwCntr          ;preset cw timebase counter

        movlw   TEN             ;preset decade counters
        movwf   secCnt          ;1 second down counter
        movwf   tenCnt          ;10 second down counter

        clrf    hangTmr         ;clear hang timer
        clrf    tOutTmr         ;clear timeout timer
        clrf    idTmr           ;clear idTimer
        clrf    isdTmr          ;clear isdTimer
        clrf    muteTmr         ;clear muting timer
        clrf    sISDTmr         ;clear ISD back off timer
        clrf    cmdCnt          ;clear command counter
        clrf    dBounce         ;clear debounce timer counter
        movlw   TONES
        movwf   toneCnt         ;preset tone counter

        btfsc   PORTA,INITBIT   ;check to see if init is pulled low
        goto    NoInit          ;init is not low, continue...

        bsf     flags,init      ;initialization in progress

        BANKSEL EEADR
        movlw   EELAST          ;get last address to initialize
        movwf   EEADR           ;set EEPROM address to program 
InitLp
        call    InitDat         ;get init data byte 
        movwf   EEDATA          ;put into EEPROM data register
        call    EEProg          ;program byte
        movf    EEADR,f         ;load status, set Z if zero (last byte done)
        btfsc   STATUS,Z        ;skip if Z is clear (not last byte)
        goto    InitISD         ;done initializing EEPROM data
        decf    EEADR,f         ;decrement EEADR
        goto    InitLp 

InitISD
        movlw   d'1'            ;0.1 sec message length default
        movwf   EEDATA          ;put into EEPROM data register
        movlw   EEM0LEN         ;address of message 0 length
        movwf   EEADR           ;set EEPROM address to program 
        call    EEProg          ;program byte
        incf    EEADR,f         ;increment address of byte to init
        call    EEProg          ;program byte EEM1LEN
        incf    EEADR,f         ;increment address of byte to init
        call    EEProg          ;program byte EEM2LEN
        incf    EEADR,f         ;increment address of byte to init
        call    EEProg          ;program byte EEM3LEN

NoInit
        bsf     STATUS,RP0      ;select bank 1
        movlw   b'00001111'     ;low 4 bits are input, RA4 is muting control
        movwf   TRISA           ;set port a as outputs
        bcf     STATUS,RP0      ;select bank 1

        call    GetData         ;read EEPROM data

        movlw   b'10100000'     ;enable interrupts, & Timer 0 overflow
        movwf   INTCON 

Loop
        ;check CW bit
        btfss   tFlags,CWTICK   ;is the CWTICK set      
        goto    NoCW
        bcf     tFlags,CWTICK   ;reset the CWTICK flag bit

        ;
        ;CW sender
        ;
        btfss   flags,cwOn      ;sending CW?
        goto    NoCW            ;nope
        decfsz  cwTmr,f         ;decrement CW timer
        goto    NoCW            ;not zero
        
        btfss   flags,beepOn    ;was "key" down?
        goto    CWKeyUp         ;nope
                                ;key was down        
        bcf     flags,beepOn    ;key->up
        decf    cwByte,w        ;test CW byte to see if 1
        btfsc   STATUS,Z        ;was it 1 (Z set if cwByte == 1)
        goto    CWNext          ;it was 1...
        movlw   CWIESP          ;get cw inter-element space
        movwf   cwTmr           ;preset cw timer
        goto    NoCW            ;done with this pass...

CWNext                          ;get next character of message
        incf    cwBuff,f        ;increment offset
        movf    cwBuff,w        ;get offset
        call    ReadEE          ;get char from EEPROM
        movwf   cwByte          ;store character bitmap
        btfsc   STATUS,Z        ;is this a space (zero)
        goto    CWWord          ;yes, it is 00
        incf    cwByte,w        ;check to see if it is FF
        btfsc   STATUS,Z        ;if this bitmap was FF then Z will be set
        goto    CWWord          ;yes, it is FF
        movlw   CWILSP          ;no, not 00 or FF, inter letter space
        movwf   cwTmr           ;preset cw timer
        goto    NoCW            ;done wiht this pass...

CWWord                          ;word space
        movlw   CWIWSP          ;get word space
        movwf   cwTmr           ;preset cw timer
        goto    NoCW            ;done wiht this pass...

CWKeyUp                         ;key was up, key again...
        incf    cwByte,w        ;is cwByte == ff?
        btfsc   STATUS,Z        ;Z is set if cwByte == ff
        goto    CWDone          ;got EOM

        movf    cwByte,f        ;check for zero/word space
        btfss   STATUS,Z        ;is it zero
        goto    CWTest          ;no...
                                ;is 00, word space...
        incf    cwBuff,f        ;increment offset
        movf    cwBuff,w        ;get offset
        call    ReadEE          ;get char from EEPROM
        movwf   cwByte          ;store character bitmap
        btfsc   STATUS,Z        ;check for another word space
        goto    NoCW            ;if another space, done with this pass...
CWTest
        movlw   CWDIT           ;get dit length
        btfsc   cwByte,0        ;check low bit
        movlw   CWDAH           ;get DAH length
        movwf   cwTmr           ;preset cw timer
        bsf     flags,beepOn    ;turn key->down
        rrf     cwByte,f        ;rotate cw bitmap
        bcf     cwByte,7        ;clear the MSB
        goto    NoCW            ;done with this pass...

CWDone                          ;done sending CW
        bcf     flags,cwOn      ;turn off CW flag

NoCW
        movlw   b'11110001'     ;set timer flags mask
        andwf   tFlags,f        ;clear timer flags
        btfss   tFlags,TICK     ;check to see if a tick has happened
        goto    Loop1
        
        ;
        ; 100ms tick has occurred...
        ;
        bcf     tFlags,TICK     ;reset tick flag
        bsf     tFlags,TENTH    ;set tenth second flag
        decfsz  secCnt,f        ;decrement 1 second counter
        goto    Loop1           ;not zero (not 1 sec interval)

        ;
        ; 1s tick has occurred...
        ;
        movlw   TEN             ;preset decade counter
        movwf   secCnt          

        bsf     tFlags,ONESEC   ;set one second flag

        decfsz  tenCnt,f        ;decrement 10 second counter
        goto    Loop1           ;not zero (not 10 second interval)

        ;
        ; 10s tick has occurred...
        ;
        movlw   TEN             ;preset decade counter
        movwf   tenCnt
        bsf     tFlags,TENSEC   ;set ten second flag 

        ;
        ; main loop for repeater controller
        ;
Loop1
        ;computed GOTO used as a switch()
        movlw   h'00'
        movwf   PCLATH          ;ensure that computed goto will stay in range
        movf    state,w         ;get state into w
        addwf   PCL,f           ;add w to PCL
        goto    Quiet           ;0
        goto    Repeat          ;1
        goto    TimeOut         ;2
        goto    Hang            ;3
        goto    CasEnd          ;4

Quiet
        btfsc   tFlags,TFLCOR   ;is squelch open?
        goto    CasEnd          ;no

        btfss   cfgFlag,SIMPLEX ;simplex mode?
        goto    QKeyUp
                                ; *** SIMPLEX ***
        btfsc   flags,cwOn      ;is cw playing?
        goto    CasEnd          ;can't go into record if cw is playing

        movf    isdTmr,f        ;check ISD timer
        btfss   STATUS,Z        ;is it zero
        goto    CasEnd          ;no, ISD is playing, don't record

        movlw   SRPT            ;
        movwf   state           ;change state to repeat

        bcf     PORTB,isdRec    ;stop any recording message
        bcf     PORTB,isdPlay   ;stop any playing message
        bcf     PORTB,isdA0     ;reset message address bits
        bcf     PORTB,isdA1     
        bcf     PORTB,ptt       ;turn transmitter off
        bsf     flags,isdRecF   ;set record mode
        clrf    msgNum          ;set message number to zero
        bsf     msgNum,ISDMSG   ;set message to be for ISD
        movlw   ISDSMAX         ;get maximum simplex message length
        movwf   isdTmr          ;preset max duration counter
        clrf    isdRTmr         ;zero recorded duration timer
        bcf     PORTA,MUTE      ;unmute
        bsf     PORTB,isdRec    ;start recording

        movf    idTmr,f         ;check ID timer
        btfss   STATUS,Z        ;is it zero?
        goto    CasEnd          ;non zero
        movf    idDly,w         ;get ID timer delay into w
        movwf   idTmr           ;store to down-counter
        goto    CasEnd

QKeyUp
        bsf     PORTB,ptt       ;turn transmitter on

KeyUp   
        movf    isdTmr,f        ;check ISD timer
        btfsc   STATUS,Z        ;is it zero
        goto    Key0            ;yes, no message playing
        btfsc   msgNum,1        ;is it an ID message?
        goto    Key0            ;no, let it go
                                ;stomp on playing voice message
        clrf    isdTmr          ;clear ISD timer
        bcf     PORTB,isdPlay   ;turn off ISD1240 playback
        movlw   CW_ID           ;play CW Id
        movwf   msgNum          ;set message number
        call    PlayMsg         ;play the message

Key0
        bcf     PORTA,MUTE      ;unmute
        btfss   flags,cwOn      ;is cw playing?
        bcf     flags,beepOn    ;no, make sure that beep is off.

        movf    tOutDly,w       ;get timeout delay into w
        movwf   tOutTmr         ;preset timeout counter

        movlw   SRPT            
        movwf   state           ;change state to repeat

        btfss   msgNum,MSGREC   ;is record flag set?
        goto    Key1            ;nope...
        bcf     msgNum,MSGREC   ;clear record flag
        bsf     flags,isdRecF   ;set record mode
        movlw   ISDMAX          ;get maximum length...
        movwf   isdTmr          ;preset max duration
        clrf    isdRTmr         ;clear recorded duration timer
        bsf     PORTB,isdRec    ;turn on ISD record

Key1
        movf    idTmr,f         ;check ID timer
        btfss   STATUS,Z        ;is it zero?
        goto    Key2            ;non zero
        
        bsf     flags,initID    ;ID timer was zero, set initial ID flag
        goto    CasEnd
        
Key2
        btfss   flags,sentID    ;sent ID recently?     
        goto    CasEnd          ;no

        bcf     flags,sentID    ;clear recent ID flag
        
        movf    idDly,w         ;get ID timer delay into w
        movwf   idTmr           ;store to down-counter
        goto    CasEnd

Repeat
        btfss   tFlags,ONESEC   ;check to see if one second tick
        goto    Repeat1         ;nope...

        decfsz  tOutTmr,f       ;decrement timeout timer
        goto    Repeat1         ;not to zero yet...
        goto    TimedOut        ;timed out!

Repeat1
        btfss   tFlags,TFLCOR   ;is squelch open?
        goto    CasEnd          ;no, keep repeating
        bsf     PORTA,MUTE      ;mute the audio...
        clrf    muteTmr         ;cancel timed unmute from dtmf muting
        
        btfss   flags,isdRecF   ;is it in record mode?
        goto    CorOff          ;nope, skip next part
        bcf     PORTB,isdRec    ;recording, carrier dropped, stop recording
        bcf     flags,isdRecF   ;turn off record flag
        clrf    isdTmr          ;clear ISD timer
        btfss   cfgFlag,SIMPLEX ;in simplex mode?
        goto    RecEnd          ;no
                                ; *** SIMPLEX ***
SimPlay
        movlw   ISDBKOF         ;get the ISD back off delay
        movwf   sISDTmr         ;save the ISD back off delay
        bsf     PORTB,ptt       ;turn transmitter on
        movlw   SQUIET          
        movwf   state           ;change state to quiet
        goto    CasEnd
        
RecEnd
        movf    msgNum,w        ;get message number
        andlw   b'00000011'     ;mask out bit 2-7
        addlw   EEM0LEN         ;add address of message 0 length
        movwf   EEADR           ;set EEPROM address
        decf    isdRTmr,w       ;get timer - 1 (less 100 ms)
        movwf   EEDATA          ;put into EEPROM data register...
        call    EEProg          ;save message length

CorOff                          ;cor on->off transition
        btfsc   cfgFlag,SIMPLEX ;in simplex mode?
        goto    SimPlay         ;play (truncated) recorded message 

        clrf    muteTmr         ;reset the mute timer
        clrf    tOutTmr         ;clear time out timer
        movf    hangDly,w       ;get hang timer preset
        btfsc   STATUS,Z        ;is hang timer preset 0?
        goto    NoHang          ;no hang time
        movwf   hangTmr         ;preset hang timer
        movlw   SHANG            
        movwf   state           ;change state to hang
        goto    CorOff2

NoHang
        movlw   SQUIET          ;change state to quiet
        movwf   state           ;save state

CorOff2
        btfss   flags,initID    ;check initial id flag
        goto    CkId2           ;not set...
        movlw   ISD_IID         ;initial ID
        movwf   msgNum          ;set message number
        call    PlayMsg         ;play the message
        goto    ResetID         ;reset timers, flags, & continue        

CkId2
        btfsc   flags,sentID    ;id sent lately?
        goto    CasEnd          ;yes, go on...

        ;
        ;if (idTmr <= idSoon) then goto StartID
        ;implemented as: if ((IDSOON-idTimer)>=0) then goto StartID
        ;
        movf    idTmr,w         ;get idTmr into W
        sublw   IDSOON          ;IDSOON-w ->w
        btfss   STATUS,C        ;C is clear if result is negative
        goto    CasEnd          ;don't need to ID yet...

        movlw   ISD_ID          ;regular ID
        movwf   msgNum          ;set message number
        call    PlayMsg         ;play the message
        goto    ResetID         ;reset timers, flags, & continue        

TimedOut
        bsf     PORTA,MUTE      ;mute the audio...
        clrf    muteTmr         ;reset the mute timer
        movlw   STIMOUT
        movwf   state           ;change state to timed out
        movlw   ISD_TO          ;ISD time out message
        movwf   msgNum          ;set message number
        call    PlayMsg         ;play the message
        goto    CasEnd
        
Hang    
        btfss   tFlags,TFLCOR   ;is squelch open?
        goto    KeyUp           ;yes!

        btfss   tFlags,TENTH    ;check to see if tenth second tick
        goto    CasEnd

        btfsc   flags,cwOn      ;is cw playing?
        goto    Hang2           ;yes, don't ctsy beep

        btfsc   cfgFlag,NOCTSY  ;check for suppressed courtesy tone
        goto    Hang2           ;suppressed...

        ;test to see if time for ctsy tone here
        movf    hangTmr,w       ;get hang timer
        addlw   5               ;add 500 ms
        subwf   hangDly,w       ;subtract hang delay
        btfss   STATUS,Z        ;zero if equal
        goto    Hang1
        movf    isdTmr,f        ;check isd timer
        btfss   STATUS,Z        ;is it zero?
        goto    Hang2           ;no; ISD is playing, don't beep
        btfsc   cfgFlag,ISDCTSY ;check for ISD stored courtesy tone
        goto    ISDCtsy
        bsf     flags,beepOn    ;turn on beep
        goto    Hang2

ISDCtsy                         ;want to play ISD message 3 for courtesy tone
        movlw   ISD_TM          ;ISD tail message plays as courtesy tone
        movwf   msgNum          ;set message number
        call    PlayMsg         ;play the message
        goto    Hang2

Hang1
        btfsc   cfgFlag,ISDCTSY ;check for ISD stored courtesy tone
        goto    Hang2

        movf    hangTmr,w       ;get hang timer
        addlw   7               ;add 700 ms so beep is 200 ms long
        btfsc   flags,init      ;in init mode?
        addlw   3               ;add another 300 ms so beep is 500 ms long
        subwf   hangDly,w       ;subtract hang delay
        btfss   STATUS,Z        ;zero if equal
        goto    Hang2
        bcf     flags,beepOn    ;turn off beep

Hang2
        decfsz  hangTmr,f       ;decrement hang timer
        goto    CasEnd          ;not zero yet
        
        movlw   SQUIET          
        movwf   state           ;change state to quiet

        movf    tMsgCtr,f       ;check tail message counter
        btfsc   STATUS,Z        ;Z will be set if counter is zero, skip
        goto    CasEnd          ;tMsgCtr is zero
        decfsz  tMsgCtr,f       ;decrement the tail message counter
        goto    CasEnd          ;not zero yet
        movlw   EETMSG          ;get address of tail message counter preset
        call    ReadEE          ;read EEPROM
        movwf   tMsgCtr         ;restore w into tail message counter
        movlw   ISD_TM          ;get the tail message
        movwf   msgNum          ;save it as the message to play
        call    PlayMsg         ;play the message
        goto    CasEnd          ;done

TimeOut
        btfss   tFlags,TFLCOR   ;is squelch open?
        goto    CasEnd          ;no, stay timed out...
        
        movlw   SQUIET          
        movwf   state           ;change state to quiet

        movlw   ISD_TO          ;ISD time out message
        movwf   msgNum          ;set message number
        call    PlayMsg         ;play the message

CasEnd
        movf    isdTmr,f        ;check isdTimer
        btfsc   STATUS,Z        ;is it zero?
        goto    ID1             ;yes, don't need to check it's timer...

        btfss   tFlags,TENTH    ;check to see if tenth second tick
        goto    ID1             ;nope

        btfsc   flags,isdRecF   ;is the ISD in record mode?
        incf    isdRTmr,f       ;yes. increment the record timer

        decfsz  isdTmr,f        ;decrement ISD1240 play timer
        goto    ID1             ;not zero yet...
        btfss   flags,isdRecF   ;is it in record mode
        goto    ISDpOff         ;no

        bcf     PORTB,isdRec    ;recording, time is up, truncate recording
        bcf     flags,isdRecF   ;turn off record flag
        btfsc   cfgFlag,SIMPLEX ;in simplex mode?
        goto    ID1             ;yes, don't store message length

                                ;store message length
        movf    msgNum,w        ;get message number
        andlw   b'00000011'     ;mask out bit 2-7
        addlw   EEM0LEN         ;add address of message 0 length
        movwf   EEADR           ;set EEPROM address

        decf    isdRTmr,w       ;get timer - 1
        movwf   EEDATA          ;put into EEPROM data register...
        call    EEProg          ;save message length
        goto    ID1             ;

ISDpOff
        bcf     PORTB,isdPlay   ;zero, turn off ISD1240 playback

ID1
        movf    idTmr,f         
        btfsc   STATUS,Z        ;is idTmr 0
        goto    CkBkOff         ;yes...

        btfss   tFlags,TENSEC   ;check to see if ten second tick
        goto    CkBkOff         ;nope...

        decfsz  idTmr,f         ;decrement ID timer
        goto    CkBkOff         ;not zero yet...
                                ;id timer is zero! time to ID
        btfsc   flags,sentID    ;check recent id flag
        goto    ID2             ;set...

StartID                         ;id timer timeout...
        movlw   ISD_ID          ;regular ID
        btfss   tFlags,TFLCOR   ;is squelch open?
        movlw   CW_ID           ;CW ID
        movwf   msgNum          ;set message number
        call    PlayMsg         ;play the message

ResetID
        movf    idDly,w         ;get ID timer delay into w
        movwf   idTmr           ;store to idTmr down-counter
        bcf     flags,initID    ;clear initial ID flag
        bsf     flags,sentID    ;set recent ID flag
        goto    CkBkOff          

ID2
        bcf     flags,sentID    ;clear recent ID flag

CkBkOff
        movf    sISDTmr,f       ;check ISD backoff timer
        btfsc   STATUS,Z        ;is it zero?
        goto    CkTone          ;yes
        btfss   tFlags,TENTH    ;check to see if tenth second tick
        goto    CkTone          ;nope
        decfsz  sISDTmr,f       ;decrement ISD1240 backoff timer
        goto    CkTone          ;not zero yet...
        movlw   ISD_SM          ;ISD simplex message
        movwf   msgNum          ;set message number
        call    ISDPlay         ;start the message playing

CkTone
        btfss   PORTB,dv        ;check M8870 digit valid
        goto    NoTone          ;not set
        btfsc   flags,lastDV    ;check to see if set on last pass
        goto    ToneDon         ;it was already set
        bsf     flags,lastDV    ;set lastDV flag

        btfsc   cfgFlag,NOMUTE  ;check for no muting flag
        goto    MuteEnd         ;no muting...
        
        movlw   MUTEDLY         ;get mute timer delay
        movwf   muteTmr         ;preset mute timer
        bsf     PORTA,MUTE      ;set muting

MuteEnd
        movf    PORTA,w         ;get DTMF digit
        andlw   TMASK           ;mask off hi nibble
        movwf   tone            ;save digit
        goto    ToneDon 

NoTone
        btfss   flags,lastDV    ;is lastDV set
        goto    ToneDon         ;nope...
        bcf     flags,lastDV    ;clear lastDV flag...

        btfsc   flags,init      ;in init mode?
        goto    WrTone          ;yes, go write the tone

        movf    toneCnt,w       ;test toneCnt
        btfss   STATUS,Z        ;is it zero?
        goto    CkDigit         ;no

        ;password has been successfully entered, start storing tones

        ;make sure that there is room for this digit
        movlw   MAXCMD          ;get max # of command tones
        subwf   cmdCnt,w        ;cmdCnt - MAXCMD -> w
        btfsc   STATUS,Z        ;if Z is set then there is no more room
        goto    Wait            ;no room, just ignore it...

        ;there is room for this digit, calculate buffer address...
        movlw   tBuf1           ;get address of first byte in buffer
        addwf   cmdCnt,w        ;add offset
        movwf   FSR             ;set indirection register
        movf    tone,w          ;get tone
        call    MapDTMF         ;convert to hex value
        movwf   INDF            ;save into buffer location
        incf    cmdCnt,f        ;increment cmdCnt
        goto    Wait

CkDigit
        ;check this digit against the code table
        sublw   TONES           ;w = TONES - w; w now has digit number
        addlw   EETTPRE         ;w = w + EETTPRE; the digit's EEPROM address
        call    ReadEE          ;read EEPROM
        subwf   tone,w          ;w = tone - w
        btfss   STATUS,Z        ;is w zero?
        goto    NotTone         ;no...
        decf    toneCnt,f       ;decrement toneCnt
        goto    ToneDon

NotTone
        movlw   TONES
        subwf   toneCnt,w       
        btfsc   STATUS,Z        ;is this the first digit?
        goto    BadTone         ;yes
        movlw   TONES           ;reset to check to see if this digit
        movwf   toneCnt         ;is the first digit...
        goto    CkDigit

WrTone                          ;save tone in EEPROM to init password
        movf    toneCnt,w       ;test toneCnt
        sublw   TONES           ;w = TONES - w; w now has digit number
        addlw   EETTPRE         ;w = w + EETTPRE; the digit's EEPROM address
        movwf   EEADR           ;EEADR = w
        movf    tone,w          ;get tone
        movwf   EEDATA          ;put into EEPROM data register...
        call    EEProg          ;call EEPROM prog routine

        decfsz  toneCnt,f       ;decrement tone count        
        goto    ToneDon         ;not zero, still in init mode
        bcf     flags,init      ;zero, out of init mode

BadTone       
        movlw   TONES           ;no... get number of command tones into w
        movwf   toneCnt         ;preset number of command tones

ToneDon
        movlw   SACTIVE         ;get active mask
        andwf   state,w         ;check to see if active, zero is not active
        btfss   STATUS,Z        ;skip next if not active
        goto    Wait
        movf    isdTmr,f        ;check isdTmr for 0
        btfss   STATUS,Z        ;skip next if zero
        goto    Wait
        movf    sISDTmr,f       ;check ISD back off timer for 0
        btfss   STATUS,Z        ;skip next if zero
        goto    Wait
        btfsc   flags,cwOn      ;is cw sender going?
        goto    Wait            ;yes, keep going...
        bcf     PORTB,ptt       ;turn transmitter off

Wait
        btfss   tFlags,TENTH    ;check to see if one tenth second tick
        goto    Wait1           ;nope...

        movf    muteTmr,f       ;test mute timer
        btfsc   STATUS,Z        ;Z is set if not DTMF muting
        goto    Wait1           ;
        decfsz  muteTmr,f       ;decrement muteDly
        goto    Wait1           ;have not reached the end of the mute time
        bcf     PORTA,MUTE      ;unmute

Wait1
        btfsc   tFlags,TFLCOR   ;is squelch open?
        goto    CorOn           ;yes
        btfss   flags,lastCor   ;cor is off, is last COR off?
        goto    Loop            ;last COR is also off, do nothing here
        ;COR on->off transition (receiver has just unsquelched)
        bcf     flags,lastCor   ;clear last COR flag
        call    ClrTone         ;clear password tones & commands
        goto    Loop

CorOn
        btfsc   flags,lastCor   ;cor is ON, is last COR on?
        goto    Loop            ;last COR is also on, do nothing here
        ;COR off->on transition (receiver has just squelched)
        bsf     flags,lastCor   ;set last COR flag

        ;evaluate touch tones in buffer
        movf    cmdCnt,f        ;check to see if any stored tones
        btfsc   STATUS,Z        ;is it zero?
        goto    Loop            ;no stored tones

        movlw   MAXCMD          ;get max # of command tones
        subwf   cmdCnt,w        ;cmdCnt - MAXCMD -> w
        btfss   STATUS,Z        ;if Z is set then there are enough digits
        goto    CmdDone         ;not enough command digits...

        ;there are tones stored in the buffer...
        swapf   tBuf1,w         ;swap nibble of tBuf1 and store in w
        iorwf   tBuf2,w         ;or in low nibble (tBuf2)
        movwf   tBuf1           ;store resultant 8 bit value into tBuf1

        swapf   tBuf3,w         ;swap nibble of tBuf3 and store in w
        iorwf   tBuf4,w         ;or in low nibble (tBuf4)
        movwf   tBuf3           ;store resultant 8 bit value into tBuf3

        ;test the address...
        btfsc   tBuf1,7         ;bit 7 is not allowed         
        goto    BadCmd
        btfsc   tBuf1,6         ;bit 6 indicates command: 4xxx,5xxx,6xxx,7xxx
        goto    MsgCmd

        ;program the byte...
        movf    tBuf1,w         ;get address
        movwf   EEADR
        movf    tBuf3,w         ;get data byte
        movwf   EEDATA
        call    EEProg          ;program EE byte

        movlw   CW_OK
        movwf   msgNum
        call    PlayMsg

        ;test to see if any of the runtime variables need modification
TstEnab
        movf    tBuf1,w         ;get address
        btfss   STATUS,Z        
        goto    TstConf         
        movf    tBuf3,f
        btfss   STATUS,Z        ;is data 0?
        goto    TstEna1
        movlw   SDISABL
        movwf   state
        goto    TstDone
TstEna1
        movlw   SQUIET          ;enable repeater
        movwf   state
        bcf     flags,initID    ;
        bcf     flags,sentID    ;
        goto    TstDone

TstConf
        movf    tBuf1,w         ;get address
        sublw   EECONF          ;subtract CONFIG address
        btfss   STATUS,Z        
        goto    TstHang
        movf    tBuf3,w
        movwf   cfgFlag         ;store w into config flag

        clrf    hangTmr         ;clear hang timer
        clrf    tOutTmr         ;clear timeout timer
        clrf    isdTmr          ;clear isdTimer
        clrf    muteTmr         ;clear muting timer
        clrf    sISDTmr         ;clear ISD back off timer
        bcf     PORTB,isdRec    ;stop any recording message

        clrf    state           ;reset to quiet state
        goto    TstDone

TstHang
        movf    tBuf1,w         ;get address
        sublw   EEHANG          ;subtract HANG address
        btfss   STATUS,Z        
        goto    TstTOut
        movf    tBuf3,w
        movwf   hangDly         ;store w into hang time delay preset
        goto    TstDone
        
TstTOut
        movf    tBuf1,w         ;get address
        sublw   EETOUT          ;subtract TIMEOUT address
        btfss   STATUS,Z        
        goto    TstID
        movf    tBuf3,w
        movwf   tOutDly         ;store w into time out delay preset
        goto    TstDone

TstID
        movf    tBuf1,w         ;get address
        sublw   EEID            ;subtract ID address
        btfss   STATUS,Z        
        goto    TstTM
        movf    tBuf3,w
        movwf   idDly           ;store w into ID delay preset
        goto    TstDone

TstTM
        movf    tBuf1,w         ;get address
        sublw   EETMSG          ;subtract tail message counter address
        btfss   STATUS,Z        
        goto    TstDone
        movf    tBuf3,w
        movwf   tMsgCtr         ;store w into tail message counter
        goto    TstDone

TstDone
        call    ClrTone
        goto    Loop

MsgCmd                          ;4x, 5x, 6x, 7x commands
        movf    tBuf1,w         ;get command byte
        andlw   b'10111110'     ;check for invalid values
        btfss   STATUS,Z        ;
        goto    BadCmd          ;only 40, 41 are valid now

        ;right after movf
        ;jeff
        movlw   h'02'           ;this value must equal address' high byte
        movwf   PCLATH          ;ensure that computed goto will stay in range
        swapf   tBuf1,w         ;swap command byte into w
        andlw   b'00000011'     ;mask bits that make up remainder of command
        addwf   PCL,f           ;add w to PCL
        goto    Cmd4x           ;note that the 4 bit has been stripped so 4 = 0
        goto    Cmd5x
        goto    Cmd6x
        goto    Cmd7x

Cmd4x
        btfss   tBuf1,0         
        goto    MsgPlay         ;40nn command

        movf    tBuf3,w         ;get argument
        movwf   msgNum          ;save into message number
        call    ISDRec          ;get ready to record...
        goto    Loop

Cmd5x
        movf    tBuf2,f         ;check 2nd digit
        btfss   STATUS,Z        ;is it zero?
        goto    BadCmd          ;nope

        btfsc   tBuf3,0         ;lo bit clear?
        goto    Cmd50Odd        ;nope, 51, 53, etc.
        
        btfsc   tBuf4,0         ;lo bit clear?
        goto    Cmd50ES         ;nope, set (turn on)
        bcf     PORTB,CTL0      ;clear output (off/lo)
        goto    GoodCmd

Cmd50ES 
        bsf     PORTB,CTL0      ;set output (on/hi)
        goto    GoodCmd
        
Cmd50Odd
        
        btfsc   tBuf4,0         ;lo bit clear?
        goto    Cmd50OS         ;nope, set (turn on)
        bcf     PORTB,CTL1      ;clear output (off/lo)
        goto    GoodCmd

Cmd50OS 
        bsf     PORTB,CTL1      ;set output (on/hi)
        goto    GoodCmd

Cmd6x
Cmd7x
        goto    BadCmd
        
MsgPlay                         ;command 40
        movf    tBuf3,w         ;get argument
        movwf   msgNum          ;save into message number
        call    PlayMsg
        goto    Loop
BadCmd
        movlw   CW_NG
        goto    CmdRes
GoodCmd
        movlw   CW_OK
CmdRes
        movwf   msgNum
        call    PlayMsg
CmdDone
        call    ClrTone
        goto    Loop

;
;Read EEPROM variables
;
GetData
        movlw   EEENAB
        call    ReadEE          ;read EEPROM
        btfss   STATUS,Z        ;Z is set if disabled
        goto    GDEnab
        movlw   SDISABL         ;set state disabled
        movwf   state           ;save state
        goto    GDHang

GDEnab
        movlw   SQUIET          ;set state enabled
        movwf   state           ;save state
        bcf     flags,initID    ;
        bcf     flags,sentID    ;
GDHang
        movlw   EECONF          ;get address of configuration byte
        call    ReadEE          ;read EEPROM
        movwf   cfgFlag         ;store w into config flag copy

        movlw   EEHANG          ;get address of hang timer preset value
        call    ReadEE          ;read EEPROM
        movwf   hangDly         ;store w into hang time delay preset

        movlw   EETOUT          ;get address of timeout timer preset value
        call    ReadEE          ;read EEPROM
        movwf   tOutDly         ;store w into timeout delay preset

        movlw   EEID            ;get address of ID timer preset value
        call    ReadEE          ;read EEPROM
        movwf   idDly           ;store w into id timer delay preset

        movlw   EETMSG          ;get address of tail message counter preset
        call    ReadEE          ;read EEPROM
        movwf   tMsgCtr         ;store w into tail message counter
        return

PlayMsg
        btfss   msgNum,4        ;is bit 4 clear?
        goto    StartCW         ;yes, it's a CW message
        btfsc   cfgFlag,SIMPLEX ;in simplex mode?
        goto    MsgCWID         ;no recorded messages, only CWID
        btfss   cfgFlag,NOISD   ;is the ISD absent?
        goto    ISDPlay         ;no, play audio message
        bcf     msgNum,4        ;convert ISD message to CW message
        btfss   msgNum,1        ;is it not an ID
        goto    MsgCWID         ;it is an id message
        btfsc   msgNum,0        ;skip if timout message
        return                  ;don't even try to play tail message
        bsf     msgNum,0        ;set the bits to make Timeout Message
        bcf     msgNum,1        ;set the bits to make Timeout Message
        goto    StartCW         ;play the CW timeout message

MsgCWID 
        bcf     msgNum,0        ;make it message # 0
;
; Start sending a CW message
;
StartCW
        movlw   b'00000011'     ;mask out illegal values
        andwf   msgNum,f        ;mask it...
        call    GetCwMsg        ;lookup message
                                ;message offset is now in W
        movwf   cwBuff          ;save offset
        call    ReadEE          ;read byte from EEPROM
        movwf   cwByte          ;save byte in CW bitmap
        movlw   CWIWSP          ;get startup delay
        movwf   cwTmr           ;preset cw timer
        bcf     flags,beepOn    ;make sure that beep is off
        bsf     flags,cwOn      ;turn on CW sender
        bsf     PORTB,ptt       ;turn on PTT...
        return

;
;Play message from ISD1240; message address in msgNum
;
ISDPlay
        bcf     PORTB,isdA0     ;reset message address bits
        bcf     PORTB,isdA1     
        btfsc   msgNum,0        ;check bit 0
        bsf     PORTB,isdA0
        btfsc   msgNum,1        ;check bit 1
        bsf     PORTB,isdA1

        btfss   msgNum,ISDSIM   ;check bit 2
        goto    PNorm           ;not set
        movf    isdRTmr,f       ;check to see if this is 0
        btfsc   STATUS,Z        ;is it zero?
        return                  ;yes, bail out.

        incf    isdRTmr,w       ;check to see if it is 255
        btfsc   STATUS,Z        ;is it now zero?
        return                  ;yes, bail out.

        decf    isdRTmr,w       ;get message duration - 100 ms
        movwf   isdTmr          ;save into timer
        goto    PNow            ;play the message 

PNorm
        movf    msgNum,w        ;get message number
        andlw   b'00000011'     ;mask out bits 2-7
        addlw   EEM0LEN         ;add the base of the message lengths
        movwf   EEADR           ;save address
        call    ReadEE          ;read EEPROM, w will have message length after
        movwf   isdTmr          ;preset message timer
        btfsc   STATUS,Z        ;is the length 0
        return                  ;yes, don't play.
        bsf     PORTB,ptt       ;turn transmitter on
        
PNow
        bsf     PORTB,isdPlay   ;start ISD1240 playback
        return

;
;Record Message into ISD1240; message address in msgNum
;
ISDRec
        bcf     PORTB,isdA0     ;reset message address bits
        bcf     PORTB,isdA1     
        btfsc   msgNum,0        ;check bit 0
        bsf     PORTB,isdA0
        btfsc   msgNum,1        ;check bit 1
        bsf     PORTB,isdA1
        bsf     msgNum,MSGREC   ;set message record bit        
        return

;
; Read EEPROM byte
; address is supplied in W on call, data is returned in w
;
ReadEE
        movwf   EEADR           ;EEADR = w
        bsf     STATUS,RP0      ;select bank 1
        bsf     EECON1,RD       ;read EEPROM
        bcf     STATUS,RP0      ;select bank 0
        movf    EEDATA,w        ;get EEDATA into w
        return

;
; clear tone buffer and reset good digit counters
;

ClrTone
        movlw   TONES           ;no... get number of command tones into w
        movwf   toneCnt         ;preset number of command tones
        clrf    cmdCnt          ;clear number of command bytes...
        clrf    tBuf1           ;clear command buffer bytes
        clrf    tBuf2
        clrf    tBuf3
        return

;
; Program EEPROM byte
;
EEProg
        bsf     STATUS,RP0      ;select bank 1
        bcf     INTCON,GIE      ;disable interrupts
        bsf     EECON1,WREN     ;enable EEPROM write
        movlw   h'55'
        movwf   EECON2          ;write 55
        movlw   h'AA'
        movwf   EECON2          ;write AA
        bsf     EECON1,WR       ;start write
        bcf     EECON1,WREN     ;disable write
EEPLoop
        nop
        btfsc   EECON1,WR       ;is write cycle complete?
        goto    EEPLoop         ;wait for write to finish

        bsf     INTCON,GIE      ;enable interrupts
        ;bcf     STATUS,RP0      ;select bank 0
        return

        dw      'C'
        dw      'O'
        dw      'P'
        dw      'Y'
        dw      'R'
        dw      'I'
        dw      'G'
        dw      'H'
        dw      'T'
        dw      ' '
        dw      '('
        dw      'C'
        dw      ')'
        dw      ' '
        dw      '1'
        dw      '9'
        dw      '9'
        dw      '6'
        dw      ','
        dw      ' '
        dw      'J'
        dw      'E'
        dw      'F'
        dw      'F'
        dw      'R'
        dw      'E'
        dw      'Y'
        dw      ' '
        dw      'B'
        dw      '.'
        dw      ' '
        dw      'O'
        dw      'T'
        dw      'T'
        dw      'E'
        dw      'R'
        dw      'S'
        dw      'O'
        dw      'N'
        dw      '.'
        dw      ' '
        dw      ' '

        dw      'A'
        dw      'L'
        dw      'L'
        dw      ' '
        dw      'C'
        dw      'O'
        dw      'M'
        dw      'M'
        dw      'E'
        dw      'R'
        dw      'C'
        dw      'I'
        dw      'A'
        dw      'L'
        dw      ' '
        dw      'R'
        dw      'I'
        dw      'G'
        dw      'H'
        dw      'T'
        dw      'S'
        dw      ' '
        dw      'R'
        dw      'E'
        dw      'S'
        dw      'E'
        dw      'R'
        dw      'V'
        dw      'E'
        dw      'D'
        dw      ' '
        dw      'B'
        dw      'Y'
        dw      ' '
        dw      'T'
        dw      'H'
        dw      'E'
        dw      ' '
        dw      'A'
        dw      'U'
        dw      'T'
        dw      'H'
        dw      'O'
        dw      'R'
        dw      '.'

        org     0380h
;
; EEPROM Memory Map (@ 2100h)
;   00 enable/disable flag
;   01 configuration flag
;   02 hang timer preset
;   03 timeout timer preset
;   04 id timer preset
;   05 tail message count
;   06-08 CW OK ( 3 bytes)
;   09-0b CW NG ( 3 bytes)
;   0c-0e CW TO ( 3 bytes)
;   0f-1a CW id (12 bytes)
;   1b-37 empty (29 bytes)
;   38 isd message 0 length
;   39 isd message 1 length
;   3a isd message 2 length
;   3b isd message 3 length
;   3c-3f Password (4 bytes)
;

;
; Lookup values to load EEPROM addresses with at initialize time 
; if EEADR > EEIEND, return 0.
;
InitDat

        movf    EEADR,w         ;get current address
        sublw   EEIEND          ;EEIEND - EEADR -> w
        btfss   STATUS,C        ;C is clear if result is negative
        retlw   0               ;zero this location       

        movlw   h'03'           ;this subroutine is in the top 256 bytes
        movwf   PCLATH          ;ensure that computed goto will stay in range
        movf    EEADR,w         ;get EEPROM address into w
        addwf   PCL,f           ;add w to PCL
        retlw   h'01'           ;00 -- enable flag
        retlw   h'00'           ;01 -- configuration flag
        retlw   h'32'           ;02 -- hang timer preset, in tenths
        retlw   h'1e'           ;03 -- timeout timer preset, in 1 seconds
        retlw   h'36'           ;04 -- id timer preset, in 10 seconds
        retlw   h'00'           ;05 -- tail message count
        retlw   h'0f'           ;06 -- 'O'      1
        retlw   h'0d'           ;07 -- 'K'      2
        retlw   h'ff'           ;08 -- EOM      3
        retlw   h'05'           ;09 -- 'N'      1
        retlw   h'0b'           ;0a -- 'G'      2
        retlw   h'ff'           ;0b -- EOM      3
        retlw   h'03'           ;0c -- 'T'      1
        retlw   h'0f'           ;0d -- 'O'      2
        retlw   h'ff'           ;0e -- EOM      3
        retlw   h'09'           ;0f -- 'D'      1
        retlw   h'02'           ;10 -- 'E'      2
        retlw   h'00'           ;11 -- space    3
        retlw   h'05'           ;12 -- 'N'      4
        retlw   h'10'           ;13 -- 'H'      5
        retlw   h'0a'           ;14 -- 'R'      6
        retlw   h'15'           ;15 -- 'C'      7
        retlw   h'29'           ;16 -- '/'      8
        retlw   h'3c'           ;17 -- '2'      9
        retlw   h'ff'           ;18 -- EOM     10
        retlw   h'ff'           ;19 -- EOM     11
        retlw   h'ff'           ;1a -- EOM     12  can fit 6 letter id....
        
        page
        org     03E4h           ;set this subroutine in last bit of memory

;
; Lookup EEPROM address of CW message based on index of message
;
GetCwMsg
        movlw   h'03'           ;this subroutine is in the top 256 bytes
        movwf   PCLATH          ;ensure that computed goto will stay in range
        movf    msgNum,w        ;get msgNum into w
        addwf   PCL,f           ;add w to PCL
        retlw   EECWID          ;0 = ID message
        retlw   EECWTO          ;1 = 1 timeout message
        retlw   EECWOK          ;2 = 2 ok message
        retlw   EECWNG          ;3 = 3 ng message

; DTMF to HEX mapping
;
;   ___ ___ ___ ___
;  |   |   |   |   |
;  | 1 | 2 | 3 | A |
;  |___|___|___|___|
;  |   |   |   |   |
;  | 4 | 5 | 6 | B |
;  |___|___|___|___|
;  |   |   |   |   |
;  | 7 | 8 | 9 | C |
;  |___|___|___|___|
;  |   |   |   |   |
;  |*/E| 0 |#/F| D |
;  |___|___|___|___|
;

MapDTMF
        movlw   h'03'           ;this subroutine is in the top 256 bytes
        movwf   PCLATH          ;ensure that computed goto will stay in range
        movf    tone,w          ;get tone into w
        addwf   PCL,f           ;add w to PCL
        retlw   0d              ;0 = D key 
        retlw   01              ;1 = 1 key
        retlw   02              ;2 = 2 key
        retlw   03              ;3 = 3 key
        retlw   04              ;4 = 4 key
        retlw   05              ;5 = 5 key
        retlw   06              ;6 = 6 key
        retlw   07              ;7 = 7 key
        retlw   08              ;8 = 8 key
        retlw   09              ;9 = 9 key
        retlw   00              ;A = 0 key
        retlw   0e              ;B = * key (e)
        retlw   0f              ;C = # key (f)
        retlw   0a              ;D = A key
        retlw   0b              ;E = B key
        retlw   0c              ;F = C key

        end


; MORSE CODE encoding...
;
; 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.  characters with more than 7 elements (error) cannot be sent.
;
; sk ...-.- 01101000  58
; ar .-.-.  00101010  2a
; bt -...-  00110001  31
; / -..-.   00101001  29
; 0 -----   00111111  3f
; 1 .----   00111110  3e
; 2 ..---   00111100  3c
; 3 ...--   00111000  38
; 4 ....-   00110000  30
; 5 .....   00100000  20
; 6 -....   00100001  21
; 7 --...   00100011  23
; 8 ---..   00100111  27
; 9 ----.   00101111  2f
; a .-      00000110  06
; b -...    00010001  11
; c -.-.    00010101  15
; d -..     00001001  09
; e .       00000010  02
; f ..-.    00010100  14
; g --.     00001011  0b
; h ....    00010000  10
; i ..      00000100  04
; j .---    00011110  1e
; k -.-     00001101  0d
; l .-..    00010010  12
; m --      00000111  07
; n -.      00000101  05
; o ---     00001111  0f
; p .--.    00010110  16
; q --.-    00011011  1b
; r .-.     00001010  0a
; s ...     00001000  08
; t -       00000011  03
; u ..-     00001100  0c
; v ...-    00011000  18
; w .--     00001110  0e
; x -..-    00011001  19
; y -.--    00011101  1d
; z --..    00010011  13
; space     00000000  00 space (special exception)
; EOM       11111111  ff end of message (special exception)
 

Pommie

Well-Known Member
Most Helpful Member
Thanks Terry,
Not moving them would probably have not caused a problem but every now and again it would cause a crash that would be very hard to find.

Mike.
Hope you enjoyed dinner.
 

sagor1

Active Member
16F628A datasheet recommends testing GIE when writing to EEPROM:

Code:
BSF STATUS, RP0 ;Bank 1
BSF EECON1, WREN ;Enable write
BCF INTCON, GIE ;Disable INTs.
BTFSC INTCON,GIE ;See AN576
GOTO $-2
MOVLW 55h ;
MOVWF EECON2 ;Write 55h
MOVLW AAh ;
MOVWF EECON2 ;Write AAh
BSF EECON1,WR ;Set WR bit
;begin write, etc. here

Considering this is a controller, any interrupt (timer) already triggered while GIE is cleared, will continue to run. Just a thought, no harm adding the extra 2 lines of code.
 

Jaison

New Member
Friends still unsuccessful. same with the two codes of Terry and Ian. I made an attempt with this code below to flash the PTT output led and the led flashed ok.

;*************************************************** ***********
; Processor: PIC16F628 at 4 MHz using internal RC oscillator
; Function: Flash the LED connected to RA2
; Hardware: Testboard K4
; Filename: 628LED.asm
; Author: Lars Petersen, oz1bxm@pobox.com
; Website: www.oz1bxm.dk/PIC/628LED.htm
; Credit: Tony Nixon's LED flasher
;*************************************************** ***********

LIST P=16F628, R=DEC ; Use the PIC16F628 and decimal system

#include "P16F628.INC" ; Include header file

__config _INTRC_OSC_NOCLKOUT & _LVP_OFF & _WDT_OFF & _PWRTE_ON & _BODEN_ON

CBLOCK 0x20 ; Declare variable addresses starting at 0x20
Loop1,Loop2
ENDC
;
; -----------
; INITIALIZE
; -----------
;
ORG 0x000 ; Program starts at 0x000

CLRF PORTA ; Initialize port A
CLRF PORTB ; initialize port B

BSF STATUS,RP0 ; RAM bank 1

CLRF TRISA ; All pins port A output
CLRF TRISB ; All pins port B output

BCF STATUS,RP0 ; RAM bank 0
;
; ------------------------
; FUNCTION OF PORT A PINS
; ------------------------
;
MOVLW 7
MOVWF CMCON ; Comparators off, all pins digital I/O
;
; ----------
; MAIN LOOP
; ----------
;
Main BSF PORTB,1 ; Turn on LED connected to RB1
CALL delay
BCF PORTB,1 ; Turn off LED connected to RB1
CALL delay
GOTO Main
;
; ---------------
; DELAY 250 MSEC
; ---------------
;
delay MOVLW 250
MOVWF Loop1
Outer MOVLW 200
MOVWF Loop2
Inner NOP
NOP
DEFSZ Loop2,F
GOTO Inner ; Inner loop = 5 usec.
DEFSZ Loop1,F
GOTO Outer
RETURN

END
 

Pommie

Well-Known Member
Most Helpful Member
16F628A datasheet recommends testing GIE when writing to EEPROM:

Code:
BSF STATUS, RP0 ;Bank 1
BSF EECON1, WREN ;Enable write
BCF INTCON, GIE ;Disable INTs.
BTFSC INTCON,GIE ;See AN576
GOTO $-2
MOVLW 55h ;
MOVWF EECON2 ;Write 55h
MOVLW AAh ;
MOVWF EECON2 ;Write AAh
BSF EECON1,WR ;Set WR bit
;begin write, etc. here

Considering this is a controller, any interrupt (timer) already triggered while GIE is cleared, will continue to run. Just a thought, no harm adding the extra 2 lines of code.
Completely superfluous.

Mike.
Edit, the datasheet does indeed recommend this but if you check AN576 it only applies to 16Cxxx, so not applicable.
 
Last edited:

augustinetez

Active Member
I figured it might be a good idea to track down any other info on the repeater controller to see if we were missing anything.

Lets just say maybe we might be - the code we are updating is loaded with default values which might be different to what is loaded in Jaisons 16C84 - I don't recall ever using a 16C84, so correct me if I'm wrong - you can't read back the contents of the 16C series like you can with the F series? If you could retrieve the EEprom contents, they could be compared to the defaults and even updated in the file.

Default values:
EEprom.jpg


The user guide attached is for the version D unit, but the details appear to be the same as the original article apart from using a 16F84.
 

Attachments

  • nhrc-2_manual-revd.pdf
    320.6 KB · Views: 85

Latest threads

New Articles From Microcontroller Tips

Top