mirror of https://github.com/arendst/Tasmota.git
435 lines
11 KiB
C++
435 lines
11 KiB
C++
|
|
#include "SevenSegmentTM1637.h"
|
|
|
|
|
|
SevenSegmentTM1637::SevenSegmentTM1637(uint8_t pinClk, uint8_t pinDIO) :
|
|
_pinClk(pinClk),
|
|
_pinDIO(pinDIO)
|
|
{
|
|
// setup pins
|
|
pinAsOutput(_pinClk);
|
|
pinAsOutput(_pinDIO);
|
|
digitalHigh(_pinClk);
|
|
digitalHigh(_pinDIO);
|
|
|
|
// setup defaults
|
|
setCursor(0, TM1637_DEFAULT_CURSOR_POS);
|
|
setPrintDelay(TM1637_DEFAULT_PRINT_DELAY);
|
|
setColonOn(TM1637_DEFAULT_COLON_ON);
|
|
setBacklight(TM1637_DEFAULT_BACKLIGHT);
|
|
|
|
// write command SET_DATA (Command1) Defaults
|
|
command(
|
|
TM1637_COM_SET_DATA |
|
|
TM1637_SET_DATA_WRITE |
|
|
TM1637_SET_DATA_A_ADDR |
|
|
TM1637_SET_DATA_M_NORM
|
|
);
|
|
|
|
|
|
|
|
};
|
|
|
|
// Print API ///////////////////////////////////////////////////////////////////
|
|
// single byte
|
|
size_t SevenSegmentTM1637::write(uint8_t byte) {
|
|
TM1637_DEBUG_PRINT(F("write byte:\t")); TM1637_DEBUG_PRINTLN((char)byte);
|
|
|
|
size_t n = 0;
|
|
if ( _cursorPos == _numCols ) {
|
|
shiftLeft(_rawBuffer, _numCols);
|
|
_rawBuffer[_cursorPos] = encode( (char)byte );
|
|
// buffer, length, position
|
|
printRaw( _rawBuffer, _numCols, 0);
|
|
++n;
|
|
};
|
|
|
|
if (_cursorPos < _numCols) {
|
|
_rawBuffer[_cursorPos] = encode( (char)byte );
|
|
// buffer, length, position
|
|
printRaw( _rawBuffer, _cursorPos+1, 0);
|
|
setCursor(1, _cursorPos + 1);
|
|
++n;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
// null terminated char array
|
|
size_t SevenSegmentTM1637::write(const char* str) {
|
|
TM1637_DEBUG_PRINT(F("write char*:\t")); TM1637_DEBUG_PRINTLN(str);
|
|
uint8_t encodedBytes[4];
|
|
|
|
encode(encodedBytes, str, 4);
|
|
uint8_t i =4;
|
|
while( str[i] != '\0' ) {
|
|
printRaw(encodedBytes);
|
|
shiftLeft(encodedBytes, 4);
|
|
encodedBytes[3] = encode( str[i] );
|
|
i++;
|
|
if ( i == TM1637_MAX_CHARS) {
|
|
break;
|
|
}
|
|
}
|
|
return i;
|
|
};
|
|
|
|
// byte array with length
|
|
size_t SevenSegmentTM1637::write(const uint8_t* buffer, size_t size) {
|
|
TM1637_DEBUG_PRINT(F("write uint8_t*:\t("));
|
|
for(size_t i=0; i < size; i++) {
|
|
TM1637_DEBUG_PRINT((char)buffer[i]);
|
|
TM1637_DEBUG_PRINT(i == size -1?F(""):F(", "));
|
|
}
|
|
TM1637_DEBUG_PRINT(F(") "));
|
|
TM1637_DEBUG_PRINT(size);
|
|
|
|
uint8_t encodedBytes[TM1637_MAX_CHARS];
|
|
|
|
if ( size > TM1637_MAX_CHARS) {
|
|
size = TM1637_MAX_CHARS;
|
|
}
|
|
size_t length = encode(encodedBytes, buffer, size);
|
|
TM1637_DEBUG_PRINT(F(" (")); TM1637_DEBUG_PRINT(length); TM1637_DEBUG_PRINT(F(", "));
|
|
TM1637_DEBUG_PRINT(_cursorPos); TM1637_DEBUG_PRINTLN(F(")"));
|
|
printRaw(encodedBytes, length, _cursorPos);
|
|
return length;
|
|
};
|
|
|
|
// Liquid cristal API
|
|
void SevenSegmentTM1637::begin(uint8_t cols, uint8_t rows) {
|
|
_numCols = cols;
|
|
_numRows = rows;
|
|
clear();
|
|
};
|
|
|
|
void SevenSegmentTM1637::init(uint8_t cols, uint8_t rows) {
|
|
begin(cols, rows);
|
|
}
|
|
|
|
void SevenSegmentTM1637::clear(void) {
|
|
uint8_t rawBytes[4] = {0,0,0,0};
|
|
printRaw(rawBytes);
|
|
home();
|
|
};
|
|
|
|
void SevenSegmentTM1637::home(void) {
|
|
setCursor(0, 0);
|
|
};
|
|
|
|
void SevenSegmentTM1637::setCursor(uint8_t row, uint8_t col) {
|
|
col = (col > TM1637_MAX_COLOM -1)?TM1637_MAX_COLOM-1:col;
|
|
_cursorPos = col;
|
|
|
|
};
|
|
|
|
void SevenSegmentTM1637::setBacklight(uint8_t value) {
|
|
value = (value > 100 )?100:value; // 0..100 brightness
|
|
// Store the backlight value
|
|
_backLightValue = value;
|
|
// scale backlight value to 0..8
|
|
value /= 10; // 0..10
|
|
value = (value > 8 )? 8:value; // only 8 levels and off
|
|
uint8_t cmd = TM1637_COM_SET_DISPLAY;;
|
|
switch ( value ) {
|
|
case 0:
|
|
cmd |= TM1637_SET_DISPLAY_OFF;
|
|
break;
|
|
case 1:
|
|
cmd |= TM1637_SET_DISPLAY_ON | TM1637_SET_DISPLAY_1;
|
|
break;
|
|
case 2:
|
|
cmd |= TM1637_SET_DISPLAY_ON | TM1637_SET_DISPLAY_2;
|
|
break;
|
|
case 3:
|
|
cmd |= TM1637_SET_DISPLAY_ON | TM1637_SET_DISPLAY_4;
|
|
break;
|
|
case 4:
|
|
cmd |= TM1637_SET_DISPLAY_ON | TM1637_SET_DISPLAY_10;
|
|
break;
|
|
case 5:
|
|
cmd |= TM1637_SET_DISPLAY_ON | TM1637_SET_DISPLAY_11;
|
|
break;
|
|
case 6:
|
|
cmd |= TM1637_SET_DISPLAY_ON | TM1637_SET_DISPLAY_12;
|
|
break;
|
|
case 7:
|
|
cmd |= TM1637_SET_DISPLAY_ON | TM1637_SET_DISPLAY_13;
|
|
break;
|
|
case 8:
|
|
cmd |= TM1637_SET_DISPLAY_ON | TM1637_SET_DISPLAY_14;
|
|
break;
|
|
};
|
|
#if TM1637_DEBUG
|
|
bool ack = command(cmd);
|
|
TM1637_DEBUG_PRINT(F("SET_DISPLAY:\t")); TM1637_DEBUG_PRINTLN((
|
|
cmd
|
|
), BIN);
|
|
TM1637_DEBUG_PRINT(F("Acknowledged:\t")); TM1637_DEBUG_PRINTLN(ack);
|
|
#else
|
|
command(cmd);
|
|
#endif
|
|
};
|
|
|
|
void SevenSegmentTM1637::setContrast(uint8_t value) {
|
|
setBacklight(value);
|
|
}
|
|
|
|
void SevenSegmentTM1637::on(void) {
|
|
setBacklight(TM1637_DEFAULT_BACKLIGHT);
|
|
};
|
|
|
|
void SevenSegmentTM1637::off(void) {
|
|
setBacklight(0);
|
|
clear();
|
|
};
|
|
|
|
// SevenSegmentTM1637 public methods
|
|
void SevenSegmentTM1637::blink(uint8_t blinkDelay, uint8_t repeats, uint8_t maxBacklight, uint8_t minBacklight) {
|
|
for (uint8_t i=0; i < repeats; i++) {
|
|
setBacklight(minBacklight); // turn backlight off
|
|
delay(blinkDelay);
|
|
setBacklight(maxBacklight); // turn backlight on
|
|
delay(blinkDelay);
|
|
}
|
|
// restore backlight
|
|
setBacklight(_backLightValue);
|
|
}
|
|
|
|
void SevenSegmentTM1637::setPrintDelay(uint16_t printDelay) {
|
|
_printDelay = printDelay;
|
|
};
|
|
|
|
bool SevenSegmentTM1637::getColonOn(void) {
|
|
return (_colonOn);
|
|
};
|
|
|
|
void SevenSegmentTM1637::setColonOn(bool setToOn) {
|
|
_colonOn = setToOn;
|
|
}
|
|
void SevenSegmentTM1637::printRaw(uint8_t rawByte, uint8_t position) {
|
|
uint8_t cmd[2];
|
|
cmd[0] = TM1637_COM_SET_ADR | position;
|
|
cmd[1] = rawByte;
|
|
if (position == 1) { cmd[1]|=(_colonOn)?TM1637_COLON_BIT:0; };
|
|
command(cmd, 2);
|
|
};
|
|
|
|
void SevenSegmentTM1637::printRaw(const uint8_t* rawBytes, size_t length, uint8_t position) {
|
|
// if fits on display
|
|
if ( (length + position) <= _numCols) {
|
|
uint8_t cmd[5] = {0, };
|
|
cmd[0] = TM1637_COM_SET_ADR | (position & B111); // sets address
|
|
memcpy(&cmd[1], rawBytes, length); // copy bytes
|
|
|
|
// do we have to print a colon?
|
|
if ( position < 2 ) { // printing after position 2 has never a colon
|
|
if ( position == 0 && length >= 2) {
|
|
// second index is the colon
|
|
cmd[2] |= (_colonOn)?TM1637_COLON_BIT:0;
|
|
} else {
|
|
// first index is the colon
|
|
cmd[1] |= (_colonOn)?TM1637_COLON_BIT:0;
|
|
}
|
|
}
|
|
// TM1637_DEBUG_PRINT(F("ADDR :\t")); TM1637_DEBUG_PRINTLN(cmd[0],BIN);
|
|
// TM1637_DEBUG_PRINT(F("DATA0:\t")); TM1637_DEBUG_PRINTLN(cmd[1],BIN);
|
|
command(cmd, length+1); // send to display
|
|
}
|
|
// does not fit on display, need to print with delay
|
|
else {
|
|
// First print 1-4 characters
|
|
uint8_t numtoPrint = _numCols - position;
|
|
printRaw(rawBytes, numtoPrint, position);
|
|
delay(_printDelay);
|
|
|
|
// keep printing 4 characters till done
|
|
uint8_t remaining = length - numtoPrint + 3;
|
|
uint8_t i = 1;
|
|
while( remaining >= _numCols) {
|
|
printRaw(&rawBytes[i], _numCols, 0);
|
|
delay(_printDelay);
|
|
remaining--;
|
|
i++;
|
|
};
|
|
}
|
|
|
|
};
|
|
|
|
// Helpers
|
|
uint8_t SevenSegmentTM1637::encode(char c) {
|
|
if ( c < ' ') { // 32 (ASCII)
|
|
return 0;
|
|
}
|
|
return pgm_read_byte_near(AsciiMap::map + c - ' ');
|
|
};
|
|
|
|
uint8_t SevenSegmentTM1637::encode(int16_t d) {
|
|
// can only encode single digit
|
|
if ( d > 9 || d < 0) {
|
|
return 0;
|
|
};
|
|
return pgm_read_byte_near(AsciiMap::map + d + '0' - ' ');
|
|
};
|
|
|
|
size_t SevenSegmentTM1637::encode(uint8_t* buffer, const char* str, size_t bufferSize) {
|
|
size_t i;
|
|
|
|
for (i=0; i < bufferSize; i++) {
|
|
if (str[i] == '\0' ) {
|
|
return i;
|
|
}
|
|
buffer[i] = encode( str[i] );
|
|
};
|
|
return i;
|
|
}
|
|
|
|
size_t SevenSegmentTM1637::encode(uint8_t* buffer, const uint8_t* byteArr, size_t bufferSize) {
|
|
size_t i;
|
|
|
|
for (i=0; i < bufferSize; i++) {
|
|
buffer[i] = encode( (char)byteArr[i] );
|
|
};
|
|
return i;
|
|
}
|
|
|
|
void SevenSegmentTM1637::shiftLeft(uint8_t* buffer, size_t length) {
|
|
for (uint8_t i=0; i < length ; i++) {
|
|
buffer[i] = buffer[i+1];
|
|
}
|
|
}
|
|
|
|
// SevenSegmentTM1637 LOW LEVEL
|
|
bool SevenSegmentTM1637::command(uint8_t cmd) const{
|
|
return command(_pinClk, _pinDIO, cmd);
|
|
};
|
|
|
|
bool SevenSegmentTM1637::command(uint8_t pinClk, uint8_t pinDIO, uint8_t cmd) {
|
|
comStart(pinClk, pinDIO);
|
|
comWriteByte(pinClk, pinDIO,cmd);
|
|
bool acknowledged = comAck(pinClk, pinDIO);
|
|
comStop(pinClk, pinDIO);
|
|
return acknowledged;
|
|
}
|
|
|
|
bool SevenSegmentTM1637::command(const uint8_t* commands, uint8_t length) const {
|
|
return command(_pinClk, _pinDIO, commands, length);
|
|
};
|
|
|
|
bool SevenSegmentTM1637::command(uint8_t pinClk, uint8_t pinDIO, const uint8_t* commands, uint8_t length) {
|
|
bool acknowledged = true;
|
|
comStart(pinClk, pinDIO);
|
|
for (uint8_t i=0; i < length;i++) {
|
|
comWriteByte(pinClk, pinDIO, commands[i]);
|
|
acknowledged &= comAck(pinClk, pinDIO);
|
|
};
|
|
comStop(pinClk, pinDIO);
|
|
return acknowledged;
|
|
}
|
|
|
|
uint8_t SevenSegmentTM1637::comReadByte(void) const {
|
|
uint8_t readKey = 0;
|
|
|
|
comStart();
|
|
comWriteByte(TM1637_COM_SET_DATA | TM1637_SET_DATA_READ);
|
|
comAck();
|
|
|
|
pinAsInput(_pinDIO);
|
|
digitalHigh(_pinDIO);
|
|
delayMicroseconds(5);
|
|
|
|
for ( uint8_t i=0; i < 8; i++) {
|
|
|
|
readKey >>= 1;
|
|
digitalLow(_pinClk);
|
|
delayMicroseconds(30);
|
|
|
|
digitalHigh(_pinClk);
|
|
|
|
if ( isHigh(_pinDIO) ) {
|
|
readKey = readKey | B10000000;
|
|
};
|
|
|
|
delayMicroseconds(30);
|
|
|
|
|
|
};
|
|
pinAsOutput(_pinDIO);
|
|
comAck();
|
|
comStop();
|
|
return readKey;
|
|
};
|
|
|
|
void SevenSegmentTM1637::comWriteByte(uint8_t command) const{
|
|
comWriteByte(_pinClk, _pinDIO, command);
|
|
};
|
|
|
|
void SevenSegmentTM1637::comWriteByte(uint8_t pinClk, uint8_t pinDIO, uint8_t command) {
|
|
// CLK in bits
|
|
for ( uint8_t i=0; i < 8; i++) {
|
|
digitalLow(pinClk); // CLK LOW
|
|
|
|
if ( command & B1) {
|
|
digitalHigh(pinDIO);// DIO HIGH
|
|
} else {
|
|
digitalLow(pinDIO); // DIO LOW
|
|
}
|
|
delayMicroseconds(TM1637_CLK_DELAY_US);
|
|
|
|
command >>= 1;
|
|
|
|
digitalHigh(pinClk); // CLK HIGH
|
|
delayMicroseconds(TM1637_CLK_DELAY_US);
|
|
};
|
|
}
|
|
|
|
void SevenSegmentTM1637::comStart(void) const {
|
|
comStart(_pinClk, _pinDIO);
|
|
};
|
|
|
|
void SevenSegmentTM1637::comStart(uint8_t pinClk, uint8_t pinDIO) {
|
|
digitalHigh(pinDIO); // DIO HIGH
|
|
digitalHigh(pinClk); // CLK HIGH
|
|
delayMicroseconds(TM1637_CLK_DELAY_US);
|
|
|
|
digitalLow(pinDIO); // DIO LOW
|
|
}
|
|
|
|
void SevenSegmentTM1637::comStop(void) const {
|
|
comStop(_pinClk, _pinDIO);
|
|
};
|
|
|
|
void SevenSegmentTM1637::comStop(uint8_t pinClk, uint8_t pinDIO) {
|
|
digitalLow(pinClk); // CLK LOW
|
|
delayMicroseconds(TM1637_CLK_DELAY_US);
|
|
|
|
digitalLow(pinDIO); // DIO LOW
|
|
delayMicroseconds(TM1637_CLK_DELAY_US);
|
|
|
|
digitalHigh(pinClk); // CLK HIGH
|
|
delayMicroseconds(TM1637_CLK_DELAY_US);
|
|
|
|
digitalHigh(pinDIO); // DIO HIGH
|
|
}
|
|
|
|
bool SevenSegmentTM1637::comAck(void) const {
|
|
return comAck(_pinClk, _pinDIO);
|
|
};
|
|
|
|
bool SevenSegmentTM1637::comAck(uint8_t pinClk, uint8_t pinDIO) {
|
|
bool acknowledged = false;
|
|
|
|
digitalLow(pinClk); // CLK LOW
|
|
pinAsInputPullUp(pinDIO); // DIO INPUT PULLUP (state==HIGH)
|
|
delayMicroseconds(TM1637_CLK_DELAY_US);
|
|
|
|
acknowledged = isLow(pinDIO);// Ack should pull the pin low again
|
|
|
|
digitalHigh(pinClk); // CLK HIGH
|
|
delayMicroseconds(TM1637_CLK_DELAY_US);
|
|
|
|
digitalLow(pinClk); // CLK LOW
|
|
pinAsOutput(pinDIO);
|
|
|
|
return acknowledged;
|
|
}
|