• 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.

assembly code with 16 memory locations, only need 2 locations

Cyber

New Member
Thread starter #1
Hi
I am new to PIC Assembly coding, But have been using Arduino for a few years now.
Any help with the following would be very much appreciated, and help me to understand the code.

I have download a freely available .asm file for a signal generator and have the project working on a breadboard layout.

I am now wanting to adapt the code to my requirements.
I have got stuck on the following:

The code has 16 memory location for the frequency. Memory locations set from "MemButton" press steps through the 16 stored frequencies.
I only need 2 frequency memory locations, and the MemButton to toggle between the 2 memory locations.

This is the part of the code regarding the MemButton:-

Code:
        LIST P=16F627A
        INCLUDE "p16F627A.inc"
        errorlevel  2

        __config    0x3F50     ;   ..1101010000  LV Programming off , INTOSC I/O on A6/7, MCLRE tied to Vcc

    #define         DDSreset          PORTA, 0
    #define         FData          PORTA, 1       ;DDS Data on port A
    #define         FQud            PORTA, 2
    #define         WClk            PORTA, 3

        #define         NLED            PORTA, 4
    #define        LCDE        PORTA, 6
    #define        LCDRS        PORTA, 7

    #define        LCDPORT        PORTB        ;B4-7

        #define         RotI            PORTB, 0    ;Drives interrupt
        #define         RotQ            PORTB, 1
        #define         Button          PORTB, 2
    #define        MemButton        PORTB, 3

        #define         Updated        Flags, 0   ;Set after synth update 

    PLL     =     0


    LINE1         =    0x80        ;Address of start of each each line of text on
    LINE2         =    0x80 + d'64'    ;  the LCD module, + command for setting it
    LINE3         =    0x80 + d'16'
    LINE4         =    0x80 + d'80'

        LCDHINIBBLE =       1   ;0 for LCD on Port bits 0-3, 1 for bits 4-7

    STEP1    =    1        ;0.01
    STEP2    =    d'10'        ;0.1Hz
    STEP3    =    d'100'        ;1Hz   
    STEP4    =    d'1000'
    STEP5    =    d'10000'
    STEP6    =    d'100000'    ;1kHz    ;>6 bits allowed here
    STEP7    =    d'1000000'    ;10kHz    ; " "  " 
    STEP8    =    d'10000000'    ;100kHz    ; " "  "    

    CHARMARK =     "^"   

  org 0x2100

FREQCONST      de 0x00,0x00,0x57,0xF5,0xFF,0x86        ;Tuning step / Fclock * 2^ 64,   0.01Hz, 125MHz
;FREQCONST      de 0x00,0x04,0x4B,0x82,0xFA,0x10        ;Tuning step / Fclock * 2^ 64,   0.01Hz, 10MHz

StFreq        de    0x00, 0xD1, 0xCE, 0xF0    ;137.5kHz    Turn on value
        de    0x02, 0xFD, 0x13, 0x60    ;501.4kHz
;        de    0x0A, 0xFF, 0x3F, 0x20    ;1.845MHz
;        de    0x16, 0x81, 0xB8, 0x00    ;3.776
;        de    0x1F, 0x83, 0x52, 0x60    ;5.287
;        de    0x2A, 0x9E, 0x08, 0xC0    ;7.15
;        de    0x3C, 0x0E, 0xC1, 0x80    ;10.076
;        de    0x55, 0x2B, 0x48, 0xA0    ;14.289
;        de    0x6B, 0xE8, 0x83, 0x00    ;18.104
;        de    0x7F, 0x07, 0x88, 0x00    ;21.312
;        de    0x94, 0x70, 0x7D, 0x00    ;24.904
;        de    0xAC, 0x86, 0x90, 0xA0    ;28.945
;        de    0x00, 0x01, 0x86, 0xA0    ;1000Hz
;        de    0x00, 0x02, 0x49, 0xF0    ;1500Hz
;        de    0x00, 0x00, 0x9C, 0x40    ;400Hz
;        de    0x00, 0x00, 0x00, 0x64    ;1Hz

    org     0   
    nop
    clrw
    movwf   INTCON      ;disable interrupts
    goto    StartUp     ;jump to main code
;.....................................................
  org 4     ;Interrupt routine, every time RotI goes low to high
    movwf   Wreg            ;Save W
    swapf   STATUS , W      ; nb.  movwf does not affect any STATUS bits
    movwf   StsReg          ;Stave STATUS, without affecting it

    btfss   INTCON, INTF
    goto    OtherInt

    clrf    TMR0            ;Reset every pulse.
    bcf     INTCON, T0IF    ; gives 4.1ms delay before T0IF is set

    bcf     Updated         ;Force an update on next timeout 

    bcf     INTCON , INTE   ;Disable interrupt until routine is completed
    bcf     INTCON , INTF   ;Clear interrupt flag
    btfss   RotQ            ;Reverse these if tuning direction is wrong
    call    FreqUp
    btfsc   RotQ
    call    FreqDn

    bsf     INTCON , INTE   ;Re enable the interrupt
    goto    CarryOnInt
;................
OtherInt
CarryOnInt

    swapf   StsReg , W      ;Restore STATUS
    movwf   STATUS
    swapf   Wreg            ;Restore W
    swapf   Wreg , W        ; nb.  movf affects Z bit
    retfie

;=============================================================
StartUp
    clrf    PORTA           ;Special setup to disable comparator on 'F628
    movlw   7
    movwf   CMCON


    bsf     STATUS,RP0  ;ram page 1
    movlw   b'00000000' ;
    movwf   PORTA       ;
    movlw   b'00001111' ;B0/1/2/3  - I/Q/Buttons
    movwf   PORTB       ;

    movlw   b'01000010'     ;Internal input, Prescalar /4,  pull-ups
    movwf   OPTION_REG

    bcf     STATUS,RP0  ;ram page 0

        ;

    clrf    PORTA
    bsf    DDSreset
    clrf    D4
    movlw    PLL
    addwf    D4

    call    SetUpLCD
    bcf    DDSreset

    call    IntroMsg
    call    ShowConst
    movlw    d'40'
    call    LongerDel    ;2s
