Funkwecker mit ESP in MicroPython - Teil 5 - TM1637 7-Segment Anzeige - AZ-Delivery
led_display_aw

This post is also available as PDF document for download.

For a watch you need a befitting display, which is also readable from a distance. The OLED was - and is very useful for the development and maintenance of a circuit along with programming the controller, but for our goal, the alarm clock, rather suboptimal. Therefore, today it is about integrating a 4-fold seven-segment-LED display. What I found is a display with 4 digits and a number height of approx. 10mm, a good compromise between readability and space parasite. It is also possible to set the brightness in eight stages. This is good for a night of brightness.

The control takes place via only two lines. With the help of the data sheet, it quickly became clear that the transmission protocol corresponds almost exactly to the I2C protocol, but not quite. The only deviation: no hardware address is sent at the beginning of the transfer. But otherwise there is a start condition, a stop condition and a acknowledge bit, as with the I2C bus. Because there is no device address, of course there may only be one display component on the bus.

Of course, the I2C module, which is built into the core of Micropython, cannot be used by these circumstances. So I knitted a replacement module based on the data sheet, which optimally fulfills the conditions for the watch display. The display still had a surprise in stock. But more about that later. How to display the display correctly for hours and minutes, read this in this episode of

Micropython on the ESP32 and ESP8266

today

A watch with LED display

First of all, we take care of the hardware of the display. In addition to this itself, an LDR module is also required for the clock. The driver module for the seven-segment ads sits on the underside of the module.

Figure 1: TM1637 from above

Figure 1: TM1637 from above

Figure 2: TM1637 from below

Figure 2: TM1637 from below

The previous structure contains the ESP32 Lolin, IR receivers and IR transmitters, the DS3231 module a button and an LED, as well as an OLED display.

We have already done a lot in the previous parts. We can the REC (Remote Control) read out and have one own IR station realized. The possibility a PS/2 keyboard to the ESP32 To connect, allows the RC5 control to be read without having to be connected and finally we have it ESP32 an RTC module of high accuracy.

Today the LED module is added and so that the ESP32 can automatically adapt the brightness of the display to the environment, we also donate an LDR (Light dependent resistor = photo resistance).

Hardware

1 ESP32 Dev Kit C unpleasant or ESP32 NODEMCU Module WiFi Development Board or Nodemcu-ESP-32S kit
1 Ky-022 Set IR receiver
1 Ky-005 IR Infrarot transmitter transceiver module
1 0.91 inch OLED I2C display 128 x 32 pixels
1 Breadboard Kit - 3x Jumper Wire M2M/F2M/F2F + 3 Set MB102 Breadbord Compatible with Arduino and Raspberry Pi - 1x Set
1 Ky-004 button module
various Jumper Wire cable 3 x 40 pcs
1 Real Time Clock RTC DS3231 I2C real -time clock
1 TM1637 4 DIGIT 7 segment LED display module
1 Ky-018 Photo LDR resistance Photo resistor sensor
2 NPN transistor BC337 or similar
1 Resistance 1.0 kΩ
1 Resistance 10 kΩ
1 Resistance 330 Ω
1 Resistance 47Ω
1 Resistance 560Ω
1 LED (color at will)
1 Adapter PS/2 according to USB or PS/2 socket
1 Logic Analyzer
1 PS/2 keyboard

The Logic Analyzer is a very useful instrument if it is hooked when it comes to serial data transmission. In many cases, it replaces an expensive DSO (digital memory oscilloscope) and also offers the advantage of longer recordings, into which you can then zoom in. There is one for the device linked here Free operating software, the part is controlled via the PC. It helped me in many desperate cases, also in this case. The protocol of the TM1637 is sufficiently shown in the data sheet, but you are happy to overlook a detail. If you then compare the pulse diagram in the data sheet with what you have created yourself, you get to solving the problem very quickly.

Here is the circuit for the current state of affairs. Figure 3 shows the display of the display, in Figure 4 the DS3231 module is still included.

