СЕМИСЕГМЕНТНЫЙ ИНДИКАТОР НА 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; }