ShowInitLoop
    call    Delay50   
    btfss    Button        ;If button held down at start, freezes intro window
    goto    ShowInitLoop

    call    ClrDisp
    clrf    Flags
    movlw    2
    movwf   ButtonPress
    clrf    CurrentMem

    movlw    LINE2 + d'10
    call    LCDCmd
    movlw    CHARMARK   
    call    LCDChar

    call    DispMem
    call    LoadFreq
    call    DispFreq
    call    SendSynth
      call    Delay50
        call    SendSynth         ;Send twice just in case

    bsf    INTCON, INTF
    bsf     INTCON, GIE

    goto    JumpIn        ;Enter main loop so display is set correctly
;.......................
MainLoop
    btfss    MemButton
    goto    DoMemory

    btfsc   Button
    goto    NoButton

    call    Delay50
    btfsc   Button
        goto    NoButton

        clrf    ButtCount          ;Button pressed for 1s stores freq
SavLoop
    call    Delay50
    incf    ButtCount
    movlw   d'20'
    subwf   ButtCount, W
    btfsc   STATUS, C
    goto    SaveFreqs
    btfss   Button
    goto    SavLoop

    decf    ButtonPress
    movlw    7
    btfsc    ButtonPress, 7    ;Test for underflow
    movwf    ButtonPress    ;Cycles round 7 - 0

JumpIn       
    movlw    LINE2 + 2    ;Show the digit being changed
    call    LCDCmd
    movlw    " "        ;Clear existing marker
    call    LCDChar
    movlw    " "
    call    LCDChar
    movlw    " "
    call    LCDChar
    movlw    " "
    call    LCDChar
    movlw    " "
    call    LCDChar
    movlw    " "
    call    LCDChar
    movlw    " "
    call    LCDChar
    movlw    " "
    call    LCDChar
    movlw    " "
    call    LCDChar
    movlw    " "
    call    LCDChar

    movf    ButtonPress, W        ;0-6 depending on digit being changed. 0 = LSD
    sublw    d'10'            ;move Back from position of LS digit   
    movwf    Temp

    movlw    5            ;Need to bypass the decimal point for ButtonPress = 5/ 6
    subwf    ButtonPress, W        ;W = BP - 5, if +ve/0, C=1, move back one
    btfsc    STATUS, C   
    decf    Temp

    movf    Temp, W
    addlw    LINE2
    call    LCDCmd            ;Position under the digit to be changed
    movlw    CHARMARK
    call    LCDChar   
               
    movlw   0       
    subwf    ButtonPress, W
    btfss    STATUS, Z
    goto    NotButt0

    movlw    LOW(STEP1)
    movwf    StepLo
    movlw    HIGH(STEP1)
    movwf    StepMe
    clrf    StepHi
    goto    DoneButt
;...........
NotButt0
    movlw   1       
    subwf    ButtonPress, W
    btfss    STATUS, Z
    goto    NotButt1

    movlw    LOW(STEP2)
    movwf    StepLo
    movlw    HIGH(STEP2)
    movwf    StepMe
    clrf    StepHi
    goto    DoneButt
;...........
NotButt1
    movlw   2
    subwf    ButtonPress, W
    btfss    STATUS, Z
    goto    NotButt2

    movlw    LOW(STEP3)
    movwf    StepLo
    movlw    HIGH(STEP3)
    movwf    StepMe
    clrf    StepHi
    goto    DoneButt
;...........
NotButt2
    movlw   3
    subwf    ButtonPress, W
    btfss    STATUS, Z
    goto    NotButt3

    movlw    LOW(STEP4)
    movwf    StepLo
    movlw    HIGH(STEP4)
    movwf    StepMe
    clrf    StepHi
    goto    DoneButt
;...........
NotButt3
    movlw   4
    subwf    ButtonPress, W
    btfss    STATUS, Z
    goto    NotButt4

    movlw    LOW(STEP5)
    movwf    StepLo
    movlw    HIGH(STEP5)
    movwf    StepMe
    clrf    StepHi
    goto    DoneButt
;...........
NotButt4
    movlw   5
    subwf    ButtonPress, W
    btfss    STATUS, Z
    goto    NotButt5

    movlw    LOW(STEP6)
    movwf    StepLo
    movlw    (STEP6 >> d'8') & 0xFF 
    movwf    StepMe
    movlw    (STEP6 >> d'16') & 0xFF 
    movwf    StepHi
    goto    DoneButt
;.......
NotButt5
    movlw   6
    subwf    ButtonPress, W
    btfss    STATUS, Z
    goto    NotButt6

    movlw    LOW(STEP7)
    movwf    StepLo
    movlw    (STEP7 >> d'8') & 0xFF 
    movwf    StepMe
    movlw    (STEP7 >> d'16') & 0xFF 
    movwf    StepHi
    goto    DoneButt
;........
NotButt6
    movlw    LOW(STEP8)
    movwf    StepLo
    movlw    (STEP8 >> d'8') & 0xFF 
    movwf    StepMe
    movlw    (STEP8 >> d'16') & 0xFF 
    movwf    StepHi

DoneButt
        call    DispFreq
NoButton
        btfsc   INTCON, T0IF    ;Look for 4ms timeout, ie. no rotary 
        goto    DoUpdate        ; encoder  activity for this period

        call    Delay50

        goto    MainLoop
;...............
DoUpdate
        btfss   Updated         ;See if it has already been done
        goto    DoOne
        goto    MainLoop
;...............
DoOne
        bcf     INTCON, INTE    ;Inhibit interrupt while doing update
        bsf     Updated         ;To prevent repeatedly sending the same data

    call    CalcDDS        ;generate D0..3 from Frequency register
    call    DispFreq
    call    DispCode
    call    SendSynth

    bsf     INTCON, INTE
    goto    MainLoop
;..........
SaveFreqs
    movlw    LOW(StFreq)
    addwf    CurrentMem, W
    movwf    Whi
    movf    F3, W
    call    StoreEE
    incf    Whi
    movf    F2, W
    call    StoreEE
    incf    Whi   
    movf    F1, W
    call    StoreEE
    incf    Whi
    movf    F0, W
    call    StoreEE

    movlw    LINE1
    call    LCDCmd

    movlw   " "
    call    LCDChar
    movlw   " "
    call    LCDChar
    movlw   "-"
    call    LCDChar
    movlw   "-"
    call    LCDChar   
    movlw   " "
    call    LCDChar
    movlw   "S"
    call    LCDChar
    movlw   "A"
    call    LCDChar
    movlw   "V"
    call    LCDChar
    movlw   "E"
    call    LCDChar
    movlw   "D"
    call    LCDChar
    movlw   " "
    call    LCDChar
    movlw   "-"
    call    LCDChar
    movlw   "-"
    call    LCDChar
    movlw   " "
    call    LCDChar
    movlw   " "
    call    LCDChar

ButtWait
    btfss   Button
    goto    ButtWait
    call    DispFreq

    goto    MainLoop
;-----------------------------
DoMemory
    call    Delay50
    btfsc    MemButton
    goto    NoButton
MbuttUp
    call    Delay50
    btfss    MemButton
    goto    MbuttUp

    movlw    4        ;Count in multiples of 4,  00 - 0x2C
    addwf    CurrentMem, W
    andlw    b'00111100'
    movwf    CurrentMem
   
    call    DispMem
    call    LoadFreq
    call    CalcDDS
    call    DispFreq
    call    DispCode   
    call    SendSynth

    goto    NoButton
;==========================   SUBROUTINES   ==============================
FreqUp
    movf    StepLo, W
    addwf   F0
    btfss   STATUS, C
    goto    FrqUp1Done       ;if FreqMe already = 0 and no overflow then
    incf    F1           ;  an error occurs here without the jump out
    btfsc   STATUS, Z       ; Test for overflow after above increment
    incf    F2           ;
    btfsc   STATUS, Z   
    incf    F3           ;

FrqUp1Done
    movf    StepMe, W
    addwf   F1
    btfss   STATUS, C
    goto    FrqUp2Done
    incf    F2
    btfsc   STATUS, Z
    incf    F3

FrqUp2Done
    movf    StepHi, W
    addwf   F2
    btfsc   STATUS, C
    incf    F3

    return
;-------------------------------
FreqDn
    movf    StepLo, W
    subwf   F0
    btfsc   STATUS, C       ;If borrowed, C=0
    goto    FrqDwn1Done

    decf    F1           ;decf doesn't set carry flag, so we need to test
    comf    F1, W        ; for FreqHi going from 0 > 0xFF by complementing
    btfss   STATUS, Z       ; then test for zero
    goto    FrqDwn1Done

    decf    F2
    comf    F2, W   
    btfsc   STATUS, Z   
    decf    F3

    comf    F3, W   
    btfsc   STATUS, Z
    goto    GoneNeg

FrqDwn1Done
    movf    StepMe, W
    subwf   F1
    btfsc   STATUS, C       
    goto    FrqDwn2Done

    decf    F2         
    comf    F2, W
    btfsc   STATUS, Z     
    decf    F3

    comf    F3, W   
    btfsc   STATUS, Z
    goto    GoneNeg

FrqDwn2Done
    movf    StepHi, W
    subwf   F2
    btfss   STATUS, C       
    decf    F3         

    comf    F3, W   
    btfsc   STATUS, Z
    goto    GoneNeg

    return
;...............
GoneNeg
    clrf    F0
    clrf    F1
    clrf    F2
    clrf    F3
    return

;-------------------------------
CalcDDS                ;Calculates D0..3 for DDS,  = FREQCONST * F0..3 / 2^32
    movf    F0, W
    movwf   A0
    movf    F1, W
    movwf   A1
    movf    F2, W
    movwf   A2
    movf    F3, W
    movwf   A3

    movlw   LOW(FREQCONST + 5)
    call    GetEE
    movwf   B0
    movlw   LOW(FREQCONST + 4)
    call    GetEE
    movwf   B1
    movlw   LOW(FREQCONST + 3)
    call    GetEE
    movwf   B2
    movlw   LOW(FREQCONST + 2)
    call    GetEE
    movwf   B3
    movlw   LOW(FREQCONST + 1)
    call    GetEE
    movwf   B4
    movlw   LOW(FREQCONST)
    call    GetEE
    movwf   B5

    call    Multiply48x32        ;A * B / 2^16  ....  Truncated to 64 bit result
               
    movf    Acc5, W     ;Divide by another 2^16 to compensate for DDS constant
    movwf   D3          ;  by offsetting accumulator by 16 bits to give the 
    movf    Acc4, W    ;  32 bit word for the DDS
    movwf   D2
    movf    Acc3, W
    movwf   D1
    movf    Acc2, W
    movwf   D0


    return
;----------------------------------
DispMem
    movlw    LINE2 + d'12'
    call    LCDCmd
    movlw    "M"
    call    LCDChar
    movlw    "e"
    call    LCDChar
    movlw    "m"
    call    LCDChar
    rrf    CurrentMem, W
    movwf    Temp
    rrf    Temp, W
    andlw    0x0F
   
    addlw    "A"
    call    LCDChar
    return