Figure 3: The 7-segment display for the clock

Figure 3: The 7-segment display for the clock

Figure 4: DS3231 and alarm clock display

Figure 4: DS3231 and alarm clock display

Figure 5: four times 7-segment LED display

Figure 5: four times 7-segment LED display

The software

For flashing and the programming of the ESP32:

Thonny or

µpycraft

Logic 2 operating software From Saleae

Used firmware for the ESP32:

V1.19.1 (2022-06-18).

Used firmware for the ESP8266:

V1.19.1 (2022-06-18).

The micropython programs for the project:

tm1637_4.py: API for the 4- and 6-digit 7-segment display with the TM1637

ds3231.py: Driver module for the RTC module

oled.py: OLED-API

SSD1306.PY: OLED hardware driver

7segment.py: Demo program of a watch

Micropython - Language - Modules and Programs

To install Thonny you will find one here Detailed instructions (English version). There is also a description of how that Micropython firmware (As of 18.06.2022) on the ESP chip burned becomes.

Micropython is an interpreter language. The main difference to the Arduino IDE, where you always flash entire programs, is that you only have to flash the Micropython firmware once on the ESP32 so that the controller understands micropython instructions. You can use Thonny, µpycraft or ESPTOOL.PY. For Thonny I have the process here described.

As soon as the firmware has flashed, you can easily talk to your controller in a dialogue, test individual commands and see the answer immediately without having to compile and transmit an entire program beforehand. That is exactly what bothers me on the Arduino IDE. You simply save an enormous time if you can check simple tests of the syntax and hardware to trying out and refining functions and entire program parts via the command line before knitting a program from it. For this purpose, I always like to create small test programs. As a kind of macro, they summarize recurring commands. Whole applications then develop from such program fragments.

Autostart

If the program is to start autonomously by switching on the controller, copy the program text into a newly created blank tile. Save this file under boot.py in WorkSpace and upload it to the ESP chip. The program starts automatically the next time the reset or switching on.

Test programs

Programs from the current editor window in the Thonny-IDE are started manually via the F5 button. This can be done faster than the mouse click on the start button, or via the menu run. Only the modules used in the program must be in the flash of the ESP32.

In between, Arduino id again?

Should you later use the controller together with the Arduino IDE, just flash the program in the usual way. However, the ESP32/ESP8266 then forgot that it has ever spoken Micropython. Conversely, any espressif chip that contains a compiled program from the Arduino IDE or AT-Firmware or Lua or ... can be easily provided with the micropython firmware. The process is always like here described.

The class TM1637

There are four- and six-digit LED displays that are controlled with the chip TM1637. I found differences in the structure or in the assignment of the individual digits. The class described here therefore dies from one Early written version in the places where the length of the display and/or the digit arrangement play a role. But it covers both types of display.

The TM1637 does not use a hardware address, as is usually the case on the I2C bus, I mentioned that above. There are also no registers, but only commands, commands, namely three: Data Command, Display and Control Command and Address Command. The signal sequence in the figure represents writing access with automatic counting of the address (auto-increment) after each data byte sent.

The sequence begins with a start-up condition, Dio goes to low while CLK is on high.

Figure 6: Signal course when writing in the SRAM of the TM1637

Figure 6: Signal course when writing in the SRAM of the TM1637

With the falling clock flank, the controller places the first database on the dio line and then relies on High, the TM1637 takes over the bit. The first byte is the data command, 0x40. If 8 bits, starting at the LSB (Least Significant bit = lowest bit), are transferred, the TM1637 pulls dio to low when the transmission was ok with a falling clock. The ninth rising clock flank triggers the Acknowledge-bit. A stop condition follows (CLK is high, Dio follows up after a delay) and immediately afterwards a new start condition.

With the Address Command 0xc0, the controller then sends the first memory address from which the data is continued. After each data byte there is a Acknowledge and a stop condition after the last byte.

