Shop OBEX P1 Docs P2 Docs Learn Events
Beginner: 74HC595's Configured in Parallel? — Parallax Forums

Beginner: 74HC595's Configured in Parallel?

Chad1Chad1 Posts: 26
edited 2014-09-03 09:45 in General Discussion
Hi All,

I built what is essentially a "clicker counter," where button presses either increment or decrement the count on a double digit 7 segment display. I wrote the code in Spin and used the Simple_74HC595.spin object file to drive the shift registers. Here's some psuedo code to help you understand my solution...

OBJ
shift : "Simple_74HC595.spin"

PUB Main | i

shift.init(SRCLK, RCLK, SER) 'Initialize ONE display

i := 0 'Initialize i as 0
shift.Out(long[@Num]) 'Display 0

repeat
|-if (ina[BT1] == 1)
|-- i := i + 1
|-- if (i > 99)
|--- i := 0
|-- waitpne(0000000000000000, |<BT1, 0) 'Wait until BT1 is de-pressed
|-- shift.Out(long[@Num]) 'Display ith element in Num array

DAT
Num long $003F,$0006,... 'Array containing 7SEG numeral data


My Problem:
I'd like to add anther one of these "clicker counters" in parallel to control separately, but it seems I can only control one display at a time using the Simple_74HC595.spin object file. I want each display to run independently of one another, with separate buttons controlling separate individual displays. Sticking with the "clicker counter" analogy, it would be like having one in each hand, controlling them separately. I configured the circuit so that each display "block" would have unique data lines, but as mentioned the Simple_74HC595.spin object file only supports shift registers configured in series, not parallel (i.e. one data line).

Proposed circuit...
Untitled.png


Can anyone help with/recommend possible solutions?

Thanks a lot!
576 x 337 - 230K