;-------------------------
DispFreq
    movf    F0, W
    movwf    A0
    movf    F1, W
    movwf    A1
    movf    F2, W
    movwf    A2
    movf    F3, W
    movwf    A3

    call    BinToBCD 

    movlw    LINE1
    call    LCDCmd            ;Use leading zero blanking on first two digits
    movlw    " "
    call    LCDChar            ;Preset first two to spaces
    movlw    " "
    call    LCDChar           

    movf    BCDUi            ;Test for Both MS digits = 00
    btfsc    STATUS, Z
    goto    NoMSDs   

    movlw    LINE1            ;If not, reposition at start
    call    LCDCmd           

    swapf    BCDUi, W
    andlw    0x0F
    btfsc    STATUS, Z
    movlw    0xF0            ;Modify to print a space in place of 0
    addlw    0x30
    call    LCDChar

    movf    BCDUi, W        ;Want this to print a zero if it gets here
    andlw    0x0F
    addlw    0x30
    call    LCDChar

NoMSDs
    movlw    LINE1 + 2
    call    LCDCmd           
    swapf    BCDVi, W
    andlw    0x0F
    addlw    0x30
    call    LCDChar

    movf    BCDVi, W
    andlw    0x0F
    addlw    0x30
    call    LCDChar

    swapf    BCDHi, W
    andlw    0x0F
    addlw    0x30
    call    LCDChar

    movlw    "."
    call    LCDChar

    movf    BCDHi, W
    andlw    0x0F
    addlw    0x30
    call    LCDChar

    swapf    BCDMe, W
    andlw    0x0F
    addlw    0x30
    call    LCDChar

    movf    BCDMe, W
    andlw    0x0F
    addlw    0x30
    call    LCDChar

    swapf    BCDLo, W
    andlw    0x0F
    addlw    0x30
    call    LCDChar

    movf    BCDLo, W
    andlw    0x0F
    addlw    0x30
    call    LCDChar

    movlw    " "
    call    LCDChar
    movlw    " "
    call    LCDChar
    movlw    " "
    call    LCDChar
    movlw    " "
    call    LCDChar
    movlw    " "
    call    LCDChar
    movlw    LINE1 + d'12'
    call    LCDCmd
    movlw    "k"
    call    LCDChar
    movlw    "H"
    call    LCDChar
    movlw    "z"
    call    LCDChar
    return
;-------------------------------
DispCode
    movlw    LINE4 + d'1'
    call    LCDCmd
    movlw    "0"
    call    LCDChar
    movlw    "x"
    call    LCDChar

    movf    D4, W
    call    ShowHex
    movlw    "."
    call    LCDChar
    movf    D3, W
    call    ShowHex
    movf    D2, W
    call    ShowHex
    movf    D1, W
    call    ShowHex
    movf    D0, W
    call    ShowHex

    movlw    " "
    call    LCDChar
    return
;-------------------------------
BinToBCD            ;Takes in A3/A2/A1/A0, calculates packed BCD equivalent
    clrf    BCDUi    ;Result in BCDUi/3/2/1/0
    clrf    BCDVi    ;Also uses BCDCounter, BCDTemp  Destroys A
    clrf    BCDHi    ;  may be able to reuse Acc registers in some cases
    clrf    BCDMe
    clrf    BCDLo
    movlw   d'32'
    movwf   BCDCounter
BCDloop
    rlf     A0
    rlf     A1
    rlf     A2
    rlf     A3
    rlf     BCDLo
    rlf     BCDMe 
    rlf     BCDHi 
    rlf     BCDVi 
    rlf     BCDUi
    decfsz  BCDCounter      ;Need a final shift only, so loop count here
    goto    BCDgo
    goto    BCDone
    ;..........
BCDgo
    movf    BCDUi , W
    addlw   3
    movwf   BCDTemp
    btfsc   BCDTemp , 3
    movwf   BCDUi            ;If BCDUi >= 5, add 3 and store back

    movf    BCDUi , W
    addlw   0x30
    movwf   BCDTemp
    btfsc   BCDTemp , 7
    movwf   BCDUi            ;Adjust BCDUi if > 80

    movf    BCDVi  , W
    addlw   3
    movwf   BCDTemp
    btfsc   BCDTemp , 3
    movwf   BCDVi       

    movf    BCDVi  , W
    addlw   0x30
    movwf   BCDTemp
    btfsc   BCDTemp , 7
    movwf   BCDVi       

    movf    BCDHi  , W   ;Repeating for middle then low digits
    addlw   3
    movwf   BCDTemp
    btfsc   BCDTemp , 3
    movwf   BCDHi       

    movf    BCDHi  , W
    addlw   0x30
    movwf   BCDTemp
    btfsc   BCDTemp , 7
    movwf   BCDHi     

    movf    BCDMe  , W   ;
    addlw   3
    movwf   BCDTemp
    btfsc   BCDTemp , 3
    movwf   BCDMe     

    movf    BCDMe  , W
    addlw   0x30
    movwf   BCDTemp
    btfsc   BCDTemp , 7
    movwf   BCDMe   

    movf    BCDLo  , W   ;
    addlw   3
    movwf   BCDTemp
    btfsc   BCDTemp , 3
    movwf   BCDLo     

    movf    BCDLo  , W
    addlw   0x30
    movwf   BCDTemp
    btfsc   BCDTemp , 7
    movwf   BCDLo   

    goto    BCDloop
    ;...........
BCDone
    return

;---------------------------------------------------

ShowHex       ;Convert byte to ASCII / Hex and print to LCD
    movwf   Temp2           ;Uses Temp2 , Temp
    swapf   Temp2 , W   
    andlw   0x0F            ;High nibble
    addlw   0x30            ;Convert to ASCII
    movwf   Temp            ;Temp contains correct ASCII for "0" to "9"
    sublw   0x39            ;W = "9" - W,  if > "9" answer -ve so C=0
    movlw   7               ;(Does not affect status bits)
    btfss   STATUS , C
    addwf   Temp            ;Add 7 for "A" - "F"
    movf    Temp , W
    call    LCDChar        ;Make sure Temp2 is preserved

    movf    Temp2 , W       ;Recover original data
    andlw   0x0F            ;Low nibble
    addlw   0x30           
    movwf   Temp
    sublw   0x39           
    movlw   7             
    btfss   STATUS , C
    addwf   Temp           
    movf    Temp , W
    call    LCDChar
   
    movf    Temp2 , W       ;Restore original data to W
                            ; as this is a test mode only
    return