The third command, with its own start-Condition, Acknowledge and Stop Condition, controls the display. The lower three bits set the brightness, Bit 3 switches on or off.

Let's take a look at how everything can be implemented in terms of program. We start with a low import volume.





A few exception classes for error treatment follow. The container class Tm1637_error inherit from Exception, the mother of all exception. The subclasses of Tm1637_error.





The class TM1637 is declared. The constants set the underlying values ​​for the commands. MSB serves to activate the decimal point (or double point) of a digit by the segment code ornamented becomes. We will see what this operation is based on shortly.





To the variables, the list A and the bytearar Segm, I have to go out something that is only concerned with the 6-digit display.

The TM1637 can control up to six digits. To my astonishment, the sequence of the digits in a 6-digit display was not from left to right, or the other way round, but as in Figure 7. The matter was a little complicates, also for our four-digit display, for digital success and memory assignment 1: 1. The address command always addresses the display positions in the order of the relative memory addresses from 0 to 5 if you want to use auto -increment. In the four-digit display, this also corresponds to the digit arrangement, but not the 6-digit.

Figure 7: Display arrangement

Figure 7: Display arrangement

If I now form an display ring from a measured value, the digits cannot be sent to the display in their natural order because it creates a small mess. From 123456 would 321654, sometimes something else! The list a =[2,1,0,5,4,3] the assignment between the string position and the display position. What is in position 0 in the string must be written in the memory for the Digit 2 so that the number appears on the far left in the display. So the 1 has to land in Digit 2. The index in the list is therefore the position in the number of digits, the addressed list element, is the digit number, where the number, or better, whose segment pattern is supposed to land. I'll come back to it later.

The bytearar Segm Contains the segment patterns of the digits 0 to 9 according to the scheme in Figure 8.

Figure 8: segment arrangement

Figure 8: segment arrangement

Each segment corresponds to a bit position according to the following pattern:

Figure 9: Dib coding

Figure 9: Dib coding

If we write 0x6d in the display storage 3, a 5 appears in the position on the right in the 6 Series display and if we start with the address 0xC0, then 0x6d must be transmitted as fourth to land in 0xc3.

It continues with the constructor of the class TM1637, the method __init__().





Three position parameters must be handed over, the number of digits in nofdig, the PIN objects for CLK and dio, as well as the optional keyword parameter Brightness for the contrast or the brightness as you want. If no argument is handed over for this, the default value is valid 3. All parameters are assigned instance attributes, the contrast value is also checked for compliance with the value range, as well nofdig. Lies Brightness not in the permissible area, then one Brightnesserror-Sexception thrown. delay Set the delay for the level change in the start and stop condition and between the clock flanks and thus determine the frequency on the clock line.

The pins are set to exit. As a delay for the clock, I present 5µs, which corresponds to a nominal frequency of 100kHz. We wait briefly, delete the display, then the constructor reports the operational readiness of the object in the terminal.

With latency() we can do the integer argument in Val As the value of the delay in the attribute delay Start after the value range (1… 20 for 500kHz ... 25kHz) was limited if necessary. Called without an argument, the method provides the current value of delay back.





The method start -on() follows the above requirements for the signal sequence. The idle state on both lines is high. Dio Go to low first, then follows CLK.





To create a stop condition, Dio must first be safe on low and the clock line at high. Delayed then goes to high.





The transfer of the data command bytes is embedded between the start and stop condition.





The same applies to Writedispcntrl(). However, more bits are carried out on the bare commandobyte 0x80 Ornament gripped on. With Overdraft = 0x08 we use bit 3. We switch on the display. The three contrast bits 2-0 are in Brightness.





writebyte() is the universal method for sending a byte taking into account the Acknowledge bits, which is not scanned. Otherwise we would have to switch to the entrance, read in the condition and then switch back to the output. So far no mistake has occurred, so I left out the exam.





