ESPHome 2026.2.1
Loading...
Searching...
No Matches
tm1638.cpp
Go to the documentation of this file.
1#include "tm1638.h"
2#include "sevenseg.h"
3#include "esphome/core/hal.h"
5#include "esphome/core/log.h"
6
7namespace esphome {
8namespace tm1638 {
9
10static const char *const TAG = "display.tm1638";
11static const uint8_t TM1638_REGISTER_FIXEDADDRESS = 0x44;
12static const uint8_t TM1638_REGISTER_AUTOADDRESS = 0x40;
13static const uint8_t TM1638_REGISTER_READBUTTONS = 0x42;
14static const uint8_t TM1638_REGISTER_DISPLAYOFF = 0x80;
15static const uint8_t TM1638_REGISTER_DISPLAYON = 0x88;
16static const uint8_t TM1638_REGISTER_7SEG_0 = 0xC0;
17static const uint8_t TM1638_REGISTER_LED_0 = 0xC1;
18static const uint8_t TM1638_UNKNOWN_CHAR = 0b11111111;
19
20static const uint8_t TM1638_SHIFT_DELAY = 4; // clock pause between commands, default 4ms
21
23 this->clk_pin_->setup(); // OUTPUT
24 this->dio_pin_->setup(); // OUTPUT
25 this->stb_pin_->setup(); // OUTPUT
26
30
31 this->clk_pin_->digital_write(false);
32 this->dio_pin_->digital_write(false);
33 this->stb_pin_->digital_write(false);
34
36
37 this->reset_(); // all LEDs off
38}
39
41 ESP_LOGCONFIG(TAG,
42 "TM1638:\n"
43 " Intensity: %u",
44 this->intensity_);
45 LOG_PIN(" CLK Pin: ", this->clk_pin_);
46 LOG_PIN(" DIO Pin: ", this->dio_pin_);
47 LOG_PIN(" STB Pin: ", this->stb_pin_);
48 LOG_UPDATE_INTERVAL(this);
49}
50
52 if (this->listeners_.empty())
53 return;
54
55 uint8_t keys = this->get_keys();
56 for (auto &listener : this->listeners_)
57 listener->keys_update(keys);
58}
59
61 uint8_t buttons = 0;
62
63 this->stb_pin_->digital_write(false);
64
65 this->shift_out_(TM1638_REGISTER_READBUTTONS);
66
68
70
71 for (uint8_t i = 0; i < 4; i++) { // read the 4 button registers
72 uint8_t v = this->shift_in_();
73 buttons |= v << i; // shift bits to correct slots in the byte
74 }
75
77
78 this->stb_pin_->digital_write(true);
79
80 return buttons;
81}
82
83void TM1638Component::update() { // this is called at the interval specified in the config.yaml
84 if (this->writer_.has_value()) {
85 (*this->writer_)(*this);
86 }
87
88 this->display();
89}
90
92
94 for (uint8_t i = 0; i < 8; i++) {
95 this->set_7seg_(i, buffer_[i]);
96 }
97}
98
100 uint8_t num_commands = 16; // 16 addresses, 8 for 7seg and 8 for LEDs
101 uint8_t commands[num_commands];
102
103 for (uint8_t i = 0; i < num_commands; i++) {
104 commands[i] = 0;
105 }
106
107 this->send_command_sequence_(commands, num_commands, TM1638_REGISTER_7SEG_0);
108}
109
111
112void TM1638Component::set_led(int led_pos, bool led_on_off) {
113 this->send_command_(TM1638_REGISTER_FIXEDADDRESS);
114
115 uint8_t commands[2];
116
117 commands[0] = TM1638_REGISTER_LED_0 + (led_pos << 1);
118 commands[1] = led_on_off;
119
120 this->send_commands_(commands, 2);
121}
122
123void TM1638Component::set_7seg_(int seg_pos, uint8_t seg_bits) {
124 this->send_command_(TM1638_REGISTER_FIXEDADDRESS);
125
126 uint8_t commands[2] = {};
127
128 commands[0] = TM1638_REGISTER_7SEG_0 + (seg_pos << 1);
129 commands[1] = seg_bits;
130
131 this->send_commands_(commands, 2);
132}
133
134void TM1638Component::set_intensity(uint8_t brightness_level) {
135 this->intensity_ = brightness_level;
136
137 this->send_command_(TM1638_REGISTER_FIXEDADDRESS);
138
139 if (brightness_level > 0) {
140 this->send_command_((uint8_t) (TM1638_REGISTER_DISPLAYON | intensity_));
141 } else {
142 this->send_command_(TM1638_REGISTER_DISPLAYOFF);
143 }
144}
145
147
148uint8_t TM1638Component::print(uint8_t start_pos, const char *str) {
149 uint8_t pos = start_pos;
150
151 bool last_was_dot = false;
152
153 for (; *str != '\0'; str++) {
154 uint8_t data = TM1638_UNKNOWN_CHAR;
155
156 if (*str >= ' ' && *str <= '~') {
157 data = progmem_read_byte(&TM1638Translation::SEVEN_SEG[*str - 32]); // subract 32 to account for ASCII offset
158 } else if (data == TM1638_UNKNOWN_CHAR) {
159 ESP_LOGW(TAG, "Encountered character '%c' with no TM1638 representation while translating string!", *str);
160 }
161
162 if (*str == '.') // handle dots
163 {
164 if (pos != start_pos &&
165 !last_was_dot) // if we are not at the first position, backup by one unless last char was a dot
166 {
167 pos--;
168 }
169 this->buffer_[pos] |= 0b10000000; // turn on the dot on the previous position
170 last_was_dot = true; // set a bit in case the next chracter is also a dot
171 } else // if not a dot, then just write the character to display
172 {
173 if (pos >= 8) {
174 ESP_LOGI(TAG, "TM1638 String is too long for the display!");
175 break;
176 }
177 this->buffer_[pos] = data;
178 last_was_dot = false; // clear dot tracking bit
179 }
180
181 pos++;
182 }
183 return pos - start_pos;
184}
185
187
188uint8_t TM1638Component::print(const char *str) { return this->print(0, str); }
189
190uint8_t TM1638Component::printf(uint8_t pos, const char *format, ...) {
191 va_list arg;
192 va_start(arg, format);
193 char buffer[64];
194 int ret = vsnprintf(buffer, sizeof(buffer), format, arg);
195 va_end(arg);
196 if (ret > 0)
197 return this->print(pos, buffer);
198 return 0;
199}
200uint8_t TM1638Component::printf(const char *format, ...) {
201 va_list arg;
202 va_start(arg, format);
203 char buffer[64];
204 int ret = vsnprintf(buffer, sizeof(buffer), format, arg);
205 va_end(arg);
206 if (ret > 0)
207 return this->print(buffer);
208 return 0;
209}
210
211uint8_t TM1638Component::strftime(uint8_t pos, const char *format, ESPTime time) {
212 char buffer[64];
213 size_t ret = time.strftime(buffer, sizeof(buffer), format);
214 if (ret > 0)
215 return this->print(pos, buffer);
216 return 0;
217}
218uint8_t TM1638Component::strftime(const char *format, ESPTime time) { return this->strftime(0, format, time); }
219
221
224 this->stb_pin_->digital_write(false);
225 this->shift_out_(value);
226 this->stb_pin_->digital_write(true);
227}
228
229void TM1638Component::send_commands_(uint8_t const commands[], uint8_t num_commands) {
230 this->stb_pin_->digital_write(false);
231
232 for (uint8_t i = 0; i < num_commands; i++) {
233 uint8_t command = commands[i];
234 this->shift_out_(command);
235 }
236 this->stb_pin_->digital_write(true);
237}
238
240 this->stb_pin_->digital_write(false);
241 this->shift_out_(value);
242}
243
244void TM1638Component::send_command_sequence_(uint8_t commands[], uint8_t num_commands, uint8_t starting_address) {
245 this->send_command_(TM1638_REGISTER_AUTOADDRESS);
246 this->send_command_leave_open_(starting_address);
247
248 for (uint8_t i = 0; i < num_commands; i++) {
249 this->shift_out_(commands[i]);
250 }
251
252 this->stb_pin_->digital_write(true);
253}
254
256 uint8_t value = 0;
257
258 for (int i = 0; i < 8; ++i) {
259 value |= dio_pin_->digital_read() << i;
260 delayMicroseconds(TM1638_SHIFT_DELAY);
261 this->clk_pin_->digital_write(true);
262 delayMicroseconds(TM1638_SHIFT_DELAY);
263 this->clk_pin_->digital_write(false);
264 delayMicroseconds(TM1638_SHIFT_DELAY);
265 }
266 return value;
267}
268
270 for (int i = 0; i < 8; i++) {
271 this->dio_pin_->digital_write((val & (1 << i)));
272 delayMicroseconds(TM1638_SHIFT_DELAY);
273
274 this->clk_pin_->digital_write(true);
275 delayMicroseconds(TM1638_SHIFT_DELAY);
276
277 this->clk_pin_->digital_write(false);
278 delayMicroseconds(TM1638_SHIFT_DELAY);
279 }
280}
281
282} // namespace tm1638
283} // 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
void set_7seg_(int seg_pos, uint8_t seg_bits)
Definition tm1638.cpp:123
float get_setup_priority() const override
Definition tm1638.cpp:91
std::vector< KeyListener * > listeners_
Definition tm1638.h:75
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 tm1638.cpp:211
GPIOPin * clk_pin_
brghtness of the display 0 through 7
Definition tm1638.h:70
void send_command_leave_open_(uint8_t value)
Definition tm1638.cpp:239
void send_command_sequence_(uint8_t commands[], uint8_t num_commands, uint8_t starting_address)
Definition tm1638.cpp:244
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 tm1638.cpp:190
void set_intensity(uint8_t brightness_level)
Definition tm1638.cpp:134
uint8_t uint8_t void set_led(int led_pos, bool led_on_off)
Definition tm1638.cpp:112
void send_commands_(uint8_t const commands[], uint8_t num_commands)
Definition tm1638.cpp:229
void shift_out_(uint8_t value)
Definition tm1638.cpp:269
void send_command_(uint8_t value)
Definition tm1638.cpp:222
uint8_t uint8_t uint8_t print(uint8_t pos, const char *str)
Print str at the given position.
Definition tm1638.cpp:148
mopeka_std_values val[4]
@ FLAG_OUTPUT
Definition gpio.h:28
@ FLAG_INPUT
Definition gpio.h:27
const float PROCESSOR
For components that use data from sensors like displays.
Definition component.cpp:85
const char *const TAG
Definition spi.cpp:7
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
va_end(args)
void IRAM_ATTR HOT delayMicroseconds(uint32_t us)
Definition core.cpp:28
size_t size_t pos
Definition helpers.h:729
size_t size_t const char va_start(args, fmt)
uint8_t progmem_read_byte(const uint8_t *addr)
Definition core.cpp:49
A more user-friendly version of struct tm from time.h.
Definition time.h:17
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:16
std::string print()