;------------------------------
LCDChar
        bsf     LCDRS
        goto    LcdNibble
LCDCmd                          ;Command byte to LCD module RS = 0
        bcf     LCDRS
LcdNibble
        movwf   Temp            ;LCD is on high order nibble of LCDPORT
        movf    Temp, W
        andlw   0xF0            ;mask to low order bits
        movwf   LCDPORT         ;MS Nibble to PORT 4/7
        nop
        bsf     LCDE
        nop
        bcf     LCDE            ;Strobe in high order nibble
        nop
        swapf   Temp , W        ;load low order nibble
        andlw   0xF0            ;mask to low order bits
        movwf   LCDPORT
        nop
        bsf     LCDE
        nop
        bcf     LCDE            ;Strobe in low order nibble
        call    Delay100us

        return
;-------------------------------
SetUpLCD
    call    Delay50
        bcf     LCDE            ;LCDPORT - B0-B3 to be used for nibble data
        bcf     LCDRS

        movlw   0x30        ;LCDPORT is on Hig Nibble
        movwf   LCDPORT         ;R/W - Write  RS = 0  E = Low
        nop
        bsf     LCDE
        nop
        bcf     LCDE            ;strobe in first $30 
        call    Delay5
       
        bsf     LCDE
        nop
        bcf     LCDE            ;second $30
        call    Delay5
       
        bsf     LCDE
        nop
        bcf     LCDE            ;third $30
        call    Delay5

        movlw   0x20            ;set nibble node $20
        movwf   LCDPORT
        nop
        bsf     LCDE
        nop
        bcf     LCDE
        nop                     ;LCD Module now working in nibble mode
                                ;  so we can now use the routines
        movlw   0x28            ;Sets 4bit, 2 lines 5x10 dots
        call    LCDCmd         
        movlw   0x1C            ;Cursor move, shift right
        call    LCDCmd
        movlw   0x0C            ;Display on, Cursor on, Blink
        call    LCDCmd
        movlw   0x04            ;Increment cursor
        call    LCDCmd
        movlw   0x01            ;Clear and Home
        call    LCDCmd
        call    Delay5          ;could eventually use RS232 delay
                         
    call    ClrDisp
    return
;-------------------------------
ClrDisp
    movlw   1
    call    LCDCmd
    call    Delay50
    return
;-------------------------------
Delay100us     
    movlw   d'19'
    movwf   DelCount
ShortDelLoop
    nop
    nop
    decfsz  DelCount
    goto    ShortDelLoop
    return
;-------------------------------
Delay50            ;General purpose 50ms delay
    movlw   d'250'
    movwf   DelCount2
Del50Loop
    call    Delay100us
    call    Delay100us
    decfsz  DelCount2
    goto    Del50Loop
    return
;----------------------------
Delay5              ;5ms delay for LCD setup
    movlw   d'50'
    movwf   DelCount2
Del5Loop
    call    Delay100us
    decfsz  DelCount2
    goto    Del5Loop
    return
;-------------------------------
LongerDel                       ;Delays by W * 50ms
    movwf   Counter
LongDelLoop
    call    Delay50
    decfsz  Counter
    goto    LongDelLoop
    return
;------------------------------
LoadFreq
    movlw    LOW(StFreq)
    addwf    CurrentMem, W
    call    GetEE
    movwf    F3

    movlw    LOW(StFreq + 1)
    addwf    CurrentMem, W
    call    GetEE
    movwf    F2

    movlw    LOW(StFreq + 2)
    addwf    CurrentMem, W
    call    GetEE
    movwf    F1

    movlw    LOW(StFreq + 3)
    addwf    CurrentMem, W
    call    GetEE
    movwf    F0
    return
;-----------------------------=
GetEE         ;different from ;F84   EE registers all in bank 1 now 
    bsf     STATUS,RP0      ;ram page 1
    movwf   EEADR
    bsf     EECON1 , RD
    movf    EEDATA , W
    bcf     STATUS , RP0    ;ram page 0
    return
;-------------------------
StoreEE           ;Enter with W = EE data,  Whi = EE address
    bsf     STATUS, RP0
    movwf   EEDATA
    bcf     STATUS, RP0
    movf    Whi, W
    bsf     STATUS, RP0
    movwf   EEADR   

    bsf     STATUS , RP0    ;All EE registers in Bank 1

    bsf     EECON1 , WREN   ;Enable EEprom writing
    movlw   0x55
    movwf   EECON2
    movlw   0xAA
    movwf   EECON2
    bsf     EECON1 , WR

    bcf     STATUS, RP0     ;PIR1 register is in bank 0
EEwaitW
   
    btfss   PIR1 , EEIF
    goto    EEwaitW
    bcf     PIR1 , EEIF       ;has to be cleared manually

    bsf     STATUS, RP0
    bcf     EECON1 , WR
    bcf     STATUS , RP0
    return
;-------------------------
ConstructR0
    return
;-----------------------------


;--------------------
Multiply48x32       ;32x 48 bit multiplication, followed by /2^16
    clrf    Acc0   ;Input A0/1/2/3 and B0/1/2/3/4/5, output Acc0---7
    clrf    Acc1        ;A destroyed,  B kept
    clrf    Acc2        ;64 bit answer, LSBs thrown away
    clrf    Acc3       
    clrf    Acc4
    clrf    Acc5
    clrf    Acc6
    clrf    Acc7        ;Extend A range by changing counter and adding 
                        ;  extra RRF Ax terms
    movlw   d'32'       
    movwf   Counter
