Help with changing assembler code written for common cathode to common anode

Thread Starter

bance

Joined Aug 11, 2012
315
Hi guys,

This is my first post here, though been lurking for a while.... thanks for all the help I've already received.

I'm trying to learn how to program with assembly language, and I've been working through these very useful tutorials.

The problem I have is that the code is written for common cathode displays, and I only have common anode.

I've googled around but have only found examples of code written in 'c' this obviously won't allow me to modify the code to achieve my goals. A search of these
forums turned up this, (http://forum.allaboutcircuits.com/showthread.php?t=35871) but that approach won't work in this case since I'm using a PIC16f684 14 pin device and the segments are spread across two ports, though I did manage to figure that method for myself when using a single display (it worked well,)
in this case because the the ports are overwritten each time the display is updated, the bits controlling the transistors are constantly in a high state and thus all segments are lit at the same time, at least I think that's what's happening.
My code differs from the original in that I have changed the parity of the PORTC lookup table (making the pins active low) and added an exclusive or (XORLW) instruction to reverse the parity of the single bit in PORTA that relates to the 7 segment display. At least that's the approach I think will work, however for whatever reason it's a no go!

Anybody got any thoughts?

Original code can be found here (page 15)

My code is as attached.

My circuit works ok (tested by setting transistors base high, and grounding at each segment pin)
 

Attachments

MMcLaren

Joined Feb 14, 2010
842
Schematic, please?

Have you swapped out the active high input NPN sinking column drivers with active low input PNP sourcing column drivers?
 
Last edited:

Thread Starter

bance

Joined Aug 11, 2012
315
Thanks for the reply,

The circuit works, it's the code that I have the problem with.

Yes, I have placed high side switching transistors, and with different code the circuit behaves as it should.
 

MMcLaren

Joined Feb 14, 2010
842
Then your modified (inverted) tb7segA and tb7segC tables should be correct and you simply need to remove those 'xorlw' instructions and change the polarity of the digit enable instructions.

Regards, Mike

Rich (BB code):
dsp_ones
        ; display ones digit using shadow register
        Lookup  tb7segA,ones        ; lookup ones pattern for porta
        banksel PORTA               ;   and output it
        movwf   sPORTA
        Lookup  tb7segC,ones        ; repeat  for portc
        movwf   sPORTC
        bcf     sONES               ; enable ones display
        goto    dsp_end

dsp_tens
        ; display tens digit using shadow register
        Lookup  tb7segA,tens        ; lookup tens pattern for porta
        banksel PORTA               ;   and output it
        movwf   sPORTA
        Lookup  tb7segC,tens        ; repeat  for portc
        movwf   sPORTC
        bcf     sTENS               ; enable tens display
        goto    dsp_end

dsp_mins
        ; display mins digit using shadow register
        Lookup  tb7segA,mins        ; lookup mins pattern for porta
        banksel PORTA               ;   and output it
        movwf   sPORTA
        Lookup  tb7segC,mins        ; repeat  for portc
        movwf   sPORTC
        bcf     sMINS               ; enable mins display
 

Thread Starter

bance

Joined Aug 11, 2012
315
DOH!!!!!

How obvious was that, I guess that's experience for you........

Thanks very much for your help, Mike.

Got any ideas why the XORLW instruction didn't work?

Incidentally, the code is still not correct it's counting ones and tens but no mins.....

More debugging:D

Thx Steve.
 

MMcLaren

Joined Feb 14, 2010
842
Got any ideas why the XORLW instruction didn't work?
Hi Steve,

Since you inverted the bits in the tb7segA table, you already had the correct pattern to, (A) set active low cathode segment 'G' (RA2) correctly, and, (B) turn off the active low "mins" (RA4), "tens" (RA1), and "ones" (RA0) digit select lines. Your 'xorlw' instruction was flipping the digit select bits from '1' (off) back to '0' (on) and then the 'bsf' instruction was actually turning off the one display that you wanted to enable.

Incidentally, you could have used the original tb7segA and tb7segC tables along with some 'xorlw' instructions to perform the same function, perhaps like this;

Rich (BB code):
dsp_ones
	Lookup  tb7segA,ones    ; segment pattern for porta
        xorlw   b'010110'       ; RA4 off, RA2 flip, RA1 off, RA0 on
        movwf   sPORTA          ; set segment 'G', enable ones digit
        Lookup  tb7segC,ones    ; segment pattern for portc
        xorlw   b'111111'       ;
        movwf   sPORTC          ; set segments 'F'..'A'
        goto    dsp_end         ;
dsp_tens
        Lookup  tb7segA,tens    ; segment pattern for porta
        xorlw   b'010101'       ; RA4 off, RA2 flip, RA1 on, RA0 off
        movwf   sPORTA          ; set segment 'G', enable tens digit
        Lookup  tb7segC,tens    ; segment pattern for portc
        xorlw   b'111111'       ;
        movwf   sPORTC          ; set segments 'F'..'A'
        goto    dsp_end         ;
dsp_mins
        Lookup  tb7segA,mins    ; segment pattern for porta
        xorlw   b'000111'       ; RA4 on, RA2 flip, RA1 off, RA0 off
        movwf   sPORTA          ; set segment 'G', enable mins digit
        Lookup  tb7segC,mins    ; segment pattern for portc
        xorlw   b'111111'       ;
        movwf   sPORTC          ; set segments 'F'..'A'
dsp_end
There's probably a few things the program author could have done differently. First, the use of shadow registers in this program are unnecessary, and second, there's a slight problem with his display refresh sequence. Specifically, when the author updates PORTA from the sPORTA shadow the old digit is turned off and the new digit is turned on with the new digit 'G' segment data while PORTC still contains the old digit 'F'..'A' segment data. It takes another two cycles before PORTC contains the new digit 'F'..'A' segment data. Two cycles may not seem like much but it very well could be enough to perceive a 'ghosting' artifact on the display. Most programmers will blank the display, then setup new digit segment data, then enable and display the new digit. The following code does just that (while eliminating the unnecessary shadow registers);

Rich (BB code):
dsp_ones
	Lookup  tb7segA,ones    ; segment pattern for porta
        movwf   PORTA           ; blank the display, set 'G'
        Lookup  tb7segC,ones    ; segment pattern for portc
        movwf   PORTC           ; set segments 'F'..'A'
        movlw   b'000001'       ; mask for 'ones' digit (RA0)
        goto    dsp_end         ;
dsp_tens
        Lookup  tb7segA,tens    ; segment pattern for porta
        movwf   PORTA           ; blank the display, set 'G'
        Lookup  tb7segC,tens    ; segment pattern for portc
        movwf   PORTC           ; set segments 'F'..'A'
        movlw   b'000010'       ; mask for 'tens' digit (RA1)
        goto    dsp_end         ;
dsp_mins
        Lookup  tb7segA,mins    ; segment pattern for porta
        movwf   PORTA           ; blank the display, set 'G'
        Lookup  tb7segC,mins    ; segment pattern for portc
        movwf   PORTC           ; set segments 'F'..'A'
        movlw   b'010000'       ; mask for 'mins' digit (RA4)
dsp_end
        xorwf   PORTA,F         ; enable & display new digit
Actually, there are probably several ways to streamline the ISR, if you wanted. While perhaps not nearly as intuitive or readable, some variations could be considerably smaller;

Rich (BB code):
GENVAR  UDATA                   ; general variables
ones	RES	1		; 0..9
tens    RES	1		; 0..9
mins    RES     1               ; 0..9
temp    RES     1               ;
colsel  RES     1		; '010000','000010','000001'
Rich (BB code):
isrproc
        movwf   cs_W            ; save W                      |B?
        movf    STATUS,w        ; save status                 |B?
        movwf   cs_STATUS       ;                             |B?
        clrf    STATUS          ; bank 0                      |B0
        bcf     INTCON,T0IF     ; clear TMR0 interrupt flag   |B0
refresh
        movf    ones,W          ; get 'ones', 0..9            |B0
        btfsc   colsel,0        ; ones last? no, skip, else   |B0
        movf    tens,W          ; get 'tens', 0..9            |B0
        btfsc   colsel,1        ; tens last? no, skip, else   |B0
        movf    mins,W          ; get 'mins', 0..9            |B0
        movwf   temp            ; save temporarily            |B0
        Lookup  tb7segA,temp    ; segment pattern for porta   |B0
        movwf   PORTA           ; blank display, setup 'G'    |B0
        Lookup  tb7segC,temp    ; segment pattern for portc   |B0
        movwf   PORTC           ; setup segments 'F'..'A'     |B0
        movlw   b'000001'       ; bit mask for 'ones' (RA0)   |B0
        btfsc   colsel,0        ; ones last? no, skip, else   |B0
        movlw   b'000010'       ; bit mask for 'tens' (RA1)   |B0
        btfsc   colsel,1        ; tens last? no, skip, else   |B0
        movlw   b'010000'       ; bit mask for 'mins' (RA4)   |B0
        movwf   colsel          ; update column select mask   |B0
        xorwf   PORTA,F         ; display new digit           |B0
isrexit
        movf    cs_STATUS,W     ; restore status              |B0
        movwf   STATUS          ;                             |B?
        swapf   cs_W,F          ; restore W                   |B?
        swapf   cs_W,W          ;                             |B?
        retfie                  ;                             |B?
If you haven't already, please take time to learn how to use the MPLAB Simulator, Watch window, and StopWatch. These tools are invaluable for debugging/qualifying code.

Have fun. Cheerful regards, Mike
 
Last edited:

Thread Starter

bance

Joined Aug 11, 2012
315
Thank's Mike,

I haven't had time to try your code yet, but I will.

I've been using the gooligum tutorials to get myself up and running with PIC's and to be fair the original author states that the code is not always optimal but is trying to provide generic tutorials that will provide the basis to allow the student to further explore more exotic methods/microcontrollers to their own ends.

I haven't yet found a good tutorial on MPSIM although I have tried running each tutorial in the simulator, this isn't helped by the fact that I use LINUX, and that when I originally downloaded the MPLABX program it was in beta, therefore not complete. I fear that one of the incomplete elements was the simulator, for instance, I cannot find any reference to stopwatch nor the 'memory map' (a hex or binary table...?) that I have seen here and there on the internet.
In the version I have installed, delays are interminable and the sim refuses to acknowledge breakpoints.These comments, are, as I hope you understand, observations and not complaints. I would 'upgrade' MPLAB to the latest release, but because it was installed from source and not through a package manager this a major pain, still I'm about to reformat my HDD's and get rid of those pesky WINDOZE (I've had a dual boot system) so the upgrade isn't that far away:)

If you Know of a good tutorial on MPSIM, TCLspice or NGspice please feel free to share it.

ohh and I have worked out that I can use an IFDEF/ELSE statement to reduce the 'delay' dilemma, is this the most elegant way to do it?

Once again thanks for the help, I will explore and try your code modifications and report back!

Steve
 
Top