СЕМИСЕГМЕНТНЫЙ ИНДИКАТОР НА TM1637 В MICROCHIP STUDIO

 

Здесь я опять применил своего рода реверс-инженеринг, переделав гейские ардуино-библиотеки под православную Microchip Studio. Оттуда было вычищено всякого говно типа DigitalWrite() и прочая еритическая мерзость, которая так нравится всем заднеприводным. Ну а затем я объединил несколько раздельных файвлов в одну наглядную программу. В принципе, получилась даже относительно простая. Это версия Си++, данное обстоятельство необходимо учитывать при создании проекта.

/*
/  TM1637 Control program C++ version
/  https://madmentat.ru
/  2024
*/
#define F_CPU 16000000UL  // Определяем частоту процессора как 16 МГц
#include <avr/io.h>
#include <util/delay.h>
#define CLK_PIN PB1
#define DIO_PIN PB2
#define BUTTON_PIN PD2
#define SEG_A   0b00000001
#define SEG_B   0b00000010
#define SEG_C   0b00000100
#define SEG_D   0b00001000
#define SEG_E   0b00010000
#define SEG_F   0b00100000
#define SEG_G   0b01000000
#define DEFAULT_BIT_DELAY  100
#define TM1637_I2C_COMM1    0x40
#define TM1637_I2C_COMM2    0xC0
#define TM1637_I2C_COMM3    0x80
int number = 1982; // Начальное число
class TM1637Display {
    public:
    TM1637Display(uint8_t pinClk, uint8_t pinDIO, unsigned int bitDelay = DEFAULT_BIT_DELAY);
    void setBrightness(uint8_t brightness, bool on = true);
    void setSegments(const uint8_t segments[], uint8_t length = 4, uint8_t pos = 0);
    void clear();
    void showNumberDec(int num, bool leading_zero = false, uint8_t length = 4, uint8_t pos = 0);
    void showNumberDecEx(int num, uint8_t dots = 0, bool leading_zero = false, uint8_t length = 4, uint8_t pos = 0);
    void showNumberHexEx(uint16_t num, uint8_t dots = 0, bool leading_zero = false, uint8_t length = 4, uint8_t pos = 0);
    uint8_t encodeDigit(uint8_t digit);
    protected:
    void bitDelay();
    void start();
    void stop();
    bool writeByte(uint8_t b);
    void showDots(uint8_t dots, uint8_t* digits);
    void showNumberBaseEx(int8_t base, uint16_t num, uint8_t dots = 0, bool leading_zero = false, uint8_t length = 4, uint8_t pos = 0);
    private:
    uint8_t m_pinClk;
    uint8_t m_pinDIO;
    uint8_t m_brightness;
    unsigned int m_bitDelay;
};
//
//      A
//     ---
//  F |   | B
//     -G-
//  E |   | C
//     ---
//      D
const uint8_t digitToSegment[] = {
    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.
    DDRB &= ~(1 << m_pinClk);
    DDRB &= ~(1 << m_pinDIO);
    PORTB &= ~(1 << m_pinClk);
    PORTB &= ~(1 << m_pinDIO);
}
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)
{
    start();
    writeByte(TM1637_I2C_COMM1);
    stop();
    start();
    writeByte(TM1637_I2C_COMM2 + (pos & 0x03));
    for (uint8_t k = 0; k < length; k++)
    writeByte(segments[k]);
    stop();
    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) {
        for (uint8_t i = 0; i < (length - 1); i++)
        digits[i] = 0;
        digits[length - 1] = encodeDigit(0);
        } else {
        for (int i = length - 1; i >= 0; --i) {
            uint8_t digit = num % base;
            if (digit == 0 && num == 0 && !leading_zero)
            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()
{
    _delay_us(100);
}
void TM1637Display::start()
{
    DDRB |= (1 << m_pinDIO);
    bitDelay();
}
void TM1637Display::stop()
{
    DDRB |= (1 << m_pinDIO);
    bitDelay();
    DDRB &= ~(1 << m_pinClk);
    bitDelay();
    DDRB &= ~(1 << m_pinDIO);
    bitDelay();
}
bool TM1637Display::writeByte(uint8_t b)
{
    uint8_t data = b;
    for (uint8_t i = 0; i < 8; i++) {
        DDRB |= (1 << m_pinClk);
        bitDelay();
        if (data & 0x01)
        DDRB &= ~(1 << m_pinDIO);
        else
        DDRB |= (1 << m_pinDIO);
        bitDelay();
        DDRB &= ~(1 << m_pinClk);
        bitDelay();
        data >>= 1;
    }
    DDRB |= (1 << m_pinClk);
    DDRB &= ~(1 << m_pinDIO);
    bitDelay();
    DDRB &= ~(1 << m_pinClk);
    bitDelay();
    uint8_t ack = PINB & (1 << m_pinDIO);
    if (ack == 0)
    DDRB |= (1 << m_pinDIO);
    bitDelay();
    DDRB |= (1 << m_pinClk);
    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];
}
TM1637Display display(CLK_PIN, DIO_PIN);
void setup() {
    // Установка пинов для CLK и DIO как выходы
    DDRB |= (1 << CLK_PIN) | (1 << DIO_PIN);
    // Установка пина кнопки как вход с подтяжкой
    DDRD &= ~(1 << BUTTON_PIN);  // Установить PD2 как вход
    PORTD |= (1 << BUTTON_PIN);  // Включить внутренний подтягивающий резистор на PD2
    display.setBrightness(0x0f); // Установка максимальной яркости
    display.showNumberDec(number, true); // Отображение начального числа с ведущими нулями
}
void loop() {
    static bool buttonPressed = false; // Для отслеживания состояния кнопки
    // Проверка состояния кнопки
    if ((PIND & (1 << BUTTON_PIN)) == 0) { // Кнопка нажата
        if (!buttonPressed) { // Изменение состояния кнопки
            buttonPressed = true;
            number++; // Увеличение числа
            display.showNumberDec(number, true); // Обновление дисплея
        }
        } else {
        buttonPressed = false; // Сброс состояния кнопки, когда она не нажата
    }
    _delay_ms(50); // Задержка для подавления дребезга
}
int main(void) {
    setup(); // Вызов функции настройки
    while (1) {
        loop(); // Основной цикл программы
    }
}

 Версия на православном Си:

/*
 * TM1637 Control program С version
 * https://madmentat.ru
 * 2024
 */
#define F_CPU 16000000UL  // Определяем частоту процессора как 16 МГц
#include <avr/io.h>
#include <util/delay.h>
#include <stdbool.h>
#define CLK_PIN PB1
#define DIO_PIN PB2
#define BUTTON_PIN PD2
#define SEG_A   0b00000001
#define SEG_B   0b00000010
#define SEG_C   0b00000100
#define SEG_D   0b00001000
#define SEG_E   0b00010000
#define SEG_F   0b00100000
#define SEG_G   0b01000000
#define DEFAULT_BIT_DELAY  100
#define TM1637_I2C_COMM1    0x40
#define TM1637_I2C_COMM2    0xC0
#define TM1637_I2C_COMM3    0x80
int number = 1982; // Начальное число
const uint8_t digitToSegment[] = {
    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;
void bitDelay(void);
void start(void);
void stop(void);
bool writeByte(uint8_t b);
void setBrightness(uint8_t brightness, bool on);
void setSegments(const uint8_t segments[], uint8_t length, uint8_t pos);
void clear(void);
void showNumberDec(int num, bool leading_zero, uint8_t length, uint8_t pos);
void showNumberDecEx(int num, uint8_t dots, bool leading_zero, uint8_t length, uint8_t pos);
void showNumberHexEx(uint16_t num, uint8_t dots, bool leading_zero, uint8_t length, uint8_t pos);
void showNumberBaseEx(int8_t base, uint16_t num, uint8_t dots, bool leading_zero, uint8_t length, uint8_t pos);
void showDots(uint8_t dots, uint8_t* digits);
void bitDelay(void) {
    _delay_us(DEFAULT_BIT_DELAY);
}
void start(void) {
    DDRB |= (1 << DIO_PIN);
    bitDelay();
}
void stop(void) {
    DDRB |= (1 << DIO_PIN);
    bitDelay();
    DDRB &= ~(1 << CLK_PIN);
    bitDelay();
    DDRB &= ~(1 << DIO_PIN);
    bitDelay();
}
bool writeByte(uint8_t b) {
    uint8_t data = b;
    for (uint8_t i = 0; i < 8; i++) {
        DDRB |= (1 << CLK_PIN);
        bitDelay();
        if (data & 0x01)
            DDRB &= ~(1 << DIO_PIN);
        else
            DDRB |= (1 << DIO_PIN);
        bitDelay();
        DDRB &= ~(1 << CLK_PIN);
        bitDelay();
        data >>= 1;
    }
    DDRB |= (1 << CLK_PIN);
    DDRB &= ~(1 << DIO_PIN);
    bitDelay();
    DDRB &= ~(1 << CLK_PIN);
    bitDelay();
    uint8_t ack = PINB & (1 << DIO_PIN);
    if (ack == 0)
        DDRB |= (1 << DIO_PIN);
    bitDelay();
    DDRB |= (1 << CLK_PIN);
    bitDelay();
    return ack;
}
void setBrightness(uint8_t brightness, bool on) {
    uint8_t m_brightness = (brightness & 0x7) | (on ? 0x08 : 0x00);
    // Здесь можно добавить код для применения яркости
}
void setSegments(const uint8_t segments[], uint8_t length, uint8_t pos) {
    start();
    writeByte(TM1637_I2C_COMM1);
    stop();
    start();
    writeByte(TM1637_I2C_COMM2 + (pos & 0x03));
    for (uint8_t k = 0; k < length; k++)
        writeByte(segments[k]);
    stop();
    start();
    writeByte(TM1637_I2C_COMM3 + (0x0f & 0x0f)); // Используем максимальную яркость
    stop();
} 
void clear(void) {
    uint8_t data[] = { 0, 0, 0, 0 };
    setSegments(data, 4, 0);
}
void showNumberDec(int num, bool leading_zero, uint8_t length, uint8_t pos) {
    showNumberDecEx(num, 0, leading_zero, length, pos);
} 
void 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 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 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) {
        for (uint8_t i = 0; i < (length - 1); i++)
            digits[i] = 0;
        digits[length - 1] = digitToSegment[0];
    } else {
        for (int i = length - 1; i >= 0; --i) {
            uint8_t digit = num % base;
            if (digit == 0 && num == 0 && !leading_zero)
                digits[i] = 0;
            else
                digits[i] = digitToSegment[digit & 0x0f];
            if (digit == 0 && num == 0 && negative) {
                digits[i] = minusSegments;
                negative = false;
            }
            num /= base;
        }
        if (dots != 0)
            showDots(dots, digits);
    }
 
    setSegments(digits, length, pos);
}
void showDots(uint8_t dots, uint8_t* digits) {
    for (int i = 0; i < 4; ++i) {
        digits[i] |= (dots & 0x80);
        dots <<= 1;
    }
}
int main(void) {
    // Установка пинов для CLK и DIO как выходы
    DDRB |= (1 << CLK_PIN) | (1 << DIO_PIN);
    // Установка пина кнопки как вход с подтяжкой
    DDRD &= ~(1 << BUTTON_PIN);  // Установить PD2 как вход
    PORTD |= (1 << BUTTON_PIN);  // Включить внутренний подтягивающий резистор на PD2
    setBrightness(0x0f, true); // Установка максимальной яркости
    showNumberDec(number, true, 4, 0); // Отображение начального числа с ведущими нулями
    while (1) {
        static bool buttonPressed = false; // Для отслеживания состояния кнопки
        // Проверка состояния кнопки
        if ((PIND & (1 << BUTTON_PIN)) == 0) { // Кнопка нажата
            if (!buttonPressed) { // Изменение состояния кнопки
                buttonPressed = true;
                number++; // Увеличение числа
                showNumberDec(number, true, 4, 0); // Обновление дисплея
            }
        } else {
            buttonPressed = false; // Сброс состояния кнопки, когда она не нажата
        }
        _delay_ms(50); // Задержка для подавления дребезга
    }
    return 0;
}