diff --git a/SevenSegmentsDisp/Disp595.h b/SevenSegmentsDisp/Disp595.h new file mode 100644 index 0000000..e5a5ffa --- /dev/null +++ b/SevenSegmentsDisp/Disp595.h @@ -0,0 +1,455 @@ +/* + + Быстрая и функциональная библиотка для модулей семисегментного дисплея TM74HC595 + построенных на базе одноименных сдвиговых регистров, без динамической индикации. + Для обеспечения нормальной работы необходимо вручную обслуживать динамическую + индикацию дисплея, вызывая метод .tickManual() с периодом 500-5000 мкс, используя + прерывания таймера или .tick() в чистом от блокирующих функций loop. + + - Обслуживание динамчиеской индикации встроенным таймером на micros() + - Ручное обслуживание динамчиеской индикации при необходимости + - Поддержка чисел со знаком минус + - Вывод int с нулями и без нулей слева + - Вывод float с указанной точностью с нулями слева и без + - Вывод float с автоматическим выбором точности + - Вывод символа на нужную позицию, не трогает остальные знакоместа + - Вывод массива символов (0 - 4 шт.) с выравниванием по левому / правому краю + - Вывод 4х символов на дисплей вручную + - Вывод бегущих строк (блокирующая функция) + - Управление любой из точек дисплея + - Очистка дисплея + - Обнаружение и вывод ошибки переполнения дисплея (-OVF и OVF) + - Программная регулирвока яркости дисплея + + Краткое описание доступных методов смотрите ниже, в классе. + + Библиотека для простой реализации прерываний на аппаратных таймерах + https://github.com/AlexGyver/GyverLibs/tree/master/GyverTimers + + V1.0 от 24/01/2021 by Egor 'Nich1con' Zakharov, специально для AlexGyver + + ... + + Краткая документация: + Disp595 (uint8_t dio, uint8_t sclk, uint8_t rclk); // Конструктор дисплея + void tick(void); // Обслуживание динамической индикации со встроенным таймером на micros() + void tickManual(void); // Обслуживание динамической индикации вручную (для помещения в прерывание таймера и т.д.) + void displayIntNulls(int16_t data); // Вывод int с нулями слева + void displayInt(int16_t data); // Вывод int без нулей слева + void displayFloatNulls(float data, uint8_t base); // Вывод float с нулями слева, указанием кол-ва знаков (1 - 3) + void displayFloatNulls(float data); // Вывод float с нулями слева, 1 знак после запятой + void displayFloat(float data, uint8_t base); // Вывод float без нулей слева, указанием кол-ва знаков (1 - 3) + void displayFloat(float data); // Вывод float без нулей слева, 1 знак после запятой + void displayByte(uint8_t a, uint8_t b, uint8_t c, uint8_t d); // Прямой вывод 4х байтов (символов) на дисплей + void point(uint8_t pos, bool state); // Добавление / удаление точки на позиции 0-3 (слева) + void clear(void); // Очистка дисплея + void brightness(uint8_t bright) // Установка значения яркости (0 - 7), по умолчанию максимум (если обьявлена DISP595_BRIGHTNESS) + void runningString(uint8_t *str, uint8_t size, uint16_t ms) // Вывод бегущей строки размера size, с задержкой ms, внутри функции tick НЕ ОБСЛУЖИВАЕТСЯ + void runningString(uint8_t *str, uint8_t size, uint16_t ms, bool useTick); // Аналогично, но можно вручную включить / выключить встроенный в функцию tick() + + Дефайны, которые можно обьявить ПЕРЕД подключением библиотеки: + DISP595_BRIGHTNESS -> Обьявить для подключения программной регулирвоки яркости дисплея + DISP595_BRIGHTNESS_DEPTH число -> Глубина программной яркости, по умолчанию 8 градаций, больше - плавнее регулировка, сильнее мерацание дисплея без повышения частоты индикации. + DISP595_FAST_PERIOD число -> Период в мкс динамической индикации во втроенном таймере метода tick для режима С ИСПОЛЬЗОВАНИЕМ РЕГУЛИРОВКИ ЯРКОСТИ + DISP595_SLOW_PERIOD число -> То же самое, но для стандартного режима (постоянная яркость) + + Константы: + ALIGN_LEFT - выравнивание неполной строки по левому краю + ALIGN_RIGHT - выравнивание неполной строки по правому краю + +*/ + + +#define ALIGN_LEFT true +#define ALIGN_RIGHT false + +#define digits(a) pgm_read_byte(&digs[a]) +#define masks(a) pgm_read_byte(&msks[a]) + +#ifndef DISP595_BRIGHTNESS_DEPTH +#define DISP595_BRIGHTNESS_DEPTH 8 +#endif + +#ifndef DISP595_FAST_PERIOD +#define DISP595_FAST_PERIOD 500 +#endif + +#ifndef DISP595_SLOW_PERIOD +#define DISP595_SLOW_PERIOD 3500 +#endif + +#pragma once +#include // Стандартная либа Arduino +#include // Битовые маски для вывода символов + +const uint8_t digs[] PROGMEM = {_0, _1, _2, _3, _4, _5, _6, _7, _8, _9}; // Массив цифр для вывода чисел +const uint8_t msks[] PROGMEM = {0b1000, 0b0100, 0b0010, 0b0001}; // Масив битовых маск для выбора знакоместа + +class Disp595 { + public: + + Disp595 (uint8_t dio, uint8_t sclk, uint8_t rclk) { +#ifdef __AVR__ + _clk_port = portOutputRegister(digitalPinToPort(sclk)); + _data_port = portOutputRegister(digitalPinToPort(dio)); + _latch_port = portOutputRegister(digitalPinToPort(rclk)); + _clk_mask = digitalPinToBitMask(sclk); + _data_mask = digitalPinToBitMask(dio); + _latch_mask = digitalPinToBitMask(rclk); +#else + _clk_pin = sclk; + _data_pin = dio; + _latch_pin = rclk; +#endif + pinMode(dio, OUTPUT); + pinMode(sclk, OUTPUT); + pinMode(rclk, OUTPUT); + } + + +#ifdef DISP595_BRIGHTNESS + void brightness(uint8_t bright) { + softPwmDuty = constrain(bright, 0, DISP595_BRIGHTNESS_DEPTH - 1); + } +#endif + + void tick(void) { +#ifdef DISP595_BRIGHTNESS + if (micros() - dispTimer >= DISP595_FAST_PERIOD) +#else + if (micros() - dispTimer >= DISP595_SLOW_PERIOD) +#endif + { + dispTimer = micros(); + tickManual(); + } + } + + void tickManual(void) { +#ifdef DISP595_BRIGHTNESS + if (softPwmCounter == softPwmDuty) { + displayWrite(_empty, masks(dispPtr)); + } + + if (++softPwmCounter >= DISP595_BRIGHTNESS_DEPTH) { + softPwmCounter = 0; + if (++dispPtr > 3) dispPtr = 0; + displayWrite(dispBuf[dispPtr], masks(dispPtr)); + } +#else + displayWrite(dispBuf[dispPtr], masks(dispPtr)); // Вывод текущего знакоместа + if (++dispPtr > 3) dispPtr = 0; // Сдвиг знакоместа +#endif + } + + void displayIntNulls(int16_t data) { + bool flag = false; // Работа со знаком + if (data < 0) { + data *= -1; + flag = true; + } + if (data > (flag ? 999 : 9999)) { // Работа с диапазоном + displayBytes(flag ? _dash : _empty, _O, _V, _F); + return; + } + + dispBuf[0] = (flag ? _dash : digits((int16_t)data / 1000)); // Заполнение буфера напрямую цифрами + dispBuf[1] = digits((int16_t)(data / 100) % 10); + dispBuf[2] = digits((int16_t)(data / 10) % 10); + dispBuf[3] = digits((int16_t)data % 10); + } + + + + void displayInt(int16_t data) { + bool flag = false; // Работа с минусом + uint8_t buf = 0; + + if (data < 0) { + data *= -1; + flag = true; + } + + if (data > (flag ? 999 : 9999)) { // Отслеживание пределов + displayBytes(flag ? _dash : _empty, _O, _V, _F); + return; + } + + clear(); + dispBuf[3] = digits((int16_t)data % 10); // Крайний символ выводится всегда + if (flag) dispBuf[2] = _dash; // Сразу ставим минус левее если входящее число меньше нуля + if (data > 9) { // Если знаков больше 1 + dispBuf[2] = digits((int16_t)(data / 10) % 10); // Заменяем минус (если он есть) на число + if (flag)dispBuf[1] = _dash; // Следующий знак сразу заполняем минусом + } + if (data > 99) { // Если знаков больше двух + dispBuf[1] = digits((int16_t)(data / 100) % 10);// Заменяем минус на число + if (flag)dispBuf[0] = _dash; // Сразу ставим минус на след позицию + } + if (data > 999) { // Если знаков больше 3х и минуса нет (очевидно) + dispBuf[0] = digits((int16_t)(data / 1000) % 10); // Заменяем последний знак цифрой + } + } + + + void displayFloatNulls(float data, uint8_t base) { + base = constrain(base, 1, 3); // Аналогично проверка на пределы + bool flag = false; + + if (data < 0) { // Работа с минусом + data *= -1; + flag = true; + } + + uint16_t whole = floor(data); // Подготовка целой и дробнйо части в целочисленном исполнении + uint16_t fract = floor(((float)data - whole) * fastPow10(base)); + // Пример: 326.429 -> whole = 326, fract = 429; + + if (whole > fastPow10((flag ? 3 : 4) - base) - 1) { // Проверка на выползание за пределы + displayBytes(flag ? _dash : _empty, _O, _V, _F); + return; + } + + uint8_t whole_digits[3]; // Буферы(а) для цифр + uint8_t fract_digits[3]; + + whole_digits[0] = digits(whole > 99 ? (int16_t)(whole / 100) % 10 : 0); // Подготовка цифр + whole_digits[1] = digits(whole > 9 ? (int16_t)(whole / 10) % 10 : 0); + whole_digits[2] = digits((int16_t)whole % 10); + + fract_digits[0] = digits(fract > 99 ? (int16_t)(fract / 100) % 10 : 0); + fract_digits[1] = digits(fract > 9 ? (int16_t)(fract / 10) % 10 : 0); + fract_digits[2] = digits((int16_t)fract % 10); + + clear(); + switch (base) { // Вывод согласно точности + case 1: + dispBuf[0] = (flag ? _dash : whole_digits[0]); + dispBuf[1] = whole_digits[1]; + dispBuf[2] = whole_digits[2]; + dispBuf[3] = fract_digits[2]; + break; + case 2: + dispBuf[0] = (flag ? _dash : whole_digits[1]); + dispBuf[1] = whole_digits[2]; + dispBuf[2] = fract_digits[1]; + dispBuf[3] = fract_digits[2]; + break; + case 3: + dispBuf[0] = whole_digits[2]; + dispBuf[1] = fract_digits[0]; + dispBuf[2] = fract_digits[1]; + dispBuf[3] = fract_digits[2]; + break; + } + point(3 - base, true); + } + + + void displayFloatNulls(float data) { + displayFloatNulls(data, 1); // Дефолт вывод float - с одним дробным знаком, с нулями слева + } + + + void displayFloat(float data, uint8_t base) { + base = constrain(base, 1, 3); // Ограничение кол-ва дробных знаков + bool flag = false; // Флаг отрицательного числа + + if (data < 0) { // Если число меньше нуля + data *= -1; // Сделать положительным + flag = true; + } + + uint16_t whole = floor(data); // Получить целую часть в целочисленном виде + uint16_t fract = floor(((float)data - whole) * fastPow10(base)); // Получить дробную часть в целочисленном виде + // Пример: 326.429 -> whole = 326, fract = 429; + + if (whole > fastPow10((flag ? 3 : 4) - base) - 1) { // Если не хватает знаков на дисплее + displayBytes(flag ? _dash : _empty, _O, _V, _F); // Выводим 'OVF' + return; // Завершаем функцию + } + + uint8_t whole_digits[3]; // Буфер для цифр целой части + uint8_t fract_digits[3]; // Аналогично для дробной + + + whole_digits[0] = (whole > 99 ? digits((uint16_t)(whole / 100) % 10) : _empty); // Подготовка трех символов чисел + whole_digits[1] = (whole > 9 ? digits((uint16_t)(whole / 10) % 10) : _empty); // Для целой части + whole_digits[2] = digits((int16_t)whole % 10); + + fract_digits[0] = digits(fract > 99 ? (int16_t)(fract / 100) % 10 : 0); // Подготовка символов + fract_digits[1] = digits(fract > 9 ? (int16_t)(fract / 10) % 10 : 0); // Для дробной части + fract_digits[2] = digits((int16_t)fract % 10); + + clear(); // Очистка дисплея + switch (base) { // Разное кол-во знаков + case 1: + dispBuf[0] = (flag and whole > 9 ? _dash : whole_digits[0]); // Работаем с минусом при необходимости + dispBuf[1] = (flag and whole < 9 ? _dash : whole_digits[1]); // Занимаем все знакоместа + dispBuf[2] = whole_digits[2]; + dispBuf[3] = fract_digits[2]; + break; + case 2: + dispBuf[0] = (flag ? _dash : whole_digits[1]); + dispBuf[1] = whole_digits[2]; + dispBuf[2] = fract_digits[1]; + dispBuf[3] = fract_digits[2]; + break; + case 3: + dispBuf[0] = whole_digits[2]; + dispBuf[1] = fract_digits[0]; + dispBuf[2] = fract_digits[1]; + dispBuf[3] = fract_digits[2]; + break; + } + point(3 - base, true); + } + + + void displayFloat(float data) { + displayFloat(data, 1); // Дефолт вывод float - с одним дробным знаком, без нулей слева + } + + + void displayFloatAuto(float data) { + uint8_t base = 0; + if (data > 0 and floor(fabs(data)) < 10) { // Если число без минуса и целая часть меньше 10 - можно вывести 3 дробных знака + base = 3; + } else if (floor(fabs(data)) < (data > 0 ? 100 : 10)) { // Если есть минус или же целая часть в пределах 9 / 99 - выводим 2 знака + base = 2; + } else { // Иначе выводим с 1 знаком, вылезания за пределы задетектит сама функция вывода float + base = 1; + } + displayFloatNulls(data, base); // Выводим число с нужной точностью + } + + + void displayByte(uint8_t data, uint8_t pos) { + dispBuf[pos] = data; // Просто заполняем нужный элемент буфера символом + } + + + void displayBytes(uint8_t a, uint8_t b, uint8_t c, uint8_t d) { + dispBuf[0] = a; // Прямой вывод 4х байт + dispBuf[1] = b; + dispBuf[2] = c; + dispBuf[3] = d; + } + + + void displayBytes(uint8_t *str, uint8_t size, bool align = true) { + size = constrain(size, 1, 4); // Ограничение длинны массива + for (uint8_t i = 0; i < size; i++) { + dispBuf[(align ? i : 3 - i)] = str[(align ? i : (size - 1) - i)]; // Перенос массива в буфер дисплея + } + } + + + void point(uint8_t pos, bool state) { + bitWrite(dispBuf[pos], 7, !state); + } + + + void clear(void) { + dispBuf[0] = _empty; + dispBuf[1] = _empty; + dispBuf[2] = _empty; + dispBuf[3] = _empty; + } + + + void runningString(uint8_t *str, uint8_t size, uint16_t ms) { + runningString(str, size, ms, false); + } + + + void runningString(uint8_t *str, uint8_t size, uint16_t ms, bool useTick) { + uint8_t strBuf[size + 8]; // Временный буфер для всей строки + uint8_t strPtr = 0; + uint32_t strTimer = millis(); + + for (uint8_t i = 0; i < 4; i++) { // Добавляем пустые символы в начало строки + strBuf[i] = _empty; + } + for (uint8_t i = 0; i < size; i++) { // Добавляем символы самой строки + strBuf[i + 4] = str[i]; + } + for (uint8_t i = size + 4; i < size + 8; i++) { // Добавляем пустые символы в конец + strBuf[i] = _empty; + } + + while (strPtr < size + 4) { + if (useTick) tick(); + if (millis() - strTimer >= ms) { + strTimer = millis(); + displayBytes(strBuf[strPtr], strBuf[strPtr + 1], strBuf[strPtr + 2], strBuf[strPtr + 3]); + strPtr++; + } + } + } + + + private: + volatile uint8_t dispBuf[4] = {0xFF, 0xFF, 0xFF, 0xFF}; + volatile uint8_t dispPtr = 0; + uint32_t dispTimer = 0; + +#ifdef DISP595_BRIGHTNESS + volatile uint8_t softPwmDepth = 8; + volatile uint8_t softPwmDuty = 7; + volatile uint8_t softPwmCounter = 0; +#endif + + + void displayWrite(uint8_t data, uint8_t mask) { +#ifdef __AVR__ + fastShiftOut(MSBFIRST, data); + fastShiftOut(MSBFIRST, mask); + *_latch_port |= _latch_mask; + *_latch_port &= ~ _latch_mask; +#else + shiftOut(_data_pin, _clk_pin, MSBFIRST, data); + shiftOut(_data_pin, _clk_pin, MSBFIRST, mask); + digitalWrite(_latch_pin, HIGH); + digitalWrite(_latch_pin, LOW); +#endif + } + + uint16_t fastPow10(uint8_t exp) { // Быстрое возведение 10 в степень + switch (exp) { + case 1: return 10; + case 2: return 100; + case 3: return 1000; + } + return 1; + } + +#ifdef __AVR__ + void fastShiftOut(uint8_t bitOrder, uint8_t data) { + for (uint8_t i = 0; i < 8; i++) { + if (bitOrder == MSBFIRST) { + if (data & (1 << 7)) *_data_port |= _data_mask; + else *_data_port &= ~_data_mask; + data <<= 1; + } else { + if (data & 1) *_data_port |= _data_mask; + else *_data_port &= ~_data_mask; + data >>= 1; + } + *_clk_port |= _clk_mask; + *_clk_port &= ~_clk_mask; + } + } + + volatile uint8_t *_clk_port; + volatile uint8_t *_data_port; + volatile uint8_t *_latch_port; + uint8_t _clk_mask; + uint8_t _data_mask; + uint8_t _latch_mask; +#else + uint8_t _clk_pin; + uint8_t _data_pin; + uint8_t _latch_pin; +#endif +}; \ No newline at end of file diff --git a/SevenSegmentsDisp/Disp595_symbols.h b/SevenSegmentsDisp/Disp595_symbols.h new file mode 100644 index 0000000..5352f25 --- /dev/null +++ b/SevenSegmentsDisp/Disp595_symbols.h @@ -0,0 +1,56 @@ +#pragma once + +/* + Битовые маски символов для библиотеки Disp595 +*/ + +#define _A 0b10001000 +#define _B 0b10000000 +#define _C 0b11000110 +#define _D 0b11000000 +#define _E 0b10000110 +#define _F 0b10001110 +#define _G 0b11000010 +#define _H 0b10001001 +#define _J 0b11100001 +#define _L 0b11000111 +#define _N 0b11001000 +#define _O 0b11000000 +#define _P 0b10001100 +#define _S 0b10010010 +#define _U 0b11000001 +#define _V 0b11000001 +#define _Y 0b10010001 +#define _a 0b10100000 +#define _b 0b10000011 +#define _c 0b10100111 +#define _d 0b10100001 +#define _e 0b10000100 +#define _f 0b10001110 +#define _h 0b10001011 +#define _i 0b11101111 +#define _j 0b11110001 +#define _l 0b11111001 +#define _n 0b10101011 +#define _o 0b10100011 +#define _q 0b10011000 +#define _r 0b10101111 +#define _t 0b10000111 +#define _u 0b11100011 +#define _v 0b11100011 +#define _y 0b11100011 +#define _dash 0b10111111 +#define _under 0b11110111 +#define _equal 0b10110111 +#define _empty 0b11111111 + +#define _0 0b11000000 +#define _1 0b11111001 +#define _2 0b10100100 +#define _3 0b10110000 +#define _4 0b10011001 +#define _5 0b10010010 +#define _6 0b10000010 +#define _7 0b11111000 +#define _8 0b10000000 +#define _9 0b10010000 diff --git a/SevenSegmentsDisp/SevenSegmentsDisp.h b/SevenSegmentsDisp/SevenSegmentsDisp.h new file mode 100644 index 0000000..ccb43e0 --- /dev/null +++ b/SevenSegmentsDisp/SevenSegmentsDisp.h @@ -0,0 +1,12 @@ +/* + Набор быстрых и удобных библиотек для работы с семисегментными дисплеями совместно с Arduino. + Документацию к конкретным библиотекам контроллеров дисплеев см. в заголовочных файлах библиотек. + + V1.0 от 24/01/2021 - Добавлена библиотека 'Disp595.h' для модулей дисплеев на базе сдвиговых регистров TM74HC595 + + ... +*/ + +#pragma once +#include +#include "Disp595.h" // Либа дисплея TM74HC595 \ No newline at end of file diff --git a/SevenSegmentsDisp/examples/TM74HC595 Display/brightness/brightness.ino b/SevenSegmentsDisp/examples/TM74HC595 Display/brightness/brightness.ino new file mode 100644 index 0000000..fdf2645 --- /dev/null +++ b/SevenSegmentsDisp/examples/TM74HC595 Display/brightness/brightness.ino @@ -0,0 +1,37 @@ +/* + Простой пример программного управления яркостью + Обслуживание динамической индикации берет на себя аппаратный Timer 2 + https://alexgyver.ru/lessons/timer-isr/ +*/ + +#define DATA_PIN 11 +#define SCLK_PIN 10 +#define RCLK_PIN 12 +#define DISP_PERIOD 500 // Период динамической индикации в мкс, делаем почаще! +#define DISP595_BRIGHTNESS // Сообщаем библиотеке, что будем использовать регулировку яркости! +// #define DISP595_BRIGHTNESS_DEPTH 10 // Глубину яркости можно настроить, больше - плавнее, но сильнее мерцание (по умолч. 8) + +#include +#include + +Disp595 disp(DATA_PIN, SCLK_PIN, RCLK_PIN); + +void setup() { + Timer2.setPeriod(DISP_PERIOD); // Заводим Timer 2 на прерывания с нужным периодом + Timer2.enableISR(); // Включаем прерывания Timer 2 + + disp.displayBytes(_t, _E, _S, _t); // Вывод символов +} + +void loop() { + disp.brightness(0); // Устанавливаем яркость в диапазоне (0 - 7) + delay(1000); + disp.brightness(3); + delay(1000); + disp.brightness(7); + delay(1000); +} + +ISR(TIMER2_A) { // Прерывание Timer 2 + disp.tickManual(); // Обслуживание динамической индикации дисплея +} diff --git a/SevenSegmentsDisp/examples/TM74HC595 Display/demo/demo.ino b/SevenSegmentsDisp/examples/TM74HC595 Display/demo/demo.ino new file mode 100644 index 0000000..d6b5a1f --- /dev/null +++ b/SevenSegmentsDisp/examples/TM74HC595 Display/demo/demo.ino @@ -0,0 +1,139 @@ +/* + Демонстрация всего функционала, вывод разных данных на дисплей TM74HC595 + Обслуживание динамической индикации берет на себя аппаратный Timer 2 + https://alexgyver.ru/lessons/timer-isr/ +*/ + +#define DATA_PIN 11 +#define SCLK_PIN 10 +#define RCLK_PIN 12 +#define DISP_PERIOD 3000 // Период динамической индикации в мкс (500-6000) +// #define DISP_PERIOD 500 // Если используется регулировка яркости, дергать tick() надо чаще! + +// #define DISP595_BRIGHTNESS // Использовать регулировку яркости +// #define DISP595_BRIGHTNESS_DEPTH 10 // Глубину яркости можно изменить (по умолч. 8), больше - плавнее яркость, но сильнее мерцание дисплея + +#include +#include + +Disp595 disp(DATA_PIN, SCLK_PIN, RCLK_PIN); + +void setup() { + Timer2.setPeriod(DISP_PERIOD); // Заводим Timer 2 на прерывания с нужным периодом + Timer2.enableISR(); // Включаем прерывания Timer 2 +} + +void loop() { + + /* Вывод встроенных и кастомных символов, сырых данных на элеменыт дисплея */ + disp.displayBytes(_H, _E, _L, _P); // Прямой вывод данных (символов) на дисплей + disp.point(0, true); // ПОСЛЕ вывода данных можно добавить / удалить точки + disp.point(3, true); // Указываем позицию точки слева (0 - 3) и включаем / выключаем ее (true / false) + delay(1000); + + /* + Программное управление яркостью дисплея + Чем больше глубина яркости - тем чаще нужно дергать tick()! + (если DISP595_BRIGHTNESS обьявлен перед подключением) + */ + /* + disp.brightnessDepth(8); // Установка "глубины" яркости - количества градаций, по умолчанию 8 градаций + + for (uint8_t i = 7; i > 0; i--) { + disp.brightness(i); // Яркость в диапазоне 0-7 + delay(500); + } + + delay(1000); + + for (uint8_t i = 0; i < 8; i++) { + disp.brightness(i); // Яркость в диапазоне 0-7 + delay(500); + } + */ + + + /* Вывод одиночных символов на нужную позицию СЛЕВА */ + disp.displayByte(_L, 3); // Заменяем 3й символ с 'P' на 'L' + delay(1000); + + + /* Вывод массива символов на дисплей с выравниванием по левому / правому краю */ + uint8_t data[] = {_D, _A}; + disp.clear(); + disp.displayBytes(data, sizeof(data)); // Вывод массива символов с выравниванием по левому краю + delay(1000); + + disp.clear(); + disp.displayBytes(data, sizeof(data), ALIGN_RIGHT); // Вывод массива символов с выравниванием по правому краю + delay(1000); + + disp.clear(); + disp.displayBytes(data, sizeof(data), ALIGN_LEFT); // Вывод массива символов с выравниванием по левому краю + delay(1000); + + + /* Вывод бегущих строк */ + uint8_t str[] = {_1, _2, _3, _4, _5, _empty, _t, _E, _S, _t}; + disp.runningString(str, sizeof(str), 300); // Вывод бегущей строки, указываем массив символов, размер, задержку в мс + + + /* Вывод целых чисел без нулей слева */ + for (int8_t i = -50; i < 50; i++) { + disp.displayInt(i); + delay(100); + } + + + /* Вывод целых чисел c нулями слева */ + for (int8_t i = 50; i > -50; i--) { + disp.displayIntNulls(i); + delay(100); + } + + /* Вывод чисел с плавающей точкой без нулей слева */ + disp.displayFloat(-12.34); // Без указания точности, дробных знаков - 1 + delay(1000); + disp.displayFloat(-12.34, 1); // Или же кол-во знаков можно ввести вручную, от 1 до 3 + delay(1000); + disp.displayFloat(12.34, 2); // Выводить можно как положительные, так и отрицательные числа + delay(1000); + disp.displayFloat(1.234, 3); // Но при выводе 3х десятичных знаков, места под знак минуса не достаточно + delay(1000); + + + /* Вывод чисел с плавающей точкой с нулями слева */ + disp.displayFloat(-3.14); // Тут все аналоично, но с нулями слева + delay(1000); + disp.displayFloat(-1.34, 1); + delay(1000); + disp.displayFloat(3.1415, 2); + delay(1000); + disp.displayFloat(3.1415, 3); + delay(1000); + + + /* Вывод числа + символов */ + for (uint8_t i = 0; i < 30; i++) { + int value = random(0, 99); + disp.displayInt(value); // СНАЧАЛА выводим число int + disp.displayByte(_t, 0); // Пустые символы можем вручную заполнить символами + disp.displayByte(_equal, 1); + delay(200); + } + + + /* Вывод числа + массива символов */ + uint8_t strData[] = {_P, _H}; + disp.displayFloat(1.2, 1); // СНАЧАЛА выводим число float (заняли всего 2 символа) + disp.displayBytes(strData, sizeof(strData)); // Пустые символы можем заполнить массивом символов + delay(1000); + + /* Очистка дисплея */ + disp.clear(); // Буфер дисплея очищается + delay(3000); +} + +ISR(TIMER2_A) { // Прерывание Timer 2 + disp.tickManual(); // Обслуживание динамической индикации дисплея +} diff --git a/SevenSegmentsDisp/examples/TM74HC595 Display/floatAuto/floatAuto.ino b/SevenSegmentsDisp/examples/TM74HC595 Display/floatAuto/floatAuto.ino new file mode 100644 index 0000000..186da9d --- /dev/null +++ b/SevenSegmentsDisp/examples/TM74HC595 Display/floatAuto/floatAuto.ino @@ -0,0 +1,35 @@ +/* + Простой пример вывода чисел с плавающей точкой (float),с автоматическим выбором точности + Обслуживание динамической индикации берет на себя аппаратный Timer 2 + https://alexgyver.ru/lessons/timer-isr/ +*/ + +#define DATA_PIN 11 +#define SCLK_PIN 10 +#define RCLK_PIN 12 +#define DISP_PERIOD 3000 // Период динамической индикации в мкс (500-6000) + +#include +#include + +Disp595 disp(DATA_PIN, SCLK_PIN, RCLK_PIN); + +void setup() { + Timer2.setPeriod(DISP_PERIOD); // Заводим Timer 2 на прерывания с нужным периодом + Timer2.enableISR(); // Включаем прерывания Timer 2 +} + +void loop() { + disp.displayFloatAuto(16.384); // Вывод числа с автоматическим выбором точности + delay(1000); + disp.displayFloatAuto(8.192); // Выведет с точностью 3 знака + delay(1000); + disp.displayFloatAuto(-4.096); // Выведет с точностью 2 знака + delay(1000); + disp.displayFloatAuto(-12.048); // Выведет с точносью 1 знак + delay(1000); +} + +ISR(TIMER2_A) { // Прерывание Timer 2 + disp.tickManual(); // Обслуживание динамической индикации дисплея +} diff --git a/SevenSegmentsDisp/examples/TM74HC595 Display/floatWithNulls/floatWithNulls.ino b/SevenSegmentsDisp/examples/TM74HC595 Display/floatWithNulls/floatWithNulls.ino new file mode 100644 index 0000000..5bb1f81 --- /dev/null +++ b/SevenSegmentsDisp/examples/TM74HC595 Display/floatWithNulls/floatWithNulls.ino @@ -0,0 +1,35 @@ +/* + Простой пример вывода чисел с плавающей точкой (float),С НУЛЯМИ СЛЕВА, на дисплей TM74HC595 + Обслуживание динамической индикации берет на себя аппаратный Timer 2 + https://alexgyver.ru/lessons/timer-isr/ +*/ + +#define DATA_PIN 11 +#define SCLK_PIN 10 +#define RCLK_PIN 12 +#define DISP_PERIOD 3000 // Период динамической индикации в мкс (500-6000) + +#include +#include + +Disp595 disp(DATA_PIN, SCLK_PIN, RCLK_PIN); + +void setup() { + Timer2.setPeriod(DISP_PERIOD); // Заводим Timer 2 на прерывания с нужным периодом + Timer2.enableISR(); // Включаем прерывания Timer 2 +} + +void loop() { + disp.displayFloatNulls(16.384); // Вывод числа С НУЛЯМИ СЛЕВА (минус всегда крайний слева) + delay(500); + disp.displayFloatNulls(8.192, 1); // Можно указать кол-во дробных знаков, (без указания - 1 знак) + delay(500); + disp.displayFloatNulls(-4.096, 2); // Можно выводить и отрицательные числа + delay(500); + disp.displayFloatNulls(2.048, 3); // Но в случае с 3мя знаками, доступны только положительные (не хватает символов) + delay(500); +} + +ISR(TIMER2_A) { // Прерывание Timer 2 + disp.tickManual(); // Обслуживание динамической индикации дисплея +} diff --git a/SevenSegmentsDisp/examples/TM74HC595 Display/floatWithoutNulls/floatWithoutNulls.ino b/SevenSegmentsDisp/examples/TM74HC595 Display/floatWithoutNulls/floatWithoutNulls.ino new file mode 100644 index 0000000..145a87b --- /dev/null +++ b/SevenSegmentsDisp/examples/TM74HC595 Display/floatWithoutNulls/floatWithoutNulls.ino @@ -0,0 +1,35 @@ +/* + Простой пример вывода чисел с плавающей точкой (float),БЕЗ НУЛЕЙ СЛЕВА, на дисплей TM74HC595 + Обслуживание динамической индикации берет на себя аппаратный Timer 2 + https://alexgyver.ru/lessons/timer-isr/ +*/ + +#define DATA_PIN 11 +#define SCLK_PIN 10 +#define RCLK_PIN 12 +#define DISP_PERIOD 3000 // Период динамической индикации в мкс (500-6000) + +#include +#include + +Disp595 disp(DATA_PIN, SCLK_PIN, RCLK_PIN); + +void setup() { + Timer2.setPeriod(DISP_PERIOD); // Заводим Timer 2 на прерывания с нужным периодом + Timer2.enableISR(); // Включаем прерывания Timer 2 +} + +void loop() { + disp.displayFloat(16.384); // Вывод числа БЕЗ НУЛЕЙ СЛЕВА (минус следует за ближайшим числом) + delay(500); + disp.displayFloat(-8.192, 1); // Можно указать кол-во дробных знаков, (без указания - 1 знак) + delay(500); + disp.displayFloat(-4.096, 2); // Можно выводить и отрицательные числа + delay(500); + disp.displayFloat(2.048, 3); // Но в случае с 3мя знаками, доступны только положительные (не хватает символов) + delay(500); +} + +ISR(TIMER2_A) { // Прерывание Timer 2 + disp.tickManual(); // Обслуживание динамической индикации дисплея +} diff --git a/SevenSegmentsDisp/examples/TM74HC595 Display/intWithNulls/intWithNulls.ino b/SevenSegmentsDisp/examples/TM74HC595 Display/intWithNulls/intWithNulls.ino new file mode 100644 index 0000000..fb6573d --- /dev/null +++ b/SevenSegmentsDisp/examples/TM74HC595 Display/intWithNulls/intWithNulls.ino @@ -0,0 +1,30 @@ +/* + Простой пример вывода целых чисел (unsigned int / int), С НУЛЯМИ СЛЕВА, на дисплей TM74HC595 + Обслуживание динамической индикации берет на себя аппаратный Timer 2 + https://alexgyver.ru/lessons/timer-isr/ +*/ + +#define DATA_PIN 11 +#define SCLK_PIN 10 +#define RCLK_PIN 12 +#define DISP_PERIOD 3000 // Период динамической индикации в мкс (500-6000) + +#include +#include + +Disp595 disp(DATA_PIN, SCLK_PIN, RCLK_PIN); + +void setup() { + Timer2.setPeriod(DISP_PERIOD); // Заводим Timer 2 на прерывания с нужным периодом + Timer2.enableISR(); // Включаем прерывания Timer 2 +} + +void loop() { + int value = random(-99, 99); // Получим случайное число со знаком в диапазоне (-99...99) + disp.displayIntNulls(value); // Вывод числа С НУЛЯМИ СЛЕВА (минус всегда крайний слева) + delay(500); // Задержка между сменой +} + +ISR(TIMER2_A) { // Прерывание Timer 2 + disp.tickManual(); // Обслуживание динамической индикации дисплея +} diff --git a/SevenSegmentsDisp/examples/TM74HC595 Display/intWithoutNulls/intWithoutNulls.ino b/SevenSegmentsDisp/examples/TM74HC595 Display/intWithoutNulls/intWithoutNulls.ino new file mode 100644 index 0000000..2fb4abe --- /dev/null +++ b/SevenSegmentsDisp/examples/TM74HC595 Display/intWithoutNulls/intWithoutNulls.ino @@ -0,0 +1,30 @@ +/* + Простой пример вывода целых чисел (unsigned int / int),БЕЗ НУЛЕЙ СЛЕВА, на дисплей TM74HC595 + Обслуживание динамической индикации берет на себя аппаратный Timer 2 + https://alexgyver.ru/lessons/timer-isr/ +*/ + +#define DATA_PIN 11 +#define SCLK_PIN 10 +#define RCLK_PIN 12 +#define DISP_PERIOD 3000 // Период динамической индикации в мкс (500-6000) + +#include +#include + +Disp595 disp(DATA_PIN, SCLK_PIN, RCLK_PIN); + +void setup() { + Timer2.setPeriod(DISP_PERIOD); // Заводим Timer 2 на прерывания с нужным периодом + Timer2.enableISR(); // Включаем прерывания Timer 2 +} + +void loop() { + int value = random(-99, 99); // Получим случайное число со знаком в диапазоне (-99...99) + disp.displayInt(value); // Вывод числа БЕЗ НУЛЕЙ СЛЕВА (минус следует за ближайшим числом) + delay(500); // Задержка между сменой +} + +ISR(TIMER2_A) { // Прерывание Timer 2 + disp.tickManual(); // Обслуживание динамической индикации дисплея +} diff --git a/SevenSegmentsDisp/examples/TM74HC595 Display/noTimer/noTimer.ino b/SevenSegmentsDisp/examples/TM74HC595 Display/noTimer/noTimer.ino new file mode 100644 index 0000000..17bdc12 --- /dev/null +++ b/SevenSegmentsDisp/examples/TM74HC595 Display/noTimer/noTimer.ino @@ -0,0 +1,42 @@ +/* + Простой пример вывода данных на дисплей TM74HC595, БЕЗ использования прерываний таймера. + В этом случае вывод бегущей строки и вообще любые другие блокирующие функции в цикле loop + приведут к потере работоспособности дисплея. + Необходимо отказаться от delay и использовать таймеры на millis() / micros() + https://alexgyver.ru/lessons/time/ +*/ + +#define DATA_PIN 11 +#define SCLK_PIN 10 +#define RCLK_PIN 12 + +/* Периоды встроенного в .tick() таймера можно указать вручную ПЕРЕД подключенеим библиотеки */ +// #define DISP595_FAST_PERIOD 300 // Период при использовании регулировки яркости (по умолч. 500 мкс) +// #define DISP595_SLOW_PERIOD 1000 // период при использовании статической яркости (по умолч. 3500 мкс) + +#include + +Disp595 disp(DATA_PIN, SCLK_PIN, RCLK_PIN); + +void setup() {} + +void loop() { + /* Использование встроенного таймера на micros */ + disp.tick(); // Таймер уже встроен в .tick() + + /* Все остальные задачи не блокируют цикл loop */ + static uint32_t timer = millis(); + if (millis() - timer >= 500) { + timer = millis(); // Каждые 500 мс + disp.displayInt(analogRead(A0)); // Выводим актуальное значение с аналог. пина A0 + } + + /* Ручное обслуживание дисплея при помощи таймера на micros */ + /* + static uint32_t dispTimer = micros(); + if (micros() - dispTimer >= DISP_PERIOD) { + dispTimer = micros(); + disp.tickManual(); // "голый" .tick() + } + */ +} diff --git a/SevenSegmentsDisp/examples/TM74HC595 Display/runningString/runningString.ino b/SevenSegmentsDisp/examples/TM74HC595 Display/runningString/runningString.ino new file mode 100644 index 0000000..b4280ef --- /dev/null +++ b/SevenSegmentsDisp/examples/TM74HC595 Display/runningString/runningString.ino @@ -0,0 +1,34 @@ +/* + Простой пример вывода бегущей строки на дисплей TM74HC595 + Обслуживание динамической индикации берет на себя аппаратный Timer 2 + https://alexgyver.ru/lessons/timer-isr/ +*/ + +#define DATA_PIN 11 +#define SCLK_PIN 10 +#define RCLK_PIN 12 +#define DISP_PERIOD 3000 // Период динамической индикации в мкс (500-6000) + +#include +#include + +Disp595 disp(DATA_PIN, SCLK_PIN, RCLK_PIN); + +void setup() { + Timer2.setPeriod(DISP_PERIOD); // Заводим Timer 2 на прерывания с нужным периодом + Timer2.enableISR(); // Включаем прерывания Timer 2 +} + +void loop() { + uint8_t str[] = { // Создаем массив с нашей строкой + _t, _E, _S, _t, _empty, _dash, _1, _2, _3, _4, _5 // Доступны не все символы! + }; + + // Так как используется таймер, встроенный в функцию вывода tick использовать НЕ НУЖНО, просто не указываем 4й аргумент или указываем его как false + disp.runningString(str, sizeof(str), 150); // Передаем строку, ее размер, задержку между сдвигами в мс + //disp.runningString(str, sizeof(str), 150, false); // Можно явно отключить встроенный tick, 4м аргументом +} + +ISR(TIMER2_A) { // Прерывание Timer 2 + disp.tickManual(); // Обслуживание динамической индикации дисплея +} diff --git a/SevenSegmentsDisp/examples/TM74HC595 Display/stringNoTimer/stringNoTimer.ino b/SevenSegmentsDisp/examples/TM74HC595 Display/stringNoTimer/stringNoTimer.ino new file mode 100644 index 0000000..42c10a6 --- /dev/null +++ b/SevenSegmentsDisp/examples/TM74HC595 Display/stringNoTimer/stringNoTimer.ino @@ -0,0 +1,26 @@ +/* + Простой пример вывода бегущей строки на дисплей TM74HC595 + Обслуживание динамической индикации ВСТРОЕННО в функцию вывода +*/ + +#define DATA_PIN 11 +#define SCLK_PIN 10 +#define RCLK_PIN 12 + +#include + +Disp595 disp(DATA_PIN, SCLK_PIN, RCLK_PIN); + +void setup() { + +} + +void loop() { + uint8_t str[] = { // Создаем массив с нашей строкой + _t, _E, _S, _t, _empty, _dash, _1, _2, _3, _4, _5 // Доступны не все символы! + }; + + // Так как таймер не используется, нужно активировать встроенный tick, 4м аргументом 'true' + disp.runningString(str, sizeof(str), 150, true); // Передаем строку, ее размер, задержку между сдвигами в мс, включаем встроенный tick + // Если помимо вывода бегущей строки других задач у дисплея нет - дополнительный tick в главном цикле необязателен +} diff --git a/SevenSegmentsDisp/examples/TM74HC595 Display/symbols/symbols.ino b/SevenSegmentsDisp/examples/TM74HC595 Display/symbols/symbols.ino new file mode 100644 index 0000000..bc85406 --- /dev/null +++ b/SevenSegmentsDisp/examples/TM74HC595 Display/symbols/symbols.ino @@ -0,0 +1,52 @@ +/* + Простой пример прямого вывода данных на дисплей TM74HC595 + Обслуживание динамической индикации берет на себя аппаратный Timer 2 + https://alexgyver.ru/lessons/timer-isr/ +*/ + +#define DATA_PIN 11 +#define SCLK_PIN 10 +#define RCLK_PIN 12 +#define DISP_PERIOD 3000 // Период динамической индикации в мкс (500-6000) + +#include +#include + +Disp595 disp(DATA_PIN, SCLK_PIN, RCLK_PIN); + +void setup() { + Timer2.setPeriod(DISP_PERIOD); // Заводим Timer 2 на прерывания с нужным периодом + Timer2.enableISR(); // Включаем прерывания Timer 2 +} + +void loop() { + disp.displayBytes(_H, _E, _L, _P); // Вывод сразу 4х символов + delay(1000); // Задержка между сменой + disp.displayBytes(_U, _S, _empty, _empty); // Доступны не все символы! (см. GyverTM74HC595.h) + delay(1000); // Задержка между сменой + + disp.clear(); // Очистка дисплея + + disp.displayByte(_dash, 3); // Вывод байта (символа) на нужную позцию (0 - 3) слева + disp.displayByte(_under, 2); + disp.displayByte(_dash, 1); + disp.displayByte(_under, 0); + delay(1000); + + uint8_t str[] = {_P, _H} ; // Выводим массив из нескольких байт (остальные символы остаются нетронутыми) + disp.clear(); // Очистка дисплея + disp.displayBytes(str, sizeof(str)); // Вывод символов с выравниванием по ЛЕВОМУ краю + delay(1000); + + disp.clear(); + disp.displayBytes(str, sizeof(str), ALIGN_RIGHT); // Выраванивание можно сделать и по правому краю + delay(1000); + + disp.clear(); + disp.displayBytes(str, sizeof(str), ALIGN_LEFT); // Или же вручную укзать левый край + delay(1000); +} + +ISR(TIMER2_A) { // Прерывание Timer 2 + disp.tickManual(); // Обслуживание динамической индикации дисплея +} diff --git a/SevenSegmentsDisp/keywords.txt b/SevenSegmentsDisp/keywords.txt new file mode 100644 index 0000000..9dde6de --- /dev/null +++ b/SevenSegmentsDisp/keywords.txt @@ -0,0 +1,84 @@ +####################################### +# Syntax Coloring Map For GyverTM74HC595 +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +Disp595 KEYWORD1 +SevenSegmentsDisp KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +ALIGN_RIGHT LITERAL1 +ALIGN_LEFT LITERAL1 +DISP595_BRIGHTNESS LITERAL1 +DISP595_BRIGHTNESS_DEPTH LITERAL1 +DISP595_FAST_PERIOD LITERAL1 +DISP595_SLOW_PERIOD LITERAL1 +tick KEYWORD2 +tickManual KEYWORD2 +displayIntNulls KEYWORD2 +displayInt KEYWORD2 +displayFloatNulls KEYWORD2 +displayFloat KEYWORD2 +displayFloatAuto KEYWORD2 +displayByte KEYWORD2 +displayBytes KEYWORD2 +point KEYWORD2 +clear KEYWORD2 +runningString KEYWORD2 +brightness KEYWORD2 +brightnessDepth KEYWORD2 +_A KEYWORD2 +_B KEYWORD2 +_C KEYWORD2 +_D KEYWORD2 +_E KEYWORD2 +_F KEYWORD2 +_G KEYWORD2 +_H KEYWORD2 +_J KEYWORD2 +_L KEYWORD2 +_N KEYWORD2 +_O KEYWORD2 +_P KEYWORD2 +_S KEYWORD2 +_U KEYWORD2 +_V KEYWORD2 +_Y KEYWORD2 +_a KEYWORD2 +_b KEYWORD2 +_c KEYWORD2 +_d KEYWORD2 +_e KEYWORD2 +_f KEYWORD2 +_h KEYWORD2 +_i KEYWORD2 +_j KEYWORD2 +_l KEYWORD2 +_n KEYWORD2 +_o KEYWORD2 +_q KEYWORD2 +_r KEYWORD2 +_t KEYWORD2 +_u KEYWORD2 +_v KEYWORD2 +_y KEYWORD2 +_dash KEYWORD2 +_under KEYWORD2 +_equal KEYWORD2 +_empty KEYWORD2 +_degree KEYWORD2 +_0 KEYWORD2 +_1 KEYWORD2 +_2 KEYWORD2 +_3 KEYWORD2 +_4 KEYWORD2 +_5 KEYWORD2 +_6 KEYWORD2 +_7 KEYWORD2 +_8 KEYWORD2 +_9 KEYWORD2 \ No newline at end of file