Comments

  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-08-31 13:52
    I have lots of projects where I use shift registers in parallel.

    Where does one find this "Simple_74HC595.spin". I'll take a look at it and see how hard it would be to add an additional data line.
  • Chad1Chad1 Posts: 26
    edited 2014-08-31 14:00
    Hi Duane,

    Thanks for the quick reply. I updated the original post with the object file as an attachment. Would appreciate any help you can provide!
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-08-31 14:47
    It's dangerous to upload a program without testing it but sometimes I get lucky and they'll work right of the bat.

    This program "should" work the same as the other but now you add a channel parameter with each call.

    There are two channels but it could be changed to make more. If I were clever, I'd have a way to make the number of channels a parameter but that would take a lot more work (and cleverness).

    Let me now if it does or doesn't work.
  • Chad1Chad1 Posts: 26
    edited 2014-08-31 15:51
    Thanks again for your help! Unfortunately it doesn't seem to work. Nothing happens; my displays don't illuminate and the button inputs don't trigger any response. I tried to narrow down the problem but it seems to begin with the first shift1 command in Main...



    OBJ
    shift1 : "Channels_74HC595.spin"


    PUB Main | i

    shift1.init(SRCLK, RCLK, SER, SER2) 'Initialize the object

    i := 0 'Initialize i as 0

    shift1.Out(1, long[@Num]) 'Display 0 on Display #1
    shift1.Out(2, long[@Num]) 'Display 0 on Display #2

    repeat
    |-if ina[BT1] == 1
    |-- i := i + 1
    |-- if (i > 100)
    |--- i := 0
    |-- waitpne(0000000000000000, |<BT1, 0)
    |-- shift1.Out(1, long[@Num]) 'Display ith value in Num array on Display #1


    I did confirm the integrity of my circuit (no shorts, loose connections, etc.) because the code for the previous revision of the object file still works. I studied your edits to the object file and will continue debugging. But I would still really appreciate further help if you have the time.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-08-31 17:06
    The channels are numbered zero and one.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-08-31 17:32
    Wow, I'm a bit surprised because the modified program works.

    I used this program to test the modified object.
    CON                                          
      _clkmode = xtal1 + pll16x 
      _xinfreq = 5_000_000
    
    
      SHIFT_REGISTER_DATA = 18
      SHIFT_REGISTER_CLOCK = 16
      SHIFT_REGISTER_LATCH = 17
    
    
    OBJ
    
    
      Shift : "Channels_74HC595"
       
    PUB Setup 
    
    
      Shift.init(SHIFT_REGISTER_CLOCK, SHIFT_REGISTER_LATCH, SHIFT_REGISTER_DATA, SHIFT_REGISTER_DATA + 1)
    
    
      repeat
        repeat result from 0 to 7
          Shift.High(0, result) 
          Shift.High(1, 7 - result) 
          waitcnt(clkfreq / 2 + cnt)
          Shift.Low(0, result) 
          Shift.Low(1, 7 - result) 
    
    
    
  • Chad1Chad1 Posts: 26
    edited 2014-08-31 17:47
    SUCCESS!!! I didn't start the channel count at 0, as you pointed out. I'm glad it was just something dumb on my part. Many, many thanks for your help and time, Duane!
  • Chad1Chad1 Posts: 26
    edited 2014-09-01 10:51
    Hi again, Duane,

    How easy would it be to implement PWM into the object file? I'm wanting to decrease the power consumption of my circuit and thought using persistence of vision on the displays would help a lot. Problem is my attempts have failed. I leveraged a PUB from an existing object file (attached below) and tried to make it work for the file you updated. Can't seem to figure out how to merge the two properly. Any thoughts?


    PUB SetPWM(channel, bit_pos, freq, duty) | total

    ' v2.2 added: Limit duty cycle 0% to 100% duty #>= 0
    duty <#= 100


    ' v2.2 added: if freq == 0, turns off output.
    if duty == 0 or freq == 0
    |- Low(channel, ???)
    elseif duty == 100
    |- High(channel, ???)
    else
    |- total := clkfreq / freq
    |- ClockPin := ???
    |- LatchPin := duty * (total / 100)
    |- DataPin[channel] := total - LatchPin


    74HC595_MultiPWM.spin
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-09-01 13:11
    Chad1 wrote: »
    How easy would it be to implement PWM into the object file?

    Not easy at all.

    I use that PWM '595 object in several projects (including the one I'm currently working on). IMO, it's a very useful object.

    Using PWM with shift registers can be tricky. I have a RGB LED array project which I use multiple high power shift register to control the LEDs. By using PWM on the LEDs, I get all sorts of color combinations but there's a limit to how many brightness levels I can achieve with PWM while using a lot of arrays. With two arrays and six '595 chips, I can only get 5-bit (32) brightness control with each LED before the flicker becomes a problem.

    Do you want to control the brightness of all the LEDs together or do you need to control the brightness of the individual LEDs? Controlling all the LED together is easy. If you use PWM on the enable pin, you can dim all the LED together.

    I initially tied the enable pin low on the PCBs I had made but I finally realized having access to the enable pins of the '595 is very useful and my newest board bring these pins out to the connector.

    How many LEDs do you want to control? The PWM object can control 32 LEDs. When I had more LEDs than 32 I wanted to control, I used multiple instances of the PWM object. At least this is what I'd do before I learned to program in assembly and I could write my own dedicated drivers.

    Last time I looked (several years ago), the PWM shift register object (I'm pretty sure it's the same one you posted) was too complicated for me to understand. I like to think I now know enough to modify it, by it wouldn't be easy.

    Back when I made a 12x10 LED array and used a stack of '595 chips to control it, I found it easier to write my own driver to control the chips than to try to modify the driver you posted.

    attachment.php?attachmentid=80501&d=1303579233


    Chad1 wrote: »
    Can't seem to figure out how to merge the two properly. Any thoughts?

    The two programs don't lend themselves to being merged.

    If you're using 32 or fewer LEDs, just use the LED sequentially instead of in parallel. If you need more than 32 LEDs use two instances of the object. If you just want to adjust the brightness of all the LEDs together use PWM on the enable pin.
  • Chad1Chad1 Posts: 26
    edited 2014-09-01 14:22
    Duane Degn wrote: »
    Do you want to control the brightness of all the LEDs together or do you need to control the brightness of the individual LEDs?

    Brightness isn't all that important, just the fact that PWM will allow me to save a lot of power. I'm using three relatively large (0.80" digit size) double-digit 7 segment displays which chew up more power than I'd like. To answer your question, I'd prefer all three displays to have equal brightness, so that can be controlled together. The important thing is that the digits on each display must be controlled independently, which is what you helped me solve yesterday.
    Duane Degn wrote: »
    How many LEDs do you want to control?

    Since I'm using three double digit 7 segment displays, I need to control 48 LEDs total. It's too bad the solution isn't very straightforward, but I guess that's when you learn the most. Thank you for your time and suggestions!
  • jmgjmg Posts: 15,173
    edited 2014-09-02 19:11
    Chad1 wrote: »
    Brightness isn't all that important, just the fact that PWM will allow me to save a lot of power.

    Rather than try to PWM thru the Serial Shift registers, you could simply vary the common anode voltage to all the LEDs.
    That can be just a RC DAC into the ADJ pin of a LM317
  • Chad1Chad1 Posts: 26
    edited 2014-09-03 09:45
    jmg wrote: »
    Rather than try to PWM thru the Serial Shift registers, you could simply vary the common anode voltage to all the LEDs.
    That can be just a RC DAC into the ADJ pin of a LM317

    Thanks for the tip, jmg. I actually thought of a way to incorporate PWM that is much easier than modifying an object file or adding cost to my BOM. In my loop where digits are displayed from button presses, I end it by writing all zeros to the displays for a short amount of time. It's essentially user-defined, loop generated PWM. This cut the current consumption of the circuit almost in half while maintaining sufficient LED brightness, so I'm pretty pleased.
Sign In or Register to comment.