Arduino and the TM1637 4-digit seven-segment display

In one of my Arduino projects I needed to show some numbers. Luckily, a 4 digit display lain around on my desk. Because it had a built-in driver which would save me from all the hassle with shift registers it looked like a perfect fit. I checked the chip the display was using and it was labeled “TM1637”. I was already familiar with the TM1638 (for more details see my recent post about using a TM1638 based board with Arduino) chip so I thought making the TM1637 work should be easy. Unfortunately, while there are some similarities between the chips getting the TM1637 to work took me longer than I had expected. When I finally aligned all the moving pieces I decided to create a standalone sample which will hopefully be helpful to other people playing with TM1637 based displays. To make the sample a good demo I just took my Nokia LCD clock sample, replaced the Nokia LCD display with the TM1637 display and updated the code accordingly and ended up with a TM1637 clock:

TM1637 clock

TM1637 clock


Let’s get started from taking a closer look at the TM1637 display. The TM1637 display has four pins VCC, GND, DIO, CLK. Similarly to the TM1638 the TM1637 uses a protocol to communicate with the display. While commands themselves are very similar to the ones used by the TM1638 board sending the data is a little different. The display does not have the STB pin the TM1638 board had so separating commands and arguments works differently. A start signal needs to be sent before sending a command to the display. Once the command has been sent a stop signal needs to be used. If a command has arguments another start signal needs to be sent and then after all arguments have been sent the stop signal needs to be used. The start signal is just setting the CLK and DIO pins to HIGH and then setting them to LOW. The stop signal is setting the CLK and DIO pins to LOW and then to HIGH. The CLK pin should not change the state more frequently than 250kHz so I added a little delay between state changes. Here is how my corresponding start and stop functions look like:

void start(void) 
{ 
    digitalWrite(clock,HIGH);//send start signal to TM1637 
    digitalWrite(data,HIGH); 
    delayMicroseconds(5); 
 
    digitalWrite(data,LOW); 
    digitalWrite(clock,LOW); 
    delayMicroseconds(5); 
} 
 
void stop(void) 
{ 
    digitalWrite(clock,LOW); 
    digitalWrite(data,LOW); 
    delayMicroseconds(5); 

    digitalWrite(clock,HIGH); 
    digitalWrite(data,HIGH); 
    delayMicroseconds(5); 
} 

The display has three commands:

  • initialize the display and set brightness
  • display value at a given position
  • display values starting from a given position

The first command just initializes the display and sets the brightness. This is done by sending the %1000abbb value where the a bit activates (if set to 1) or deactivates (if set to 0) the display and the bbb bits control the brightness (with 000 being the darkest and 111 being the brightest).
The second command allows controlling a single digit of the display. It requires sending 3 bytes to the display: 0x44 %110000aa X where the aa bits in the second byte are used to select the position of the digit to control while X is the value to be displayed encoded in the standard 7 segment coding (as explained here).
Finally, the last command is used to control multiple digits and can consists of up to 6 bytes. Typically you want use all the digits in which case you send the following bytes to the display – 0x40 0xC0 W X Y Z. The first byte is the command identifier the second byte tells the display to start at the first position and W X Y Z are the values to be displayed on subsequent positions (again in the standard 7 segment encoding).
Here are is a short summary of commands:

START (0x88|%00000aaa) STOP initialize and set the brightness
START 0x44 STOP START (0xC0|%000000aa) X STOP display value X at position %000000aa
START 0x40 STOP START 0xC0 W X Y Z STOP display values W X Y Z starting from position 0

When sending data to the display timing is the tricky part. Apparently (if I understood the machine translation of the data sheet which is in Chinese correctly), the CLK pin should not change the state more frequently than 250kHz. This means that I could not use the Arduino shiftOut function because it does not allow to provide the delay after setting the DIO pin. Instead I had to come up with my own function (I called it writeValue) that emulates the shiftOut function but which uses a delay after setting the DIO pin. (Yes, it did made me think that my other projects may have some kind of issue due to writing data too fast but, hey, they worked!). Another thing is that the chip is acknowledging it received data successfully by setting the DIO pin to HIGH after each byte of data has been written. I have never seen it fail and am not even sure what I would be supposed to do if it did. Probably in my little projects this does not matter too much – I am constantly writing to the display so I hope that a subsequent write will succeed and therefore even though the writeValue function returns a result I am ignoring it. The writeValue function looks as follows:

