avishorp / TM1637

Arduino library for TM1637 (LED Driver)
GNU Lesser General Public License v3.0
428 stars 218 forks source link

ESP32 problems #78

Open Amli2011 opened 3 years ago

Amli2011 commented 3 years ago

After trying all library for TM1637 in arduino, and all of them either was incompatible or showing garbage (and sometimes right) on the display. Display was confirmed working on an esp8266.

After trying around I changed the clock output from pinMode to digitalWrite and it is now stable. I do think the ESP32 implementation of pinMode does not make a clean switch from LOW to INPUT or the other way. And the data transfer becomes out of sync because of that. As the clock line is never driven from the display chip I tried to just use digitalWrite. The data pin is not changed because it is not critical in the timing.

I know this is out of spec as the clock line technically should not be driven high, only by a resistor. But TM1637 never drives the clock line so it would not be a conflict.

I do not know the right way to make a patch, so I attach the whole edited TM1637Display.cpp . I did do several tries to get it to work, it might be remimensts of code changes not actual to my latest fix, but I think I cleaned it up.

` // Author: avishorp@gmail.com // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

extern "C" {

include

include

include

}

include

include

define TM1637_I2C_COMM1 0x40

define TM1637_I2C_COMM2 0xC0

define TM1637_I2C_COMM3 0x80

// // A // --- // F | | B // -G- // E | | C // --- // D const uint8_t digitToSegment[] = { // XGFEDCBA 0b00111111, // 0 0b00000110, // 1 0b01011011, // 2 0b01001111, // 3 0b01100110, // 4 0b01101101, // 5 0b01111101, // 6 0b00000111, // 7 0b01111111, // 8 0b01101111, // 9 0b01110111, // A 0b01111100, // b 0b00111001, // C 0b01011110, // d 0b01111001, // E 0b01110001 // F };

static const uint8_t minusSegments = 0b01000000;

TM1637Display::TM1637Display(uint8_t pinClk, uint8_t pinDIO, unsigned int bitDelay) { // Copy the pin numbers m_pinClk = pinClk; m_pinDIO = pinDIO; m_bitDelay = bitDelay;

// Set the pin direction and default value.
// Both pins are set as inputs, allowing the pull-up resistors to pull them up
pinMode(m_pinClk, OUTPUT);
digitalWrite(m_pinClk, HIGH);
pinMode(m_pinDIO,INPUT);

// digitalWrite(m_pinClk, LOW); digitalWrite(m_pinDIO, LOW); }

void TM1637Display::setBrightness(uint8_t brightness, bool on) { m_brightness = (brightness & 0x7) | (on? 0x08 : 0x00); }

void TM1637Display::setSegments(const uint8_t segments[], uint8_t length, uint8_t pos) { // Write COMM1 start(); writeByte(TM1637_I2C_COMM1); stop();

// Write COMM2 + first digit address
start();
writeByte(TM1637_I2C_COMM2 + (pos & 0x03));

// Write the data bytes
for (uint8_t k=0; k < length; k++)
  writeByte(segments[k]);

stop();

// Write COMM3 + brightness
start();
writeByte(TM1637_I2C_COMM3 + (m_brightness & 0x0f));
stop();

}

void TM1637Display::clear() { uint8_t data[] = { 0, 0, 0, 0 }; setSegments(data); }

void TM1637Display::showNumberDec(int num, bool leading_zero, uint8_t length, uint8_t pos) { showNumberDecEx(num, 0, leading_zero, length, pos); }

void TM1637Display::showNumberDecEx(int num, uint8_t dots, bool leading_zero, uint8_t length, uint8_t pos) { showNumberBaseEx(num < 0? -10 : 10, num < 0? -num : num, dots, leading_zero, length, pos); }

void TM1637Display::showNumberHexEx(uint16_t num, uint8_t dots, bool leading_zero, uint8_t length, uint8_t pos) { showNumberBaseEx(16, num, dots, leading_zero, length, pos); }

void TM1637Display::showNumberBaseEx(int8_t base, uint16_t num, uint8_t dots, bool leading_zero, uint8_t length, uint8_t pos) { bool negative = false; if (base < 0) { base = -base; negative = true; }

uint8_t digits[4];

if (num == 0 && !leading_zero) {
    // Singular case - take care separately
    for(uint8_t i = 0; i < (length-1); i++)
        digits[i] = 0;
    digits[length-1] = encodeDigit(0);
}
else {
    //uint8_t i = length-1;
    //if (negative) {
    //  // Negative number, show the minus sign
    //    digits[i] = minusSegments;
    //  i--;
    //}

    for(int i = length-1; i >= 0; --i)
    {
        uint8_t digit = num % base;

        if (digit == 0 && num == 0 && leading_zero == false)
            // Leading zero is blank
            digits[i] = 0;
        else
            digits[i] = encodeDigit(digit);

        if (digit == 0 && num == 0 && negative) {
            digits[i] = minusSegments;
            negative = false;
        }

        num /= base;
    }

    if(dots != 0)
    {
        showDots(dots, digits);
    }
}
setSegments(digits, length, pos);

}

void TM1637Display::bitDelay() { delayMicroseconds(m_bitDelay); }

void TM1637Display::start() { pinMode(m_pinDIO, OUTPUT); bitDelay(); }

void TM1637Display::stop() { pinMode(m_pinDIO, OUTPUT); bitDelay(); digitalWrite(m_pinClk, HIGH); bitDelay(); pinMode(m_pinDIO, INPUT); bitDelay(); }

bool TM1637Display::writeByte(uint8_t b) { uint8_t data = b;

// 8 Data Bits for(uint8_t i = 0; i < 8; i++) { // CLK low digitalWrite(m_pinClk, LOW); // digitalWrite(m_pinClk, LOW; bitDelay();

// Set data bit
if (data & 0x01)
  pinMode(m_pinDIO, INPUT);
else
  pinMode(m_pinDIO, OUTPUT);

bitDelay();

// CLK high
digitalWrite(m_pinClk, HIGH);
bitDelay();
data = data >> 1;

}

// Wait for acknowledge // CLK to zero digitalWrite(m_pinClk, LOW); pinMode(m_pinDIO, INPUT); bitDelay();

// CLK to high digitalWrite(m_pinClk, HIGH); bitDelay(); uint8_t ack = digitalRead(m_pinDIO); if (ack == 0) pinMode(m_pinDIO, OUTPUT);

bitDelay(); digitalWrite(m_pinClk, LOW); bitDelay();

return ack; }

void TM1637Display::showDots(uint8_t dots, uint8_t* digits) { for(int i = 0; i < 4; ++i) { digits[i] |= (dots & 0x80); dots <<= 1; } }

uint8_t TM1637Display::encodeDigit(uint8_t digit) { return digitToSegment[digit & 0x0f]; }`

Amli2011 commented 3 years ago

After more testing with my changed code, I do see it is necessary to specify the bitdelay to get it to work. like this: TM1637Display display(Clk, DIO, 50); I had it on 500 from a previous test. and it delayed my main program. I tried without and the display became unstable. tested some values and ended up on 50. It may be possible to fintune this.