gpiozero / gpiozero

A simple interface to GPIO devices with Raspberry Pi
https://gpiozero.readthedocs.io/
Other
1.94k stars 305 forks source link

7 seg displays #485

Closed martinohanlon closed 8 years ago

martinohanlon commented 8 years ago

Im going to be using a 7 seg display in an upcoming project, so I thought it was time it was added to gpiozero, can I get some comments on my thinking so far:

Next step would be to create a multi digit 7 segment display. The way these work (generally) is that in addition to the 8 pins for the display they have additional pins to state which digit should be turned on. To make each digit show a different number you would use plexing to flash individual digits to give the appearance of a multi digit display.

lurch commented 8 years ago

See also #357 I haven't got round to looking through the sample code posted there myself yet.

martinohanlon commented 8 years ago

Thanks, I did a search for 'seg' on the issues too and didnt find any.

bennuttall commented 8 years ago

7SegmentDisplay is not a valid class name in Python, and 7seg is not a valid object name :P

I'm not sure about seg.value = "a" because .value should be boolean or float to be compatible with the rest of the library.

Other than that, sounds good. Do various 7seg displays tend to work the same way?

lurch commented 8 years ago

I'm not sure about seg.value = "a" because .value should be boolean or float to be compatible with the rest of the library.

Yeah, that was my gut reaction too - glad to see I wasn't alone ;-) But it then begs the question, how do we map the LEDs illuminated on a 7-segment display (or 8-segment if it also contains a decimal-point) to a single .value between 0 and 1 (or -1 and +1)? There doesn't seem to be any obvious solution... The only thing I can think of is to treat the 8-segments as elements of a bit-field, and than divide by 256.0 to get a floating-point value (so all segments off would be 0.0; all segments on would be 1.0; and segments 'a' and 'c' turned on would be ((2**0 + 2**2) / 256.0) = ((1 + 4) / 256.0) = 0.01953125). So we could then do seg2.source = seg1.values, and it'd work as expected, provided seg1 and seg2 were initialised with their segments in the same order.

But to maintain ease-of-use, we'd also want some kind of .character property, where you could do seg.character = 3 (with the int automatically being converted to str) or seg.character = "A". Or perhaps seg.number = 3 and seg.hexnumber = 0xa? shrug

P.S. Another approach would be to treat SevenSegmentDisplay as a CompositeOutputDevice subclass, and have .value be a tuple of bools (so my earlier segments a and c example would be (False, False, False, False, False, True, False, True)). double shrug

martinohanlon commented 8 years ago

I'm not sure about seg.value = "a" because .value should be boolean or float to be compatible with the rest of the library.

Yeah I thought it was a bit weird, one of the reasons I asked for comment. Less weird would be an 8 bit field, represented as 0 - 1.

It should definitely have a 'friendly' method for showing a number/character how about .display?

bennuttall commented 8 years ago

.display would work.

It might make sense to have .value as an n-tuple, like (I assume) LEDCollection already is.

martinohanlon commented 8 years ago

Thought about it a bit:

Inheriting LEDCollection will bring CompositeOutputDevice and value will be a tuple of booleans.

A couple of methods:

which would obviously set the tuple in the .value property

lurch commented 8 years ago

Just having had another look at the docs, I wonder if it would make more sense to just inherit from LEDBoard, rather than LEDCollection? And then add the display and decimal_point methods that you mention. Being a geeky programmer type, I'd love there to be a hexdisplay function too ;-)

I'll try to have a more in-depth look at #357 this evening, while these ideas are fresh in my mind.

dglaude commented 8 years ago

I vote for hex too.

On 17 Oct 2016 17:10, "Andrew Scheller" notifications@github.com wrote:

Just having had another look at the docs http://gpiozero.readthedocs.io/en/v1.3.1/api_boards.html#ledboard, I wonder if it would make more sense to just inherit from LEDBoard, rather than LEDCollection? And then add the display and decimal_point methods that you mention. Being a geeky programmer type, I'd love there to be a hexdisplay function too ;-)

I'll try to have a more in-depth look at #357 https://github.com/RPi-Distro/python-gpiozero/issues/357 this evening, while these ideas are fresh in my mind.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/RPi-Distro/python-gpiozero/issues/485#issuecomment-254236118, or mute the thread https://github.com/notifications/unsubscribe-auth/ASiRnOxKFhG3yehJrxRNx-Bpuy-FKZw4ks5q04__gaJpZM4KYjMj .

martinohanlon commented 8 years ago

First stab in the dark at SevenSegmentDisplay:

It needs a display_hex function.

Some thoughts:

from gpiozero import LEDCollection, LEDBoard
from time import sleep

class SevenSegmentDisplay(LEDBoard):
    layouts = {"1": (False, True, True, False, False, False, False),
        "2": (True, True, False, True, True, False, True),
        "3": (True, True, True, True, False, False, True),
        "4": (False, True, True, False, False, True, True),
        "5": (True, False, True, True, False, True, True),
        "6": (True, False, True, True, True, True, True),
        "7": (True, True, True, False, False, False, False),
        "8": (True, True, True, True, True, True, True),
        "9": (True, True, True, True, False, True, True),
        "0": (True, True, True, True, True, True, False),
        " ": (False, False, False, False, False, False, False),
        "A": (True, True, True, False, True, True, True),
        "B": (True, True, True, True, True, True, True),
        "C": (True, False, False, True, True, True, False),
        "D": (False, True, True, True, True, False, True),
        "E": (True, False, False, True, True, True, True),
        "F": (True, False, False, False, True, True, True),
        "G": (True, False, True, True, True, True, False),
        "H": (False, True, True, False, True, True, True)}

    def __init__(self, *pins, **kwargs):
        # 7 segment displays must have 8 pins
        if len(pins) < 7 or len(pins) > 8:
            raise ValueError('7 segment display must have 7 or 8 pins')
        # Don't allow 7 segments to contain collections
        for pin in pins:
            assert not isinstance(pin, LEDCollection)
        pwm = kwargs.pop('pwm', False)
        active_high = kwargs.pop('active_high', True)
        super(SevenSegmentDisplay, self).__init__(*pins, pwm=pwm, active_high=active_high)

    def display(self, char):
        char = char.upper()
        if char in SevenSegmentDisplay.layouts.keys():
            layout = SevenSegmentDisplay.layouts[char]
            for led in range(0,7):
                self[led].value = layout[led]

    def decimal_point(self, on):
        # does the 7seg display have a decimal point (i.e pin 8)
        if len(self) > 7:
            self[7].value = on
lurch commented 8 years ago

Looking good...

Some comments: (apologies if there's too much here!)

Common anode / cathode is supported by the active_high property, this could be changed to common_cathode to make it more descriptive

For consistency, it should remain as active_high. You could always enhance the active_high docstring to make it clearer, as RGBLED does.

It needs a display_hex function.

That's easy:

    def display_hex(self, hexnumber):
        self.display(hex(hexnumber)[2:])

Should pins be passed in as a, b, c, d, e, f, g...

There's part of me that still wonders if that's the best approach (see my comments in https://github.com/RPi-Distro/python-gpiozero/issues/357#issuecomment-254356623 ) as that way it'd create a namedtuple, so you could do sevenseg.b.on() in addition to sevenseg[1].on()

martinohanlon commented 8 years ago

@lurch Thanks for the comments, they are really useful.

martinohanlon commented 8 years ago

Closing issue, PR #488 submitted.