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:
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.
[…] 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 […]
LikeLike
[…] I found this blog that explained what was needed. Most of the other tutorials used a number of libraries […]
LikeLike
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.
LikeLike
It’s been a while but AFAIR ACK always worked for me.
LikeLike
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.
LikeLiked by 1 person
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
LikeLike
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 ?
LikeLike
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 ?
LikeLike
I don’t know. Sorry!
LikeLike
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.
LikeLike
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
LikeLike
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
LikeLike