Can I multiplex a 2-digit 7-segment display one segment at a time? - Page 1
Forum section: electronics / beginners

author: Peabody
author_rank: Super Contributor
timestamp: December 01, 2018, 06:22:19 pm
content: I'm working on a project which will display a duty cycle percentage from 00 to 99, using two 7-segment common cathode digits. I have enough IO lines for the seven segments and two cathode drives, and had planned to multiplex the two digits in the usual way. That would require 7 resistors for the segments as well as an NPN transistor and base resistor on each cathode.I'll use an MSP430 MCU, and the code will be written in assembler. So it occurred to me that the code would be simple enough to fire each of the 14 segments one at a time. Since only one segment would ever be on at a time, that would let me replace the 7 anode resistors and the cathode transistors with just one resistor on each cathode.But of course that would mean that the average brightness would be pretty low, and the effective refresh rate for an individual segment pretty low as well. Tentatively, the background refresh rate is 488 Hz, which would refresh each segment at about 35 Hz, but I could speed that up if necessary.This would be great for the parts count, but I suspect this may be a bridge too far. Has anyone here ever tried something like this, even with one digit? Can I test the brightness issue by multiplying the resistor by 14 and seeing if the segment is still visible? That would be 6.8K instead of 470 ohms. Or is that not really equivalent to 470 ohms 1/14 of the time? Seems like it might not even turn on using 6.8K. And this is all 3.3V by the way.The other potential complication is that if this thing works, it will probably be redone using an Arduino, and I'm not sure the efficient assembler code could be duplicated in C. Still, it would be nice to do without all those resistors and transistors.What do you think?

author: ogden
author_rank: Super Contributor
timestamp: December 01, 2018, 06:32:46 pm
content: Quote from: Peabody on December 01, 2018, 06:22:19 pmThis is not where you save on code simplicity. Look at segment multiplex as PWM. For 7 segments it (on/off) is at 1:7 rate, for 14 segments accordingly 1:14. Blinking will be more noticeable and it will be twice as dim.

author: Nusa
author_rank: Super Contributor
timestamp: December 01, 2018, 06:55:35 pm
content: (For real fun, look up charlieplexing. Sadly, that doesn't work so well when individual led's are tied to common cathodes.)First off, how many I/O lines do you actually have for this purpose? If it's 14 or more, you don't even have to multiplex.Second, realize the sizing of resistors in the circuit needs to change with the duty cycle, except when the goal is to dim the display. If the duty cycle is low enough, you may not need resistors at all!Third, while assembly is less portable than C, C is usually just as efficient when done right. Whether it's portable will depend more on the compatibility of assumptions you made about the hardware than anything else.

author: Peabody
author_rank: Super Contributor
timestamp: December 01, 2018, 10:15:26 pm
content: Quote from: Nusa on December 01, 2018, 06:55:35 pmI did look at some videos on charlieplexing, but they all related to individual LEDs. I didn't see anything related to 7-segment displays.With 7 + 2 I/O lines assigned to the display, I have one pin left over. It's a 20-pin MCU, with 16 I/O pins, but I also have a rotary encoder, a momentary switch, an LED, a buzzer, and an SSR trigger. So I don't have another 7 pins for the display.I had forgotten that the resistors could be much lower value, and the current much higher, for brief periods of time. And the point here is not so much to save on power but rather to save on parts. So if it's not too blinky, this may actually work. I think it's at least worth writing some code to test it. But between the MSP430G2553 processor and the TDSR1350 digits, I'm still looking at something under 10ma. That's common anode, isn't it, not common cathode. Sorry, I misremembered that.My comment on Arduino was just based on my experience with others who use them a lot. I don't see much bit-wise activity in their code, and it appears that a main focus of Arduino is to separate you as much as possible from the actual registers. Assembler, for me at least, is the opposite of that on both counts. In my code for this, there will be no MAIN other than to set up the interrupt, then go to sleep. Everything will happen in the interrupt service routine, and the processor will sleep in between. I don't see that kind of stuff in Arduino sketches. But of course that doesn't mean it can't be done.

