Hein (fub) wrote,

  • Mood:

Shift Registers

For the past two days, I've been working with shift registers. More specifically, with the 74HC4094. It has been... frustrating.

You see, I still can't read IC datasheets. Well, I can read them, but I can't wrap my brain around their meaning. I need someone to explain to me in plain language what it exactly is that an IC does. I found this page some time ago, which was a tremendous help -- but the software presented on that page is based on using the 74HC595. And there's a notable difference between the two: the 4094 has an Output Enable pin.

But! I figured it out. Here's how you use a 4094 as shift register:
- Pull the strobe line (pin 1 on the 4094) low;
- Pull the stobe line high again;
- Pull the Output Enable line (pin 15) low;
- Then, you can start to clock in your data:
    - Put your value (either high or low) on the data pin (pin 2);
    - Pull the clock (pin 3) high (the 4094 reacts to the rising edge of the clock pin);
    - Pull the clock low.
- After clocking in your data, pull the Output Enable pin high.

And it works. I now have one shift register driving a single 7-segment LED display. I have displays with a common +, so a 1 on the shift register means there's no current and thus the segment is off. A 0 on the shift register means there is current and thus the segment is on. It seems the shift register has no problems sinking 8 * 17mA, which means I don't have to use lots of transistors.
When the PIC 16F628A runs with a 4MHz crystal (thus on 1 MIPS), you don't even need wait loops between clocking in your data -- at least with one register. I intend to experiment with chaining the registers together next.

Here's the code I currently use. It counts down from 9 to 0 and then starts over again.
At the start of the program, the states of the shift register's parallel outputs are 'indetermined', which means you get odd effects. So in the procedure 'clear_shifter', I clock in eight 1's to turn all segments off.
Then, in the main_loop, I set the number of different patterns I have (10). For each step, I look up the bit pattern that I need to show. Then, for each of the 8 bits, I clock in the most significant bit first, and shift the bits to the left, making sure that new bits that are added to the right of the byte are all 1s.

; Shift register test
; Counts down from 9 to 0, then starts over again.

        LIST P=16F628    ; Use the PIC16F628 and decimal system

        #include "P16F628.INC"  ; Include header file

        __config  _XT_OSC & _LVP_OFF & _WDT_OFF & _PWRTE_OFF & _BODEN_OFF

        cblock 0x20

        goto init

        addwf PCL, f
        retlw b'10000001'        ; 0
        retlw b'10000001'        ; 0
        retlw b'10110111'        ; 1
        retlw b'11000010'        ; 2
        retlw b'10010010'        ; 3
        retlw b'10110100'        ; 4
        retlw b'10011000'        ; 5
        retlw b'10001000'        ; 6
        retlw b'10110011'        ; 7
        retlw b'10000000'        ; 8
        retlw b'10010000'        ; 9

        bsf STATUS,RP0          ; RAM PAGE 1
        clrf TRISB                ; portB all pins output
        clrf TRISA                ; portA all pins output
        MOVLW        b'10001000'        ; Set the options (prescaler for watchdog timer)
        MOVWF        OPTION_REG
        bcf STATUS,RP0          ; RAM PAGE 0

        CLRF        INTCON                ; No interrupts
        movlw 0x07
        movwf CMCON                ; No comparators
        CLRF PORTA
        CLRF PORTB
        ; Set the stobe high
        bsf PORTA, 0
        ; First, we set all of the outputs high
        movlw 0x08
        movwf steps
        bcf PORTA, 0                ; Pull stobe low to latch inputs
        bsf PORTA, 0                ; Strobe back high
        bcf PORTA, 3                ; OE low
        bsf PORTA, 1                ; Data high
clear        bsf PORTA, 2                ; Clock high
        bcf PORTA, 2                ; Clock low
        decfsz steps, f
        goto clear
        bsf PORTA, 3                ; OE high

        movlw 0x0a
        movwf steps
        movf steps, W
        call get_number
        movwf cur_val
        movlw 0x08
        movwf steps_2
        bcf PORTA, 0                ; Pull stobe low to latch inputs
        bsf PORTA, 0                ; Strobe back high
        bcf PORTA, 3                ; OE low
        btfss cur_val, 7
        goto send_zero
        bsf PORTA, 1
        goto send_clock
        bcf PORTA, 1
        bsf PORTA, 2                ; Clock high
        bcf PORTA, 2                ; Clock low
        bsf STATUS, C
        rlf cur_val, f
        movf cur_val, W
        decfsz steps_2, f
        goto inner_step_loop
        bsf PORTA, 3                ; OE high
        call wait
        decfsz steps, f
        goto step_loop                ; Step 9 times
        goto main_loop                ; Start anew

        movlw 0xff                ; Pause for a bit
        movwf counter
loopx        movlw 0xff
        movwf counter_2
loopy        movlw 0x0a
        movwf counter_3
loopz        decfsz counter_3, f
        goto loopz
        decfsz counter_2, f
        goto loopy
        decfsz counter, f
        goto loopx


  • Animal Crossiversary

    One year ago, when the COVID-19 restrictions had just started, Animal Crossing:New Horizons was released. I had pre-ordered and pre-downloaded it…

  • Things that happened this week

    A power interruption. We had gotten a letter from the company that manages the power lines that they’d be working on the infrastructure on…

  • Goodbye 2020

    Remember when Animal Crossing: New Horizons came out just as we went into the first lockdown, and it turned into a bit of a lifeline for many…

  • Post a new comment


    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded