The TM1637 is a 8 segments led controller which can control up to 6 displays and key scan of 16 inputs.
There are multiple boards but the most common is using 4 displays with two dots in the middle so can be used as a timer display.

The protocol is similar to I2C but is simpler as there is no need of device address.
So the protocol is the following:
- Start Signal
- Command Data Byte
- Optional Data Byte(s)
- End Signal
Start Signal
-
CLKmust beHIGH -
DIOmust transition fromHIGHtoLOW
End Signal
-
CLKmust beHIGH -
DIOmust transition fromLOWtoHIGH
Sending Data
-
DIOmust be set to value whenCLKis low - Send 8 bits, each clock cycle can be at most
2us(maximum speed of500Khz) - After 8 bits the 9th clock cycle the chip will send an ACK setting DIO to
LOW
There are 3 types of commands:
- Data command (write to displays or read key scan)
- Address command (which display to use, it can be up to 6 displays, but the board only contain 4)
-
Display, set displays
ON/OFFand set brightness (8 possible levels)
The Data command allows to send a specific address or auto-increment (the most common scenario) so after setting the initial address it can be sent all the data to write in the displays without need to keep setting the address after each command.
The examples in the datasheet shows that Display commands are sent at the end; but there is no need for that, it can be sent before any Data command to set the configuration; after set, there is no need to be changed (except for some reason the display is reset)
The displays in the board are 8 Segments Displays

Actually are 7 Segments Displays as there is no dot and the two dots in the middle are handled by the second display.
The byte order is: Xgfedcba where X is the dot or DP
Arduino Code
To make work in Arduino, you need 2 pin inputs and three functions:
- Start Transfer
- End Transfer
- Byte Write
void dataTransferStart() {
// according to doc, start must be
// a transition of DIO from LOW to HIGH
// when a CLK clock is HIGH
digitalWrite(PIN_DIO, HIGH);
digitalWrite(PIN_CLK, HIGH);
delayClock();
digitalWrite(PIN_DIO, LOW);
delayClock();
digitalWrite(PIN_CLK, LOW);
delayClock();
}
void dataTransferEnd() {
// according to doc, end must be
// a transition of DIO from HIGH to LOW
// when a CLK clock is HIGH
digitalWrite(PIN_DIO, LOW);
digitalWrite(PIN_CLK, HIGH);
delayClock();
digitalWrite(PIN_DIO, HIGH);
digitalWrite(PIN_CLK, LOW);
delayClock();
}
unsigned char writeByte(unsigned char data) {
// clock is assumed to be low, but just in case
digitalWrite(PIN_CLK, LOW);
for (unsigned char i = 0; i < 8; i++) {
digitalWrite(PIN_DIO, (data & 0x1) ? HIGH : LOW);
data = data >> 1;
// run a clock cycle
delayClock();
digitalWrite(PIN_CLK, HIGH);
delayClock();
digitalWrite(PIN_CLK, LOW);
}
// here the chip does an ACK for one cycle
pinMode(PIN_DIO, INPUT);
delayClock();
unsigned char ack = digitalRead(PIN_DIO);
// finish clock cycle
digitalWrite(PIN_CLK, HIGH);
delayClock();
digitalWrite(PIN_CLK, LOW);
pinMode(PIN_DIO, OUTPUT);
return ack;
}
The commands are very simple, the two MSB bits define the type of command:
-
01Data -
10Display -
11Address
The most simple is the display:
void setBrightness(unsigned char brightness) {
// display settings
dataTransferStart();
// this will be 0b10_00_1_XXX
writeByte(CMD_DISPLAY | CMD_DISPLAY_ON | (brightness & 0x7));
dataTransferEnd();
}
So the 0b10_00_1_XXX means: 10 is the Display command, the 00 are “irrelevant” items in the datasheet, 1 is to enable the display and XXX is the level of the brightness.
The full code and example is here: https://github.com/danguer/arduino-examples/tree/main/tm1637
Links

