Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for 4-digit TM1637 display #51

Open
thijstriemstra opened this issue Jan 15, 2017 · 10 comments
Open

Support for 4-digit TM1637 display #51

thijstriemstra opened this issue Jan 15, 2017 · 10 comments

Comments

@thijstriemstra
Copy link
Collaborator

Recently got one of these 4 Bits TM1637 Digital Tube LED Clock displays. Would be cool to support this in luma.led_matrix.

@thijstriemstra
Copy link
Collaborator Author

I've ordered one for you @rm-hull if you want to play around with it.

@twdkeule
Copy link
Collaborator

twdkeule commented Jan 19, 2017

I already encountered this while looking to buy one: raspberrytips.nl

Also found this on github

@thijstriemstra
Copy link
Collaborator Author

Ok. It uses wiringPi2. Thanks for info though.

@rm-hull
Copy link
Owner

rm-hull commented Feb 14, 2017

@thijstriemstra - Package arrived today

@thijstriemstra
Copy link
Collaborator Author

thijstriemstra commented Feb 15, 2017

Yay nice :) @rm-hull any luck getting it to work?

@rm-hull rm-hull changed the title Support for 4-digit display Support for 4-digit TM1637 display Mar 4, 2017
@rm-hull
Copy link
Owner

rm-hull commented Mar 4, 2017

I connected this up, but not getting anything displayed (connected to an RPi Zero) using the scripts from https://raspberrytips.nl/tm1637-4-digit-led-display-raspberry-pi/

Not sure if it's a dud or something specific to the pi zero.

@thijstriemstra
Copy link
Collaborator Author

Here's an arduino reference library with a wiring table: https://github.com/bremme/arduino-tm1637

Hardware setup

TM1637 PIN Arduino PIN Description
CLK Any digital pin Clock
DIO Any digital pin Digital output
VCC 5V Supply voltage
GND GND Ground

And using https://github.com/johnlr/raspberrypi-tm1637 I couldn't get it to work with CLK on gpio 21 and DIO on 20.

@thijstriemstra
Copy link
Collaborator Author

@thijstriemstra
Copy link
Collaborator Author

thijstriemstra commented Mar 14, 2017

Also couldn't get https://raspberrytips.nl/tm1637-4-digit-led-display-raspberry-pi/ to work. @twdkeule did you get it to work?

@thijstriemstra
Copy link
Collaborator Author

thijstriemstra commented Oct 18, 2020

any chance we can resurrect this @rm-hull? :) one of my most used projects uses this display and it feels weird to use a 'third-party' library for this, I'd love to use luma for this.

Update: I thought I was using a library but turns out it's some code I copy/pasted from somewhere, don't remember where. Anyway, here it is:

import math
import logging
import threading
from time import sleep, localtime

from ..utils import GPIO as IO


logger = logging.getLogger(__name__)

HexDigits = [0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F,
            0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71, 0x3D, 0x76,
            0x06, 0x1E, 0x76, 0x38, 0x55, 0x54, 0x3F, 0x73, 0x67,
            0x50, 0x6D, 0x78, 0x3E, 0x1C, 0x2A, 0x76, 0x6E, 0x5B,
            0x00, 0x40, 0x63, 0xFF]

ADDR_AUTO = 0x40
ADDR_FIXED = 0x44
STARTADDR = 0xC0
# DEBUG = False