The for loop pushes the handed over to the dio line with the LSB. CLK is still on low. The byte is pushed to the right by i = 0 to 7 positions and now the LSB is masked. The result is 0 or 1. This controlls the output DIO.

After the condition is stabilized, we create an increasing flank to CLK, the TM1637 samplates the condition on dio. After the clock is back on low, the next bit follows, the process is repeated until all bits are outside. CLK remains after the last bit for delay Milliseconds on low, then the last thing is the Acknowledge clock, which ends again with CLK = low. Another byte or a stop condition can now follow.

The method is used to test the display but also for output very specific patterns, for example for ASCII signs segment(). In SEG the pattern is handed over (default 0xff) and in POS The number of the digit (default 0x00). The output position is checked. In contrast to the 6-digit display with the idiosyncratic digit arrangement described above, the digits on the 4-digit display in the order of the memory cells are placed from 0 to 3 from left to right. The translation using the list A So is not necessary here. The query of the digitan number decides on the corresponding correct placement of the segment code in the SRAM of the TM1637. One Positional orception is thrown if the position is not in the permissible area.





Writedatacmd() Has your own start and stop condition. Before the address is sent, a start-up condition must be installed. According to the basic memory address 0xC0 with Odered Digit number as a relative address content, the segment description byte, the stop condition and the display control byte follow. Here is an example of a 4-series display.





Figure 10: Letter but lettering

Figure 10: Letter but lettering

contrast() works similarly to latency(). The current value is returned without an argument. With a value between 0 and 7 including the borders, the brightness is re -set. In connection with a photo resistance, for example, the brightness of the display could automatically adjust the ambient light. That is exactly what we will do later.





To delete the display, I send four or six zero-bytes.





The tupel segment Contains a bytearar with the segment codes and an integer. This indicates the number of the digit, in which the decimal point must be controlled if the number is the type float acts. The value -1 identifies an integer. We come to talk more about it below. We hand over the tupel writes().

Done a function test of all filaments lump test() according to the same pattern as Clear display().





Send up to six segment patterns from a given position, which can writes(). The patterns are in the tupel, the position comes behind POS from which is written. We carry out plausibility control for this value. The length of the sample string is also checked.

We are breaking the tupel segments in pattern and decimal point position. The string can only be as long as from POS Digits are still there, we test that.





If everything fits, we send the data command, followed by a start condition and the start address. The for loop brings the digits to the correct position, depending on the type of display.

The I In the for loop, the physical storage positions in the SRAM of the TM1637 go through. With the 6-series display, it serves as a pointer in the list A. The element at the respective list position is a pointer on the position of the sign in the string or bytearar. The code for this character is written in the storage point that is currently I is addressed.

If P the value of A[I] or I Has, the MSB is still Odered for the segment code, which means that the decimal point is activated. Then the byte is sent to the TM1637.

After the usually six/four bytes comes a stop condition and then the display control command.

Here is the method Number2 segment(), which converted the whole or the number of floors to a segment code strings.

The segment patterns for numbers that we have with Number2 segment() Create all start from the real digit position on the far left. This is the physical position 2 in the memory of a 6 Series display or position 0 in the 4-series display. We always have to start the broadcast with the relative memory address 0, absolutely 0xC0, otherwise we would have to send the address to every data byte. However, we want to use the auto-increment and send the data bytes in a washing up. The format string for integers "{:>6} "or" {:>4} "or comma numbers" {:>7.} "or" {:>5.} "Generate depending on the display length.





If there is a decimal point in the dial, which is only useful for the 6-series display, then we remember its position and delete it from the string. Because the point must be assigned to the previous number in the display, we subtract 1.

Then we create a bytearar from the length of the string that we fill with the segment codes. Special cases such as spaces or minus signs are taken into account. Normal digits deliver with ordained() The ASCII code of the character. We get the index into the list Segmif we subtract 48 of them. We build the segment code in bytearar segment a. Once everything is done, we return the array and the point position as a tupel.