author: mikerj
author_rank: Super Contributor
timestamp: December 01, 2018, 10:47:28 pm
content: Quote from: Peabody on December 01, 2018, 10:15:26 pmA forum member, matseng posted aninstructablethat permits a level of charliplexing on 7 segment displays, 9 pins will allow you to drive up to 8 digits at the cost of some code complexity. This isn't very useful if you are only driving two digits, but worth remembering. If you need to save pins then you could drive the displays with a couple of shift registers.

author: Nusa
author_rank: Super Contributor
timestamp: December 01, 2018, 11:12:02 pm
content: You might find this article useful:https://tinkerlog.com/2009/04/05/driving-an-led-with-or-without-a-resistor/Charlieplexing was for fun; I already said it wouldn't work well in your case, and why. Common cathode or anode, same issue.Arduino is one of those poorly defined words that one has to define from context, since the speaker usually doesn't tell you what they actually mean when they say it. In this case the contexts mentioned were hardware and C. The arduino hardware is is typically, but not always, a member of the ATMega family, most commonly the ATMega328. There is nothing "special" about this microcontroller simply because it's classified as an Arduino processor. You can write assembly for it, if that's what you choose. Or C. Or anything else you can find a compiler for.But now that you've mentioned software, the arduino hand-holding software libraries are entirely optional. You don't have to use them. If you want to talk directly to ports instead of using library routines, just do it. Nothing special about it, other than you may have to know more about the hardware you're using. Ditto for the arduino IDE; you don't have to use it. And once you're talking directly with hardware, C and assembly are comparable in efficiency. Including for interrupt handlers.But yes, many aspects of the arduino IDE and libraries suck. For beginners and anyone who isn't pushing the limits that doesn't matter. That's why it's as successful as it is; because it works for simple projects.

author: spec
author_rank: Frequent Contributor
timestamp: December 02, 2018, 02:26:51 am
content: Quote from: Peabody on December 01, 2018, 06:22:19 pmIt is advisable with fast responding lights to refresh not less than 60Hz to avoid viewer distress.Just in case: the eyes response is logarithmic so you can reduce the average power of a LED without a corresponding impression of less brightness.I would suggest that you do a feasibility test with just one segment and a signal generator or 555 or MCU generating the pulse. That way you will see the effect. By the way, it would be best to pass the maximum specified current through each segment to maximize the light output.I would be surprised, with just 14 segments, if there was a problem.

author: Kasper
author_rank: Frequent Contributor
timestamp: December 02, 2018, 03:03:37 am
content: Have you tried using a resistor on the cathode instead of on each segment with normal multiplexing? That would probably make '1' brighter than '8' but if you give a shorter pulse for '1' than for '8', you could dim '1' to be more similar to '8'. Haven't tried this myself, just an idea.

author: Peabody
author_rank: Super Contributor
timestamp: December 02, 2018, 05:27:02 am
content: Ok, I worked up a quick and dirty test using the MSP430 controller. I just did one segment, and confirmed with my scope that it was ON 1/14 of the time - 2ms out of 28ms. I found that it was plenty bright enough using a 470 ohm resistor. It was even acceptable using a 1K, but I prefer the brighter look. There is no discernable flicker at all.So I consider this to be a complete success. And the current draw will be a constant 7ma, or an average of 0.5ma per segment. Not bad at all. I kinda suspect that this worked out as well as it did mainly because of the fancy Vishay TDSR1350 7-segment display. Looking at the datasheet, it is indeed a low current part. A more normal display might not do so well, but I think pretty much anything would work with the right resistor. I was particularly pleased with the lack of flicker. The persistence of human vision works to our advantage.So in the full version, I'll have the seven segments of both digits directly connected to I/O pins, with no resistors, and the two common anode pins connected to I/O pins through 470 ohm resistors. That's a reduction from 9 resistors and 2 transistors to 2 resistors and no transistors. Not bad.If I get time tomorrow, I'll see what would happen if it were four digits multiplexed the same way, with each segment ON 2ms out of 56ms.