MultLoop           
    bcf     STATUS, C
    rrf     A3
    rrf     A2
    rrf     A1
    rrf     A0          ;Effectivley adds shifted version of B
    btfss   STATUS, C   ; into Acc depending on working bit of A
    goto    NoMult      ; by shifting the accumulator instead of B itself

    movf    B0, W       ;Get B0 value and add
    addwf   Acc2        ; into shifted accumulator if 1 in 
    btfss   STATUS, C   ; appropriate bit in Avalue
    goto    MulAdd1
    incf    Acc3
    btfss   STATUS, Z
    goto    MulAdd1     
    incf    Acc4
    btfss   STATUS, Z
    goto    MulAdd1     
    incf    Acc5
    btfss   STATUS, Z
    goto    MulAdd1     
    incf    Acc6
    btfss   STATUS, Z
    goto    MulAdd1
    movlw   1           ;Need more complex addition routine for last Acc as
    addwf   Acc7        ; final Carry has to be preserved for the shift
MulAdd1
    movf    B1, W
    addwf   Acc3
    btfss   STATUS, C
    goto    MulAdd2
    incf    Acc4
    btfss   STATUS, Z
    goto    MulAdd2
    incf    Acc5
    btfss   STATUS, Z
    goto    MulAdd2
    incf    Acc6
    btfss   STATUS, Z
    goto    MulAdd2
    movlw   1
    addwf   Acc7
MulAdd2
    movf    B2, W
    addwf   Acc4
    btfss   STATUS, C
    goto    MulAdd3
    incf    Acc5
    btfss   STATUS, Z
    goto    MulAdd3
    incf    Acc6
    btfss   STATUS, Z
    goto    MulAdd3
    movlw   1
    addwf   Acc7
MulAdd3
    movf    B3, W
    addwf   Acc5
    btfss   STATUS, C
    goto    MulAdd4
    incf    Acc6
    btfss   STATUS, Z
    goto    MulAdd4
    movlw   1
    addwf   Acc7
MulAdd4
    movf    B4, W
    addwf   Acc6
    btfss   STATUS, C
    goto    MulAdd5
    movlw   1
    addwf   Acc7
MulAdd5
    movf    B5, W
    addwf   Acc7

NoMult                  ;Need to rotate in carry from final addition.  C is
    rrf     Acc7        ; already zero if we've jumped in here.
    rrf     Acc6
    rrf     Acc5
    rrf     Acc4
    rrf     Acc3       
    rrf     Acc2
    rrf     Acc1
    rrf     Acc0
    decfsz  Counter
    goto    MultLoop

    return              ;Acc7/6/5/4/3/2/1/0 = A * B     
;------------------------------------------------------------------
Div2N                           ;Divides Acc by 2^N.  N in W
    movwf   Counter         ;Does not work if entered with 0
    movf    Counter
    btfsc   STATUS , Z      ;So trap it out
    return
DivLoop
    bcf     STATUS , C
    rrf     Acc3
    rrf     Acc2
    rrf     Acc1
    rrf     Acc0
    decfsz  Counter
    goto    DivLoop
    return
;------------------------------
ShowConst
    movlw    LINE3 + 2
    call    LCDCmd

        movlw   "F"
        call    LCDChar
        movlw   "r"
        call    LCDChar
        movlw   "e"
        call    LCDChar
        movlw   "q"
        call    LCDChar
        movlw   " "
        call    LCDChar
        movlw   "C"
        call    LCDChar
        movlw   "o"
        call    LCDChar
        movlw   "n"
        call    LCDChar
        movlw   "s"
        call    LCDChar
        movlw   "t"
        call    LCDChar
    movlw   "."
        call    LCDChar
        movlw   " "
        call    LCDChar
        movlw   "="
        call    LCDChar


    movlw    LINE4 + 1
    call    LCDCmd

    movlw    "0"
    call    LCDChar
    movlw    "x"
    call    LCDChar
        movlw   LOW(FREQCONST + 0)
        call    GetEE
        call    ShowHex
        movlw   LOW(FREQCONST + 1)
        call    GetEE
      call    ShowHex
        movlw   LOW(FREQCONST + 2)
        call    GetEE
      call    ShowHex
        movlw   LOW(FREQCONST + 3)
        call    GetEE
        call    ShowHex
        movlw   LOW(FREQCONST + 4)
        call    GetEE
        call    ShowHex
        movlw   LOW(FREQCONST + 5)
        call    GetEE
    call    ShowHex
   
    return
;-------------------------------------
IntroMsg
    movlw   LINE1 + 5
    call    LCDCmd

    movlw   "G"
    call    LCDChar
    movlw   "4"
    call    LCDChar
    movlw   "J"
    call    LCDChar
    movlw   "N"
    call    LCDChar
    movlw   "T"
    call    LCDChar
    movlw   " "
    call    LCDChar

    movlw   LINE2 + 1
    call    LCDCmd

    movlw   "A"
    call    LCDChar
    movlw   "D"
    call    LCDChar
    movlw   "9"
    call    LCDChar
    movlw   "8"
    call    LCDChar
    movlw   "5"
    call    LCDChar
    movlw   "0"
    call    LCDChar
    movlw   " "
    call    LCDChar
    movlw   "C"
    call    LCDChar
    movlw   "o"
    call    LCDChar
    movlw   "n"
    call    LCDChar
    movlw   "t"
    call    LCDChar
    movlw   "r"
    call    LCDChar
    movlw   "o"
    call    LCDChar
    movlw   "l"
    call    LCDChar

    return
;--------------------------------------
SendSynth               ;Send Tx registers as a serial data to DDS
        movf    D0 , W
        call    Write9850
        movf    D1 , W
        call    Write9850
        movf    D2 , W
        call    Write9850
        movf    D3 , W
        call    Write9850
        movf    D4 , W          ;Phase word
        call    Write9850
        bcf     WClk

    goto    $+1
        bsf     FQud      ;+ve edge of FQud sets 9850 internal reg
        goto    $+1
        bcf     FQud
        bcf     FData
        nop

        return
