Added support for TM1638 Seven-Segment Display, Buttons and LED

This commit is contained in:
Ajith Vasudevan 2021-02-18 22:44:15 +05:30
parent 3c791ca9bb
commit 4beb589c18
11 changed files with 1300 additions and 186 deletions

View File

@ -0,0 +1,276 @@
![ module pics ](https://github.com/gavinlyonsrepo/TM1638plus/blob/master/extra/images/tm16383.jpg)
Table of contents
---------------------------
* [Overview](#overview)
* [Installation](#installation)
* [Features](#features)
* [Model One](#model-one)
* [Model Two](#model-two)
* [Model Three](#model-three)
* [Notes](#notes)
* [Memory](#memory)
* [Pic Ports](#pic-port)
Overview
--------------------------------------------
* Name: TM1638plus
* Description:
An Arduino library to display data on a 8-digit TM1638 seven segment module.
This library supports 3 different models, pictured above from left to right.
1. Model 1, The (8 KEY & 8 LED) variant which has 8 LED's and 8 Push buttons.
2. Model 2, The (QYF 16 KEY) variant which has 16 pushbuttons.
3. Model 3, The (LKM1638) variant which has 8 bi-colour LED's and 8 Push buttons.
* Main Author: Gavin Lyons.
* Tested on Development platforms:
1. Arduino UNO & NANO v3 .
2. ATtiny85 .
3. ESP32.
4. STM32 STM32F103C8T6 "the blue pill".
5. ESP8266.
6. Teensy 4.0. (may not work at highest frequency see notes section)
* History: see CHANGELOG.md in extra folder
* Contributors: [gabormay](https://github.com/gabormay) [centic9](https://github.com/centic9) [wunderbaum](https://github.com/wunderbaum)
Installation
------------------------------
The library is included in the official Arduino library manger and the optimum way to install it
is using the library manager which can be opened by the *manage libraries* option in Arduino IDE.
Search "tm1638" in search bar of library manager to find it.
See link below for instruction for this and for the other methods too.
[Installing Additional Arduino Libraries guide](https://www.arduino.cc/en/Guide/Libraries)
Features
----------------------
Connections to MCU:
1. GPIO = STB = Strobe
2. GPIO = CLK = Clock
3. GPIO = DIO = Data input / output
4. GND
5. VCC 5V.
This device is 5V if using 3.3V MCU, level shift.
This library supports three variants of the TM1638, which for purposes of this documentation,
will be named Model 1 ,Model 2 and Model 3.
| Model No | Module Name | LEDS | Push buttons |
| ------ | ------ | ------ | ------ |
| 1 | TM1638 LED & KEY | 8 red only | 8 |
| 2 | TM1638 KEYS, QYF | 0 | 16 |
| 3 | TM1638 V1.3 or LKM1638 | 8 bi color, red and green | 8 |
There are two sets of files to support model 1 & 2 . I kept them separate as the models are wired quite different, Model 1 address by digit, while Model 2 address by segment. So the code is quite different for most functions. Model 3 uses same code as Model 1, just different example file and different use of LED functions. Common settings, data and functions are in the TM1638plus_common.x files.
| Model | Header | Code file | TEST files |
| ------ | ------ | ------ | ------ |
| 1 | TM1638plus.h | TM1638plus.cpp | TM1638plus_HELLOWORLD_Model1.ino TM1638plus_TEST_Model1.ino |
| 3 | Same as model 1 | Same as model 1 | TM1638plus_TEST_Model3.ino |
| 2 | TM1638plus_Model2.h | TM1638plus_Model2.cpp | TM1638plus_HELLOWORLD_Model2 TM1638plus_TEST_Model2.ino |
Model One
--------------------------------------
TM1638 Module 8 Push buttons 8 LEDS (LED & KEY)
![ module ](https://github.com/gavinlyonsrepo/pic_16F18446_projects/blob/master/images/TM1638.jpg)
![ sch ](https://github.com/gavinlyonsrepo/pic_16F18446_projects/blob/master/images/TM1638_2.jpg)
This variant consist of an 8-digit seven segment display with decimal points,
8 Leds and 8 Push buttons. Two 4 digit 3461AS-1 (.34 inch, 4 digit ,common Cathode, decimal point, RED) are used in this module giving a total of 8 digits. A TM1638 controller chip drives the unit.
The unit is marked (LED & KEY).
**Model 1 Library Functions**
The commented functions can be found in library header file TM1638plus.h.
The library support ASCII ,text ,Hex and allows for setting individual segments,
and the decimal point of segment.
The TM1638plus_TEST.ino contains a set of tests demonstrating library functions.
For more information see the commented headers in header file.
1. Print an ASCII character.
2. Print an ASCII character with a dot/decimal point.
3. Print a Hexadecimal digit(0-15).
4. Print a long integer number with or without leading zeros.
5. Print two integer numbers (0-9999) to each nibble with or without leading zeros.
6. Print a text string(dots are replaced and dot is turned on preceding digit),
"abc.def" becomes "abcdef" with c decimal point segment switched on.
7. Read buttons status. User may have to debounce buttons depending on application.
debouncing left out to minimise library size.
See [URL LINK](https://github.com/gavinlyonsrepo/Arduino_Clock_3)
for a practical real world example of using this library,
including a example of debouncing the key presses. It is also possible to read multiple key presses.
8. Reset and init module functions.
9. Adjust brightness of module. Support 8 degree brightness adjustment.
If user wishes to change the default brightness at start-up change,
The DEFAULT_BRIGHTNESS define in header file.
10. Manually set segments to create custom patterns.
11. Switch the 8 LEDS on and off, both a set one LED and set all LEDS methods available.
Model Two
-----------------------------------------
TM1638 Module 16 Push buttons (16 KEY) (QYF).
![ module ](https://github.com/gavinlyonsrepo/TM1638plus/blob/master/extra/images/tm16381.jpg)
![ sch ](https://github.com/gavinlyonsrepo/TM1638plus/blob/master/extra/images/tm16382.jpg)
They consist of an 8-digit seven segment display with decimal points,
and 16 Push buttons.Two 4 digit 3461BS-1 (.34 inch, 4 digit ,common Anode, decimal point, RED)are used in this module giving a total of 8 digits. A TM1638 controller chip drives the unit.
NB : If your display shows "56781234" for "12345678" see Notes section. Note A.
**Model 2 Library Functions**
The commented functions can be found in library header file TM1638plus_Model2.h.
The library support Strings,decimal ,Hex ,raw ASCII data, setting individual segments,
and the decimal point. For more detailed information on functions see commented headers in header file(.h).
1. Print a Hexadecimal number with or without leading zeros
2. Print a decimal number with or without leading zeros
3. Manually set segments to create custom patterns.
4. Print two 4 digit decimal number(0-9999) to each nibble with or without leading zeros.
5. Print a text string, dot function supported.
6. Read buttons status. User may want to debounce buttons depending on application.
See TM1638plus_ADC_TEST_Model2.ino for debounce button example.
Two different functions to read buttons.
7. Reset and init module functions.
8. Adjust brightness of module. Support 8 degree brightness adjustment.
If user wishes to change the default brightness at start-up change,
The "DEFAULT_BRIGHTNESS" define in header file.
9. Print raw ASCII data without reference to font file.
Model Three
-----------------------------------------
There are different PCB's of these modules on market,
This library was tested on no 3 below. I think this software will work for all of them
and the differences in PCB are related to connectors, layout and component placement.
This module is a variant of Model 1. The differences are the LEDs are bigger and bi-color
both red and green, The seven segment display is larger and extra connectors are added for Daisy chaining.
Two 4 digit KYX-5461AS-7.3 (.54 inch, 4 digit ,common cathode, decimal point, RED)are used in this module
giving a total of 8 digits.
1. LKM1638 v1.1
2. LKM1638 v1.2
3. TM1638 V1.3
![ module ](https://github.com/gavinlyonsrepo/TM1638plus/blob/master/extra/images/tm16384.jpg)
**Model 3 Library Functions**
The code is the same as model 1 and there is one unique model 3 example file.
setLED and setLEDs functions behaviour is the only difference in code base between 1 and 3.
SetLED: The difference is when you call the setLED function you pass the following to get LEDs to change colour. For more detailed information on functions see commented headers in header file(.h).
| Model | setLED Value | result |
| ---- | ---- | ---- |
| 1 & 3 | 0 | LED off |
| 3 | 1 | Led green on |
| 3 | 2 | LED red on |
| 1 | 1 | LED on |
SetLEDs: When you pass call the setLEDs function you can pass a word pattern where upper byte is turns LEDs green on and lower byte turns LEDs red on . Model one ignores lower byte, Set to 0x00 always.
1. Model 3 setLEDs(word) = 0xGGRR
3. Model 1 setLEDs(word) = 0xRR00
Notes
--------------------------
1. Swapped data on Display issue on some Model 2 modules
2. Anomaly's on High frequency micro-controllers.
3. Driving multiple displays.
4. Detecting multiple buttons pressed together.
*Note A* : Swapped display Issue: Model 2 only
For Some users using this library the nibbles in information display byte
where swapped around. This is because there are different versions of modules on market with different wiring. See issue #3 on github called Swapped display :: "12345678" becomes "56781234".
If you test library and you see this issue, in order to fix this when you declare the
Object, set the fourth parameter "swap_nibbles" to True, The default is false.
| PCB Model noted Label | Operation | Object constructor 4th parameter |
| ------ | ------ | ------ |
| QYF-TM1638 | default operation | false |
| QYF-TM1638 -Ver 1.0 | Swapped display Fix | true |
*Note B* : High frequency micro-controllers.
This library uses a software SPI-like protocol and may not work fully on
micro-controllers running at a very high frequency, without some adjustments to timing.
Its a SPI-like interface with a single bidirectional data wire DIO.
The TM1638 is basically a slow SPI device (< 500kHz) in DIO mode. The clock uses the equivalent of SPI mode 3 (normally high, clocks data on the rising edge). The problem is that the native Arduino shiftIn()/shiftOut() wire functions are simply too fast for this device (technically the clock signalling for the TM1638 is inverted but as it triggers on a rising edge still it is tolerant of that).
To make this work with fast devices, the shift clocking is slowed with a small delay (on the order of a microsecond). As of version 1.6 a new parameter *(_HIGH_FREQ)* has been introduced to constructor it is false by default. Set to true for high frequency MCU ~> 100Mhz. This will fix the issue of HF MCU not reading buttons correctly(ESP-Xs). The High_Freq parameter causes a custom shift-in function to be used.
The Teensy results have been sent to me, I don't have these MCU's them at time of writing.
| IC | frequency | Status |
| ------ | ------ | ------ |
| ATtiny85 | 1Mhz internal | Working |
| Arduino UNO | 16 MHz | Working |
| Arduino Nano | 16 MHz | Working |
| STM32 "blue pill" STM32F103C8T6 | 72Mhz | Working |
| ESP8266 | 160Mhz | Working |
| ESP 32 | 240 MHz | Working, with high_freq set to true |
| Teensy 4.0| 150Mhz | Working model 1, no Data rest of models |
| Teensy 4.0| 396Mhz | Not working on model1 , no Data rest of models |
*Note C* : Driving multiple displays.
It is possible to drive multiple modules. Share the DIO and CLK lines and use a unique
STB line for each device. see issue number 10 at github for example code.
*Note D* : Detecting multiple buttons pressed together.
Model 1 and Model 3 CAN detect multiple buttons pressed.
Model 3 has two different functions:
1. ReadKey16 returns a byte with decimal value 1-16 this function cannot
detect multiple buttons pressed.
2. ReadKey16Two returns a 16 bit integer where each bit corresponds to the 16 switch's.
However due to the wiring of the module, see SG-X lines on schematic,
Pressing Certain combinations of buttons will cause the data on Seven Segments to
change. So the simultaneous use of multiple key presses and the seven segments display
is problematic. See issue 12 on github for more details.
Memory
-------------------------------
Version 1.4.
1. Model 1 memory usage NANO, basic hello world sketch.
Sketch uses 1488 bytes (4%) of program storage space.
Global variables use 22 bytes (1%) of dynamic memory.
2. Model 2 memory usage NANO, basic hello world sketch.
Sketch uses 1536 bytes (5%) of program storage space.
Global variables use 23 bytes (1%) of dynamic memory.
Pic Port
-------------------
MicroChip PIC XC8 port.
I have ported this library to the PIC for the XC8 compiler:
[ Link ](https://github.com/gavinlyonsrepo/pic_16F18446_projects)

View File

@ -0,0 +1,35 @@
# -----------------------------------------
# Syntax coloring for TM1638plus library
# -----------------------------------------
# Datatypes (such as objects)
TM1638plus KEYWORD1
TM1638plus_Model2 KEYWORD1
# Methods / functions
displayBegin KEYWORD2
reset KEYWORD2
brightness KEYWORD2
DisplayDecNumNibble KEYWORD2
readButtons KEYWORD2
setLED KEYWORD2
setLEDs KEYWORD2
displayText KEYWORD2
displayASCIIwDot KEYWORD2
displayASCII KEYWORD2
display7Seg KEYWORD2
displayHex KEYWORD2
displayIntNum KEYWORD2
DisplaySegments KEYWORD2
DisplayHexNum KEYWORD2
DisplayDecNum KEYWORD2
DisplayStr KEYWORD2
ASCIItoSegment KEYWORD2
ReadKey16 KEYWORD2
ReadKey16Two KEYWORD2
# Constants

View File

@ -0,0 +1,9 @@
name=TM1638plus
version=1.7.0
author=Gavin Lyons <glyons66@hotmail.com>
maintainer=Gavin Lyons <glyons66@hotmail.com>
sentence=TM1638plus is an Arduino library to control TM1638 seven segment modules.
paragraph=It supports Push Buttons, LEDs, ASCII, Decimal, Hexadecimal,text strings and the decimal point. Small Memory footprint.
category=Display
url=https://github.com/gavinlyonsrepo/TM1638plus
architectures=*

View File

@ -0,0 +1,191 @@
/*
* Project Name: TM1638
* File: TM1638plus.cpp
* Description: source file arduino library for TM1638 module(LED & KEY). Model 1 & Model 3
* Author: Gavin Lyons.
* Created May 2019
* URL: https://github.com/gavinlyonsrepo/TM1638plus
*/
#include "TM1638plus.h"
TM1638plus::TM1638plus(uint8_t strobe, uint8_t clock, uint8_t data, bool highfreq) {
_STROBE_IO = strobe;
_DATA_IO = data;
_CLOCK_IO = clock;
_HIGH_FREQ = highfreq;
}
void TM1638plus::displayBegin() {
pinMode(_STROBE_IO , OUTPUT);
pinMode(_DATA_IO, OUTPUT);
pinMode(_CLOCK_IO , OUTPUT);
sendCommand(TM_ACTIVATE);
brightness(TM_DEFAULT_BRIGHTNESS);
reset();
}
void TM1638plus::sendCommand(uint8_t value)
{
digitalWrite(_STROBE_IO, LOW);
sendData(value);
digitalWrite(_STROBE_IO, HIGH);
}
void TM1638plus::sendData(uint8_t data)
{
if (_HIGH_FREQ == false)
shiftOut(_DATA_IO, _CLOCK_IO, LSBFIRST, data);
else
TM_common.HighFreqshiftOut(_DATA_IO, _CLOCK_IO, LSBFIRST, data);
}
void TM1638plus::reset() {
sendCommand(TM_WRITE_INC); // set auto increment mode
digitalWrite(_STROBE_IO, LOW);
sendData(TM_SEG_ADR); // set starting address to
for (uint8_t i = 0; i < 16; i++)
{
sendData(0x00);
}
digitalWrite(_STROBE_IO, HIGH);
}
void TM1638plus::setLED(uint8_t position, uint8_t value)
{
pinMode(_DATA_IO, OUTPUT);
sendCommand(TM_WRITE_LOC);
digitalWrite(_STROBE_IO, LOW);
sendData(TM_LEDS_ADR + (position << 1));
sendData(value);
digitalWrite(_STROBE_IO, HIGH);
}
void TM1638plus::setLEDs(uint16_t ledvalues)
{
for (uint8_t LEDposition = 0; LEDposition < 8; LEDposition++) {
uint8_t colour = 0;
if ((ledvalues & (1 << LEDposition)) != 0) {
colour |= TM_RED_LED; //scan lower byte, set Red if one
}
if ((ledvalues & (1 << (LEDposition + 8))) != 0) {
colour |= TM_GREEN_LED; //scan upper byte, set green if one
}
setLED(LEDposition, colour);
}
}
void TM1638plus::displayIntNum(unsigned long number, boolean leadingZeros)
{
char values[TM_DISPLAY_SIZE + 1];
snprintf(values, TM_DISPLAY_SIZE + 1, leadingZeros ? "%08ld" : "%ld", number);
displayText(values);
}
void TM1638plus::DisplayDecNumNibble(uint16_t numberUpper, uint16_t numberLower, boolean leadingZeros)
{
char valuesUpper[TM_DISPLAY_SIZE + 1];
char valuesLower[TM_DISPLAY_SIZE/2 + 1];
snprintf(valuesUpper, TM_DISPLAY_SIZE/2 + 1, leadingZeros ? "%04d" : "%d", numberUpper);
snprintf(valuesLower, TM_DISPLAY_SIZE/2 + 1, leadingZeros ? "%04d" : "%d", numberLower);
strcat(valuesUpper ,valuesLower);
displayText(valuesUpper);
}
void TM1638plus::displayText(const char *text) {
char c, pos;
pos = 0;
while ((c = (*text++)) && pos < TM_DISPLAY_SIZE) {
if (*text == '.' && c != '.') {
displayASCIIwDot(pos++, c);
text++;
} else {
displayASCII(pos++, c);
}
}
}
void TM1638plus::displayASCIIwDot(uint8_t position, uint8_t ascii) {
// add 128 or 0x080 0b1000000 to turn on decimal point/dot in seven seg
display7Seg(position, pgm_read_byte(&SevenSeg[ascii- TM_ASCII_OFFSET]) + TM_DOT_MASK_DEC);
}
void TM1638plus::display7Seg(uint8_t position, uint8_t value) { // call 7-segment
sendCommand(TM_WRITE_LOC);
digitalWrite(_STROBE_IO, LOW);
sendData(TM_SEG_ADR + (position << 1));
sendData(value);
digitalWrite(_STROBE_IO, HIGH);
}
void TM1638plus::displayASCII(uint8_t position, uint8_t ascii) {
display7Seg(position, pgm_read_byte(&SevenSeg[ascii - TM_ASCII_OFFSET]));
}
void TM1638plus::displayHex(uint8_t position, uint8_t hex)
{
uint8_t offset = 0;
if (hex <= 9)
{
display7Seg(position, pgm_read_byte(&SevenSeg[hex + TM_HEX_OFFSET]));
// 16 is offset in reduced ASCII table for 0
}else if ((hex >= 10) && (hex <=15))
{
// Calculate offset in reduced ASCII table for AbCDeF
switch(hex)
{
case 10: offset = 'A'; break;
case 11: offset = 'b'; break;
case 12: offset = 'C'; break;
case 13: offset = 'd'; break;
case 14: offset = 'E'; break;
case 15: offset = 'F'; break;
}
display7Seg(position, pgm_read_byte(&SevenSeg[offset-TM_ASCII_OFFSET]));
}
}
uint8_t TM1638plus::readButtons()
{
uint8_t buttons = 0;
uint8_t v =0;
digitalWrite(_STROBE_IO, LOW);
sendData(TM_BUTTONS_MODE);
pinMode(_DATA_IO, INPUT);
for (uint8_t i = 0; i < 4; i++)
{
if (_HIGH_FREQ == false)
v = shiftIn(_DATA_IO, _CLOCK_IO, LSBFIRST) << i;
else
v = TM_common.HighFreqshiftin(_DATA_IO, _CLOCK_IO, LSBFIRST) << i;
buttons |= v;
}
pinMode(_DATA_IO, OUTPUT);
digitalWrite(_STROBE_IO, HIGH);
return buttons;
}
void TM1638plus::brightness(uint8_t brightness)
{
uint8_t value = 0;
value = TM_BRIGHT_ADR + (TM_BRIGHT_MASK & brightness);
sendCommand(value);
}

View File

@ -0,0 +1,104 @@
/*
* Project Name: TM1638plus
* File: TM1638plus.h
* Description: TM1638plus.h header file arduino library for TM1638 module(LED & KEY). Model 1 & Model 3
* Author: Gavin Lyons.
* Created May 2019
* URL: https://github.com/gavinlyonsrepo/TM1638plus
*/
#ifndef TM1638PLUS_H
#define TM1638PLUS_H
#if (ARDUINO >=100)
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include "TM1638plus_common.h"
class TM1638plus {
public:
// Constructor
//Parameters
// 1. strobe = GPIO STB pin
// 2. clock = GPIO CLK pin
// 3. data = GPIO DIO pin
// 4. higfreq Changes the value of parameter _HIGH_FREQ which is default false
// This is used when running high freq MCU CPU (~>100Mhz) because of issues with button function.
// Pass true when running high freq MCU CPU (~>100Mhz).
TM1638plus(uint8_t strobe, uint8_t clock, uint8_t data, bool highfreq = false);
// Methods
void displayBegin(); // Begin method , sets pinmodes , Call in setup
void reset(void); // Reset / Clear module
//Sets the brightness level on a scale of brightness = 0 to 7.
//0 is not turned off, it's just the lowest brightness.
//If user wishes to change the default brightness at start-up change.
//The DEFAULT_BRIGHTNESS define in header file.
void brightness(uint8_t brightness);
//Read buttons returns a byte with value of buttons 1-8 b7b6b5b4b3b2b1b0
// 1 pressed, zero not pressed.
//User may have to debounce buttons depending on application.
//See [URL LINK](https://github.com/gavinlyonsrepo/Arduino_Clock_3)
// for de-bonce example.
uint8_t readButtons(void);
// Send Text to Seven segments, passed char array pointer
// dots are removed from string and dot on preceding digit switched on
// "abc.def" will be shown as "abcdef" with c decimal point turned on.
void displayText(const char *text);
// Send ASCII value to seven segment, pass position 0-7 and ASCII value byte
void displayASCII(uint8_t position, uint8_t ascii);
// Same as displayASCII function but turns on dot/decimal point as well
void displayASCIIwDot(uint8_t position, uint8_t ascii) ;
// Send HEX value to seven segment, pass position 0-7 and hex value(DEC) 0-15
void displayHex(uint8_t position, uint8_t hex);
// Send seven segment value to seven segment
// pass position 0-7 byte of data corresponding to segments (dp)gfedcba
// i.e 0b01000001 will set g and a on.
void display7Seg(uint8_t position, uint8_t value);
//Display an integer and leading zeros optional
void displayIntNum(unsigned long number, boolean leadingZeros = true);
//Divides the display into two nibbles and displays a Decimal number in each.
//takes in two numbers 0-9999 for each nibble , and byte for decimal point display,
//and leading zeros optional
void DisplayDecNumNibble(uint16_t numberUpper, uint16_t numberLower, boolean leadingZeros = true);
// Set the LEDs. passed one 16bit integer.
// MODEL 3:
//MSB byte for the green LEDs, LS byte for the red LEDs (0xgreenred)
//ie. 0xE007 1110 0000 0000 0111 results in L8-L0 GGGX XRRR, NOTE L8 is RHS on display
// MODEL 1:
// MSB byte 1 for red LED , LSB byte n/a set to 0x00 (0xleds, 0xXX)
//i.e 0xF100 1111 0000 L8-L0 RRRRXXX0 NOTE L8 is RHS on display
void setLEDs(uint16_t greenred);
// Set an LED, pass it LED position 0-7 and value 0 or 1 , L1-L8
void setLED(uint8_t position, uint8_t value);
private:
uint8_t _STROBE_IO;
uint8_t _DATA_IO;
uint8_t _CLOCK_IO;
void sendCommand(uint8_t value);
void sendData(uint8_t data);
//This is used when running high freq CPU
bool _HIGH_FREQ = false;
TM1638plus_common TM_common;
};
#endif

View File

@ -0,0 +1,52 @@
/*
* Project Name: TM1638plus
* File: TM1638plus_common
* Description: cpp file for common data and functions between model 1 and 2 classes
* Arduino library TM1638plus
* Author: Gavin Lyons.
* URL: https://github.com/gavinlyonsrepo/TM1638plus
*/
#include "TM1638plus_common.h"
TM1638plus_common::TM1638plus_common()
{
// Blank constructor
}
uint8_t TM1638plus_common::HighFreqshiftin(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder)
{
uint8_t value = 0;
uint8_t i = 0;
for(i = 0; i < 8; ++i) {
if(bitOrder == LSBFIRST)
value |= digitalRead(dataPin) << i;
else
value |= digitalRead(dataPin) << (7 - i);
digitalWrite(clockPin, HIGH);
delayMicroseconds(1);
digitalWrite(clockPin, LOW);
delayMicroseconds(1);
}
return value;
}
void TM1638plus_common::HighFreqshiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val)
{
uint8_t i;
for (i = 0; i < 8; i++) {
if (bitOrder == LSBFIRST)
digitalWrite(dataPin, !!(val & (1 << i)));
else
digitalWrite(dataPin, !!(val & (1 << (7 - i))));
digitalWrite(clockPin, HIGH);
delayMicroseconds(1);
digitalWrite(clockPin, LOW);
delayMicroseconds(1);
}
}

View File

@ -0,0 +1,152 @@
/*
* Project Name: TM1638plus
* File: TM1638plus_common.h
* Description: header file for common data and functions between model 1 and 2 classes
* Arduino library TM1638plus
* Author: Gavin Lyons.
* URL: https://github.com/gavinlyonsrepo/TM1638plus
*/
#ifndef TM1638PLUS_COMMON_H
#define TM1638PLUS_COMMON_H
#if (ARDUINO >=100)
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#define TM_ACTIVATE 0x8F // Start up
#define TM_BUTTONS_MODE 0x42 // Buttons mode
#define TM_WRITE_LOC 0x44 // Write to a location
#define TM_WRITE_INC 0x40 // Incremental write
#define TM_SEG_ADR 0xC0 // leftmost segment Address C0 C2 C4 C6 C8 CA CC CE
#define TM_LEDS_ADR 0xC1 // Leftmost LED address C1 C3 C5 C7 C9 CB CD CF
#define TM_BRIGHT_ADR 0x88 // Brightness address
#define TM_BRIGHT_MASK 0x07 // Brightness mask
#define TM_DEFAULT_BRIGHTNESS 0x02 //can be 0x00 to 0x07
#define TM_DISPLAY_SIZE 8 //size of display
#define TM_ASCII_OFFSET 32 // Ascii table offset to jump over first missing 32 chars
#define TM_HEX_OFFSET 16 // Ascii table offset to reach number position
#define TM_DOT_MASK_DEC 128 // 0x80 Mask to switch on decimal point in seven seg.
#define TM_RED_LED 0x02 // Model 3
#define TM_GREEN_LED 0x01 // Model 3
#define TM_OFF_LED 0x00
// font , map of ASCII values/table to 7-segment, offset to position 32.
const PROGMEM unsigned char SevenSeg[] = {
0x00, /* (space) */
0x86, /* ! */
0x22, /* " */
0x7E, /* # */
0x6D, /* $ */
0xD2, /* % */
0x46, /* & */
0x20, /* ' */
0x29, /* ( */
0x0B, /* ) */
0x21, /* * */
0x70, /* + */
0x10, /* , */
0x40, /* - */
0x80, /* . */
0x52, /* / */
0x3F, /* 0 */
0x06, /* 1 */
0x5B, /* 2 */
0x4F, /* 3 */
0x66, /* 4 */
0x6D, /* 5 */
0x7D, /* 6 */
0x07, /* 7 */
0x7F, /* 8 */
0x6F, /* 9 */
0x09, /* : */
0x0D, /* ; */
0x61, /* < */
0x48, /* = */
0x43, /* > */
0xD3, /* ? */
0x5F, /* @ */
0x77, /* A */
0x7C, /* B */
0x39, /* C */
0x5E, /* D */
0x79, /* E */
0x71, /* F */
0x3D, /* G */
0x76, /* H */
0x30, /* I */
0x1E, /* J */
0x75, /* K */
0x38, /* L */
0x15, /* M */
0x37, /* N */
0x3F, /* O */
0x73, /* P */
0x6B, /* Q */
0x33, /* R */
0x6D, /* S */
0x78, /* T */
0x3E, /* U */
0x3E, /* V */
0x2A, /* W */
0x76, /* X */
0x6E, /* Y */
0x5B, /* Z */
0x39, /* [ */
0x64, /* \ */
0x0F, /* ] */
0x23, /* ^ */
0x08, /* _ */
0x02, /* ` */
0x5F, /* a */
0x7C, /* b */
0x58, /* c */
0x5E, /* d */
0x7B, /* e */
0x71, /* f */
0x6F, /* g */
0x74, /* h */
0x10, /* i */
0x0C, /* j */
0x75, /* k */
0x30, /* l */
0x14, /* m */
0x54, /* n */
0x5C, /* o */
0x73, /* p */
0x67, /* q */
0x50, /* r */
0x6D, /* s */
0x78, /* t */
0x1C, /* u */
0x1C, /* v */
0x14, /* w */
0x76, /* x */
0x6E, /* y */
0x5B, /* z */
// Note : Removed last 4 characters to reduce program size as of v 1.3.0
// 0x46, /* { */
// 0x30, /* | */
// 0x70, /* } */
// 0x01, /* ~ */
};
// Class for some common functions
class TM1638plus_common{
public:
// Constructor
TM1638plus_common();
// Used instead of arduino function "shiftin" when _HIGH_FREQ is set to true
uint8_t HighFreqshiftin(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) ;
// Used instead of arduino function "shiftOut" when _HIGH_FREQ is set to true
void HighFreqshiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val);
};
#endif

View File

@ -375,8 +375,9 @@ struct {
uint8_t param[PARAM8_SIZE]; // 2FC SetOption32 .. SetOption49
int16_t toffset[2]; // 30E
uint8_t display_font; // 312
uint8_t display_type; // 313
uint8_t free_313[44]; // 313
uint8_t free_314[43]; // 314
uint8_t tuyamcu_topic; // 33F Manage tuyaSend topic. ex_energy_power_delta on 6.6.0.20, replaced on 8.5.0.1
uint16_t domoticz_update_timer; // 340

View File

@ -321,6 +321,7 @@
#define USE_DISPLAY_RA8876 // [DisplayModel 10]
#define USE_DISPLAY_ST7789 // [DisplayModel 12] Enable ST7789 module
#define USE_DISPLAY_SSD1331 // [DisplayModel 14] Enable SSD1331 module
#define USE_DISPLAY_TM1637 // [DisplayModel 15] Enable TM1637, TM1638 modules
#undef DEBUG_THEO // Disable debug code
#undef USE_DEBUG_DRIVER // Disable debug code

View File

@ -82,6 +82,7 @@ const uint8_t DISPLAY_LOG_ROWS = 32; // Number of lines in display log
#define D_CMND_DISP_SETLED "SetLED"
#define D_CMND_DISP_BUTTONS "Buttons"
#define D_CMND_DISP_SCROLLTEXT "ScrollText"
#define D_CMND_DISP_TYPE "Type"
@ -99,7 +100,7 @@ enum XdspFunctions { FUNC_DISPLAY_INIT_DRIVER, FUNC_DISPLAY_INIT, FUNC_DISPLAY_E
, FUNC_DISPLAY_NUMBER, FUNC_DISPLAY_FLOAT, FUNC_DISPLAY_NUMBERNC, FUNC_DISPLAY_FLOATNC,
FUNC_DISPLAY_BRIGHTNESS, FUNC_DISPLAY_RAW, FUNC_DISPLAY_LEVEL, FUNC_DISPLAY_SEVENSEG_TEXT, FUNC_DISPLAY_SEVENSEG_TEXTNC,
FUNC_DISPLAY_SCROLLDELAY, FUNC_DISPLAY_CLOCK, FUNC_DISPLAY_SETLEDS, FUNC_DISPLAY_SETLED,
FUNC_DISPLAY_BUTTONS, FUNC_DISPLAY_SCROLLTEXT
FUNC_DISPLAY_BUTTONS, FUNC_DISPLAY_SCROLLTEXT, FUNC_DISPLAY_TYPE
};
enum DisplayInitModes { DISPLAY_INIT_MODE, DISPLAY_INIT_PARTIAL, DISPLAY_INIT_FULL };
@ -114,7 +115,7 @@ const char kDisplayCommands[] PROGMEM = D_PRFX_DISPLAY "|" // Prefix
"|" D_CMND_DISP_CLEAR "|" D_CMND_DISP_NUMBER "|" D_CMND_DISP_FLOAT "|" D_CMND_DISP_NUMBERNC "|" D_CMND_DISP_FLOATNC "|"
D_CMND_DISP_BRIGHTNESS "|" D_CMND_DISP_RAW "|" D_CMND_DISP_LEVEL "|" D_CMND_DISP_SEVENSEG_TEXT "|" D_CMND_DISP_SEVENSEG_TEXTNC "|"
D_CMND_DISP_SCROLLDELAY "|" D_CMND_DISP_CLOCK "|" D_CMND_DISP_TEXTNC "|" D_CMND_DISP_SETLEDS "|" D_CMND_DISP_SETLED "|"
D_CMND_DISP_BUTTONS "|" D_CMND_DISP_SCROLLTEXT
D_CMND_DISP_BUTTONS "|" D_CMND_DISP_SCROLLTEXT "|" D_CMND_DISP_TYPE
;
void (* const DisplayCommand[])(void) PROGMEM = {
@ -127,7 +128,7 @@ void (* const DisplayCommand[])(void) PROGMEM = {
, &CmndDisplayClear, &CmndDisplayNumber, &CmndDisplayFloat, &CmndDisplayNumberNC, &CmndDisplayFloatNC,
&CmndDisplayBrightness, &CmndDisplayRaw, &CmndDisplayLevel, &CmndDisplaySevensegText, &CmndDisplaySevensegTextNC,
&CmndDisplayScrollDelay, &CmndDisplayClock, &CmndDisplayTextNC, &CmndDisplaySetLEDs, &CmndDisplaySetLED,
&CmndDisplayButtons, &CmndDisplayScrollText
&CmndDisplayButtons, &CmndDisplayScrollText, &CmndDisplayType
};
char *dsp_str;
@ -1875,32 +1876,50 @@ void CmndDisplaySetLEDs(void)
void CmndDisplaySetLED(void)
{
if (!renderer) {
XdspCall(FUNC_DISPLAY_SETLED);
}
ResponseCmndChar(XdrvMailbox.data);
}
void CmndDisplayButtons(void)
{
if (!renderer) {
XdspCall(FUNC_DISPLAY_BUTTONS);
}
ResponseCmndNumber(XdrvMailbox.payload);
}
void CmndDisplayScrollText(void)
{
bool result = false;
if (!renderer) {
result = XdspCall(FUNC_DISPLAY_SCROLLTEXT);
result = XdspCall(FUNC_DISPLAY_SETLED);
}
if(result) ResponseCmndNumber(XdrvMailbox.payload);
else ResponseCmndChar(XdrvMailbox.data);
}
void CmndDisplayButtons(void)
{
bool result = false;
if (!renderer) {
result = XdspCall(FUNC_DISPLAY_BUTTONS);
}
if(result) ResponseCmndNumber(XdrvMailbox.payload);
else ResponseCmndChar(XdrvMailbox.data);
}
void CmndDisplayScrollText(void)
{
if (!renderer) {
XdspCall(FUNC_DISPLAY_SCROLLTEXT);
}
ResponseCmndChar(XdrvMailbox.data);
}
void CmndDisplayType(void)
{
if(ArgC() == 0) {
XdrvMailbox.payload = Settings.display_type;
} else {
uint8_t prev_type = Settings.display_type;
if(prev_type != XdrvMailbox.payload) {
if (!renderer) {
XdspCall(FUNC_DISPLAY_TYPE);
Settings.display_type = XdrvMailbox.payload;
}
}
}
ResponseCmndNumber(XdrvMailbox.payload);
}
void CmndDisplaySize(void)
{

View File

@ -1,5 +1,5 @@
/*
xdsp_15_tm1637.ino - Support for TM1637 seven-segment display (upto 6 digits) for Tasmota
xdsp_15_tm1637.ino - Support for TM1637- and TM1638-based seven-segment displays for Tasmota
Copyright (C) 2021 Ajith Vasudevan
@ -21,29 +21,36 @@
#ifdef USE_DISPLAY_TM1637
/*********************************************************************************************\
This driver enables the display of numbers (both integers and floats) and basic text
on the inexpensive TM1637-based seven-segment modules (tested on both 4- and 6-digit variants).
on the inexpensive TM1637- and TM1638-based seven-segment modules.
Raw segments can also be displayed.
In addition, it is also possible to set brightness (8 levels), clear the display, scroll text, display
a rudimentary bar graph, and a Clock (12 hr and 24 hr).
In addition, it is also possible to set brightness (8 levels), clear the display, scroll text,
display a rudimentary bar graph, and a Clock (12 hr and 24 hr).
To use, compile Tasmota with USE_DISPLAY and USE_DISPLAY_TM1637, or build the tasmota-display env.
The pins to use are "SSPI MOSI" and "SSPI SCLK".
Connect the TM1637 display module's DIO and CLK pins to any free GPIOs of the ESP8266 module
Connect the TM1637 or TM1638 display module's pins to any free GPIOs of the ESP8266 module
and assign the pins as follows from Tasmota's GUI:
DIO hardware pin --> "SSPI MOSI"
CLK hardware pin --> "SSPI SCLK"
Once the device restarts the following "Display" commands become available:
STB hardware pin --> "SSPI MISO" (Only for TM1638)
Once the device restarts the following "Display" commands should become available:
In case you get a stat/<TOPIC>/RESULT = {"Command":"Unknown"} result for any of these commands,
please ensure that your DisplayModel is set to 15 using the command "DisplayModel 15"
DisplaySize size {1-6}
Sets the number of digits to use. This is typically set to the actual number of digits available
in the display module. command e.g., "DisplaySize 6"
DisplayType type {0|1|2}
Sets the display type. 0 => TM1637, 4 digit
1 => TM1637, 6 digit
2 => TM1638, 8 digit
Command e.g., "DisplayType 1" // to enable TM1637 6-digit variant
DisplayClear
@ -51,6 +58,7 @@
Clears the display, command: "DisplayClear"
DisplayNumber num [,position {0-(NUM_DIGITS-1))} [,leading_zeros {0|1} [,length {1 to NUM_DIGITS}]]]
Clears and then displays number without decimal. command e.g., "DisplayNumber 1234"
@ -58,6 +66,8 @@
'leading zeros' can be 1 or 0 (default), 'length' can be 1 to NUM_DIGITS, 'position' can be 0 (left-most) to NUM_DIGITS (right-most).
See function description below for more details.
DisplayNumberNC num [,position {0-(NUM_DIGITS-1))} [,leading_zeros {0|1} [,length {1 to NUM_DIGITS}]]]
Display integer number as above, but without clearing first. e.g., "DisplayNumberNC 1234". Usage is same as above.
@ -97,10 +107,12 @@
Clears and then displays basic text. command e.g., "DisplayText ajith vasudevan"
Control 'length' and 'position' with "DisplayText <text>, <position>, <length>"
'length' can be 1 to NUM_DIGITS, 'position' can be 0 (left-most) to NUM_DIGITS-1 (right-most)
A caret(^) symbol in the text input is dispayed as the degrees(°) symbol. This is useful for displaying Temperature!
For example, the command "DisplayText 22.5^" will display "22.5°".
DisplayTextNC text [, position {0-NUM_DIGITS-1} [,length {1 to NUM_DIGITS}]]
Clears first, then displays text. Usage is same as above.
@ -132,16 +144,63 @@
"DisplayClock 2" // 24 hr format
"DisplayClock 0" // turn off clock
Commands specific to TM1638
====================================
DisplaySetLEDs bit_array {0-255}
Sets the 8 LEDs (not the digits!) on the TM1638 module to the binary number represented by the input bit_array.
For example, "DisplaySetLEDs 3" would light up the first and second LED (from left), because 3 => 00000011
DisplaySetLED position {0-7}, value {0|1}
Sets a specified LED to either ON or OFF. e.g., "DisplaySetLED 2, 1" would light up the 3rd LED (2 => 3rd position)
DisplayButtons
Causes the current state of the buttons to be returned as a "STAT" message of the form stat/TM1638/RESULT = {"DisplayButtons": <buttonvalue>}
The button value is the decimal representation of the bit-array that constitutes the button states. For example, if the 5th button is pressed and the
DisplayButtons command is issued, the response will be stat/TM1638/RESULT = {"DisplayButtons": 16} because 16 => 2^(5-1)
if the 2nd and 3rd buttons are pressed together and the DisplayButtons command is issued, the response will be
stat/TM1638/RESULT = {"DisplayButtons": 6} because 6 => 2^(2-1) + 2^(3-1)
Button Functionality (TM1638 only):
======================================
When this driver is initialized with "DisplayType 2" (TM1638), the buttons on the TM1638 module can be used
to toggle the corresponding LEDs.
In addition, if SwitchTopic is set to some value, then for each button press, a TOGGLE for that switch number is sent.
For example, if Topic = "TM1638" and SwitchTopic = "TEST_TM1638", and if S3 is pressed, then,
1) a STAT message is sent : stat/TM1638/RESULT = {"TM1638_BUTTONS":4} // (4 = 2^(3-1))
and 2) a TOGGLE command is sent: cmnd/TEST/POWER3 = TOGGLE
\*********************************************************************************************/
#define XDSP_15 15
#include "SevenSegmentTM1637.h"
SevenSegmentTM1637 *display;
#include "SevenSegmentTM1637.h"
#include <TM1638plus.h>
SevenSegmentTM1637 *disp37;
TM1638plus *disp38;
bool driverinited = false;
bool showClock = false;
bool clock24 = false;
char tm[5];
char msg[60];
uint8_t buttons;
uint8_t prevbuttons;
uint32_t NUM_DIGITS = 4;
uint32_t prev_num_digits = 4;
bool scroll = false;
@ -149,7 +208,10 @@ uint32_t scrolldelay = 4;
uint32_t scrollindex = 0;
uint32_t iteration = 0;
uint32_t brightness = 5;
char modelname[8];
enum displaytypes { TM1637, TM1638 };
uint8_t displaytype = TM1637;
bool modechanged = false;
#define BRIGHTNESS_MIN 0 // Display OFF
#define BRIGHTNESS_MAX 8
@ -157,21 +219,42 @@ uint32_t brightness = 5;
#define LEVEL_MIN 0
#define LEVEL_MAX 100
#define SCROLL_MAX_LEN 50
#define POSITION_MIN 0
#define POSITION_MAX 8
#define LED_MIN 0
#define LED_MAX 255
char scrolltext[CMD_MAX_LEN];
/*********************************************************************************************\
* Init function
\*********************************************************************************************/
bool TM1637Init(void) {
display = new SevenSegmentTM1637(Pin(GPIO_SSPI_SCLK), Pin(GPIO_SSPI_MOSI) );
NUM_DIGITS = Settings.display_size > 3 ? Settings.display_size : 4;
Settings.display_size = NUM_DIGITS;
display->begin(NUM_DIGITS, 1);
display->setBacklight(brightness * 10);
clearDisplay();
Settings.display_model = XDSP_15;
AddLog(LOG_LEVEL_INFO, PSTR("DSP: TM1637 display driver initialized"));
bool DriverInit(void) {
if(Settings.display_model == XDSP_15) {
if(driverinited) return true;
if(Settings.display_type == 2) { NUM_DIGITS = 8; displaytype = TM1638; }
else if(Settings.display_type == 1) { NUM_DIGITS = 6; displaytype = TM1637; }
else { Settings.display_type = 0; NUM_DIGITS = 4; displaytype = TM1637; }
if(displaytype == TM1637) {
strcpy(modelname, "TM1637");
disp37 = new SevenSegmentTM1637(Pin(GPIO_SSPI_SCLK), Pin(GPIO_SSPI_MOSI) );
disp37->begin(NUM_DIGITS, 1);
} else if(displaytype == TM1638) {
strcpy(modelname, "TM1638");
disp38 = new TM1638plus(Pin(GPIO_SSPI_MISO), Pin(GPIO_SSPI_SCLK), Pin(GPIO_SSPI_MOSI), true );
NUM_DIGITS = 8;
disp38->displayBegin();
}
Settings.display_size = NUM_DIGITS; // Can use to check current display size
clearDisplay();
brightness = (Settings.display_dimmer ? Settings.display_dimmer : brightness);
setBrightness(brightness);
driverinited = true;
modechanged = false;
AddLog(LOG_LEVEL_INFO, PSTR("DSP: %s display driver initialized with %d digits (DisplayType %d)"), modelname, NUM_DIGITS, Settings.display_type);
}
return true;
}
@ -182,7 +265,7 @@ bool TM1637Init(void) {
* commands: DisplayNumber num [,position {0-(NUM_DIGITS-1)} [,leading_zeros {0|1} [,length {1 to NUM_DIGITS}]]]
* DisplayNumberNC num [,position {0-(NUM_DIGITS-1)} [,leading_zeros {0|1} [,length {1 to NUM_DIGITS}]]] // "NC" --> "No Clear"
\*********************************************************************************************/
bool CmndTM1637Number(bool clear) {
bool CmndNumber(bool clear) {
char sNum[CMD_MAX_LEN];
char sLeadingzeros[CMD_MAX_LEN];
char sPosition[CMD_MAX_LEN];
@ -212,10 +295,10 @@ bool CmndTM1637Number(bool clear) {
if((position < 0) || (position > (NUM_DIGITS-1))) position = 0;
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: num=%d"), num);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: position=%d"), position);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: leadingzeros=%d"), leadingzeros);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: length=%d"), length);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: num=%d"), modelname, num);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: position=%d"), modelname, position);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: leadingzeros=%d"), modelname, leadingzeros);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: length=%d"), modelname, length);
if(clear) clearDisplay();
@ -227,17 +310,18 @@ bool CmndTM1637Number(bool clear) {
char pad = (leadingzeros ? '0': ' ');
uint32_t i = position;
uint8_t rawBytes[1];
rawBytes[0] = display->encode(pad);
for(; i<position + (length - strlen(txt)); i++) {
if(i>NUM_DIGITS) break;
display->printRaw(rawBytes, 1, i);
if(displaytype == TM1637) { rawBytes[0] = disp37->encode(pad); disp37->printRaw(rawBytes, 1, i); }
else if(displaytype == TM1638) disp38->displayASCII(i, pad);
}
for(uint32_t j = 0; i< position + length; i++, j++) {
if(txt[j] == 0) break;
rawBytes[0] = display->encode(txt[j]);
if(i>NUM_DIGITS) break;
display->printRaw(rawBytes, 1, i);
if(txt[j] == 0) break;
if(displaytype == TM1637) { rawBytes[0] = disp37->encode(txt[j]); disp37->printRaw(rawBytes, 1, i); }
else if(displaytype == TM1638) disp38->displayASCII(i, txt[j]);
}
return true;
@ -251,7 +335,7 @@ bool CmndTM1637Number(bool clear) {
* commands: DisplayFloat num [,position {0-(NUM_DIGITS-1)} [,precision {0-NUM_DIGITS} [,length {1 to NUM_DIGITS}]]]
* DisplayFloatNC num [,position {0-(NUM_DIGITS-1)} [,precision {0-NUM_DIGITS} [,length {1 to NUM_DIGITS}]]] // "NC" --> "No Clear"
\*********************************************************************************************/
bool CmndTM1637Float(bool clear) {
bool CmndFloat(bool clear) {
char sNum[CMD_MAX_LEN];
char sPrecision[CMD_MAX_LEN];
@ -292,22 +376,36 @@ bool CmndTM1637Float(bool clear) {
if((length <= 0) || (length > NUM_DIGITS)) length = NUM_DIGITS;
char s[30];
ext_snprintf_P(s, sizeof(s), PSTR("LOG: TM1637: num=%*_f"), 4, &fnum);
ext_snprintf_P(s, sizeof(s), PSTR("LOG: %s: num=%4_f"), modelname, &fnum);
AddLog(LOG_LEVEL_DEBUG, PSTR("%s"), s);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: precision=%d"), precision);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: length=%d"), length);
uint8_t rawBytes[1];
for(uint32_t i=0, j=0; i<length; i++, j++) {
if(txt[i] == 0) break;
rawBytes[0] = display->encode(txt[i]);
if(txt[i+1] == '.') {
rawBytes[0] = rawBytes[0] | 128;
i++;
length++;
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: precision=%d"), modelname, precision);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: length=%d"), modelname, length);
if(displaytype == TM1637) {
uint8_t rawBytes[1];
for(uint32_t i=0, j=0; i<length; i++, j++) {
if(txt[i] == 0) break;
rawBytes[0] = disp37->encode(txt[i]);
if(txt[i+1] == '.') {
rawBytes[0] = rawBytes[0] | 128;
i++;
length++;
}
if((j+position) > NUM_DIGITS) break;
disp37->printRaw(rawBytes, 1, j+position);
}
if((j+position) > NUM_DIGITS) break;
display->printRaw(rawBytes, 1, j+position);
}
} else if(displaytype == TM1638) {
for(uint32_t i=0, j=0; i<length; i++, j++) {
if((j+position) > 7) break;
if(txt[i] == 0) break;
if(txt[i+1] == '.') {
disp38->displayASCIIwDot(j+position, txt[i]);
i++;
length++;
}
else disp38->displayASCII(j+position, txt[i]);
}
}
return true;
}
@ -317,7 +415,7 @@ bool CmndTM1637Float(bool clear) {
// * Clears the display
// * Command: DisplayClear
// \*********************************************************************************************/
bool CmndTM1637Clear(void) {
bool CmndClear(void) {
clearDisplay();
sprintf(msg, PSTR("Cleared"));
XdrvMailbox.data = msg;
@ -325,10 +423,16 @@ bool CmndTM1637Clear(void) {
}
// /*********************************************************************************************\
// * Clears the display
// \*********************************************************************************************/
void clearDisplay (void) {
unsigned char arr[] = {0};
AddLog(LOG_LEVEL_DEBUG, PSTR("Clearing digit %d"), NUM_DIGITS);
for(int i=0; i<NUM_DIGITS; i++) display->printRaw(arr, 1, i);
if(displaytype == TM1637) {
unsigned char arr[] = {0};
for(int i=0; i<NUM_DIGITS; i++) disp37->printRaw(arr, 1, i);
} else if(displaytype == TM1638) {
for(int i=0; i<NUM_DIGITS; i++) disp38->display7Seg(i, 0);
}
}
@ -336,9 +440,9 @@ void clearDisplay (void) {
* Display scrolling text
* Command: DisplayScrollText text
\*********************************************************************************************/
bool CmndTM1637ScrollText(void) {
bool CmndScrollText(void) {
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: text=%s"), XdrvMailbox.data);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: text=%s"), modelname, XdrvMailbox.data);
if(XdrvMailbox.data_len > SCROLL_MAX_LEN) {
snprintf(msg, sizeof(msg), PSTR("Text too long. Length should be less than %d"), SCROLL_MAX_LEN);
@ -360,7 +464,7 @@ bool CmndTM1637ScrollText(void) {
* Sets the scroll delay for scrolling text.
* Command: DisplayScrollDelay delay {0-15} // default = 4
\*********************************************************************************************/
bool CmndTM1637ScrollDelay(void) {
bool CmndScrollDelay(void) {
if(scrolldelay<0) scrolldelay=0;
scrolldelay = XdrvMailbox.payload;
return true;
@ -372,28 +476,31 @@ bool CmndTM1637ScrollDelay(void) {
* Scrolls a given string. Called every 50ms
\*********************************************************************************************/
void scrollText(void) {
if(scroll) {
iteration++;
if(scrolldelay) iteration = iteration % scrolldelay;
else iteration = 0;
if(iteration) return;
iteration++;
if(scrolldelay) iteration = iteration % scrolldelay;
else iteration = 0;
if(iteration) return;
if(scrollindex > strlen(scrolltext)) {
scroll = false;
scrollindex = 0;
return;
}
bool clr = false;
uint8_t rawBytes[1];
for(uint32_t i=0, j=scrollindex; i< strlen(scrolltext); i++, j++) {
if(i > (NUM_DIGITS-1)) break;
if(scrolltext[j] == 0) {clr = true;};
char charToDisp = (clr ? ' ' : scrolltext[j]);
rawBytes[0] = display->encode(charToDisp);
display->printRaw(rawBytes, 1, i);
}
scrollindex++;
if(scrollindex > strlen(scrolltext)) {
scroll = false;
scrollindex = 0;
return;
}
bool clr = false;
uint8_t rawBytes[1];
for(uint32_t i=0, j=scrollindex; i< strlen(scrolltext); i++, j++) {
if(i > (NUM_DIGITS-1)) break;
if(scrolltext[j] == 0) {clr = true;};
if(displaytype == TM1637) {
char charToDisp = (clr ? ' ' : scrolltext[j]);
rawBytes[0] = disp37->encode(charToDisp);
disp37->printRaw(rawBytes, 1, i);
} else if(displaytype == TM1638) {
disp38->displayASCII(i, (clr ? ' ' : scrolltext[j]));
}
}
scrollindex++;
}
@ -405,7 +512,7 @@ void scrollText(void) {
* Displays a horizontal bar graph. Takes a percentage number (0-100) as input
* Command: DisplayLevel level {0-100}
\*********************************************************************************************/
bool CmndTM1637Level(void) {
bool CmndLevel(void) {
uint16_t val = XdrvMailbox.payload;
if((val < LEVEL_MIN) || (val > LEVEL_MAX)) {
sprintf(msg, PSTR("Level should be a number in the range [%d, %d]"), LEVEL_MIN, LEVEL_MAX);
@ -414,25 +521,31 @@ bool CmndTM1637Level(void) {
}
uint8_t totalBars = 2*NUM_DIGITS;
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: CmndTM1637Level totalBars=%d"), totalBars);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: CmndLevel totalBars=%d"), modelname, totalBars);
float barsToDisplay = totalBars * val / 100.0f;
char txt[5];
ext_snprintf_P(txt, sizeof(txt), PSTR("%*_f"), 1, &barsToDisplay);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: CmndTM1637Level barsToDisplay=%s"), txt);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: CmndLevel barsToDisplay=%s"), modelname, txt);
char s[4];
ext_snprintf_P(s, sizeof(s), PSTR("%*_f"), 0, &barsToDisplay);
uint8_t numBars = atoi(s);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: CmndTM1637Level numBars=%d"), numBars);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: CmndLevel numBars=%d"), modelname, numBars);
clearDisplay();
uint8_t rawBytes[1];
for(int i=1; i<=numBars; i++) {
uint8_t digit = (i-1) / 2;
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: CmndTM1637Level digit=%d"), digit);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: CmndLevel digit=%d"), modelname, digit);
uint8_t value = (((i%2) == 0) ? 54 : 48);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: CmndTM1637Level value=%d"), value);
rawBytes[0] = value;
display->printRaw(rawBytes, 1, digit);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: CmndLevel value=%d"), modelname, value);
if(displaytype == TM1637) {
rawBytes[0] = value;
disp37->printRaw(rawBytes, 1, digit);
} else if(displaytype == TM1638) {
disp38->display7Seg(digit, value);
}
}
return true;
}
@ -446,7 +559,7 @@ bool CmndTM1637Level(void) {
* bit 1 is segment B etc. The function may either set the entire display
* or any desired part using the length and position parameters.
\*********************************************************************************************/
bool CmndTM1637Raw(void) {
bool CmndRaw(void) {
uint8_t DATA[6] = { 0, 0, 0, 0, 0, 0 };
char as[CMD_MAX_LEN];
@ -496,23 +609,32 @@ bool CmndTM1637Raw(void) {
if(position < 0 || position > (NUM_DIGITS-1)) position = 0;
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: a=%d"), DATA[0]);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: b=%d"), DATA[1]);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: c=%d"), DATA[2]);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: d=%d"), DATA[3]);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: e=%d"), DATA[4]);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: f=%d"), DATA[5]);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: a=%d"), modelname, DATA[0]);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: b=%d"), modelname, DATA[1]);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: c=%d"), modelname, DATA[2]);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: d=%d"), modelname, DATA[3]);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: e=%d"), modelname, DATA[4]);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: f=%d"), modelname, DATA[5]);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: length=%d"), length);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: position=%d"), position);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: length=%d"), modelname, length);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: position=%d"), modelname, position);
uint8_t rawBytes[1];
for(uint32_t i=position; i<position+length; i++ ) {
if(i>(NUM_DIGITS-1)) break;
rawBytes[0] = DATA[i-position];
display->printRaw(rawBytes, 1, i);
if(displaytype == TM1637) {
uint8_t rawBytes[1];
for(uint32_t i=position; i<position+length; i++ ) {
if(i>(NUM_DIGITS-1)) break;
rawBytes[0] = DATA[i-position];
disp37->printRaw(rawBytes, 1, i);
}
} else if(displaytype == TM1638) {
for(uint32_t i=position; i<position+length; i++ ) {
if(i>7) break;
disp38->display7Seg(i, DATA[i-position]);
}
}
return true;
}
@ -524,7 +646,7 @@ bool CmndTM1637Raw(void) {
* position parameters without affecting the rest of the display.
* Command: DisplayText text [, position {0-(NUM_DIGITS-1)} [,length {1 to NUM_DIGITS}]]
\*********************************************************************************************/
bool CmndTM1637Text(bool clear) {
bool CmndText(bool clear) {
char sString[CMD_MAX_LEN + 1];
char sPosition[CMD_MAX_LEN];
char sLength[CMD_MAX_LEN];
@ -546,9 +668,9 @@ bool CmndTM1637Text(bool clear) {
if((position < 0) || (position > (NUM_DIGITS-1))) position = 0;
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: sString=%s"), sString);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: position=%d"), position);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: length=%d"), length);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: sString=%s"), modelname, sString);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: position=%d"), modelname, position);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: length=%d"), modelname, length);
if(clear) clearDisplay();
@ -556,18 +678,31 @@ bool CmndTM1637Text(bool clear) {
if((length < 0) || (length > NUM_DIGITS)) length = NUM_DIGITS;
uint32_t i = position;
uint8_t rawBytes[1];
for(uint32_t j = 0; i< position + length; i++, j++) {
if(i > (NUM_DIGITS-1)) break;
if(sString[j] == 0) break;
rawBytes[0] = display->encode(sString[j]);
if(sString[j+1] == '.') {
rawBytes[0] = rawBytes[0] | 128;
j++;
} else if(sString[j] == '^') {
rawBytes[0] = 1 | 2 | 32 | 64;
if(displaytype == TM1637) {
uint8_t rawBytes[1];
for(uint32_t j = 0; i< position + length; i++, j++) {
if(i > (NUM_DIGITS-1)) break;
if(sString[j] == 0) break;
rawBytes[0] = disp37->encode(sString[j]);
if(sString[j+1] == '.') {
rawBytes[0] = rawBytes[0] | 128;
j++;
} else if(sString[j] == '^') {
rawBytes[0] = 1 | 2 | 32 | 64;
}
disp37->printRaw(rawBytes, 1, i);
}
display->printRaw(rawBytes, 1, i);
} else if(displaytype == TM1638) {
for(uint32_t j = 0; i< position + length; i++, j++) {
if(i > 7) break;
if(sString[j] == 0) break;
if(sString[j+1] == '.') {
disp38->displayASCIIwDot(i, sString[j]);
j++;
} else if(sString[j] == '^') {
disp38->display7Seg(i, (1 | 2 | 32 | 64));
} else disp38->displayASCII(i, sString[j]);
}
}
return true;
@ -578,7 +713,7 @@ bool CmndTM1637Text(bool clear) {
* Sets brightness of the display.
* Command: DisplayBrightness {0-8} // 0 => off
\*********************************************************************************************/
bool CmndTM1637Brightness(void) {
bool CmndBrightness(void) {
uint16_t val = XdrvMailbox.payload;
if(ArgC() == 0) {
@ -592,20 +727,30 @@ bool CmndTM1637Brightness(void) {
return false;
}
brightness = val;
display->setBacklight(brightness*10);
setBrightness(brightness);
return true;
}
void setBrightness(uint8_t val) {
if((val < BRIGHTNESS_MIN) || (val > BRIGHTNESS_MAX)) val = 5;
Settings.display_dimmer = val;
if(displaytype == TM1637) disp37->setBacklight(val*10);
else if(displaytype == TM1638) disp38->brightness(val);
}
/*********************************************************************************************\
* Displays a clock.
* Command: DisplayClock 1 // 12-hour format
* DisplayClock 2 // 24-hour format
* DisplayClock 0 // turn off clock and clear
\*********************************************************************************************/
bool CmndTM1637Clock(void) {
bool CmndClock(void) {
showClock = XdrvMailbox.payload;
@ -613,8 +758,8 @@ bool CmndTM1637Clock(void) {
if(XdrvMailbox.payload > 1) clock24 = true;
else if(XdrvMailbox.payload == 1) clock24 = false;
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: showClock=%d"), showClock);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: clock24=%d"), clock24);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: showClock=%d"), modelname, showClock);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: clock24=%d"), modelname, clock24);
if(!showClock) {
clearDisplay();
@ -646,29 +791,144 @@ void showTime() {
if(mn < 10) snprintf(tm, sizeof(tm), PSTR("%d0%d"), hr, mn);
else snprintf(tm, sizeof(tm), PSTR("%d%d"), hr, mn);
}
uint8_t rawBytes[1];
for(uint32_t i = 0; i< 4; i++) {
rawBytes[0] = display->encode(tm[i]);
if((millis() % 1000) > 500 && (i == 1)) rawBytes[0] = rawBytes[0] | 128;
display->printRaw(rawBytes, 1, i);
if(displaytype == TM1637) {
uint8_t rawBytes[1];
for(uint32_t i = 0; i< 4; i++) {
rawBytes[0] = disp37->encode(tm[i]);
if((millis() % 1000) > 500 && (i == 1)) rawBytes[0] = rawBytes[0] | 128;
disp37->printRaw(rawBytes, 1, i);
}
} else if(displaytype == TM1638) {
for(uint32_t i = 0; i< 4; i++) {
if((millis() % 1000) > 500 && (i == 1)) disp38->displayASCIIwDot(i, tm[i]);
else disp38->displayASCII(i, tm[i]);
}
}
}
/*********************************************************************************************\
* Sets all LEDs of the display.
* Command: DisplaySetLEDs {0-255}
\*********************************************************************************************/
bool CmndSetLEDs(void) {
if(displaytype != TM1638) {
sprintf(msg, PSTR("Command not valid for DisplayType %d"), displaytype);
XdrvMailbox.data = msg;
return false;
}
if(ArgC() == 0) XdrvMailbox.payload = 0;
uint16_t val = XdrvMailbox.payload;
if((val < LED_MIN) || (val > LED_MAX)) {
sprintf(msg, PSTR("Set LEDs value should be a number in the range [%d, %d]"), LED_MIN, LED_MAX);
XdrvMailbox.data = msg;
return false;
}
disp38->setLEDs(val << 8);
return true;
}
/*********************************************************************************************\
* Sets an LED at specified position.
* Command: DisplaySetLED position {0-7}, value {0|1}
\*********************************************************************************************/
bool CmndSetLED(void) {
if(displaytype != TM1638) {
sprintf(msg, PSTR("Command not valid for DisplayType %d"), displaytype);
XdrvMailbox.data = msg;
return false;
}
if(ArgC() < 2) {
sprintf(msg, PSTR("Set LED requires two comma-separated numbers as arguments"));
XdrvMailbox.data = msg;
return false;
}
char sVal[CMD_MAX_LEN];
char sPos[CMD_MAX_LEN];
uint32_t position = 0;
uint32_t value = 0;
switch (ArgC())
{
case 2 :
subStr(sVal, XdrvMailbox.data, ",", 2);
value = atoi(sVal);
case 1 :
subStr(sPos, XdrvMailbox.data, ",", 1);
position = atoi(sPos);
}
if((position < POSITION_MIN) || (position > POSITION_MAX)) {
sprintf(msg, PSTR("First argument, position should be in the range [%d, %d]"), POSITION_MIN, POSITION_MAX);
XdrvMailbox.data = msg;
return false;
}
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1638: position=%d"), position);
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1638: value=%d"), value);
disp38->setLED(position, value);
return true;
}
/*********************************************************************************************\
* Reads the button states. Called every 50ms
\*********************************************************************************************/
bool readButtons(void) {
buttons = disp38->readButtons();
if(prevbuttons != buttons) {
prevbuttons = buttons;
if(!buttons) return true;
if(buttons) {
Response_P(PSTR("{\"TM1638_BUTTONS\":%d}"), buttons);
MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR("BUTTONS"));
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1638: buttons changed: %d"), buttons);
for(int i=0; i<8; i++) {
if(buttons & (1<<i)) {
if(SwitchGetVirtual(i)) SwitchSetVirtual(i, 0);
else SwitchSetVirtual(i, 1);
disp38->setLED(i, (1 + SwitchGetVirtual(i)) % 2 );
}
}
SwitchHandler(1);
}
}
return true;
}
/*********************************************************************************************\
* This function is called for all TM1637 Display functions.
* Returns the current state of the buttons as a decimal representation of the button states
* Command: DisplayButtons
\*********************************************************************************************/
bool TM1637Cmd(uint8_t fn) {
bool CmndButtons(void) {
if(displaytype != TM1638) {
sprintf(msg, PSTR("Command not valid for DisplayType %d"), displaytype);
XdrvMailbox.data = msg;
return false;
}
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1638: buttons=%d"), buttons);
XdrvMailbox.payload = buttons;
return true;
}
/*********************************************************************************************\
* This function is called for all Display functions.
\*********************************************************************************************/
bool MainFunc(uint8_t fn) {
bool result = false;
NUM_DIGITS = Settings.display_size;
if(prev_num_digits != NUM_DIGITS) { // Cleck for change of display size, and re-init the library
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: Size changed. Re-initializing library..."));
display = new SevenSegmentTM1637(Pin(GPIO_SSPI_SCLK), Pin(GPIO_SSPI_MOSI) );
display->begin(NUM_DIGITS, 1);
display->setBacklight(40);
clearDisplay();
prev_num_digits = NUM_DIGITS;
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: Re-initialized library"));
}
if(XdrvMailbox.data_len > CMD_MAX_LEN) {
sprintf(msg, PSTR("Command text too long. Please limit it to %d characters"), CMD_MAX_LEN);
@ -678,43 +938,52 @@ bool TM1637Cmd(uint8_t fn) {
switch (fn) {
case FUNC_DISPLAY_CLEAR:
result = CmndTM1637Clear();
result = CmndClear();
break;
case FUNC_DISPLAY_NUMBER :
result = CmndTM1637Number(true);
result = CmndNumber(true);
break;
case FUNC_DISPLAY_NUMBERNC :
result = CmndTM1637Number(false);
result = CmndNumber(false);
break;
case FUNC_DISPLAY_FLOAT :
result = CmndTM1637Float(true);
result = CmndFloat(true);
break;
case FUNC_DISPLAY_FLOATNC :
result = CmndTM1637Float(false);
result = CmndFloat(false);
break;
case FUNC_DISPLAY_BRIGHTNESS:
result = CmndTM1637Brightness();
result = CmndBrightness();
break;
case FUNC_DISPLAY_RAW:
result = CmndTM1637Raw();
result = CmndRaw();
break;
case FUNC_DISPLAY_SEVENSEG_TEXT:
result = CmndTM1637Text(true);
result = CmndText(true);
break;
case FUNC_DISPLAY_SEVENSEG_TEXTNC:
result = CmndTM1637Text(false);
result = CmndText(false);
break;
case FUNC_DISPLAY_LEVEL:
result = CmndTM1637Level();
result = CmndLevel();
break;
case FUNC_DISPLAY_SCROLLTEXT:
result = CmndTM1637ScrollText();
result = CmndScrollText();
break;
case FUNC_DISPLAY_SCROLLDELAY:
result = CmndTM1637ScrollDelay();
result = CmndScrollDelay();
break;
case FUNC_DISPLAY_SETLEDS:
result = CmndSetLEDs();
break;
case FUNC_DISPLAY_SETLED:
result = CmndSetLED();
break;
case FUNC_DISPLAY_BUTTONS:
result = CmndButtons();
break;
case FUNC_DISPLAY_CLOCK:
result = CmndTM1637Clock();
result = CmndClock();
break;
}
@ -725,23 +994,26 @@ bool TM1637Cmd(uint8_t fn) {
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
bool Xdsp15(uint8_t function)
{
bool result = false;
if (FUNC_DISPLAY_INIT_DRIVER == function) {
result = TM1637Init(); // init
if(function == FUNC_DISPLAY_MODEL) {
return true;
}
else if (XDSP_15 == Settings.display_model) {
if (Settings.display_model == XDSP_15) {
switch (function) {
case FUNC_DISPLAY_MODEL:
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: FUNC_DISPLAY_MODEL"));
result = true;
case FUNC_DISPLAY_INIT_DRIVER:
result = DriverInit(); // init
break;
case FUNC_DISPLAY_INIT:
CmndTM1637Clear();
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: TM1637: FUNC_DISPLAY_INIT"));
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: FUNC_DISPLAY_INIT: Display depends on DisplayType, currently %d"), modelname, Settings.display_type);
result = true;
break;
case FUNC_DISPLAY_TYPE:
AddLog(LOG_LEVEL_DEBUG, PSTR("LOG: %s: FUNC_DISPLAY_TYPE: DisplayType set to %d, restarting to take effect ..."), modelname, Settings.display_type);
TasmotaGlobal.restart_flag = 2;
break;
case FUNC_DISPLAY_SEVENSEG_TEXT:
case FUNC_DISPLAY_CLEAR:
@ -755,14 +1027,16 @@ bool Xdsp15(uint8_t function)
case FUNC_DISPLAY_SEVENSEG_TEXTNC:
case FUNC_DISPLAY_SCROLLTEXT:
case FUNC_DISPLAY_SCROLLDELAY:
case FUNC_DISPLAY_SETLEDS:
case FUNC_DISPLAY_SETLED:
case FUNC_DISPLAY_BUTTONS:
case FUNC_DISPLAY_CLOCK:
result = TM1637Cmd(function);
result = MainFunc(function);
break;
case FUNC_DISPLAY_EVERY_50_MSECOND:
scrollText();
if(showClock) {
showTime();
}
if(scroll) scrollText();
if(showClock) showTime();
if(displaytype == TM1638) readButtons();
break;
}
}