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