author: ogden
author_rank: Super Contributor
timestamp: December 02, 2018, 09:36:43 am
content: Quote from: Peabody on December 02, 2018, 05:27:02 am7 resistors and 2 transistors are way cheaper than pins of microcontroller you literally waste. Also as already noted - if you really have enough pins to connect every segment, then don't multiplex.QuoteBetter shift your focus of innovation into another area and stop inventing ineffective wheels.

author: Peabody
author_rank: Super Contributor
timestamp: December 02, 2018, 02:15:47 pm
content: Quote from: ogden on December 02, 2018, 09:36:43 amI didn't say that clearly enough. I'm only using 7 pins for the segments. The respective segments of both digits are connected to the same pins. The digit is selected via the common cathod or anode. So I'm using a total of 9 pins to drive two digits.

author: Peabody
author_rank: Super Contributor
timestamp: December 02, 2018, 02:24:32 pm
content: Quote from: Peabody on December 02, 2018, 05:27:02 amI did further testing and found that this doesnt work for three digits or four digits, at least at the 2ms ON time. Both produced substantial flicker.I also tested 1/16 in case the decimal point is needed, and found a hint of flicker there as well. So it appears that two digits of seven segments each (1 of14 segments at a time) is right at the edge of what works at 2ms ON time.

author: Nusa
author_rank: Super Contributor
timestamp: December 02, 2018, 03:20:43 pm
content: Flicker fusion sensitivity is going to vary among humans, so you may or may not be a good measure of the average human. Fatigue is a factor, so the well-rested are more sensitive. Metabolic rate is a factor, so the young are more sensitive. Rods are much more sensitive than cones, so peripheral vision is more sensitive. Also, flicker is easier to detect in brighter displays.I'd aim for 30 Hz as a minimum refresh rate. Higher would be better.

author: ogden
author_rank: Super Contributor
timestamp: December 02, 2018, 04:31:29 pm
content: Quote from: Peabody on December 02, 2018, 02:15:47 pmWell, then you need 2:7multiplexscan, not 1:14. If this is too difficult task for you to code, then you shall reconsider your occupation

author: Peabody
author_rank: Super Contributor
timestamp: December 02, 2018, 04:59:26 pm
content: Quote from: ogden on December 02, 2018, 04:31:29 pmI don't understand your comment. The whole point of this exercise was to see if I could multiplex one *SEGMENT* at a time, not one digit at a time. So I am NOT doing 2:7 multiplexing. Two digits have a total of 14 segments, and I'm cycling through them one at a time - the individual segments of the first digit followed by the individual segments of the second digit, one segment at a time. So every digit is turned on 1/14 of the total time. This isn't too difficult for me to code. And by the way, saying "kidding" doesn't make it any less insulting.

author: Nusa
author_rank: Super Contributor
timestamp: December 02, 2018, 05:23:44 pm
content: Quote from: Peabody on December 02, 2018, 04:59:26 pmPerceived insult aside, the guy had a point even if you missed it. Since you have independent control of the anode/cathode (whichever it was) lines, you can probably update the same segment on both digits at the same time. Current limits of the segment pins permitting.

author: ogden
author_rank: Super Contributor
timestamp: December 02, 2018, 05:45:32 pm
content: Quote from: Peabody on December 02, 2018, 04:59:26 pmYes, do *segment* at a time, but for *both* digits at the same time - so you scan all the segments of all digits in 7 steps, not 14. Also transistors are not that necessary, I/O's of msp430 are more than capable.QuoteSensitive?Sorry then.

