ESPHome 2026.3.0
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 bool last_was_dot = false;
151
152 for (; *str != '\0'; str++) {
153 uint8_t data = TM1638_UNKNOWN_CHAR;
154
155 if (*str >= ' ' && *str <= '~') {
156 // Subtract 32 to account for ASCII offset
157 data = progmem_read_byte(&TM1638Translation::SEVEN_SEG[*str - 32]);
158 } else {
159 ESP_LOGW(TAG, "Encountered character '%c' with no TM1638 representation while translating string!", *str);
160 }
161
162 if (*str == '.') {
163 // Merge dot onto previous character unless we're at the start or last was also a dot
164 if (pos != start_pos && !last_was_dot) {
165 pos--;
166 }
167 if (pos >= 8) {
168 ESP_LOGI(TAG, "TM1638 String is too long for the display!");
169 break;
170 }
171 // Turn on the dot on the previous position
172 this->buffer_[pos] |= 0b10000000;
173 last_was_dot = true;
174 } else {
175 // Not a dot, write the character to display
176 if (pos >= 8) {
177 ESP_LOGI(TAG, "TM1638 String is too long for the display!");
178 break;
179 }
180 this->buffer_[pos] = data;
181 last_was_dot = false;
182 }
183
184 pos++;
185 }
186 return pos - start_pos;
187}
188
190
191uint8_t TM1638Component::print(const char *str) { return this->print(0, str); }
192
193uint8_t TM1638Component::printf(uint8_t pos, const char *format, ...) {
194 va_list arg;
195 va_start(arg, format);
196 char buffer[64];
197 int ret = vsnprintf(buffer, sizeof(buffer), format, arg);
198 va_end(arg);
199 if (ret > 0)
200 return this->print(pos, buffer);
201 return 0;
202}
203uint8_t TM1638Component::printf(const char *format, ...) {
204 va_list arg;
205 va_start(arg, format);
206 char buffer[64];
207 int ret = vsnprintf(buffer, sizeof(buffer), format, arg);
208 va_end(arg);
209 if (ret > 0)
210 return this->print(buffer);
211 return 0;
212}
213
214uint8_t TM1638Component::strftime(uint8_t pos, const char *format, ESPTime time) {
215 char buffer[64];
216 size_t ret = time.strftime(buffer, sizeof(buffer), format);
217 if (ret > 0)
218 return this->print(pos, buffer);
219 return 0;
220}
221uint8_t TM1638Component::strftime(const char *format, ESPTime time) { return this->strftime(0, format, time); }
222
224
227 this->stb_pin_->digital_write(false);
228 this->shift_out_(value);
229 this->stb_pin_->digital_write(true);
230}
231
232void TM1638Component::send_commands_(uint8_t const commands[], uint8_t num_commands) {
233 this->stb_pin_->digital_write(false);
234
235 for (uint8_t i = 0; i < num_commands; i++) {
236 uint8_t command = commands[i];
237 this->shift_out_(command);
238 }
239 this->stb_pin_->digital_write(true);
240}
241
243 this->stb_pin_->digital_write(false);
244 this->shift_out_(value);
245}
246
247void TM1638Component::send_command_sequence_(uint8_t commands[], uint8_t num_commands, uint8_t starting_address) {
248 this->send_command_(TM1638_REGISTER_AUTOADDRESS);
249 this->send_command_leave_open_(starting_address);
250
251 for (uint8_t i = 0; i < num_commands; i++) {
252 this->shift_out_(commands[i]);
253 }
254
255 this->stb_pin_->digital_write(true);
256}
257
259 uint8_t value = 0;
260
261 for (int i = 0; i < 8; ++i) {
262 value |= dio_pin_->digital_read() << i;
263 delayMicroseconds(TM1638_SHIFT_DELAY);
264 this->clk_pin_->digital_write(true);
265 delayMicroseconds(TM1638_SHIFT_DELAY);
266 this->clk_pin_->digital_write(false);
267 delayMicroseconds(TM1638_SHIFT_DELAY);
268 }
269 return value;
270}
271
273 for (int i = 0; i < 8; i++) {
274 this->dio_pin_->digital_write((val & (1 << i)));
275 delayMicroseconds(TM1638_SHIFT_DELAY);
276
277 this->clk_pin_->digital_write(true);
278 delayMicroseconds(TM1638_SHIFT_DELAY);
279
280 this->clk_pin_->digital_write(false);
281 delayMicroseconds(TM1638_SHIFT_DELAY);
282 }
283}
284
285} // namespace tm1638
286} // 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:214
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:242
void send_command_sequence_(uint8_t commands[], uint8_t num_commands, uint8_t starting_address)
Definition tm1638.cpp:247
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:193
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:232
void shift_out_(uint8_t value)
Definition tm1638.cpp:272
void send_command_(uint8_t value)
Definition tm1638.cpp:225
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[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:33
const char *const TAG
Definition spi.cpp:7
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
const char int const __FlashStringHelper * format
Definition log.h:74
va_end(args)
void IRAM_ATTR HOT delayMicroseconds(uint32_t us)
Definition core.cpp:30
size_t size_t pos
Definition helpers.h:929
size_t size_t const char va_start(args, fmt)
uint8_t progmem_read_byte(const uint8_t *addr)
Definition core.cpp:56
A more user-friendly version of struct tm from time.h.
Definition time.h:21
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
std::string print()