Microcontroller used for Scrolling a message on a seven segment display: problem it scrolls one way

Thread Starter

James Harris 2

Joined Aug 22, 2017
7
I am tasked with creating a program that will scroll a predetermined message across a 4 display seven segment screen, the scrolling is done with an digital rotary encoder that has two Phases A,B. The screens are multiplexed so all the letters show at the same time. The problem is the message only scrolls one way and I can not find the problem. My program is below, i use the portc,5 to detect direction, and portb,1 to cause a interrupt on change. Code has to be in Assembly


Code:
; Name: PicLab9.asm
; By James Harris

    __config    _CONFIG1,            0x03F4         ; internal oscillator, WDT off
    __config    _CONFIG2,            0x3FFF
[INDENT]    #include    p16f887.inc                           ; included with MPLab
    #include    lowercase_887sfr.inc            ; in the Files folder (see note)[/INDENT]

;define variables
cblock 0x20
dig3,
dig2,
dig1,
dig0,
userflag,
direction,
w_save,
status_save,
pclath_save,
m_index, endc

;define constants
    #define    DIGSEL0    portc,3
    #define    DIGSEL1    portc,2 
    #define    DIGSEL2    portc,1
    #define    DIGSEL3    portc,0
    #define    DRE_0    userflag,0
    #define    DRE_1    userflag,1 


    org        0x00
    call    Init
    goto    Main

    org    0x04                              ; interrupt vector
        movwf     w_save                ; save registers
        swapf      status,W
        movwf     status_save
        movf       pclath,W
        movwf    pclath_save
        clrf          pclath
[INDENT]call         Isr[/INDENT]
        movf      pclath_save,W        ; restore registers
        movwf   pclath
        swapf    status_save,W
        movwf    status
        swapf     w_save,F
        swapf     w_save,W
        retfie 

Message
        movf        m_index,W
        andlw      b'00000111'             ; mask off upper bits to force m_index to 0 thru 7 only.
        addwf      pcl,F                        ; index into the table
        retlw    b'11110000'                ;J
        retlw    b'01111111'                  ;.
        retlw    b'10001001'                ;H
        retlw    b'10001000'                ;A
        retlw    b'10101111'                 ;r
        retlw    b'10101111'                 ;r
        retlw    b'11101111'                 ;i
        retlw    b'10010010'                ;s
Init
[INDENT]    bsf    status,RP0                    ;switch to Bank1 
    movlw    b'11110000'
    movwf    trisc
    movlw    b'00000000'
    movwf    trisd
    movlw    b'01100001'                   ;4MHz internal oscillator
    movwf    osccon                           ;osccon is in bank1
    banksel    anselh
    bcf        anselh,ANS10                 ;enable digital input on RB1
    banksel    option_reg
    bcf        option_reg,NOT_RBPU  ;enable pull-ups
    banksel    wpub
    bsf        wpub,WPUB1                 ;enable RB1 pull-up
    banksel    iocb
    bsf        iocb,IOCB1                    ;enable RB1 on-change interrupt
    bcf        status,RP0                     ;switch to Bank0
    clrf    m_index
    clrf    direction
    clrf    dig3                 
    clrf    dig2
    clrf    dig1
    clrf    dig0
    bsf        intcon,RBIE                ;enable interrupts
    bsf        intcon,PEIE
    bsf        intcon, GIE
    return[/INDENT]

Main
    call    Dr_encoder
    call    Display
    goto    Main

Display
    movf       dig3,W
    movwf    portd
    bcf         DIGSEL3
    call        Wait
    bsf        DIGSEL3
    movf     dig2,W
    movwf   portd
    bcf        DIGSEL2
    call      Wait
    bsf       DIGSEL2
    movf    dig1,W
    movwf portd
    bcf      DIGSEL1
    call     Wait
    bsf      DIGSEL1
    movf    dig0,W
    movwf    portd
    bcf        DIGSEL0
    call    Wait
    bsf        DIGSEL0
    return

Isr
    btfss    intcon,0
    return
    btfss    portb,1    ; previous state of portb 0
    call    RC_1    ; call if previous state was 1
    btfsc    portb,1    ; previous state of portb 1
    call    RC_0    ; call if previous state was 0
    call    Wait_1sec
    call    Dre_isr
    return

