Beginner: 74HC595's Configured in Parallel?
Chad1
Posts: 26
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...
Can anyone help with/recommend possible solutions?
Thanks a lot!
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...
Can anyone help with/recommend possible solutions?
Thanks a lot!
Comments
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.
Thanks for the quick reply. I updated the original post with the object file as an attachment. Would appreciate any help you can provide!
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.
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.
I used this program to test the modified object.
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
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.
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.
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.
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!
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.