class TM1637:
    """
    TM1637is a kind of LED (light-emitting diodedisplay) drive control special
    circuit with keyboard scan interface and it's internally integrated with
    MCU digital interface, data latch, LED high pressure drive and keyboard
    scan. Mainly used in small household electrical appliances.
    """
    __doublePoint = False
    __Clkpin = 0
    __Datapin = 0
    __brightness = 1.0  # default to max brightness
    __currentData = [0, 0, 0, 0]

    def __init__(self, CLK, DIO, brightness):
        self.__Clkpin = CLK
        self.__Datapin = DIO
        self.__brightness = brightness
        IO.setup(self.__Clkpin, IO.OUT)
        IO.setup(self.__Datapin, IO.OUT)

    def cleanup(self):
        """Stop updating clock, turn off display, and cleanup GPIO"""
        self.StopClock()
        self.Clear()
        IO.cleanup()

    def Clear(self):
        b = self.__brightness
        point = self.__doublePoint
        self.__brightness = 0
        self.__doublePoint = False
        data = [0x7F, 0x7F, 0x7F, 0x7F]
        self.Show(data)
        # Restore previous settings:
        self.__brightness = b
        self.__doublePoint = point

    def ShowInt(self, i):
        s = str(i)
        self.Clear()
        for i in range(0, len(s)):
            self.Show1(i, int(s[i]))

    def Show(self, data):
        for i in range(0, 4):
            self.__currentData[i] = data[i]

        self.start()
        self.writeByte(ADDR_AUTO)
        self.br()
        self.writeByte(STARTADDR)
        for i in range(0, 4):
            self.writeByte(self.coding(data[i]))
        self.br()
        self.writeByte(0x88 + int(self.__brightness))
        self.stop()

    def Show1(self, DigitNumber, data):
        """show one Digit (number 0...3)"""
        if(DigitNumber < 0 or DigitNumber > 3):
            return  # error

        self.__currentData[DigitNumber] = data

        self.start()
        self.writeByte(ADDR_FIXED)
        self.br()
        self.writeByte(STARTADDR | DigitNumber)
        self.writeByte(self.coding(data))
        self.br()
        self.writeByte(0x88 + int(self.__brightness))
        self.stop()

    # Scrolls any integer n (can be more than 4 digits) from right to left display.
    def ShowScroll(self, n):
        n_str = str(n)
        k = len(n_str)

        for i in range(0, k + 4):
            if (i < k):
                self.Show([int(n_str[i-3]) if i-3 >= 0 else None, int(n_str[i-2]) if i-2 >= 0 else None, int(n_str[i-1]) if i-1 >= 0 else None, int(n_str[i]) if i >= 0 else None])
            elif (i >= k):
                self.Show([int(n_str[i-3]) if (i-3 < k and i-3 >= 0) else None, int(n_str[i-2]) if (i-2 < k and i-2 >= 0) else None, int(n_str[i-1]) if (i-1 < k and i-1 >= 0) else None, None])
            sleep(1)

    def SetBrightness(self, percent):
        """Accepts percent brightness from 0 - 1"""
        max_brightness = 7.0
        brightness = math.ceil(max_brightness * percent)
        if (brightness < 0):
            brightness = 0
        if(self.__brightness != brightness):
            self.__brightness = brightness
            self.Show(self.__currentData)

    def ShowDoublepoint(self, on):
        """Show or hide double point divider"""
        if(self.__doublePoint != on):
            self.__doublePoint = on
            self.Show(self.__currentData)

    def writeByte(self, data):
        for i in range(0, 8):
            IO.output(self.__Clkpin, IO.LOW)
            if(data & 0x01):
                IO.output(self.__Datapin, IO.HIGH)
            else:
                IO.output(self.__Datapin, IO.LOW)
            data = data >> 1
            IO.output(self.__Clkpin, IO.HIGH)

        # wait for ACK
        IO.output(self.__Clkpin, IO.LOW)
        IO.output(self.__Datapin, IO.HIGH)
        IO.output(self.__Clkpin, IO.HIGH)
        IO.setup(self.__Datapin, IO.IN)

        while(IO.input(self.__Datapin)):
            sleep(0.001)
            if(IO.input(self.__Datapin)):
                IO.setup(self.__Datapin, IO.OUT)
                IO.output(self.__Datapin, IO.LOW)
                IO.setup(self.__Datapin, IO.IN)
        IO.setup(self.__Datapin, IO.OUT)

    def start(self):
        """send start signal to TM1637"""
        IO.output(self.__Clkpin, IO.HIGH)
        IO.output(self.__Datapin, IO.HIGH)
        IO.output(self.__Datapin, IO.LOW)
        IO.output(self.__Clkpin, IO.LOW)

    def stop(self):
        IO.output(self.__Clkpin, IO.LOW)
        IO.output(self.__Datapin, IO.LOW)
        IO.output(self.__Clkpin, IO.HIGH)
        IO.output(self.__Datapin, IO.HIGH)

    def br(self):
        """terse break"""
        self.stop()
        self.start()

    def coding(self, data):
        if(self.__doublePoint):
            pointData = 0x80
        else:
            pointData = 0

        if(data == 0x7F or data is None):
            data = 0
        else:
            data = HexDigits[data] + pointData
        return data

    def clock(self, military_time):
        """Clock script modified from:
            https://github.com/johnlr/raspberrypi-tm1637"""
        self.ShowDoublepoint(True)
        while (not self.__stop_event.is_set()):
            t = localtime()
            hour = t.tm_hour
            if not military_time:
                hour = 12 if (t.tm_hour % 12) == 0 else t.tm_hour % 12
            d0 = hour // 10 if hour // 10 else 36
            d1 = hour % 10
            d2 = t.tm_min // 10
            d3 = t.tm_min % 10
            digits = [d0, d1, d2, d3]
            self.Show(digits)
            # # Optional visual feedback of running alarm:
            # print digits
            # for i in tqdm(range(60 - t.tm_sec)):
            for i in range(60 - t.tm_sec):
                if (not self.__stop_event.is_set()):
                    sleep(1)

    def StartClock(self, military_time=True):
        # Stop event based on: http://stackoverflow.com/a/6524542/3219667
        self.__stop_event = threading.Event()
        self.__clock_thread = threading.Thread(
            target=self.clock, args=(military_time,))
        self.__clock_thread.start()

    def StopClock(self):
        try:
            logger.info('Attempting to stop live clock')
            self.__stop_event.set()
        except:
            logger.info('No clock to close')


class TM1637Display(object):
    """
    """
    display = None
    msg = None

    def __init__(self, clk_pin, dio_pin, brightness=1.0):
        self.clk_pin = clk_pin
        self.dio_pin = dio_pin
        self.brightness = brightness

        if IO:
            self.display = TM1637(
                CLK=self.clk_pin,
                DIO=self.dio_pin,
                brightness=self.brightness
            )
            self.clear()

    def clear(self):
        if IO:
            self.display.Clear()

    def setBrightness(self, brightness):
        if IO:
            self.display.SetBrightness(brightness)

    def write(self, msg):
        if IO:
            if msg != self.msg:
                self.msg = msg
                self.clear()
                start_pos = 0
                if len(msg) == 2:
                    start_pos = 1
                for index, ch in enumerate(msg):
                    self.display.Show1(start_pos + index, int(ch))

    def startup(self):
        if IO:
            self.setBrightness(0)
            self.write('0000')

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants