ESPHome 2025.5.0
Loading...
Searching...
No Matches
tm1637.cpp
Go to the documentation of this file.
1#include "tm1637.h"
2#include "esphome/core/log.h"
4#include "esphome/core/hal.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, "Setting up TM1637...");
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, "TM1637:");
139 ESP_LOGCONFIG(TAG, " Intensity: %d", this->intensity_);
140 ESP_LOGCONFIG(TAG, " Inverted: %d", this->inverted_);
141 ESP_LOGCONFIG(TAG, " Length: %d", this->length_);
142 LOG_PIN(" CLK Pin: ", this->clk_pin_);
143 LOG_PIN(" DIO Pin: ", this->dio_pin_);
144 LOG_UPDATE_INTERVAL(this);
145}
146
147#ifdef USE_BINARY_SENSOR
149 uint8_t val = this->get_keys();
150 for (auto *tm1637_key : this->tm1637_keys_)
151 tm1637_key->process(val);
152}
153
155 this->start_();
156 this->send_byte_(TM1637_CMD_DATA | TM1637_DATA_READ_KEYS);
157 this->start_();
158 uint8_t key_code = read_byte_();
159 this->stop_();
160 if (key_code != 0xFF) {
161 // Invert key_code:
162 // Bit | 7 6 5 4 3 2 1 0
163 // ------+-------------------------
164 // From | S0 S1 S2 K1 K2 1 1 1
165 // To | S0 S1 S2 K1 K2 0 0 0
166 key_code = ~key_code;
167 // Shift bits to:
168 // Bit | 7 6 5 4 3 2 1 0
169 // ------+------------------------
170 // To | 0 0 0 0 K2 S2 S1 S0
171 key_code = (uint8_t) ((key_code & 0x80) >> 7 | (key_code & 0x40) >> 5 | (key_code & 0x20) >> 3 | (key_code & 0x08));
172 }
173 return key_code;
174}
175#endif
176
178 for (uint8_t &i : this->buffer_)
179 i = 0;
180 if (this->writer_.has_value())
181 (*this->writer_)(*this);
182 this->display();
183}
184
191
200
202 ESP_LOGVV(TAG, "Display %02X%02X%02X%02X", buffer_[0], buffer_[1], buffer_[2], buffer_[3]);
203
204 // Write DATA CMND
205 this->start_();
206 this->send_byte_(TM1637_CMD_DATA);
207 this->stop_();
208
209 // Write ADDR CMD + first digit address
210 this->start_();
211 this->send_byte_(TM1637_CMD_ADDR);
212
213 // Write the data bytes
214 if (this->inverted_) {
215 for (int8_t i = this->length_ - 1; i >= 0; i--) {
216 this->send_byte_(this->buffer_[i]);
217 }
218 } else {
219 for (auto b : this->buffer_) {
220 this->send_byte_(b);
221 }
222 }
223
224 this->stop_();
225
226 // Write display CTRL CMND + brightness
227 this->start_();
228 this->send_byte_(TM1637_CMD_CTRL + ((this->intensity_ & 0x7) | (this->on_ ? 0x08 : 0x00)));
229 this->stop_();
230}
232 uint8_t data = b;
233 for (uint8_t i = 0; i < 8; i++) {
234 // CLK low
236 this->bit_delay_();
237 // Set data bit
238 if (data & 0x01) {
240 } else {
242 }
243
244 this->bit_delay_();
245 // CLK high
247 this->bit_delay_();
248 data = data >> 1;
249 }
250 // Wait for acknowledge
251 // CLK to zero
254 this->bit_delay_();
255 // CLK to high
257 this->bit_delay_();
258 uint8_t ack = this->dio_pin_->digital_read();
259 if (ack == 0) {
261 }
262
263 this->bit_delay_();
265 this->bit_delay_();
266
267 return ack;
268}
269
271 uint8_t retval = 0;
272 // Prepare DIO to read data
274 this->bit_delay_();
275 // Data is shifted out by the TM1637 on the CLK falling edge
276 for (uint8_t bit = 0; bit < 8; bit++) {
278 this->bit_delay_();
279 // Read next bit
280 retval <<= 1;
281 if (this->dio_pin_->digital_read()) {
282 retval |= 0x01;
283 }
285 this->bit_delay_();
286 }
287 // Return DIO to output mode
288 // Dummy ACK
290 this->bit_delay_();
292 this->bit_delay_();
294 this->bit_delay_();
296 this->bit_delay_();
297 return retval;
298}
299
300uint8_t TM1637Display::print(uint8_t start_pos, const char *str) {
301 // ESP_LOGV(TAG, "Print at %d: %s", start_pos, str);
302 uint8_t pos = start_pos;
303 bool use_dot = false;
304 for (; *str != '\0'; str++) {
305 uint8_t data = TM1637_UNKNOWN_CHAR;
306 if (*str >= ' ' && *str <= '~')
307 data = progmem_read_byte(&TM1637_ASCII_TO_RAW[*str - ' ']);
308
309 if (data == TM1637_UNKNOWN_CHAR) {
310 ESP_LOGW(TAG, "Encountered character '%c' with no TM1637 representation while translating string!", *str);
311 }
312 // Remap segments, for compatibility with MAX7219 segment definition which is
313 // XABCDEFG, but TM1637 is // XGFEDCBA
314 if (this->inverted_) {
315 // XABCDEFG > XGCBAFED
316 data = ((data & 0x80) || use_dot ? 0x80 : 0) | // no move X
317 ((data & 0x40) ? 0x8 : 0) | // A
318 ((data & 0x20) ? 0x10 : 0) | // B
319 ((data & 0x10) ? 0x20 : 0) | // C
320 ((data & 0x8) ? 0x1 : 0) | // D
321 ((data & 0x4) ? 0x2 : 0) | // E
322 ((data & 0x2) ? 0x4 : 0) | // F
323 ((data & 0x1) ? 0x40 : 0); // G
324 } else {
325 // XABCDEFG > XGFEDCBA
326 data = ((data & 0x80) ? 0x80 : 0) | // no move X
327 ((data & 0x40) ? 0x1 : 0) | // A
328 ((data & 0x20) ? 0x2 : 0) | // B
329 ((data & 0x10) ? 0x4 : 0) | // C
330 ((data & 0x8) ? 0x8 : 0) | // D
331 ((data & 0x4) ? 0x10 : 0) | // E
332 ((data & 0x2) ? 0x20 : 0) | // F
333 ((data & 0x1) ? 0x40 : 0); // G
334 }
335 use_dot = *str == '.';
336 if (use_dot) {
337 if ((!this->inverted_) && (pos != start_pos)) {
338 this->buffer_[pos - 1] |= 0b10000000;
339 }
340 } else {
341 if (pos >= 6) {
342 ESP_LOGE(TAG, "String is too long for the display!");
343 break;
344 }
345 this->buffer_[pos++] = data;
346 }
347 }
348 return pos - start_pos;
349}
350uint8_t TM1637Display::print(const char *str) { return this->print(0, str); }
351uint8_t TM1637Display::printf(uint8_t pos, const char *format, ...) {
352 va_list arg;
353 va_start(arg, format);
354 char buffer[64];
355 int ret = vsnprintf(buffer, sizeof(buffer), format, arg);
356 va_end(arg);
357 if (ret > 0)
358 return this->print(pos, buffer);
359 return 0;
360}
361uint8_t TM1637Display::printf(const char *format, ...) {
362 va_list arg;
363 va_start(arg, format);
364 char buffer[64];
365 int ret = vsnprintf(buffer, sizeof(buffer), format, arg);
366 va_end(arg);
367 if (ret > 0)
368 return this->print(buffer);
369 return 0;
370}
371
372uint8_t TM1637Display::strftime(uint8_t pos, const char *format, ESPTime time) {
373 char buffer[64];
374 size_t ret = time.strftime(buffer, sizeof(buffer), format);
375 if (ret > 0)
376 return this->print(pos, buffer);
377 return 0;
378}
379uint8_t TM1637Display::strftime(const char *format, ESPTime time) { return this->strftime(0, format, time); }
380
381} // namespace tm1637
382} // 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:185
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:372
uint8_t uint8_t uint8_t print(uint8_t pos, const char *str)
Print str at the given position.
Definition tm1637.cpp:300
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:351
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:20
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:30
uint8_t progmem_read_byte(const uint8_t *addr)
Definition core.cpp:57
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()