1. 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.
    Dismiss Notice

74HC595 Shift Register with 4 Dig Com Anode 7 segment display

Discussion in 'Code Repository' started by Mosaic, Apr 8, 2012.

  1. Mosaic

    Mosaic Well-Known Member

    Joined:
    Jun 3, 2010
    Messages:
    2,361
    Likes:
    86
    Location:
    Caribbean
    Here is a complete Proteus sim with asm code running a number of useful routines.

    1) A simple debouncer in asm, easily understood, not as eff. as a parallel debouncer.
    2) Binary to decimal conversion for counting.
    3) 7 segment lookup table to display digits.
    4) Shift register serial data transfer with column select and strobe for each digit.
    5) ASM delay in main loop to effect a precise strobe time, as opposed to an interrupt.
    6) Sampling of a couple tactile switches.

    Almost every line is commented.

    I used a 16f886 which I find to be a very flexible chip, although there are better ones now.

    Clicking Sw1 counts up, Sw2 reset the count.
    You can swap in other Shift registers, just keep track of the pinouts as they are not necessarily pin for pin replacements. The TPIC6C595 Shift reg. packs a lot more power and can drive LEDS quite bright which is necessary when strobing for best effect.

    Change the 'bin' extension to DSN to use in Proteus.
     
    • Thanks Thanks x 1
  2. colin55

    colin55 Well-Known Member

    Joined:
    Feb 14, 2009
    Messages:
    3,534
    Likes:
    82
    Location:
    Melbourne Australia
    How is 74HC04 going to sink or source a 7-segment display??????
     
  3. Mosaic

    Mosaic Well-Known Member

    Joined:
    Jun 3, 2010
    Messages:
    2,361
    Likes:
    86
    Location:
    Caribbean
    Colin:
    The hex gate is just for the simple functioning of ISIS....if u look at the bitmap pic u see that it is indicated that the gates will be replaced by PNP or P channel transistors. ISIS had sim probs with the actual transistors.
     
  4. dave

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    -
    Likes:
    0


     
  5. Jon Wilder

    Jon Wilder Active Member

    Joined:
    Oct 22, 2010
    Messages:
    834
    Likes:
    80
    Location:
    Fresno, CA
    I use the 16F886 and the F887 extensively. The F886 fit into the design and PCB layout of my MIDI controller pedals quite nicely. Very nice PIC to work with.
     
  6. Mosaic

    Mosaic Well-Known Member

    Joined:
    Jun 3, 2010
    Messages:
    2,361
    Likes:
    86
    Location:
    Caribbean
    Update

    Here is a somewhat improved version of this topic.

    The asm code is cleaned up and commented to enable the user to easily switch between 2 or 4 digit, CC or CA displays and also use tactile switches running off the column select lines to minimise pin usage.

    The new schematic is also posted as a BIN file, rename to DSN extension for Proteus.

    The switch sampling GPR etc will dovetail with my other post on parallel debouncing for handling multiple switches efficiently.

    The final improvement makes it simple to use any Dig. output pin in any port for the Shift Register and column select and switch I/O. Mix and match pins and ports freely now. This will make it easier to layout a congested PCB or work with MCU firmware that has only scattered free pins available.
     
    Last edited: Apr 21, 2012
  7. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,545
    Likes:
    85
    Location:
    Michigan, USA
    Your method looks remarkably similar to one of my MacMux designs from long ago (below) except you haven't implemented the PWM brightness control.

    The MacMux design is relatively flexible and expandable. You can use NPN or NFET drivers for CC displays along with a 74HC595 or an MIC5891 as a 'source' driver for the segments, or you can use PNP or PFET column drivers for CA displays along with a 74HC595, an MIC5821, a TPIC6C595, or similar 'sinking' driver IC for the cathode segments. Re-tasking the column/digit driver lines for use as <clk> and <dat> lines to load the driver shift registers is a hallmark of the MacMux method, as well as the ability to load multiple driver shift registers in parallel in as little as 24 instruction cycles (bit-banged multi-channel SPI).

    Regards...

    [​IMG]
     

    Attached Files:

    Last edited: Oct 16, 2015
  8. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,545
    Likes:
    85
    Location:
    Michigan, USA
    Here's a design variation that only uses four pins (not expandable, no PWM brightness control). After all this time I still haven't tested it, but you're welcome to give it a try if you like.

    Regards, Mike

    [​IMG]
     
    Last edited: Apr 27, 2012
  9. Mosaic

    Mosaic Well-Known Member

    Joined:
    Jun 3, 2010
    Messages:
    2,361
    Likes:
    86
    Location:
    Caribbean
    Thanks Mike!

    As an application of this thread it can be useful to retask an ICSP programming header to provide a pair of pushbuttons and a 2 Digit 7 segment display.

    All that needs to be done is any gp output pin must be tied to the MCLR (which is configured as an input) via 1K resistor.

    Now this GP pin plus the ICSP clk pin can be used to drive the serial data and the serial clock (respectively) of a 74hc595. The ICSP DAT pin can be used to drive the 74hc595 OE & RCK (byte) lines.

    I did this using a 2 digit CC display and 2n3904 NPN CC drivers with 1k base resistors, plus pushbuttons. The pushbuttons will corrupt the display when pressed as they drive the 2n3904's on when pressed.Releasing the buttons returns the display to normal.

    The 7 segment Display, 74HC595 and buttons go onto a daughter board with a female 5 pin receptacle to mate to the 5 pin ICSP header. Pwr and gnd are obtained from the ICSP header as well.


    This is useful to get interactive feedback from a simple MCu circuit which does not warrant having it's own dedicated display. Including the code to handle the display on custom Mcu boards as shown before in this thread permits you to have a standard portable Display daughterboard that 'jacks' in to your MCu PCBs ICSP header and can make config changes via the pushbuttons and display whatever u need on the 2 digits available.:D
     
    Last edited: Apr 29, 2012
  10. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,545
    Likes:
    85
    Location:
    Michigan, USA
    Wouldn't a DIY serial backpack be easier?
     
    Last edited: May 5, 2012
  11. Mosaic

    Mosaic Well-Known Member

    Joined:
    Jun 3, 2010
    Messages:
    2,361
    Likes:
    86
    Location:
    Caribbean
    Can't say I know what that is.
    :confused:
     
  12. ARTUZAC

    ARTUZAC New Member

    Joined:
    Apr 1, 2015
    Messages:
    1
    Likes:
    0
    Hi, to everyone. On Apr 8,2012 there is thread called
    "74HC595 Shift Register with 4 Dig Com Anode 7 segment display".

    Mosaic wrote "Here is a complete Proteus sim with asm code ....".
    I am a new member in this forum. Would someone please tell me
    what should I do to get those Proteus files ?

    Thanks in advance
    artuzac
     
  13. Mosaic

    Mosaic Well-Known Member

    Joined:
    Jun 3, 2010
    Messages:
    2,361
    Likes:
    86
    Location:
    Caribbean
    Here are the zipped files.
     

    Attached Files:

  14. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,545
    Likes:
    85
    Location:
    Michigan, USA
    Hi Mosaic:

    May I ask about the purpose of this section of code, please? It appears you're calling the GETSWITCH and Strobe subroutines at approximately ~768 usec intervals (plus the overhead of the subroutines) but you're not doing anything at the longer ~199 msec interval. I'm just curious what you may have had planned for that ~199 msec interval? Comments suggest you're using the least significant two bits of the Delay2 variable in the Strobe subroutine but I haven't found that in the code. Am I missing something?

    Code (text):

    Longloop
            CLRF    Delay1          ;
            CLRF    Delay2          ;
    LOOP
            DECFSZ  Delay1,F        ; 1 inst cycle, when  delay1=0 => test = true skip next line.
            GOTO    LOOP            ; 2 inst cycles, this  is looped 256 times before skipping to next line => 768 microsec at 1 MIP
            CALL    GETSWITCH       ; approx ~768 cycle intervals
            CALL    Strobe          ; strobe the display based on 2 lsb's of Delay2  <-- where is this used?
            DECFSZ  Delay2,F        ; 1 inst cycle
            GOTO    LOOP            ; 2 inst cyles, by adding the loops = 256 * 768 + (256*3) = 257* 768 = 197376 microsec = .2 sec.  Simple Substitute for  ISR time control.
            Goto    Longloop        ; CONTINUE
     
    If you're not using the ~199 msec interval, why not simplify the "main loop"? You wouldn't even need to preset the Delay1 variable;

    Code (text):

    ;*******************************************************************
    ;  main loop                                                       *
    ;*******************************************************************
    loop
            decfsz  Delay1,F        ; delay ~768 usecs (4-MHz)         |B0
            goto    loop            ;                                  |B0
            call    GETSWITCH       ; sample & debounce inputs         |B0
            call    Strobe          ; refresh the display              |B0
            goto    loop            ;                                  |B0
     
     
    Last edited: Oct 15, 2015
  15. granddad

    granddad Active Member

    Joined:
    Jan 18, 2015
    Messages:
    640
    Likes:
    61
    Location:
    Worcestershire UK
    ONLINE
    Could i suggest you look at MAX7219 , for 8 CC ss leds saves a heap of code , no flicker , no decode , one resistor , no transistors, addressable digits, sw brightness , dip package , 1hz to 1Mhz serial, bit bangable , daisy chain , 5volt... expencive !!! .
     
    Last edited: Oct 16, 2015
  16. Mosaic

    Mosaic Well-Known Member

    Joined:
    Jun 3, 2010
    Messages:
    2,361
    Likes:
    86
    Location:
    Caribbean
    $13 ea! If you have to avoid transistors and current limiting resistors. Maybe if the form factor limits PCB space.
     
  17. Mosaic

    Mosaic Well-Known Member

    Joined:
    Jun 3, 2010
    Messages:
    2,361
    Likes:
    86
    Location:
    Caribbean
    The 'delay2' comment seems to be a mistake it should be 'Digitstrobe', I had prev. used Delay2 in an older variant of the code (which made the code dependent on the delay loop) and the comment slipped by getting updated.

    The rest of this post is meant for the general readership, I know you know all these things already MK.

    199 msec is essentially available time resource for an application to execute other tasks, whatever they may be, at the discretion of the coder.
    Also the 768 usec interval in the delay loop can also be considered available time resource for doing other useful things in code.
    It really depends on the coder, based on the refresh rate for the desired display updates.
    The delay loop here just a tool that demos the rest of the display & key sampling code .

    If display update speeds are critical then an interrupt driven display update cycle may be justified. I have found that to be generally not required.
    Usually, when I code i build in the display & switch control (HMI) first to make the application interactive and also help debugging by displaying chosen characters/ GPR values/msgs on the fly during code progression.
    Then as code develops , more processing overheads slows the display updates. In bigger applications this can start to impact the display quality.
    Sometimes writing EPROM data can introduce excessive delays in general code based on the sample coding supplied by Microchip in 16F PIC datasheets. Proper coding can permit multi-tasked EPROM writing permitting general code flow and avoiding such delays. Similar techniques for ADC oversampling (avoiding dedicated sampling loops)can be used to permit code execution while such sampling is being done.
    Use of flags (bits) can optimize subroutine execution and reduce unnecessary overheads as well.
     
  18. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,545
    Likes:
    85
    Location:
    Michigan, USA
    Well, the program certainly deserves a cleanup. It's difficult to figure out what it's doing with the sloppy formatting and several extraneous code fragments.

    I found an interesting algorithm in the PICLIST Source Code Library for an alternate binary-to-decimal subroutine. While it takes a bit more time to execute, it's much smaller and it's isochronous. Note that the 'Rem' variable is equated to the 'Thousands' variable which is taken advantage of during the last trip through the Div10 routine.

    Code (text):
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ;                                 739 cycles (isochronous)        ~
            radix dec               ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Bin2Dec
            movf    ClickL,W        ; click count lo                  |B0
            movwf   Blo             ;                                 |B0
            movf    ClickH,W        ; click count hi                  |B0
            movwf   Bhi             ;                                 |B0
            call    Div10           ;                                 |B0
            movwf   Units           ; save 'ones'                     |B0
            call    Div10           ;                                 |B0
            movwf   Tens            ; save 'tens'                     |B0
            call    Div10           ;                                 |B0
            movwf   Hundreds        ; save 'hundreds'                 |B0
    Div10
            movlw   16              ;                                 |B0
            movwf   Ctr             ; repeat for 16 bits              |B0
            clrf    Rem             ; clear 'remainder'               |B0
    DivLoop
            rlf     Blo,W           ;                                 |B0
            rlf     Bhi,F           ;                                 |B0
            rlf     Rem,F           ; move MSB of number into Rem     |B0
            movlw   10              ;                                 |B0
            subwf   Rem,W           ; does 10 go in?                  |B0
            skpnc                   ; no, skip, else                  |B0
            movwf   Rem             ; update remainder                |B0
            rlf     Blo,F           ; shift in the borrow bit         |B0
            decfsz  Ctr,F           ; all 16 bits? yes, skip, else    |B0
            goto    DivLoop         ; loop                            |B0
            movf    Rem,W           ; note Rem equates to Thousands   |B0
            return                  ;                                 |B0
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     
    Here's your binary-to-decimal routine for comparison;
    Code (text):

    Bindec    ;calculate decimal# for each 7seg led block
        clrf Thousands
        clrf Hundreds
        clrf Tens
        clrf Units
        movf ClickL,w
        movwf TempL
        movf ClickH,w
        movwf TempH
        call Thou ; get thousands in decimal
        movlw .10 ; check for 10,000 or more
        subwf Thousands,w;  if Thousands < 10, carry is clr.
        btfsc STATUS,C ;
        goto Overrange ;
        Call Hundred ; get hundreds
        call Ten ; get tens & units.
        return
    Overrange
        movlw 0x79 ; E pattern
        movwf Thousands
        movlw b'01010000' ; r pattern
        movwf Hundreds
        Movwf Tens
        movlw 0x06 ; '1' pattern (error 1)
        movwf Units
        return



    Thou    movlw .3 ; high byte set to 3 = 768
        movwf FixedH ; high byte of # to be subtracted.
        movlw .232 ; low byte
        movwf FixedL ; 768 + 232 = 1000's column

    ThouCount
        call Subtract
        xorlw .1 ; check for returned wreg value. A  zero occurs if a 1 was returned
        btfss STATUS,Z ; branch if 1 was returned, else
        goto Fixremainder ; due to last subtraction the remainder went -ve, so we fix this.
        incf Thousands,f
        goto ThouCount

    Fixremainder ;restore remainder to continue calculating for next decimal column.
        movf    FixedL,w ; low byte
            addwf   TempL,f ; TempL=TempL + FixedL
            movf    FixedH,w ; hi byte
            btfsc   STATUS,C ; check for carry, set if  TempL + FixedL >255
            incfsz  FixedH,w ; Increment due to carry set ,if zero skip next.
            addwf   TempH,f    ; TempH=TempH+FixedH (+1 if carry was set)
        return

    Hundred    movlw 0 ; high byte set to 0
        movwf FixedH ; high byte of # to be subtracted.
        movlw .100 ; low byte
        movwf FixedL ; 0 + 100 = 100's column

    HdrdCount
        call Subtract
        xorlw .1 ; check for returned wreg value. A  zero occurs if a 1 was returned
        btfss STATUS,Z ; branch if 1 was returned, else
        goto Fixremainder ; due to last subtraction the remainder went -ve, so we fix this.
        incf Hundreds,f
        goto HdrdCount

    Ten    movlw .10
        subwf TempL,f; test for 10 if carry clr wreg is under 10
        btfsc STATUS,C ;skip if carry clr (-ve result) , else
        incf Tens,f; incr the tens column
        btfsc STATUS,C ; skip if carry clr (-ve result), else
        goto Ten ; now check for 20,30 etc
        movf TempL,w
        addlw .10; as last calc was -ve recreate +ve number.
    DispLEDS
        call Dpattern
        Movwf Units ; store 7 seg display pattern for units
        movf Tens,w
        call Dpattern
        movwf Tens; store 7 seg display pattern for tens
        movf Hundreds,w
        call Dpattern
        movwf Hundreds; store 7 seg display pattern for tens
        movf Thousands,w
        call Dpattern
        movwf Thousands
        return
    Subtract ; 2byte subtraction to determine decimal 7 seg columns
        movf    FixedL,W
            subwf   TempL,f ; TEMPL= TEMPL-FIXEDL
            movf    FixedH,W
            btfss   STATUS,C ; branch if TEMPL>FIXEDL, else
            incfsz  FixedH,W ; setup to reduced TempH by 1 extra (sim. a borrow).
            subwf   TempH,f  ;TempH=TempH-FixedH
        btfss    STATUS,C ;branch if TempH>FixedH, else
        retlw .0 ; if carry is clr return with a 0 in wreg
        retlw .1 ; if carry is set return with a 1 in wreg.
     
     
    Last edited: Oct 17, 2015
  19. Mosaic

    Mosaic Well-Known Member

    Joined:
    Jun 3, 2010
    Messages:
    2,361
    Likes:
    86
    Location:
    Caribbean
    That's a bit of apples vs oranges.

    My code u quoted does more than just Bin to Dec. Apart from being faster, it does 3 other things.
    It handles the 7 segment LED pattern display updates, the over-range error condition msg as well as provides a gen purpose 16 bit subtract (& compare routine for bubble sorting values) which is often reused for other parts of application dev.
    Around 35 lines extra for just those items.
     
  20. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,545
    Likes:
    85
    Location:
    Michigan, USA
    Yes, there are some easy-to-reconcile differences. For example, the "DispLEDS" routine at the tail end of your binary-to-decimal routine performs four separate conversions of numeric data in the "Thousands", "Hundreds", "Tens", and "Units" variables into LED segment data;
    Code (text):
    ;
    ;  excerpt from Mosaic's binary-to-decimal subroutine
    ;
    DispLEDS
            call    Dpattern
            Movwf   Units           ; store 7 seg display pattern for units
            movf    Tens,w
            call    Dpattern
            movwf   Tens            ; store 7 seg display pattern for tens
            movf    Hundreds,w
            call    Dpattern
            movwf   Hundreds        ; store 7 seg display pattern for tens
            movf    Thousands,w
            call    Dpattern
            movwf   Thousands
            return
    Since this code doesn't have anything to do with binary-to-decimal conversion, it seems out-of-place tacked onto the end of the binary-to-decimal subroutine. As an alternative... is there a reason why you couldn't leave numeric data in the "Thousands", "Hundreds", "Tens", and "Units" variables and eliminate this section of code, replacing it with a single "call Dpattern" instruction in the "Strobe" subroutine where the segment data is actually used?
    Code (text):
    ;
    ;  excerpt from Mosaic's "Strobe" subroutine
    ;
    Chk_Dcount
            bsf     Tmp1,4          ; initialize the bitmask to 0001XXXX
            clrc                    ; clear Carry
            decfsz  Offset,F        ; digit number, 1..4 on entry
            goto    ShiftDigit      ;
            bsf     Offset,3        ; make offset=8 for # of bits in Character pattern to send serially in Transmit routine called next.
            movf    INDF,W          ; get digit value, 0..9
    ->      call    Dpattern        ; get LED segment data
            movwf   Tmp             ; store in Tmp, clearing this GPR here can cause an empty display, useful for PWM Dimming.
            call    Transmit        ; setup Shift register with character data pattern.
     
    I certainly don't mean to imply there's anything wrong with your code. I'm simply pointing out a way to reconcile one of the differences you mentioned with a simple change in program organization that reduces code size and overhead and which may seem more intuitive to someone studying the program.

    Finally, since I'm familiar with this particular multiplexing method, would you mind if I pointed out a few confusing code fragments that I perceive to be problems or errors in a subsequent post? I figure if they cause me to scratch my head while muttering "huh?", they might cause similar confusion for someone studying the program who isn't as familiar with the method. It may be that I'm simply missing some subtle details or objectives and you can straighten me out.

    Thanks for reading. Have fun.

    Cheerful regards, Mike
     
    Last edited: Oct 24, 2015
  21. Mosaic

    Mosaic Well-Known Member

    Joined:
    Jun 3, 2010
    Messages:
    2,361
    Likes:
    86
    Location:
    Caribbean
    You must note that you are looking at an extract from a much larger application used as an example.
    As I recall it had to do with refresh rates and memory paging. I didn't want the refresh rate of the digit values to be the same as the strobe refresh so this method provided that flexibility.
    Then there was memory segmentation issues on 256 byte boundaries for lookup tables etc. Again, the strobe code may have been in page 2 and the character pattern lookup table was in the same page as the bin-dec code so....that's another issue.
    There will be approaches used that may not have apparent reasons in this code fragment, however, there will be reasons if the larger application was studied. Being over 7K in ASM size now....that's not really an option.

    I am certain that if each code module is studied I could find certain optimizations as there are sometimes remnants of structures from 10 versions before. I'm afraid I couldn't invest the time in that right now. Perhaps If I were to do a tut. from scratch things would be neater but more time consuming.
    So, I publish what I have that I know works and others can feel free to mod. as they need. Everyone will have their own set of requirements for their apps. Some need it compact, some need it speedy, some just need quick and dirty, some need super flexibility with indirect addressing for portability. Ain't no way what I publish can satisfy all comers...its merely a starting point.

    You're modding it as u go along...and that's cool. That's the intent, to spur on development. Perhaps the next time I need similar code I could use yours if it's a better match to the app. spec. requirements!
    Perhaps what you publish will meet the needs of some more readers .
    It's all good.

    I recently updated another thread in which I published on quadrature encoder code as BobW published an approach ( in a different thread) that seemed a better solution, so i quoted his post in my own thread. Now, I'll be using that new approach the next time I need an encoder!
     

Share This Page