RC_1
    btfsc    portc,5    ;current state 1
    bsf     DRE_1
    bsf        DRE_0
    return

RC_0
    btfss    portc,5    ;current state 1
    bsf        DRE_1
    bsf        DRE_0
    return
 

Dre_isr
    movf    portb,W                ;ends the mismatch on change
    bcf        intcon,RBIF
    btfss    DRE_0                ;detect direction
    return                        ;negative edge only
    movlw    -1                    ;CCW 
    btfss    DRE_1
    movlw    1                    ;CW
    movwf    direction
    clrf    userflag
    return

Dr_encoder
    movf    direction,W    ; CW = +1, CCW = -1,
    btfsc    status,Z    ; if direction is clear, then nothing to do
    return
    addwf    m_index,F    ; add direction to the message index
    clrf    direction    ; no change = 0
    call    Message        ; get character from the message table
    movwf    dig3        ; store it for displaying
    incf    m_index        ; point to next character
    call    Message        ; get character from the message table
    movwf    dig2        ; store it for displaying
    incf    m_index        ; point to next character
    call    Message        ; get character from the message table
    movwf    dig1        ; store it for displaying
    incf    m_index        ; point to next character
    call    Message        ; get character from the message table
    movwf    dig0        ; store it for displaying
    movlw    .3            ; restore m_index
    subwf    m_index        ; point back to first character
    return

Wait
    decfsz    waitcounter
    goto    Wait 
    return


Wait_10msec

Init_z        movlw    .4
            movwf    cntr_z

Init_y        movlw    .239
            movwf    cntr_y

Init_x
            movlw    .5
            movwf    cntr_x
     
Loop1        decfsz    cntr_x, F
            goto     Loop1             
     
            decfsz    cntr_y, F
            goto    Init_x
     
            decfsz    cntr_z, F
            goto    Init_y
            return
end
Mod edit: code tags
 
Last edited by a moderator:

takao21203

Joined Apr 28, 2012
3,702
no one will ever go through such code, even if they know the RISC mnemonics

In C language it can be managed much better. Tell the instructor it is nuts to code this in assembler. A total waste.

You have to understand you have to move the ring pointer backwards instead forwards, and this contains all kinds of problems, luckily you have just 7bits and not something like a proportional font (variable width).

so heres the code reading message from ROM table

Code:
;Dr_encoder
movf direction,W ; CW = +1, CCW = -1,
btfsc status,Z ; if direction is clear, then nothing to do
return
addwf m_index,F ; add direction to the message index
clrf direction ; no change = 0
call Message ; get character from the message table
movwf dig3 ; store it for displaying
incf m_index ; point to next character
call Message ; get character from the message table
movwf dig2 ; store it for displaying
incf m_index ; point to next character
call Message ; get character from the message table
movwf dig1 ; store it for displaying
incf m_index ; point to next character
call Message ; get character from the message table
movwf dig0 ; store it for displaying
movlw .3 ; restore m_index
subwf m_index ; point back to first character
returnDr_encoder
movf direction,W ; CW = +1, CCW = -1,
btfsc status,Z ; if direction is clear, then nothing to do
return
addwf m_index,F ; add direction to the message index
clrf direction ; no change = 0
call Message ; get character from the message table
movwf dig3 ; store it for displaying
incf m_index ; point to next character
call Message ; get character from the message table
movwf dig2 ; store it for displaying
incf m_index ; point to next character
call Message ; get character from the message table
movwf dig1 ; store it for displaying
incf m_index ; point to next character
call Message ; get character from the message table
movwf dig0 ; store it for displaying
movlw .3 ; restore m_index
subwf m_index ; point back to first character
return
this is not really good the message firstly should be read into a RAM buffer.

then you could write a copy function

start position into RAM buffer
length (here 4 digits)

then you need to handle overflow, and direction as well.
overflow means, you need to read 1 to some from the end, then reset to the start, and continue, each time you decrement the length (copied).
not really nice.

Then to change direction you need to do it backwards, decrement, read to start and then handle the overflow.

of course it can be done in assembler but its so complicated dealing with the low level stuff and leads to convoluted thinking
 
Last edited by a moderator:
Top