ESPHome 2025.5.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/log.h"
5#include "esphome/core/hal.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 ESP_LOGD(TAG, "Setting up TM1638...");
24
25 this->clk_pin_->setup(); // OUTPUT
26 this->dio_pin_->setup(); // OUTPUT
27 this->stb_pin_->setup(); // OUTPUT
28
32
33 this->clk_pin_->digital_write(false);
34 this->dio_pin_->digital_write(false);
35 this->stb_pin_->digital_write(false);
36
38
39 this->reset_(); // all LEDs off
40
41 for (uint8_t i = 0; i < 8; i++) // zero fill print buffer
42 this->buffer_[i] = 0;
43}
44
46 ESP_LOGCONFIG(TAG, "TM1638:");
47 ESP_LOGCONFIG(TAG, " Intensity: %u", this->intensity_);
48 LOG_PIN(" CLK Pin: ", this->clk_pin_);
49 LOG_PIN(" DIO Pin: ", this->dio_pin_);
50 LOG_PIN(" STB Pin: ", this->stb_pin_);
51 LOG_UPDATE_INTERVAL(this);
52}
53
55 if (this->listeners_.empty())
56 return;
57
58 uint8_t keys = this->get_keys();
59 for (auto &listener : this->listeners_)
60 listener->keys_update(keys);
61}
62
64 uint8_t buttons = 0;
65
66 this->stb_pin_->digital_write(false);
67
68 this->shift_out_(TM1638_REGISTER_READBUTTONS);
69
71
73
74 for (uint8_t i = 0; i < 4; i++) { // read the 4 button registers
75 uint8_t v = this->shift_in_();
76 buttons |= v << i; // shift bits to correct slots in the byte
77 }
78
80
81 this->stb_pin_->digital_write(true);
82
83 return buttons;
84}
85
86void TM1638Component::update() { // this is called at the interval specified in the config.yaml
87 if (this->writer_.has_value()) {
88 (*this->writer_)(*this);
89 }
90
91 this->display();
92}
93
95
97 for (uint8_t i = 0; i < 8; i++) {
98 this->set_7seg_(i, buffer_[i]);
99 }
100}
101
103 uint8_t num_commands = 16; // 16 addresses, 8 for 7seg and 8 for LEDs
104 uint8_t commands[num_commands];
105
106 for (uint8_t i = 0; i < num_commands; i++) {
107 commands[i] = 0;
108 }
109
110 this->send_command_sequence_(commands, num_commands, TM1638_REGISTER_7SEG_0);
111}
112
114
115void TM1638Component::set_led(int led_pos, bool led_on_off) {
116 this->send_command_(TM1638_REGISTER_FIXEDADDRESS);
117
118 uint8_t commands[2];
119
120 commands[0] = TM1638_REGISTER_LED_0 + (led_pos << 1);
121 commands[1] = led_on_off;
122
123 this->send_commands_(commands, 2);
124}
125
126void TM1638Component::set_7seg_(int seg_pos, uint8_t seg_bits) {
127 this->send_command_(TM1638_REGISTER_FIXEDADDRESS);
128
129 uint8_t commands[2] = {};
130
131 commands[0] = TM1638_REGISTER_7SEG_0 + (seg_pos << 1);
132 commands[1] = seg_bits;
133
134 this->send_commands_(commands, 2);
135}
136
137void TM1638Component::set_intensity(uint8_t brightness_level) {
138 this->intensity_ = brightness_level;
139
140 this->send_command_(TM1638_REGISTER_FIXEDADDRESS);
141
142 if (brightness_level > 0) {
143 this->send_command_((uint8_t) (TM1638_REGISTER_DISPLAYON | intensity_));
144 } else {
145 this->send_command_(TM1638_REGISTER_DISPLAYOFF);
146 }
147}
148
150
151uint8_t TM1638Component::print(uint8_t start_pos, const char *str) {
152 uint8_t pos = start_pos;
153
154 bool last_was_dot = false;
155
156 for (; *str != '\0'; str++) {
157 uint8_t data = TM1638_UNKNOWN_CHAR;
158
159 if (*str >= ' ' && *str <= '~') {
160 data = progmem_read_byte(&TM1638Translation::SEVEN_SEG[*str - 32]); // subract 32 to account for ASCII offset
161 } else if (data == TM1638_UNKNOWN_CHAR) {
162 ESP_LOGW(TAG, "Encountered character '%c' with no TM1638 representation while translating string!", *str);
163 }
164
165 if (*str == '.') // handle dots
166 {
167 if (pos != start_pos &&
168 !last_was_dot) // if we are not at the first position, backup by one unless last char was a dot
169 {
170 pos--;
171 }
172 this->buffer_[pos] |= 0b10000000; // turn on the dot on the previous position
173 last_was_dot = true; // set a bit in case the next chracter is also a dot
174 } else // if not a dot, then just write the character to display
175 {
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; // clear dot tracking bit
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
bool has_value() const
Definition optional.h:87
optional< tm1638_writer_t > writer_
Definition tm1638.h:73
void set_7seg_(int seg_pos, uint8_t seg_bits)
Definition tm1638.cpp:126
float get_setup_priority() const override
Definition tm1638.cpp:94
std::vector< KeyListener * > listeners_
Definition tm1638.h:74
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:69
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:137
uint8_t uint8_t void set_led(int led_pos, bool led_on_off)
Definition tm1638.cpp:115
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:151
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 char *const TAG
Definition spi.cpp:8
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
std::string print()