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

Discussion in 'Embedded Systems and Microcontrollers' started by bance, Oct 13, 2012.

  1. bance

    Thread Starter Member

    Aug 11, 2012
    315
    34
    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)
     
  2. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    Schematic, please?

    Have you swapped out the active high input NPN sinking column drivers with active low input PNP sourcing column drivers?
     
    Last edited: Oct 14, 2012
  3. bance

    Thread Starter Member

    Aug 11, 2012
    315
    34
    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.
     
  4. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    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

    Code ( (Unknown Language)):
    1. dsp_ones
    2.         ; display ones digit using shadow register
    3.         Lookup  tb7segA,ones        ; lookup ones pattern for porta
    4.         banksel PORTA               ;   and output it
    5.         movwf   sPORTA
    6.         Lookup  tb7segC,ones        ; repeat  for portc
    7.         movwf   sPORTC
    8.         [B]bcf[/B]     sONES               ; enable ones display
    9.         goto    dsp_end
    10.  
    11. dsp_tens
    12.         ; display tens digit using shadow register
    13.         Lookup  tb7segA,tens        ; lookup tens pattern for porta
    14.         banksel PORTA               ;   and output it
    15.         movwf   sPORTA
    16.         Lookup  tb7segC,tens        ; repeat  for portc
    17.         movwf   sPORTC
    18.         [B]bcf[/B]     sTENS               ; enable tens display
    19.         goto    dsp_end
    20.  
    21. dsp_mins
    22.         ; display mins digit using shadow register
    23.         Lookup  tb7segA,mins        ; lookup mins pattern for porta
    24.         banksel PORTA               ;   and output it
    25.         movwf   sPORTA
    26.         Lookup  tb7segC,mins        ; repeat  for portc
    27.         movwf   sPORTC
    28.         [B]bcf[/B]     sMINS               ; enable mins display
    29.  
     
    bance likes this.
  5. bance

    Thread Starter Member

    Aug 11, 2012
    315
    34
    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.
     
  6. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    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;

    Code ( (Unknown Language)):
    1. dsp_ones
    2.     Lookup  tb7segA,ones    ; segment pattern for porta
    3.         xorlw   b'010110'       ; RA4 off, RA2 flip, RA1 off, RA0 on
    4.         movwf   sPORTA          ; set segment 'G', enable ones digit
    5.         Lookup  tb7segC,ones    ; segment pattern for portc
    6.         xorlw   b'111111'       ;
    7.         movwf   sPORTC          ; set segments 'F'..'A'
    8.         goto    dsp_end         ;
    9. dsp_tens
    10.         Lookup  tb7segA,tens    ; segment pattern for porta
    11.         xorlw   b'010101'       ; RA4 off, RA2 flip, RA1 on, RA0 off
    12.         movwf   sPORTA          ; set segment 'G', enable tens digit
    13.         Lookup  tb7segC,tens    ; segment pattern for portc
    14.         xorlw   b'111111'       ;
    15.         movwf   sPORTC          ; set segments 'F'..'A'
    16.         goto    dsp_end         ;
    17. dsp_mins
    18.         Lookup  tb7segA,mins    ; segment pattern for porta
    19.         xorlw   b'000111'       ; RA4 on, RA2 flip, RA1 off, RA0 off
    20.         movwf   sPORTA          ; set segment 'G', enable mins digit
    21.         Lookup  tb7segC,mins    ; segment pattern for portc
    22.         xorlw   b'111111'       ;
    23.         movwf   sPORTC          ; set segments 'F'..'A'
    24. dsp_end
    25.  
    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);

    Code ( (Unknown Language)):
    1.  
    2. dsp_ones
    3.     Lookup  tb7segA,ones    ; segment pattern for porta
    4.         movwf   PORTA           ; blank the display, set 'G'
    5.         Lookup  tb7segC,ones    ; segment pattern for portc
    6.         movwf   PORTC           ; set segments 'F'..'A'
    7.         movlw   b'000001'       ; mask for 'ones' digit (RA0)
    8.         goto    dsp_end         ;
    9. dsp_tens
    10.         Lookup  tb7segA,tens    ; segment pattern for porta
    11.         movwf   PORTA           ; blank the display, set 'G'
    12.         Lookup  tb7segC,tens    ; segment pattern for portc
    13.         movwf   PORTC           ; set segments 'F'..'A'
    14.         movlw   b'000010'       ; mask for 'tens' digit (RA1)
    15.         goto    dsp_end         ;
    16. dsp_mins
    17.         Lookup  tb7segA,mins    ; segment pattern for porta
    18.         movwf   PORTA           ; blank the display, set 'G'
    19.         Lookup  tb7segC,mins    ; segment pattern for portc
    20.         movwf   PORTC           ; set segments 'F'..'A'
    21.         movlw   b'010000'       ; mask for 'mins' digit (RA4)
    22. dsp_end
    23.         xorwf   PORTA,F         ; enable & display new digit
    24.  
    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;

    Code ( (Unknown Language)):
    1. GENVAR  UDATA                   ; general variables
    2. ones    RES 1       ; 0..9
    3. tens    RES 1       ; 0..9
    4. mins    RES     1               ; 0..9
    5. temp    RES     1               ;
    6. colsel  RES     1       ; '010000','000010','000001'
    7.  
    Code ( (Unknown Language)):
    1.  
    2. isrproc
    3.         movwf   cs_W            ; save W                      |B?
    4.         movf    STATUS,w        ; save status                 |B?
    5.         movwf   cs_STATUS       ;                             |B?
    6.         clrf    STATUS          ; bank 0                      |B0
    7.         bcf     INTCON,T0IF     ; clear TMR0 interrupt flag   |B0
    8. refresh
    9.         movf    ones,W          ; get 'ones', 0..9            |B0
    10.         btfsc   colsel,0        ; ones last? no, skip, else   |B0
    11.         movf    tens,W          ; get 'tens', 0..9            |B0
    12.         btfsc   colsel,1        ; tens last? no, skip, else   |B0
    13.         movf    mins,W          ; get 'mins', 0..9            |B0
    14.         movwf   temp            ; save temporarily            |B0
    15.         Lookup  tb7segA,temp    ; segment pattern for porta   |B0
    16.         movwf   PORTA           ; blank display, setup 'G'    |B0
    17.         Lookup  tb7segC,temp    ; segment pattern for portc   |B0
    18.         movwf   PORTC           ; setup segments 'F'..'A'     |B0
    19.         movlw   b'000001'       ; bit mask for 'ones' (RA0)   |B0
    20.         btfsc   colsel,0        ; ones last? no, skip, else   |B0
    21.         movlw   b'000010'       ; bit mask for 'tens' (RA1)   |B0
    22.         btfsc   colsel,1        ; tens last? no, skip, else   |B0
    23.         movlw   b'010000'       ; bit mask for 'mins' (RA4)   |B0
    24.         movwf   colsel          ; update column select mask   |B0
    25.         xorwf   PORTA,F         ; display new digit           |B0
    26. isrexit
    27.         movf    cs_STATUS,W     ; restore status              |B0
    28.         movwf   STATUS          ;                             |B?
    29.         swapf   cs_W,F          ; restore W                   |B?
    30.         swapf   cs_W,W          ;                             |B?
    31.         retfie                  ;                             |B?
    32.  
    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: Oct 15, 2012
  7. bance

    Thread Starter Member

    Aug 11, 2012
    315
    34
    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
     
Loading...