Erriez JY-LKM1638 board library for Arduino  1.1.0
This is an optimized JY-MCU JY-LKM1638 library for Arduino. It supports 8x 7-segment display, 8 dual color LEDs and 8 buttons with a simple API.
ErriezLKM1638Board.cpp
Go to the documentation of this file.
1 /*
2  * MIT License
3  *
4  * Copyright (c) 2020 Erriez
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 
34 #if defined(__AVR__)
35 #include <avr/pgmspace.h>
36 #else
37 #include <pgmspace.h>
38 #endif
39 
40 #include "ErriezLKM1638Board.h"
41 
42 /* 7-segment bits:
43  - 0 -
44  | |
45  5 1
46  | |
47  - 6 -
48  | |
49  4 2
50  | |
51  - 3 - .7
52 */
53 
54 // 7-segment display digit defines
55 static const PROGMEM uint8_t SEGMENT_DATA[] = {
56  0b00111111, /* 0 */
57  0b00000110, /* 1 */
58  0b01011011, /* 2 */
59  0b01001111, /* 3 */
60  0b01100110, /* 4 */
61  0b01101101, /* 5 */
62  0b01111101, /* 6 */
63  0b00000111, /* 7 */
64  0b01111111, /* 8 */
65  0b01101111, /* 9 */
66  0b01110111, /* A */
67  0b01111100, /* B */
68  0b00111001, /* C */
69  0b01011110, /* D */
70  0b01111001, /* E */
71  0b01110001, /* F */
72 };
73 
80 LKM1638Board::LKM1638Board(uint8_t clkPin, uint8_t dioPin, uint8_t stbPin) :
81  TM1638(clkPin, dioPin, stbPin), _pos(0), _dots(0)
82 {
83  memset(_leds, 0, NUM_DIGITS);
84 }
85 
86 //------------------------------------------------------------------------------
87 // Buttons
88 //------------------------------------------------------------------------------
94 {
95  uint32_t keys32;
96  uint8_t keys = 0;
97 
98  /* Read 4 Byte key-scan registers */
99  keys32 = getKeys();
100 
101  /* 8 buttons on the LKM1638 board are connected to K3 only
102  * Sort the keys in BYTE1..BYTE4 bits 0 and 4 to a keys byte
103  *
104  * BIT: | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
105  * -----+---+---+---+----+---+---+---+----+------
106  * | | | | S5 | | | | S0 | BYTE1
107  * | | | | S6 | | | | S1 | BYTE2
108  * | | | | S7 | | | | S2 | BYTE3
109  * | | | | S8 | | | | S3 | BYTE4
110  */
111 
112  for (uint8_t i = 0; i < 4; i++) {
113  keys |= (keys32 >> (i * 7)) & 0xFF;
114  }
115 
116  return swapBits(keys);
117 }
118 
119 //------------------------------------------------------------------------------
120 // Turn all LED's off
121 //------------------------------------------------------------------------------
126 {
127  memset(_leds, 0, NUM_DIGITS);
128  _dots = 0;
129 
130  TM1638::clear();
131 }
132 
133 //------------------------------------------------------------------------------
134 // Dual color LED's
135 //------------------------------------------------------------------------------
144 void LKM1638Board::setColorLED(uint8_t led, LedColor color)
145 {
146  /* led=7: Left, led=0: Right
147  *
148  * 8 two color LED's are connected to SEG8 and SEG9 pins at addresses:
149  *
150  * LED1 Address 0x01
151  * LED2 Address 0x03
152  * ... ...
153  * LED8 Address 0x0F
154  *
155  *
156  * BIT0 | BIT1 |
157  * (SEG9) |(SEG10)| COLOR
158  * --------+-------+-------------
159  * 0 | 0 | OFF
160  * 0 | 1 | GREEN
161  * 1 | 0 | RED
162  * 1 | 1 | NOT ALLOWED
163  */
164  if (led < NUM_DIGITS) {
165  writeData((uint8_t)(0x01 + (swapLeds(led) << 1)), (color & 0x03));
166  }
167 }
168 
177 void LKM1638Board::colorLEDsOn(uint8_t leds, LedColor color)
178 {
179  for (uint8_t i = 0; i < NUM_COLOR_LEDS; i++) {
180  if (leds & (1 << i)) {
181  setColorLED(i, color);
182  }
183  }
184 }
185 
190 void LKM1638Board::colorLEDsOff(uint8_t leds)
191 {
192  for (uint8_t i = 0; i < NUM_COLOR_LEDS; i++) {
193  if (leds & (1 << i)) {
194  setColorLED(i, LedOff);
195  }
196  }
197 }
198 
199 //------------------------------------------------------------------------------
200 // 7-segment display IO
201 //------------------------------------------------------------------------------
206 void LKM1638Board::writeDigit(uint8_t pos)
207 {
208  if (pos < NUM_DIGITS) {
209  uint8_t leds = _leds[pos];
210  if (_dots & (1 << pos)) {
211  leds |= 0x80;
212  }
213  writeData((swapPos(pos) << 1), leds);
214  }
215 }
216 
222 void LKM1638Board::setSegmentsDigit(uint8_t pos, uint8_t segments)
223 {
224  if (pos < NUM_DIGITS) {
225  _leds[pos] = segments;
226  writeDigit(pos);
227  }
228 }
229 
235 void LKM1638Board::setDigit(uint8_t pos, uint8_t digit)
236 {
237  if (pos < NUM_DIGITS) {
238  if (digit < sizeof(SEGMENT_DATA)) {
239  setSegmentsDigit(pos, pgm_read_byte(&SEGMENT_DATA[digit]));
240  } else {
241  setSegmentsDigit(pos, 0x00);
242  }
243  }
244 }
245 
250 {
251  for (uint8_t pos = 0; pos < NUM_DIGITS; pos++) {
252  writeDigit(pos);
253  }
254 }
255 
256 //------------------------------------------------------------------------------
257 // 7-segment display dots
258 //------------------------------------------------------------------------------
263 void LKM1638Board::dotOn(uint8_t pos)
264 {
265  if (pos < NUM_DIGITS) {
266  _dots |= (1 << pos);
267  writeDigit(pos);
268  }
269 }
270 
275 void LKM1638Board::dotOff(uint8_t pos)
276 {
277  if (pos < NUM_DIGITS) {
278  _dots &= ~(1 << pos);
279  writeDigit(pos);
280  }
281 }
282 
287 void LKM1638Board::setDots(uint8_t dots)
288 {
289  _dots = dots;
290  refresh();
291 }
292 
293 //------------------------------------------------------------------------------
294 // 7-segment display position
295 //------------------------------------------------------------------------------
300 void LKM1638Board::setPrintPos(uint8_t pos)
301 {
302  if (pos < NUM_DIGITS) {
303  _pos = pos;
304  }
305 }
306 
312 {
313  return _pos;
314 }
315 
316 //------------------------------------------------------------------------------
317 // Display uint8_t
318 //------------------------------------------------------------------------------
323 void LKM1638Board::print(uint8_t value)
324 {
325  writeUnsignedValue(value, DEC, 3, 1);
326 }
327 
333 void LKM1638Board::print(uint8_t value, uint8_t radius)
334 {
335  writeUnsignedValue(value, radius, 3, 1);
336 }
337 
344 void LKM1638Board::print(uint8_t value, uint8_t radius, uint8_t maxDigits)
345 {
346  writeUnsignedValue(value, radius, maxDigits, 1);
347 }
348 
356 void LKM1638Board::print(uint8_t value, uint8_t radius, uint8_t maxDigits, uint8_t pad)
357 {
358  writeUnsignedValue(value, radius, maxDigits, pad);
359 }
360 
361 //------------------------------------------------------------------------------
362 // Display uint16_t
363 //------------------------------------------------------------------------------
364 void LKM1638Board::print(uint16_t value)
365 {
366  writeUnsignedValue(value, DEC, 5, 1);
367 }
368 
369 void LKM1638Board::print(uint16_t value, uint8_t radius)
370 {
371  writeUnsignedValue(value, radius, 5, 1);
372 }
373 
374 void LKM1638Board::print(uint16_t value, uint8_t radius, uint8_t maxDigits)
375 {
376  writeUnsignedValue(value, radius, maxDigits, 1);
377 }
378 
379 void LKM1638Board::print(uint16_t value, uint8_t radius, uint8_t maxDigits, uint8_t pad)
380 {
381  writeUnsignedValue(value, radius, maxDigits, pad);
382 }
383 
384 //------------------------------------------------------------------------------
385 // Display unsigned long
386 //------------------------------------------------------------------------------
387 void LKM1638Board::print(unsigned long value)
388 {
389  writeUnsignedValue((uint32_t)value, DEC, 8, 1);
390 }
391 
392 void LKM1638Board::print(unsigned long value, uint8_t radius)
393 {
394  writeUnsignedValue((uint32_t)value, radius, 8, 1);
395 }
396 
397 void LKM1638Board::print(unsigned long value, uint8_t radius, uint8_t maxDigits)
398 {
399  writeUnsignedValue((uint32_t)value, radius, maxDigits, 1);
400 }
401 
402 void LKM1638Board::print(unsigned long value, uint8_t radius, uint8_t maxDigits, uint8_t pad)
403 {
404  writeUnsignedValue((uint32_t)value, radius, maxDigits, pad);
405 }
406 
407 //------------------------------------------------------------------------------
408 // Display int8_t
409 //------------------------------------------------------------------------------
410 void LKM1638Board::print(int8_t value)
411 {
412  writeSignedValue(value, DEC, 4);
413 }
414 
415 void LKM1638Board::print(int8_t value, uint8_t radius)
416 {
417  writeSignedValue(value, radius, 4);
418 }
419 
420 void LKM1638Board::print(int8_t value, uint8_t radius, uint8_t maxDigits)
421 {
422  writeSignedValue(value, radius, maxDigits);
423 }
424 
425 //------------------------------------------------------------------------------
426 // Display int16_t
427 //------------------------------------------------------------------------------
428 void LKM1638Board::print(int16_t value)
429 {
430  writeSignedValue(value, DEC, 6);
431 }
432 
433 void LKM1638Board::print(int16_t value, uint8_t radius)
434 {
435  writeSignedValue(value, radius, 6);
436 }
437 
438 void LKM1638Board::print(int16_t value, uint8_t radius, uint8_t maxDigits)
439 {
440  writeSignedValue(value, radius, maxDigits);
441 }
442 
443 //------------------------------------------------------------------------------
444 // Display long
445 //------------------------------------------------------------------------------
446 void LKM1638Board::print(long value)
447 {
448  writeSignedValue((int32_t)value, DEC, 8);
449 }
450 
451 void LKM1638Board::print(long value, uint8_t radius)
452 {
453  writeSignedValue((int32_t)value, radius, 8);
454 }
455 
456 void LKM1638Board::print(long value, uint8_t radius, uint8_t maxDigits)
457 {
458  writeSignedValue((int32_t)value, radius, maxDigits);
459 }
460 
461 //------------------------------------------------------------------------------
462 // Position, pad and write value to 7-segment display
463 //------------------------------------------------------------------------------
471 void LKM1638Board::writeUnsignedValue(uint32_t value, uint8_t radius,
472  uint8_t maxDigits, uint8_t pad)
473 {
474  uint8_t numDigits;
475  uint8_t pos;
476 
477  // Get number of digits of the value
478  numDigits = getNumDigits(value, radius);
479 
480  // Check if the value fits in the reserved area on the display
481  if ((numDigits > maxDigits) || ((_pos + numDigits) > NUM_DIGITS)) {
482  displayOverflow(maxDigits);
483  return;
484  }
485 
486  // Display every digit by dividing the value with the radius:
487  // 10 for DEC, 16 for HEX and 2 for BIN
488  pos = _pos;
489  for (uint8_t i = 0; i < maxDigits; i++) {
490  if ((value == 0) && (i >= pad)) {
491  setSegmentsDigit(pos, 0x00);
492  } else {
493  setDigit(pos, (uint8_t)(value % radius));
494  }
495  pos++;
496  value /= radius;
497  }
498 }
499 
506 void LKM1638Board::writeSignedValue(int32_t value, uint8_t radius, uint8_t maxDigits)
507 {
508  uint8_t numDigits;
509  uint8_t pos;
510  bool negative = false;
511 
512  if (value < 0) {
513  negative = true;
514  value *= -1;
515  }
516 
517  // Get number of digits of the value including one minus char
518  numDigits = (uint8_t)(getNumDigits((uint32_t)value, radius) + 1);
519 
520  // Check if the value fits in the reserved area on the display
521  if ((numDigits > maxDigits) || ((_pos + numDigits) > NUM_DIGITS)) {
522  displayOverflow(maxDigits);
523  return;
524  }
525 
526  // Display every digit by dividing the value with the radius:
527  // 10 for DEC, 16 for HEX and 2 for BIN
528  pos = _pos;
529  for (uint8_t i = 0; i < maxDigits; i++) {
530  if ((value == 0) && (i >= 1)) {
531  setSegmentsDigit(pos, 0x00);
532  } else {
533  setDigit(pos, (uint8_t)(value % radius));
534  }
535  pos++;
536  value /= radius;
537  }
538 
539  // Display or hide minus char
540  if (negative) {
541  pos = (uint8_t)(_pos + numDigits - 1);
543  } else {
545  }
546 }
547 
554 uint8_t LKM1638Board::getNumDigits(uint32_t value, uint8_t radius)
555 {
556  uint8_t numDigits = 1;
557 
558  // Calculate the number of digits of a value by dividing with radius
559  for (uint8_t i = 0; i < NUM_DIGITS; i++) {
560  value /= radius;
561  if (value == 0) {
562  break;
563  } else {
564  numDigits++;
565  }
566  }
567 
568  return numDigits;
569 }
570 
575 void LKM1638Board::displayOverflow(uint8_t numDigits)
576 {
577  // Display minus char on value area
578  for (uint8_t i = 0; i < numDigits; i++) {
580  }
581 }
582 
588 uint8_t LKM1638Board::swapPos(uint8_t pos)
589 {
590  // Swap position LSB - MSB
591  return (uint8_t)(NUM_DIGITS - 1 - pos);
592 }
593 
599 uint8_t LKM1638Board::swapLeds(uint8_t led)
600 {
601  // Swap LED's LSB - MSB
602  return (uint8_t)(NUM_COLOR_LEDS - 1 - led);
603 }
604 
610 uint8_t LKM1638Board::swapBits(uint8_t data)
611 {
612  uint8_t result = 0;
613 
614  // Swap all bits in a Byte (most significant and least significant bit)
615  for (uint8_t i = 0; i < 8; i++) {
616  result <<= 1;
617  result |= data & 1;
618  data >>= 1;
619  }
620 
621  return result;
622 }
uint8_t swapLeds(uint8_t led)
Swap dual color LED&#39;s.
uint8_t swapPos(uint8_t pos)
Swap digit position.
void dotOff(uint8_t pos)
Turn dot LED off.
void writeSignedValue(int32_t value, uint8_t radius, uint8_t maxDigits)
Write signed value to display.
LKM1638Board(uint8_t clkPin, uint8_t dioPin, uint8_t stbPin)
LKM1638 constructor.
JY-LKM1638 board v1.1 library for Arduino.
uint8_t getButtons()
Read buttons.
void setDots(uint8_t dots)
Turn multiple dots on or off.
#define NUM_COLOR_LEDS
Number of dual color LED&#39;s.
void clear()
Turn all LED&#39;s off.
uint8_t getPrintPos()
Get print position.
void setPrintPos(uint8_t pos)
Set print position.
void colorLEDsOff(uint8_t leds)
Turn multiple color LED&#39;s off.
void dotOn(uint8_t pos)
Turn dot LED on.
void setSegmentsDigit(uint8_t pos, uint8_t leds)
Write LED segments of a digit.
#define NUM_DIGITS
Number of digits.
void print(uint8_t value)
Print uint8_t value.
void setDigit(uint8_t pos, uint8_t digit)
Write digit.
uint8_t _dots
Dot LED&#39;s.
void writeDigit(uint8_t pos)
Write digit position.
uint8_t getNumDigits(uint32_t value, uint8_t radius)
Get number of digits of a signed 32-bit value.
uint8_t swapBits(uint8_t data)
Swap bits.
#define SEGMENTS_MINUS
7-sgement digit minus character
void displayOverflow(uint8_t numDigits)
Display overflow with - characters.
void refresh()
Refresh display.
LedColor
Dual color LED.
uint8_t _leds[NUM_DIGITS]
LED digits.
void setColorLED(uint8_t led, LedColor color)
Set dual color LED.
uint8_t _pos
Print position.
void colorLEDsOn(uint8_t leds, LedColor color)
Turn multiple color LED&#39;s on.
#define SEGMENTS_OFF
7-sgement digit all LED&#39;s off
void writeUnsignedValue(uint32_t value, uint8_t radius, uint8_t maxDigits, uint8_t pad)
Write unsigned value to display.