The program for the clock

After the module tm1637.py To control the LED display, we will build a clock from it, or we modify the script second alarm.py from last time. We complement the import list by class TM1637_4.





We create an I2C object and set the alarm flag alarm trigger back. For the drain control, we instance a key object, button.





We hand over the I2C instance to the constructors of the OLED and DS3231 classes.





The 7-segment ad is the GPIO pins 26 (CLK) and 25 (DIO). With the number of digitan and the corresponding PIN objects, we feed the constructor of the TM1637 class and extinguish the display.

TM = TM1637 (4, PIN (26), PIN (25))

tm.Cleardisplay ()

An LDR module serves as a sensor for the brightness control. Please note that the connections for GND and +VCC are exchanged (Figures 3 and 4).

Figure 11: circuit of the LDR

Figure 11: circuit of the LDR

With the circuit as it is specified on the Break Out Board (left in Figure 11). S A low voltage if the LDR is heavily illuminated because its resistance then drops. Because the tensions on a standard circuit of resistors such as the resistance values ​​behave, the lighting becomes less and less tension at the LDR, the stronger the lighting becomes.

This is suboptimal in our case because we want the reverse behavior. The tension on S Should increase if it gets brighter so that we can also get a higher scanning value via the ADC. So the " +" connection to GND and the "-"-connection to +VCC = 3.3V. With an LDR you can easily make the polarity because it has no polarity like a photo diode, or a photo transistor. This would not be possible with these two.

To palpate the voltage S Let us connect the connection to GPIO36 (VP) on the ESP32. For this connection we generate an ADC object and adapt it to the voltage of 3.3V by choosing the weaker with 11dB. The smallest resolution with 9 bit (3.3V -> 512 Counts).





The core of the display unit is the function Timeoutput(). So that the main program of the TIMESTAMP, which is also requested by the DS3231, is also available, we declare the variable dt global. This means that it must be made known in advance in the main program (see above).

We pick up a TIMESTAMP, show the list of variables dt to and let them output in Repl. We pick out the hour and minute value and shovel the values ​​after house and minute.





For the display, the decimal values ​​must be broken down into digits. We do this again through the full number of the rest. Segm. In the case of the hourly, we use the MSB and switch on the colon that is linked to this digit. We hold the segment codes in the list time together.





The for loop reads the list and shipped the codes using the method segment() to the right place in the 4-series display.





The function alarm call() and we already know the associated IRQ administration from the previous episode.





We have the current time displayed and activate the Alarm1 at every full minute. We switch off alarm2 for the time being and reset the alarm flags of both alarms.





We read the lighting level in the main loop. We have to reduce the values ​​with the maximum ADC value of 511 to area 0… 7. In this way, we do the brightness of the display, which is supposed to shine only weakly in the dark, but more stronger with great ambientness.





When the alarm trigger is set, the clockwork must be updated and, if necessary, a wake-up alarm must be treated. The trigger is reset in any case, also the alarm flags.





The button is queried for a clean exit from the program with a deliberate tidying up. If it is pressed, we deactivate the rtcirq. This means that the ESP32 no longer automatically reacts to level change to GPIO32. exit() ends the program.





What do you do if there is no other hallway to be seen to put the watch and if there is no access to a time server on the web?

What it did, our ESP32 can then say a long -wave transmitter that is at Mainflingen near Frankfurt. A small DCF77 receiver will provide us with the times with which we can synchronize our watch exactly with the statutory time (CEZ).

In the next episode, I will tell you how to do this.

See you then!

DisplaysEsp-32Projekte für anfänger

Leave a comment

All comments are moderated before being published

Recommended blog posts

  1. ESP32 jetzt über den Boardverwalter installieren - AZ-Delivery
  2. Internet-Radio mit dem ESP32 - UPDATE - AZ-Delivery
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1 - AZ-Delivery
  4. ESP32 - das Multitalent - AZ-Delivery