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.

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

  1. 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

      1. 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

        1. 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

  2. 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

  3. 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

    1. 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

  4. 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

    1. Hi Tom,

      I guess it is just a matter of figuring out whether the zero is a leading zero and then writing 0x00 for this digit (e.g. on this line: https://github.com/moozzyk/TM1637Clock/blob/6e7f75b72f74eb2f7cd36fd86b4eb80250bc8dac/TM1637Clock/TM1637Clock.ino#L79). Currently the value of 0x3f is sent for all zeros which results in displaying `0` on the display. If you change the logic to send 0x00 for leading zeros and 0x3f for non-leading zeros the leading zeros will be blanked.

      Thanks,
      Pawel

      Like

Leave a reply to Tom umble Cancel reply