author: Peabody
author_rank: Super Contributor
timestamp: December 02, 2018, 05:46:52 pm
content: Further testing has shown that if I increase the interrupt rate from 500 Hz to 1KHz, which reduces the ON period from 2ms to 1ms, I can do four digits (1/28) with no blinking detectable by me. But of course it's not as bright since each segment is only ON 1/28 of the time instead of 1/14. Reducing the resistor value can restore brightness - up to a point.So basically this just maintains the blink rate at about 35Hz for four digits, which as others have said appears to be the controlling factor for flicker regardless of how long the blink actually lasts. Well I'm sure there's a limit to that at some point, but as the ON time gets shorter, the eye interprets this primarily as just less bright so long as the frequency remains the same.The bottom line for all of this appears to be that if you fire one segment at a time, you don't need resistors on all the segment lines, and you don't need transistors or base resistors on the common anode/cathode lines. You just need one resistor on each common anode/cathode line. And if you have flexibility as to the refresh frequency, you can make this work for four digits or more without flicker and without any power consumption penalty versus multiplexing one entire digit at a time.The coding is only a little more complicated. You would still load the segment lines' I/O port OUT register with the segment pattern to be displayed, and set the common anode/cathode pin for that digit, but then just shift a bit in the port's DIRECTION register to the left on each interrupt. Then do the other digit the same way.Thanks very much for everyone's comments and suggestions.

author: Peabody
author_rank: Super Contributor
timestamp: December 02, 2018, 05:57:24 pm
content: Quote from: Nusa on December 02, 2018, 05:23:44 pmI'm still missing it.If the top segment on one digit is supposed to be ON, but the same segment on the other digit is supposed to be OFF, I don't see how I can update both at the same time if both are connected to the same I/O pin. I only have seven I/O pins for the segments.Could you please explain it again?

author: Peabody
author_rank: Super Contributor
timestamp: December 02, 2018, 06:05:19 pm
content: Quote from: ogden on December 02, 2018, 05:45:32 pmAs I just said to Nusa, I don't see how I can do what you're suggesting if the segments on the two digits are connected to the same I/O pin. Perhaps you could explain how I would do that.Sensitive? Perhaps. But I would just never say what you said to anyone, kidding or not. And by the way, it's not my occupation.

author: Nusa
author_rank: Super Contributor
timestamp: December 02, 2018, 06:09:28 pm
content: Defining ON as whichever state for each pin is required to light the segment. OFF as either the other state or tri-state, as appropriate.Segment A ON, Anode 1 ON, Anode 2 ON = segment A lit on both digits.Segment A ON, Anode 1 OFF, Anode 2 ON = segment A lit on digit 2 onlySegment A ON, Anode 1 ON, Anode 2 OFF = segment A lit on digit 1 onlySegment A ON, Anode 1 OFF, Anode 2 OFF = segment A off on both digits.Four possibilities for each cycle. Get it now?

author: Peabody
author_rank: Super Contributor
timestamp: December 02, 2018, 06:23:24 pm
content: Quote from: Nusa on December 02, 2018, 06:09:28 pmYes. I do. Thanks for spelling it out for me. Sorry to be so dense. The coding would be more complicated, but it would indeed update both at the same time. It's kinda like charlieplexing in a way.Thanks very much.

author: ogden
author_rank: Super Contributor
timestamp: December 02, 2018, 06:32:34 pm
content: Quote from: Peabody on December 02, 2018, 06:05:19 pmOk. I'll try to explain. Default/off state of two anode pins is '1' and 7 cathode pins '0'. You just loop through all the segments by setting according anode pin to '1. After anode pin set done, you check if digit "A" segment needs to be lit - if yes, then you change it's cathode pin state to '0 otherwise set it '1'. You do the same with cathode pin of digit "B" as well. Same logic for more than twosegmentsdigits. Dunno if it explains or not - but be my guest anyway.

author: Peabody
author_rank: Super Contributor
timestamp: December 02, 2018, 08:02:54 pm
content: Yes, I understand now. Thanks very much. And this method has the advantage that you can have any number of digits without changing the timing or inducing flicker. And still only one resistor per common A or C pin. So yes, this is better. I guess it should have been obvious, but it wasn't.

author: Nusa
author_rank: Super Contributor
timestamp: December 02, 2018, 10:00:14 pm
content: Quote from: Peabody on December 02, 2018, 08:02:54 pmThe number of digits would be limited by how much current your segment pins can sink/source (usually they can sink more than they can source) with the resistor value chosen for the anodes/cathodes. And of course by how many pins are available to use.

author: Peabody
author_rank: Super Contributor
timestamp: December 02, 2018, 11:46:37 pm
content: Quote from: Nusa on December 02, 2018, 10:00:14 pmYes, I guess that's right. Anything above maybe four digits might run up against current limits on the segment driver pins. So no free lunch.It's amazing to me that neither my version nor the odgen/Nusa version of segment multiplexing appears anywhere on Youtube, or anywhere else that I can find. I may not be searching for the right thing, but everything I see on multiplexing 7-segment displays switches one full digit at a time, either directly from the MCU with all the resistors and transistors, or through various decoders or shift registers. I think Dave should do a video on this. :-)

author: Nusa
author_rank: Super Contributor
timestamp: December 03, 2018, 03:10:31 am
content: Search for "Led matrix multiplexing" for the concepts.7-segment digits are just a bunch of LED's with one of the matrix dimensions enforced in the package.You can do the same thing for input with a switch matrix.

author: Peabody
author_rank: Super Contributor
timestamp: December 07, 2018, 07:01:29 am
content: I finished coding this for the TI MSP430G2452 and breadboarded the circuit for testing, and it works well. I used the ogden-Nusa method of multiplexing two segments at a time. With a 488 Hz (2ms) interrupt rate, that makes the refresh rate about 70 Hz, which is more than enough to prevent any flicker.So as described earlier, I have no resistors on the segment lines, and a 470 ohm resistor on each common cathode line. Using Vishay's TDSR1360 displays produces bright segments, but at 3.3V and the displays reading "88", current is only 2.5ma per common cathode line, or 5ma in total to drive the displays, which I think is quite good. The Vishay displays appear to be very high efficiency red. I tried using old normal displays, and they are considerably less bright.I was going to enable each segment line via the direction register, but that would have left all the unselected pins floating, and enabling pullups might cause problems. So in the end I just left all the segment pins as outputs, with all but one being low at any time, which was no more difficult to code.I was planning for the code to determine whether the displays are CA or CC, so that one software version would support both automatically. But I couln't figure out a way to do that without adding hardware.

author: ogden
author_rank: Super Contributor
timestamp: December 07, 2018, 12:28:12 pm
content: Quote from: Peabody on December 07, 2018, 07:01:29 amCongrats! Also thank you for update - it is always good to know final results.QuoteRight. It would be easy if voltage drop of indicator LED's would be <=0.5V or so, but it is not. You can try this (not verified) idea: Take one segment pin with ADC input capabilities (from port P1), configure it as input with pull-up and enable ADC operation on this pin as well. Set common pin to '1' and measure voltage, set to '0' and measure again. If voltage follows common pin state - you got common cathode. If it's state does not follow then you either decide that indicator is common anode or faulty. You may repeat with pull-down to be sure that you got common cathode.  I am never used ADC on input with pull-up/down enabled, but IMHO it shall work according to Port1 schematics in DS.

author: Peabody
author_rank: Super Contributor
timestamp: December 07, 2018, 04:37:46 pm
content: Quote from: ogden on December 07, 2018, 12:28:12 pmYes, I think that would probably work for the TI chips, but this will probably end up on an Atmel, or maybe even something else, so I'd like to keep the logic as general as possible at this point. But I may take another look at this idea when it gets to its final home.

author: Nusa
author_rank: Super Contributor
timestamp: December 07, 2018, 07:56:24 pm
content: Other ideas that come to mind:If you have a spare input it's easy: solder pad configuration. Resistor pads if you want pick-and-place friendly. Install/omit 0-ohm resistor as required.User/Factory configurable EEPROM flag by some scheme such as holding down the switch during power-up (easy, but appears broken if done by accident) or shorting the two digit common pins together (unlikely to be an accident) during power-up.Of course, unless you replace LED's or upgrade software in the field, software configuration with two compiled versions of the binary works well too.