bool writeValue(uint8_t value) 
{ 
    for(uint8_t i = 0; i < 8; i++) 
    { 
        digitalWrite(clock, LOW); 
        delayMicroseconds(5); 
        digitalWrite(data, (value & (1 << i)) >> i); 
        delayMicroseconds(5); 
        digitalWrite(clock, HIGH); 
        delayMicroseconds(5); 
    } 
 
    // wait for ACK 
    digitalWrite(clock,LOW); 
    delayMicroseconds(5); 
 
    pinMode(data,INPUT); 
 
    digitalWrite(clock,HIGH); 
    delayMicroseconds(5); 
 
    bool ack = digitalRead(data) == 0; 
    
    pinMode(data,OUTPUT); 

    return ack; 
}

Based on this information I created a TM1637 clock as shown on the photo above. I connected a TM1637 display to Arduino as follows:

Arduino              TM1637 display
PIN #7 ------------------ CLK
PIN #8 ------------------ DIO
3.3V   ------------------ VCC
GND    ------------------ GND

The code is on github - clone it and try for yourself.

Advertisement

12 thoughts on “Arduino and the TM1637 4-digit seven-segment display

  1. […] showing other people that I am busy. Meeting the first requirement was quite simple – a TM1637 based 4-digit LED display seemed good enough for the job. The second one was a bit harder. I got a little creative and bought […]

    Like

  2. […] I found this blog that explained what was needed. Most of the other tutorials used a number of libraries […]

    Like

  3. Vendicar Decarian says:

    Do you ever see an ACK being reported from the TM1637?

    For some reason the one I have doesn’t appear to be able to return data to the Host controller.

    Like

    • moozzyk says:

      It’s been a while but AFAIR ACK always worked for me.

      Like

      • Vendicar Decarian says:

        I’m reasonable noobie when it comes to the hardware side of things, and I tend to strive to understand things pretty completely. At least to explain away the anomalies.

        It turns out that on this TM1637 board I have – nicely constructed I must say), tracing the Clk and Data lines back to the chip they are tied to ground with some capacitors.

        From the wave forms on the scope and my memory that the Arduino pull up resistors on the outputs are 10K, the caps would be somewhere around 2 microFarad. They are surface mount and hence not marked.

        I presume they are there to reduce noise. But they put a good practice limit (using square waves that are actually square) – of about 16k hz.

        At least for these cards.

        Something you might want to note in your documentation.

        Liked by 1 person

        • moozzyk says:

          That’s a really in-depth analysis! Good job! If someone is hitting this I am pretty sure they will find your comment (and can comment on their own).

          Thanks,
          Pawel

          Like

  4. I need to build a jumbo sized seven segment display of 3 digits x 6″ height. I am using a TM1637 and I need to understand one small detail.

    The grid 1 – grid 3 pins are used to select the digit. I have connected a PNP transistor between the three digits and the power supply (+24v dc),

    I have connected a NPN transistor between the 7 segments and pins A – F of the TM1637.

    Is this correct ?

    I am unable to post my schematic. Can you please help ?

    Like

  5. I need to build a jumbo sized seven segment display of 3 digits x 6″ height. I am using a TM1637 and I need to understand one small detail.

    The grid 1 – grid 3 pins are used to select the digit. I have connected a PNP transistor between the three digits and the power supply (+24v dc) and common Anode of the LED display.

    I have connected a NPN transistor between the 7 segments and pins A – F of the TM1637.

    Is this correct ?

    I am unable to post my schematic. Can you please help ?

    Like

    • moozzyk says:

      I don’t know. Sorry!

      Like

    • Klavs Rommedahl says:

      The TM1637 supports only Common Anode displays. So when a Digit is selected the GRID pin is tight to 5V. I would guess Your PNP transistor would close completely. Use a NPN instead. The SEG pins will pull Your NPN bases to GND, and Thus close the NPN, so here I would go for a PNP.

      Like

  6. Tom umble says:

    Pawel , I don’t know if you still service this blog or not, but if so, could you give a short explanation on how to implement “leading zero blanking with the TM1637? Thank you for your fine work, most helpful. Tom

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: