Working with STM32 and Displays: TM1637 4-digit 7-segment LED display

In this guide, we shall see how to work with TM1637 4-digit 7-segment LED display and use STM32F411 to display the encoder values on the display.

In this guide, we will cover the following :

  • TM1637 4-digit 7-segment LED display
  • Connection with STM32
  • Code
  • Demo

1. TM1637 4-digit 7-segment LED display:

Bare 4-digit 7-segment displays usually require 12 connection pins. That’s quite a lot and doesn’t leave much room for other sensors or modules. Thanks to the TM1637 IC mounted on the back of the display module, this number can be reduced to just four. Two pins are required for the power connections and the other two pins are used to control the segments.

7-segment displays contain 7 (or 8) individually addressable LEDs. The segments are labeled A to G and some displays also have a dot (the 8th LED). Use this image as a reference when setting the individual segments in the code later.

7-segment-display-annotated

You can buy many different display modules that use a TM1637 IC. The color, size, dots, and connection points can all be different. I don’t have experience with all the different versions of this display but as long as they use the TM1637, the code examples provided below should work.

Here you can find the basic specifications of the display module that I used in this tutorial.

TM1637 4-Digit 7-Segment Display Specifications

Operating voltage3.3 – 5 V
Current draw80 mA
Luminance levels8
Display dimensions30 x 14 mm (0.36″ digits)
Overall dimensions42 x 24 x 12 mm
Hole dimensions38 x 20, ⌀ 2.2 mm
Operating temperature-10 – 80 °C

2. Connection with STM32

The connection of M1637 4-digit 7-segment LED display as following:

TM1637STM32F411 Nucleo-64
Vcc5V
GNGGND
DIOPC1 (A4)
CLKPC0(A5)

The encoder connection as following:

Encoder PinSTM32F411-Nucleo64 Pin
GNDGND
+3V3
DTPA0
CLKPA1

For encoder hookup guide and code, please refer to this topic

3. Code:

in tm1637.c file, we start of by defining some macros that will allow us access some functionality in the code later and segments definitions as following:

#define PORTC_CLK_ENABLE RCC->AHB1ENR|=RCC_AHB1ENR_GPIOCEN 


#define CLK_PIN_ENABLE GPIOC->MODER|=(1<<0)|(0<<1)
#define DIO_PIN_ENABLE GPIOC->MODER|=(1<<2)|(0<<3)


const char segmentMap[] = {
    0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, // 0-7
    0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71, // 8-9, A-F
    0x00
};

For the initializing, we enable clock access to the port, set pins as output with internal pull-up and set brightness to 8

void tm1637Init(void)
{
	RCC->AHB1ENR|=RCC_AHB1ENR_GPIOCEN;
  GPIOC->MODER|=(1<<0)|(0<<1);
	GPIOC->MODER|=(1<<2)|(0<<3);
	GPIOC->OSPEEDR|=0xF;
	GPIOC->OTYPER|=(1<<0)|(1<<0);
	GPIOC->PUPDR|=(1<<0)|(1<<2);
	tm1637SetBrightness(8);
}

For displaying a decimal value, the following function is used:

void tm1637DisplayDecimal(int v, int displaySeparator)
{
    unsigned char digitArr[4];
    for (int i = 0; i < 4; ++i) {
        digitArr[i] = segmentMap[v % 10];
        if (i == 2 && displaySeparator) {
            digitArr[i] |= 1 << 7;
        }
        v /= 10;
    }

    _tm1637Start();
    _tm1637WriteByte(0x40);
    _tm1637ReadResult();
    _tm1637Stop();

    _tm1637Start();
    _tm1637WriteByte(0xc0);
    _tm1637ReadResult();

    for (int i = 0; i < 4; ++i) {
        _tm1637WriteByte(digitArr[3 - i]);
        _tm1637ReadResult();
    }

    _tm1637Stop();
}

To start the brightness, we can use the following function:

// Valid brightness values: 0 - 8.
// 0 = display off.
void tm1637SetBrightness(char brightness)
{
    // Brightness command:
    // 1000 0XXX = display off
    // 1000 1BBB = display on, brightness 0-7
    // X = don't care
    // B = brightness
    _tm1637Start();
    _tm1637WriteByte(0x87 + brightness);
    _tm1637ReadResult();
    _tm1637Stop();
}

For start, read results, write byte and stop, the functions shall be as following:

void _tm1637Start(void)
{
    _tm1637ClkHigh();
    _tm1637DioHigh();
    _tm1637DelayUsec(20);
    _tm1637DioLow();
}

void _tm1637Stop(void)
{
    _tm1637ClkLow();
    _tm1637DelayUsec(20);
    _tm1637DioLow();
    _tm1637DelayUsec(20);
    _tm1637ClkHigh();
    _tm1637DelayUsec(20);
    _tm1637DioHigh();
}

void _tm1637ReadResult(void)
{
    _tm1637ClkLow();
    _tm1637DelayUsec(50);
    // while (dio); // We're cheating here and not actually reading back the response.
    _tm1637ClkHigh();
    _tm1637DelayUsec(20);
    _tm1637ClkLow();
}

void _tm1637WriteByte(unsigned char b)
{
    for (int i = 0; i < 8; ++i) {
        _tm1637ClkLow();
        if (b & 0x01) {
            _tm1637DioHigh();
        }
        else {
            _tm1637DioLow();
        }
        _tm1637DelayUsec(30);
        b >>= 1;
        _tm1637ClkHigh();
        _tm1637DelayUsec(30);
    }
}

and finally delay as following:

void _tm1637DelayUsec(unsigned int i)
{
delayuS(i);
}

You may download the code from this github repository

Simple TM1637 Interface with STM32

4. Demo:

Happy coding 🙂

Add Comment

Your email address will not be published. Required fields are marked *