;--------------------------
Write9850
    movwf    Temp
        movlw   8
        movwf   BitCount
Loop9850
        bcf     WClk       ;data changes with -ve edge of clock
        rrf     Temp
        btfss   STATUS , C
        bcf     FData
        btfsc   STATUS , C
        bsf     FData
        goto    $+1
        bsf     WClk     
        goto    $+1
        decfsz  BitCount         
        goto    Loop9850

        return
;------------------------------
    cblock 0x20   
        Temp, Temp2, BTemp, Whi
        Counter
        DelCount, DelCount2
    BitCount
        ButtCount, ButtonPress
    AutoEEADR
        Flags
        Wreg, StsReg
    CurrentMem
        StepHi, StepMe, StepLo                      ;24 bit Tuning step
        A0, A1, A2, A3,
        B0, B1, B2, B3, B4, B5
    Acc0, Acc1, Acc2, Acc3, Acc4, Acc5, Acc6, Acc7
        SynthReg1, SynthReg2
        F0,F1, F2, F3                              ;Frequency Register
    D0, D1, D2, D3, D4
        BCDLo, BCDMe, BCDHi, BCDVi, BCDUi
        BCDTemp, BCDCounter
    Tx0, Tx1, Tx2, Tx3                    ;Serial shift registers 

    endc         
;------------------------------------------------
 end
 
Last edited:
#2
There are a couple of issues to consider. I think it is usually (not always) a bad idea to modify code when you don't completely understand how it works. The other thing to consider is that you are not posting the entire program.

Others here may see this more clearly and I have not spent a lot of time on it, but it looks like the 16 memory locations contain the information for eight frequencies. IF you only wanted to use the first two frequencies, you may be able to modify the code below, replacing '7' with '1', thus allowing only frequencies 0 and 1. But, again, unless you just want to do some playing around, it seems like a much better idea to spend more time learning how the program works.

Code:
decf ButtonPress
movlw 7
btfsc ButtonPress, 7 ;Test for underflow
movwf ButtonPress ;Cycles round 7 - 0
 

Cyber

New Member
Thread starter #4
There are a couple of issues to consider. I think it is usually (not always) a bad idea to modify code when you don't completely understand how it works. The other thing to consider is that you are not posting the entire program.

Others here may see this more clearly and I have not spent a lot of time on it, but it looks like the 16 memory locations contain the information for eight frequencies. IF you only wanted to use the first two frequencies, you may be able to modify the code below, replacing '7' with '1', thus allowing only frequencies 0 and 1. But, again, unless you just want to do some playing around, it seems like a much better idea to spend more time learning how the program works.

Code:
decf ButtonPress
movlw 7
btfsc ButtonPress, 7 ;Test for underflow
movwf ButtonPress ;Cycles round 7 - 0
Hi. DrG

Thank you for the advice, I will try that code mod as soon as I get a chance tomorrow.
 
#6
Hi. DrG

Thank you for the advice, I will try that code mod as soon as I get a chance tomorrow.
You should probably look for a statement that declares the starting/default frequency - maybe it is 7 and not 0, if you know what I mean. I also look forward to seeing the link to the project and complete code and think you may be able to do do what you want to do.
 

Cyber

New Member
Thread starter #8
There are a couple of issues to consider. I think it is usually (not always) a bad idea to modify code when you don't completely understand how it works. The other thing to consider is that you are not posting the entire program.

Others here may see this more clearly and I have not spent a lot of time on it, but it looks like the 16 memory locations contain the information for eight frequencies. IF you only wanted to use the first two frequencies, you may be able to modify the code below, replacing '7' with '1', thus allowing only frequencies 0 and 1. But, again, unless you just want to do some playing around, it seems like a much better idea to spend more time learning how the program works.

Code:
decf ButtonPress
movlw 7
btfsc ButtonPress, 7 ;Test for underflow
movwf ButtonPress ;Cycles round 7 - 0
I have now edited the first post to include the full code.
DrG - I have tried your suggestion re: btfsc ButtonPress, 7 ; Result - this affected the ( #define Button PORTB, 2) not the ( #define MemButton PORTB, 3).
The (Button PORTB, 2) is used to move the curser under one of the 8 digits to select the digit to modify it up or down with the Rotary Encoder
#define RotI PORTB, 0 ;Drives interrupt
#define RotQ PORTB, 1
#define Button PORTB, 2
#define MemButton PORTB, 3 - This membutton has 16 eeprom locations, "A" to "P" on the LCD display , I need to change it to 2 location "A" & "B"

I hope the above has made it a little clearer.

Also I would like to set a maximum frequency.
 
#9
I have now edited the first post to include the full code.
DrG - I have tried your suggestion re: /---/
I hope the above has made it a little clearer.

Also I would like to set a maximum frequency.
OK, you were going to post a link to the project. This is important to help you and also to credit the author.

One way to do that is to click the link icon (7th from the left on the options bar) and enter the link in the pop-up. I have done one below as an example (and I am sure there are directions somewhere to do links and lots of other things).


https://www.electro-tech-online.com...emory-locations-only-need-2-locations.154293/
 
Thread starter #12
Hi DrG
Yes I have the AD9850 and the circuit is working good on a breadboard at present.

Also I would like to set a maximum frequency, and just realised I would then need to remove the leading zeros on the display if possible.
 
#13
Try this.
Find this section of code:
Code:
   movlw   4       ;Count in multiples of 4,  00 - 0x2C
   addwf   CurrentMem, W
   andlw   b'00111100'
   movwf   CurrentMem
change
andlw b'00111100'
to
andlw b'00000100'

I am flying blind here, not having the device. It seems like a pretty cool project and a nice job of coding as far as I can tell.

IF I am reading correctly (and I very possibly am not), this should only allow the first two defined memory locations corresponding to the frequencies. The value of W will be either 0 or 4 and so the other 14 frequencies will not be seen. That is, when you turn the rotary encoder, you are adding steps of four, corresponding to the 16 frequency locations (the de table).

I would not comment out the other 14 values as you have shown, just leave everything as is and see if the change works.

As far as setting a maximum frequency, I am not sure what you mean, but start small - see if you can modify the code to only use the first two frequencies first.

Also, why do you want to do this? :)