author: Peabody
author_rank: Super Contributor
timestamp: December 16, 2018, 08:03:14 pm
content: I continue to find no written description or videos on this multiplex-by-segment ("MBS") system, and I think I will make a video on it because it is (what Auzzie-ism would Dave use?) really neat.If all lines are driven by the MCU, MBS doesn't reduce the total number of lines required. Its advantage is the elimination of the seven resistors on the segment driver lines, and the transistors on the CC or CA driver lines, needed in a multiplex-by-digit system.But if available GPIO pins are in short supply, either system may need to use an additional chip to fan out to the seven segments from a small number of GPIO outputs. Since MBS simply cycles through each of the segment lines one at a time, turning it ON no matter what is being displayed, the options for the decoder chip are expanded.A 74xx138 3-to-8 decoder would work, but would require three GPIOs. However an 8-bit shift register would also work, and since we don't need the latching feature of the HC595, an HC164 could be used, which would require only two pins - data and clock. It would be initialized at power-up by clocking in eight zeros, so a Clear pin driver wouldn't be needed.For common cathode displays, the most interesting option I've found is the ancient and lowly CD4017 decade counter with decoded outputs. Of course the HC version would be used, but this simply turns on one of 10 outputs on each clock cycle, which is exactly what's needed. This would also require two GPIO pins - clock and reset (active high). It has 10 outputs, but after 7 clocks (8 if using the decimal point), you would toggle the reset line instead of the clock, and that would leave the 0 output high, all others low.Then I wondered if you could get away with just using the clock line. Using outputs 0 through 6 for the segments, you could wire the 7 output to the reset pin, which would reset the chip and leave the 0 output high. But that leaves the problem of the power-on state of the 4017, which I believe is unpredictable. There would need to be a way to generate an active high reset when Vcc comes up, or a way to read the current value of the 0 output without dedicating a GPIO pin to do that. Well, I'm still working on that, but if you could reduce the 7 GPIO segment pins to 1, Bob would definitely be your uncle.Edit: I think the answer for single-pin driving of the HC4017 is to use the 4017's /CE pin as the falling-edge clock pin connected to the GPIO pin of the MCU, and connect a high-value resistor from that pin to the 0 output pin. Then you switch the GPIO pin between doing a HI/LO clock cycle in output mode and reading the pin in input mode, and stopping when the 0 output reads Hi. When that happens, set the output bit Hi to match what's already on the pin, then change direction to output. That prevents an unwanted clock tick from occurring. Something like 220K if that's not too much for driving the floating GPIO pin in input mode. You just want the largest resistor that still works reliably. Uncle Bob.

author: Peabody
author_rank: Super Contributor
timestamp: December 17, 2018, 06:16:24 am
content: Following up on using the HC4017, attached is a schematic that I think will work. It's for common cathode only.For two 7-segment digits, a total of three GPIO pins are used. Each additional digit would each require another GPIO pin and resistor. The number of digits is limited by the output drive of the HC4017. If I read the datasheet correctly, an output can source up to 25ma. That should be enough for 4-6 digits, depending on how efficient they are.

author: Peabody
author_rank: Super Contributor
timestamp: January 17, 2019, 04:18:31 am
content: As threatened, I've made a video on this "by-segment" method of multiplexing 7-segment displays. It's posted on my local OSH group's Youtube channel. About 13 minutes. Credit to ogden and Nusa at the end of the video.There's also a Github repo with Arduino Nano sketches illustrating coding methods.https://github.com/gbhug5a/7-Segment-Displays-Multiplex-by-SegmentFor the version using the 74HC4017 to drive the segment lines, I ended up clocking on the Clock pin, which is rising edge. Pic attached.As previously discussed here, the main point of this method is to eliminate the seven resistors on the segment lines and the transistors on the CA or CC lines, so that only a single resistor on each CA/CC line is needed. In addition, when using the 74HC4017, the total number of processor port pins needed to drive the displays is reduced to three for a two-digit display, and in general the number of port pins equals the number of digits, plus one. The 4017 option works for common cathode only.Thanks for everyone's help with this, particularly ogen and Nusa.