ESPHome 2026.5.0b1
Loading...
Searching...
No Matches
tm1637.cpp
Go to the documentation of this file.
1#include "tm1637.h"
2#include "esphome/core/hal.h"
4#include "esphome/core/log.h"
5
6namespace esphome::tm1637 {
7
8static const char *const TAG = "display.tm1637";
9const uint8_t TM1637_CMD_DATA = 0x40;
10const uint8_t TM1637_CMD_CTRL = 0x80;
11const uint8_t TM1637_CMD_ADDR = 0xc0;
12const uint8_t TM1637_UNKNOWN_CHAR = 0b11111111;
13
14// Data command bits
15const uint8_t TM1637_DATA_WRITE = 0x00;
16const uint8_t TM1637_DATA_READ_KEYS = 0x02;
17const uint8_t TM1637_DATA_AUTO_INC_ADDR = 0x00;
18const uint8_t TM1637_DATA_FIXED_ADDR = 0x04;
19
20//
21// A
22// ---
23// F | | B
24// -G-
25// E | | C
26// ---
27// D X
28// XABCDEFG
29constexpr uint8_t TM1637_ASCII_TO_RAW[] PROGMEM = {
30 0b00000000, // ' ', ord 0x20
31 0b10110000, // '!', ord 0x21
32 0b00100010, // '"', ord 0x22
33 TM1637_UNKNOWN_CHAR, // '#', ord 0x23
34 TM1637_UNKNOWN_CHAR, // '$', ord 0x24
35 0b01001001, // '%', ord 0x25
36 TM1637_UNKNOWN_CHAR, // '&', ord 0x26
37 0b00000010, // ''', ord 0x27
38 0b01001110, // '(', ord 0x28
39 0b01111000, // ')', ord 0x29
40 0b01000000, // '*', ord 0x2A
41 TM1637_UNKNOWN_CHAR, // '+', ord 0x2B
42 0b00010000, // ',', ord 0x2C
43 0b00000001, // '-', ord 0x2D
44 0b10000000, // '.', ord 0x2E
45 TM1637_UNKNOWN_CHAR, // '/', ord 0x2F
46 0b01111110, // '0', ord 0x30
47 0b00110000, // '1', ord 0x31
48 0b01101101, // '2', ord 0x32
49 0b01111001, // '3', ord 0x33
50 0b00110011, // '4', ord 0x34
51 0b01011011, // '5', ord 0x35
52 0b01011111, // '6', ord 0x36
53 0b01110000, // '7', ord 0x37
54 0b01111111, // '8', ord 0x38
55 0b01111011, // '9', ord 0x39
56 0b01001000, // ':', ord 0x3A
57 0b01011000, // ';', ord 0x3B
58 TM1637_UNKNOWN_CHAR, // '<', ord 0x3C
59 TM1637_UNKNOWN_CHAR, // '=', ord 0x3D
60 TM1637_UNKNOWN_CHAR, // '>', ord 0x3E
61 0b01100101, // '?', ord 0x3F
62 0b01101111, // '@', ord 0x40
63 0b01110111, // 'A', ord 0x41
64 0b00011111, // 'B', ord 0x42
65 0b01001110, // 'C', ord 0x43
66 0b00111101, // 'D', ord 0x44
67 0b01001111, // 'E', ord 0x45
68 0b01000111, // 'F', ord 0x46
69 0b01011110, // 'G', ord 0x47
70 0b00110111, // 'H', ord 0x48
71 0b00110000, // 'I', ord 0x49
72 0b00111100, // 'J', ord 0x4A
73 TM1637_UNKNOWN_CHAR, // 'K', ord 0x4B
74 0b00001110, // 'L', ord 0x4C
75 TM1637_UNKNOWN_CHAR, // 'M', ord 0x4D
76 0b00010101, // 'N', ord 0x4E
77 0b01111110, // 'O', ord 0x4F
78 0b01100111, // 'P', ord 0x50
79 0b11111110, // 'Q', ord 0x51
80 0b00000101, // 'R', ord 0x52
81 0b01011011, // 'S', ord 0x53
82 0b00000111, // 'T', ord 0x54
83 0b00111110, // 'U', ord 0x55
84 0b00111110, // 'V', ord 0x56
85 0b00111111, // 'W', ord 0x57
86 TM1637_UNKNOWN_CHAR, // 'X', ord 0x58
87 0b00100111, // 'Y', ord 0x59
88 0b01101101, // 'Z', ord 0x5A
89 0b01001110, // '[', ord 0x5B
90 TM1637_UNKNOWN_CHAR, // '\', ord 0x5C
91 0b01111000, // ']', ord 0x5D
92 TM1637_UNKNOWN_CHAR, // '^', ord 0x5E
93 0b00001000, // '_', ord 0x5F
94 0b00100000, // '`', ord 0x60
95 0b01110111, // 'a', ord 0x61
96 0b00011111, // 'b', ord 0x62
97 0b00001101, // 'c', ord 0x63
98 0b00111101, // 'd', ord 0x64
99 0b01001111, // 'e', ord 0x65
100 0b01000111, // 'f', ord 0x66
101 0b01011110, // 'g', ord 0x67
102 0b00010111, // 'h', ord 0x68
103 0b00010000, // 'i', ord 0x69
104 0b00111100, // 'j', ord 0x6A
105 TM1637_UNKNOWN_CHAR, // 'k', ord 0x6B
106 0b00001110, // 'l', ord 0x6C
107 TM1637_UNKNOWN_CHAR, // 'm', ord 0x6D
108 0b00010101, // 'n', ord 0x6E
109 0b00011101, // 'o', ord 0x6F
110 0b01100111, // 'p', ord 0x70
111 TM1637_UNKNOWN_CHAR, // 'q', ord 0x71
112 0b00000101, // 'r', ord 0x72
113 0b01011011, // 's', ord 0x73
114 0b00000111, // 't', ord 0x74
115 0b00011100, // 'u', ord 0x75
116 0b00011100, // 'v', ord 0x76
117 TM1637_UNKNOWN_CHAR, // 'w', ord 0x77
118 TM1637_UNKNOWN_CHAR, // 'x', ord 0x78
119 0b00100111, // 'y', ord 0x79
120 TM1637_UNKNOWN_CHAR, // 'z', ord 0x7A
121 0b00110001, // '{', ord 0x7B
122 0b00000110, // '|', ord 0x7C
123 0b00000111, // '}', ord 0x7D
124 0b01100011, // '~', ord 0x7E (degree symbol)
125};
127 this->clk_pin_->setup(); // OUTPUT
128 this->clk_pin_->digital_write(false); // LOW
129 this->dio_pin_->setup(); // OUTPUT
130 this->dio_pin_->digital_write(false); // LOW
131
132 this->display();
133}
135 ESP_LOGCONFIG(TAG,
136 "TM1637:\n"
137 " Intensity: %d\n"
138 " Inverted: %d\n"
139 " Length: %d",
140 this->intensity_, this->inverted_, this->length_);
141 LOG_PIN(" CLK Pin: ", this->clk_pin_);
142 LOG_PIN(" DIO Pin: ", this->dio_pin_);
143 LOG_UPDATE_INTERVAL(this);
144}
145
146#ifdef USE_BINARY_SENSOR
148 uint8_t val = this->get_keys();
149 for (auto *tm1637_key : this->tm1637_keys_)
150 tm1637_key->process(val);
151}
152
154 this->start_();
155 this->send_byte_(TM1637_CMD_DATA | TM1637_DATA_READ_KEYS);
156 this->start_();
157 uint8_t key_code = read_byte_();
158 this->stop_();
159 if (key_code != 0xFF) {
160 // Invert key_code:
161 // Bit | 7 6 5 4 3 2 1 0
162 // ------+-------------------------
163 // From | S0 S1 S2 K1 K2 1 1 1
164 // To | S0 S1 S2 K1 K2 0 0 0
165 key_code = ~key_code;
166 // Shift bits to:
167 // Bit | 7 6 5 4 3 2 1 0
168 // ------+------------------------
169 // To | 0 0 0 0 K2 S2 S1 S0
170 key_code = (uint8_t) ((key_code & 0x80) >> 7 | (key_code & 0x40) >> 5 | (key_code & 0x20) >> 3 | (key_code & 0x08));
171 }
172 return key_code;
173}
174#endif
175
177 for (uint8_t &i : this->buffer_)
178 i = 0;
179 if (this->writer_.has_value())
180 (*this->writer_)(*this);
181 this->display();
182}
183
190
199
201 ESP_LOGVV(TAG, "Display %02X%02X%02X%02X", buffer_[0], buffer_[1], buffer_[2], buffer_[3]);
202
203 // Write DATA CMND
204 this->start_();
205 this->send_byte_(TM1637_CMD_DATA);
206 this->stop_();
207
208 // Write ADDR CMD + first digit address
209 this->start_();
210 this->send_byte_(TM1637_CMD_ADDR);
211
212 // Write the data bytes
213 if (this->inverted_) {
214 for (int8_t i = this->length_ - 1; i >= 0; i--) {
215 this->send_byte_(this->buffer_[i]);
216 }
217 } else {
218 for (auto b : this->buffer_) {
219 this->send_byte_(b);
220 }
221 }
222
223 this->stop_();
224
225 // Write display CTRL CMND + brightness
226 this->start_();
227 this->send_byte_(TM1637_CMD_CTRL + ((this->intensity_ & 0x7) | (this->on_ ? 0x08 : 0x00)));
228 this->stop_();
229}
231 uint8_t data = b;
232 for (uint8_t i = 0; i < 8; i++) {
233 // CLK low
235 this->bit_delay_();
236 // Set data bit
237 if (data & 0x01) {
239 } else {
241 }
242
243 this->bit_delay_();
244 // CLK high
246 this->bit_delay_();
247 data = data >> 1;
248 }
249 // Wait for acknowledge
250 // CLK to zero
253 this->bit_delay_();
254 // CLK to high
256 this->bit_delay_();
257 uint8_t ack = this->dio_pin_->digital_read();
258 if (ack == 0) {
260 }
261
262 this->bit_delay_();
264 this->bit_delay_();
265
266 return ack;
267}
268
270 uint8_t retval = 0;
271 // Prepare DIO to read data
273 this->bit_delay_();
274 // Data is shifted out by the TM1637 on the CLK falling edge
275 for (uint8_t bit = 0; bit < 8; bit++) {
277 this->bit_delay_();
278 // Read next bit
279 retval <<= 1;
280 if (this->dio_pin_->digital_read()) {
281 retval |= 0x01;
282 }
284 this->bit_delay_();
285 }
286 // Return DIO to output mode
287 // Dummy ACK
289 this->bit_delay_();
291 this->bit_delay_();
293 this->bit_delay_();
295 this->bit_delay_();
296 return retval;
297}
298
299uint8_t TM1637Display::print(uint8_t start_pos, const char *str) {
300 // ESP_LOGV(TAG, "Print at %d: %s", start_pos, str);
301 uint8_t pos = start_pos;
302 bool use_dot = false;
303 for (; *str != '\0'; str++) {
304 uint8_t data = TM1637_UNKNOWN_CHAR;
305 if (*str >= ' ' && *str <= '~')
306 data = progmem_read_byte(&TM1637_ASCII_TO_RAW[*str - ' ']);
307
308 if (data == TM1637_UNKNOWN_CHAR) {
309 ESP_LOGW(TAG, "Encountered character '%c' with no TM1637 representation while translating string!", *str);
310 }
311 // Remap segments, for compatibility with MAX7219 segment definition which is
312 // XABCDEFG, but TM1637 is // XGFEDCBA
313 if (this->inverted_) {
314 // XABCDEFG > XGCBAFED
315 data = ((data & 0x80) || use_dot ? 0x80 : 0) | // no move X
316 ((data & 0x40) ? 0x8 : 0) | // A
317 ((data & 0x20) ? 0x10 : 0) | // B
318 ((data & 0x10) ? 0x20 : 0) | // C
319 ((data & 0x8) ? 0x1 : 0) | // D
320 ((data & 0x4) ? 0x2 : 0) | // E
321 ((data & 0x2) ? 0x4 : 0) | // F
322 ((data & 0x1) ? 0x40 : 0); // G
323 } else {
324 // XABCDEFG > XGFEDCBA
325 data = ((data & 0x80) ? 0x80 : 0) | // no move X
326 ((data & 0x40) ? 0x1 : 0) | // A
327 ((data & 0x20) ? 0x2 : 0) | // B
328 ((data & 0x10) ? 0x4 : 0) | // C
329 ((data & 0x8) ? 0x8 : 0) | // D
330 ((data & 0x4) ? 0x10 : 0) | // E
331 ((data & 0x2) ? 0x20 : 0) | // F
332 ((data & 0x1) ? 0x40 : 0); // G
333 }
334 use_dot = *str == '.';
335 if (use_dot) {
336 if ((!this->inverted_) && (pos != start_pos)) {
337 this->buffer_[pos - 1] |= 0b10000000;
338 }
339 } else {
340 if (pos >= 6) {
341 ESP_LOGE(TAG, "String is too long for the display!");
342 break;
343 }
344 this->buffer_[pos++] = data;
345 }
346 }
347 return pos - start_pos;
348}
349
350void TM1637Display::set_brightness(float brightness) {
351 auto intensity = clamp(brightness, 0.f, 1.f) * 7;
352 this->set_on(intensity > 0);
353 this->set_intensity(intensity);
354}
355
356uint8_t TM1637Display::print(const char *str) { return this->print(0, str); }
357
358void TM1637Display::set_buffer(const uint8_t *data, uint8_t length) {
359 uint8_t len = std::min(length, (uint8_t) sizeof(this->buffer_));
360 memcpy(this->buffer_, data, len);
361}
362
363uint8_t TM1637Display::printf(uint8_t pos, const char *format, ...) {
364 va_list arg;
365 va_start(arg, format);
366 char buffer[64];
367 int ret = vsnprintf(buffer, sizeof(buffer), format, arg);
368 va_end(arg);
369 if (ret > 0)
370 return this->print(pos, buffer);
371 return 0;
372}
373uint8_t TM1637Display::printf(const char *format, ...) {
374 va_list arg;
375 va_start(arg, format);
376 char buffer[64];
377 int ret = vsnprintf(buffer, sizeof(buffer), format, arg);
378 va_end(arg);
379 if (ret > 0)
380 return this->print(buffer);
381 return 0;
382}
383
384uint8_t TM1637Display::strftime(uint8_t pos, const char *format, ESPTime time) {
385 char buffer[64];
386 size_t ret = time.strftime(buffer, sizeof(buffer), format);
387 if (ret > 0)
388 return this->print(pos, buffer);
389 return 0;
390}
391uint8_t TM1637Display::strftime(const char *format, ESPTime time) { return this->strftime(0, format, time); }
392
393} // namespace esphome::tm1637
virtual void pin_mode(gpio::Flags flags)=0
virtual void setup()=0
virtual void digital_write(bool value)=0
virtual bool digital_read()=0
void set_brightness(float brightness)
Set the display brightness.
Definition tm1637.cpp:350
float get_setup_priority() const override
Definition tm1637.cpp:184
void dump_config() override
Definition tm1637.cpp:134
uint8_t strftime(uint8_t pos, const char *format, ESPTime time) __attribute__((format(strftime
Evaluate the strftime-format and print the result at the given position.
Definition tm1637.cpp:384
tm1637_writer_t writer_
Definition tm1637.h:87
uint8_t uint8_t uint8_t print(uint8_t pos, const char *str)
Print str at the given position.
Definition tm1637.cpp:299
std::vector< TM1637Key * > tm1637_keys_
Definition tm1637.h:90
void set_buffer(const uint8_t *data, uint8_t length)
Set raw buffer bytes from data array up to length bytes.
Definition tm1637.cpp:358
void set_intensity(uint8_t intensity)
Definition tm1637.h:55
uint8_t printf(uint8_t pos, const char *format,...) __attribute__((format(printf
Evaluate the printf-format and print the result at the given position.
Definition tm1637.cpp:363
mopeka_std_values val[3]
@ FLAG_OUTPUT
Definition gpio.h:28
@ FLAG_INPUT
Definition gpio.h:27
constexpr float PROCESSOR
For components that use data from sensors like displays.
Definition component.h:45
const uint8_t TM1637_DATA_FIXED_ADDR
Fixed address.
Definition tm1637.cpp:18
constexpr uint8_t TM1637_ASCII_TO_RAW[] PROGMEM
Definition tm1637.cpp:29
const uint8_t TM1637_CMD_DATA
Display data command.
Definition tm1637.cpp:9
const uint8_t TM1637_CMD_ADDR
Display address command.
Definition tm1637.cpp:11
const uint8_t TM1637_DATA_AUTO_INC_ADDR
Auto increment address.
Definition tm1637.cpp:17
const uint8_t TM1637_DATA_READ_KEYS
Read keys.
Definition tm1637.cpp:16
const uint8_t TM1637_UNKNOWN_CHAR
Definition tm1637.cpp:12
const uint8_t TM1637_DATA_WRITE
Write data.
Definition tm1637.cpp:15
const uint8_t TM1637_CMD_CTRL
Display control command.
Definition tm1637.cpp:10
const char int const __FlashStringHelper * format
Definition log.h:74
va_end(args)
std::string size_t len
void IRAM_ATTR HOT delayMicroseconds(uint32_t us)
Definition hal.cpp:48
size_t size_t pos
Definition helpers.h:1038
size_t size_t const char va_start(args, fmt)
uint8_t progmem_read_byte(const uint8_t *addr)
Definition hal.h:42
A more user-friendly version of struct tm from time.h.
Definition time.h:23
size_t strftime(char *buffer, size_t buffer_len, const char *format)
Convert this ESPTime struct to a null-terminated c string buffer as specified by the format argument.
Definition time.cpp:18
uint8_t ack
std::string print()
uint16_t length
Definition tt21100.cpp:0