Hope this helps.
 
Thread starter #14
Hi DrG.

Fantastic, changing andlw b'00111100' to andlw b'00000100' work perfect, I now have just the first 2 memory locations.
I see that now, changing from binary 60 to binary 4:)
Thank You very much for your help DrG.

Next step would to hide the leading zeros on the LCD display. so that if it was set to 99Hz the leading zeros would not show, i.e. 99.00 not 000.09900

I am looking to control a small AC motor
 
#15
Hi DrG.

Fantastic, changing andlw b'00111100' to andlw b'00000100' work perfect, I now have just the first 2 memory locations.
I see that now, changing from binary 60 to binary 4:)
Thank You very much for your help DrG.

Next step would to hide the leading zeros on the LCD display. so that if it was set to 99Hz the leading zeros would not show, i.e. 99.00 not 000.09900

I am looking to control a small AC motor
It would probably be a good idea for you to try and figure out the leading zero issue and let us know what you have tried first (translation: I am too lazy to go through all the code right now). I would suggest, however, that this section is a good place to start:

Code:
   swapf   BCDUi, W
   andlw   0x0F
   btfsc   STATUS, Z
   movlw   0xF0           ;Modify to print a space in place of 0
   addlw   0x30
   call   LCDChar

   movf   BCDUi, W       ;Want this to print a zero if it gets here
   andlw   0x0F
   addlw   0x30
   call   LCDChar
(0x30 is ascii for zero and 0x20 is ascii for a space, it may be as simple as changing the first addlw 0x30 to addlw 0x20 )
 

Mike - K8LH

Well-Known Member
#16
Can I assume you would want to suppress leading zero digits up to the 'ones' digit in front of the decimal point? If so, you might modify the "DispFreq" subroutine to support using a mask variable, perhaps something like this;

Code:
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;   display frequency, suppress leading zeros                     ~
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DispFreq
        movf    F0,W            ;
        movwf   A0              ;
        movf    F1,W            ;
        movwf   A1              ;
        movf    F2,W            ;
        movwf   A2              ;
        movf    F3,W            ;
        movwf   A3              ;
        call    BinToBCD        ;
        movlw   LINE1           ;
        call    LCDCmd          ; line 1, column 0
;
;  prep for leading zero suppression.  a 0 value will print as
;  a space until a non-zero value changes the mask to '0' which
;  will then print 0..9 values as ascii '0'..'9'
;
        movlw   ' '             ; suppress leading zeros          |
        movwf   zeromask        ;  "                              |
;
;  print frequency  'nnnnn.nnnnn kHz'
;
        swapf   BCDUi,W         ;                                 |
        call    PutDigit        ; 1st digit                       |
        movf    BCDUi,W         ;                                 |
        call    PutDigit        ; 2nd digit                       |
        swapf   BCDVi,W         ;                                 |
        call    PutDigit        ; 3rd digit                       |
        movf    BCDVi,W         ;                                 |
        call    PutDigit        ; 4th digit                       |
        bsf     zeromask,4      ; leading zero suppression off    |
        swapf   BCDHi,W         ;                                 |
        call    PutDigit        ; 5th digit                       |
        movlw   "."             ;                                 |
        call    LCDChar         ; '.'                             |
        movf    BCDHi,W         ;                                 |
        call    PutDigit        ; 1st decimal place               |
        swapf   BCDMe,W         ;                                 |
        call    PutDigit        ; 2nd decimal place               |
        movf    BCDMe,W         ;                                 |
        call    PutDigit        ; 3rd decimal place               |
        swapf   BCDLo,W         ;                                 |
        call    PutDigit        ; 4th decimal place               |
        movf    BCDLo,W         ;                                 |
        call    PutDigit        ; 5th decimal place               |
        movlw   " "             ;                                 |
        call    LCDChar         ;                                 |
        movlw   "k"             ;                                 |
        call    LCDChar         ;                                 |
        movlw   "H"             ;                                 |
        call    LCDChar         ;                                 |
        movlw   "z"             ;                                 |
        call    LCDChar         ;                                 |
        movlw   " "             ;                                 |
        call    LCDChar         ;                                 |
        return                  ;                                 |
PutDigit
        andlw   0x0F            ; use lower nibble                |
        skpz                    ; a zero? yes, skip, else         |
        bsf     zeromask,4      ; change mask to '0' (0x30)       |
        iorwf   zeromask,W      ; WREG = ' ' or '0'..'9'          |
        goto    LCDChar         ;                                 |
 
Last edited:
#18
Anyone know what the "synth module" is in the original author's schematic and code? Is that a part of this AD9850 DDS project?
I think it refers to a LMX2541 or LMX2470 Synthesizer Module. Not used in the present project (see note - " This module is also used for control of Fractional-N synthesizers with appropriate PIC firmware. Ignore the part on the diagram referring to LMX2xxx connections. - http://www.g4jnt.com/AD9850-Controller.pdf"), but a different one see: http://www.g4jnt.com/fractn_rot_controller.pdf
 
Thread starter #19
Anyone know what the "synth module" is in the original author's schematic and code? Is that a part of this AD9850 DDS project?
Hi Mike- K8LH
Thank You for your reply.

DrG is correct the syth module is not used in this setup, it is part of another project
 
Thread starter #20
Hi. Drg and Mike - K8LH

Thank you both for your suggestions, I will have to wait until the weekend to try them out , but can't wait.
I will let you know how I get on.

Thanks again, with your help and explanation of the code I seem to be able to understand it better than I ever would do reading lots of books and datasheets.
 

Latest threads

EE World Online Articles

Loading

 
Top