// реализовал фронт и спад, кратные 51
// устранено торможение от расчетов яркости в обработке прерывания -
// сделал массив fill_array, кот. реализует логарифмическую зависимость
// pause = 2000, counter_cycles_PWM_max= 580, front = 580, fall = 306 (кратные 255/5=51)
// убрал паузу для резкого режима
// сделал рандом:
// 2й байт = 254 (кол. байтов программы) - рандом на зажигание ОДНОЙ гирлянды
// 2й байт = 255 (кол. байтов программы) - рандом побайтно
// сделать задание скорости для каждой программы, причем надо, чтобы это совмещалось с изменением общей скорости
// сделать реверс по битам (зеркальное отражение байта)
// пауза: 2й байт = 0
// #include <GyverTimers.h>
#include <EEPROM.h>
// #include <LiquidCrystal.h>
// для программного ШИМ можно исп. все выводы, кроме А6 и А7
#define INIT_KEY 63 //ключ для EEPROM - чтобы сделать разные паузы для реального контроллера, и для WOKWI
#define STR_ADDR 0 // адрес хранения данных в EEPROM
#define NUM_LINES 8
byte PIN_LED[NUM_LINES] = {2, 3, 4, 5, 6, 7, 8, 9};
byte LED_PWM_fill[NUM_LINES]; //яркость светодиодов
bool order;
bool ignition; // зажигание
bool direction;
bool bit_reverce; // 0 - левый бит слева, 1 - левый бит справа
byte repeats = 1; // кол. повторов проходов программы
byte volatile counter_PWM; // циклы самого низкого уровня, изменяется при КАЖДОМ прерывании
uint16_t volatile counter_cycles_PWM;
// byte random_arr[];
byte brightness = 255;
// pause = 5000, counter_cycles_PWM_max= 1450, front = 714, fall = 714, кф=3,448275862069
int pause;
int pause_soft = 1500; // значение для WOKWI
int pause_hard = 600; // значение для WOKWI
// const uint16_t counter_cycles_PWM_max= 290; // для счета полных циклов во время паузы
uint16_t counter_cycles_PWM_max = floor(pause_soft/3.448275862069/10)*10; // для счета полных циклов во время паузы
// uint16_t counter_cycles_PWM_max = counter_cycles_PWM_max2/10*10;
// const uint16_t PWM_front = 102; // кратно 51 (шагу)
const uint16_t PWM_front = counter_cycles_PWM_max * 6/15;
// const uint16_t PWM_fall = 102; // от конца
//
// pause_soft = 5000, counter_cycles_PWM_max= 1450, front = 714, fall = 714, кф=3,448275862069
// const int pause_soft = 5500;
// const uint16_t counter_cycles_PWM_max= 1450; // для счета полных циклов во время паузы
// const uint16_t PWM_front = 714; // кратно 51 (шагу)
// const uint16_t PWM_fall = 714; // от конца
//*******************
// const int pause_soft = 5500; //на 500 больше, чем надо - для паузы
// const uint16_t counter_cycles_PWM_max= 1450; // для счета полных циклов во время паузы
// const uint16_t PWM_front = 663;
// const uint16_t PWM_fall = 663; // от конца
//*******************
// const int pause_soft = 7500; //на 500 больше, чем надо - для паузы
// const uint16_t counter_cycles_PWM_max= 2030; // для счета полных циклов во время паузы
// const uint16_t PWM_front = 714;
// const uint16_t PWM_fall = 714; // от конца
//
// делаем значения кратными 51
const byte step_PWM_front_cycles = PWM_front/51; // количество циклов при каждом значении fill. 51 шаг при приращении 5
// const byte step_PWM_fall_cycles = PWM_fall/51;
const uint16_t PWM_start_front = step_PWM_front_cycles * 51; // значение PWM_front, приведенное к кол. шагов
// const uint16_t PWM_start_fall = counter_cycles_PWM_max - step_PWM_fall_cycles * 51;
// const uint16_t PWM_start_fall = counter_cycles_PWM_max - step_PWM_fall_cycles * 51 + 1;
const uint16_t PWM_start_fall = counter_cycles_PWM_max - PWM_start_front + 1;
// массив значений яркости для софт-режима
const byte fill_array[51] = {0, 2, 5, 7, 8, 9, 11, 12, 15, 16, 18, 20, 22, 23, 25, 26, 28, 30, 32, 34, 36, 38, 40, 42, 45, 47, 49, 51, 54, 58, 61, 64, 67, 70, 75, 79, 83, 88, 96, 103, 111, 125, 131, 146, 158, 169, 187, 198, 212, 224, 235};
// LiquidCrystal lcd(12, 11, 10, 9, 8, 7);
// const byte prog01[][NUM_LINES] = {0b11000011, 5, 0b00011111, 0b00001111, 0b00000111, 0b00000011, 0b00000001};
const byte prog00[][NUM_LINES] = {0b01001101, 4, 0b10000001, 0b01000010, 0b00100100, 0b00011000};
const byte prog01[][NUM_LINES] = {0b1001, 5, 0b10000001, 0b01000010, 0b00100100, 0b00011000, 0b0};
const byte prog02[][NUM_LINES] = {0b0101, 8, 0b10000000, 0b01000000, 0b00100000, 0b00010000, 0b00001000, 0b00000100, 0b00000010, 0b0000001};
const byte prog03[][NUM_LINES] = {0b1001, 8, 0b10000000, 0b01000000, 0b00100000, 0b00010000, 0b00001000, 0b00000100, 0b00000010, 0b0000001};
const byte prog04[][NUM_LINES] = {0b0001, 7, 0b10000001, 0b000110000, 0b01100000, 0b000000110, 0b00110000, 0b00000011, 0b0};
const byte prog05[][NUM_LINES] = {0b1001, 8, 0b10000001, 0b11000011, 0b11100111, 0b11111111, 0b01111110, 0b00111100, 0b00011000, 0b0};
const byte prog06[][NUM_LINES] = {0b01000001, 10, 0b10000000, 0b11000000, 0b01100000, 0b00110000, 0b00011000, 0b00001100, 0b00000110, 0b00000011, 0b00000001, 0b0};
const byte prog07[][NUM_LINES] = {0b1001, 10, 0b10000000, 0b11000000, 0b11100000, 0b01110000, 0b00111000, 0b00011100, 0b00001110, 0b00000111, 0b00000011, 0b00000001};
const byte prog08[][NUM_LINES] = {0b0001, 37, 0b10000000, 0b01000000, 0b00100000, 0b00010000, 0b00001000, 0b00000100, 0b00000010, 0b00000001, 0b10000001, 0b01000001, 0b00100001, 0b00010001, 0b00001001, 0b00000101, 0b00000011, 0b10000011, 0b01000011, 0b00100011, 0b00010011, 0b00001011, 0b00000111, 0b10000111, 0b01000111, 0b00100111, 0b00010111, 0b00001111, 0b10001111, 0b01001111, 0b00101111, 0b00011111, 0b10011111, 0b01011111, 0b00111111, 0b10111111, 0b01111111, 0b11111111, 0b0};
const byte prog09[][NUM_LINES] = {0b1001, 11, 255, 0, 255, 0, 255, 255, 0, 255, 0, 255, 0};
// const byte prog04[][NUM_LINES] = {0b1001, 36, 0b10000000, 0b01000000, 0b00100000, 0b00010000, 0b00001000, 0b00000100, 0b00000010, 0b00000001, 0b10000001, 0b01000001, 0b00100001, 0b00010001, 0b00001001, 0b00000101, 0b00000011, 0b10000011, 0b01000011, 0b00100011, 0b00010011, 0b00001011, 0b00000111, 0b10000111, 0b01000111, 0b00100111, 0b00010111, 0b00001111, 0b10001111, 0b01001111, 0b00101111, 0b00011111, 0b10011111, 0b01011111, 0b00111111, 0b10111111, 0b01111111, 0b11111111};
const byte prog10[][NUM_LINES] = {0b1001, 9, 0b00010000, 0b00011000, 0b00111000, 0b00111100, 0b01111100, 0b01111110, 0b11100111, 0b11000011, 0b10000001};
const byte prog11[][NUM_LINES] = {0b0101, 4, 0b10000001, 0b01000010, 0b00100100, 0b00011000};
const byte prog12[][NUM_LINES] = {0b1001, 15, 0b10000000, 0b11000000, 0b11100000, 0b11110000, 0b11111000, 0b11111100, 0b11111110, 0b11111111, 0b01111111, 0b00111111, 0b00011111, 0b00001111, 0b00000111, 0b00000011, 0b00000001};
const byte prog13[][NUM_LINES] = {0b0101, 8, 0b10000000, 0b10000001, 0b10010001, 0b10011001, 0b11011001, 0b11011011, 0b11111011, 0b11111111};
const byte prog14[][NUM_LINES] = {0b0001, 8, 0b10000000, 0b10000001, 0b10010001, 0b10011001, 0b11011001, 0b11011011, 0b11111011, 0b11111111};
const byte prog15[][NUM_LINES] = {0b01001101, 4, 255, 255, 255, 255, 255};
const byte prog16[][NUM_LINES] = {0b00001001, 255};
const byte prog17[][NUM_LINES] = {0b00001101, 255};
const byte prog18[][NUM_LINES] = {0b00001001, 254};
const byte prog19[][NUM_LINES] = {0b00001101, 254};
const byte prog20[][NUM_LINES] = {0b00001101, 0};
const byte* all_progs[] = {(int)prog00, (int)prog01, (int)prog02, (int)prog03, (int)prog04, (int)prog05, \
(int)prog06, (int)prog07, (int)prog08, (int)prog09, (int)prog10, (int)prog11, (int)prog12, (int)prog13, \
(int)prog14, (int)prog15, (int)prog16, (int)prog17, (int)prog18, (int)prog19, (int)prog20};
byte num_progs = sizeof(all_progs)/sizeof(int);
//начало библиотеки GyverTimers
/*
Настройка и контроль прерываний по аппаратным таймерам ATmega328p, ATmega2560
Документация: https://alexgyver.ru/gyvertimers/
GitHub: https://github.com/GyverLibs/GyverTimers
Возможности:
- Поддерживаются все три таймера на ATmega328 и шесть таймеров на ATmega2560;
- Настройка периода (мкс) и частоты (Гц) прерываний:
- 8 бит таймеры: 61 Гц - 1 МГц (16 384 мкс.. 1 мкс);
- 16 бит таймеры: 0.24 Гц - 1 МГц (4 200 000 мкс.. 1 мкс);
- Автоматическая корректировка настройки периода от частоты тактирования (F_CPU);
- Функция возвращает точный установившийся период/частоту для отладки (частота ограничена разрешением таймера);
- Поддержка многоканального режима работы: один таймер вызывает 2 (ATmega328) или
3 (ATmega2560, таймеры 1, 3, 4, 5) прерывания с настраиваемым сдвигом по фазе 0-360 градусов;
- Настраиваемое действие аппаратного вывода таймера по прерыванию: высокий сигнал, низкий сигнал, переключение.
Позволяет генерировать меандр (одно- и двухтактный);
- Контроль работы таймера: старт/стоп/пауза/продолжить/инициализация;
Egor 'Nich1con' Zaharov for AlexGyver, [email protected]
https://alexgyver.ru/
MIT License
Версии:
v1.1 - исправлена ошибка в расчёте периодов
v1.2 - код разбит на h и cpp
v1.3 - поправлен незначительный баг
v1.4 - исправлена таблица частот и периодов
v1.5 - исправлен restart и resume
v1.6 - phase shift вынесен отдельным методом
v1.7 - поправлена документация
v1.8 - исправлен баг с макс периодом
v1.9 - исправлен баг с возвращаемым 2х периодом
v1.10 - добавлен флаг ready
*/
/*
-------------------------------- Arduino NANO 16 МГц (ATmega328) ------------------------------------
Таймер | Разрядность | Частоты | Периоды | Выходы | Пин Arduino | Пин МК|
--------|---------------|-------------------|-------------------|-----------|---------------|-------|
Timer0 | 8 бит | 61 Гц - 1 МГц | 16 384.. 1 мкс | CHANNEL_A | D6 | PD6 |
| | | | CHANNEL_B | D5 | PD5 |
--------|---------------|-------------------|-------------------|-----------|---------------|-------|
Timer1 | 16 бит | 0.24 Гц - 1 МГц | 4 200 000.. 1 мкс | CHANNEL_A | D9 | PB1 |
| | | | CHANNEL_B | D10 | PB2 |
--------|---------------|-------------------|-------------------|-----------|---------------|-------|
Timer2 | 8 бит | 61 Гц - 1 МГц | 16 384.. 1 мкс | CHANNEL_A | D11 | PB3 |
| | | | CHANNEL_B | D3 | PD3 |
----------------------------------------------------------------------------------------------------
------------------------------ Arduino MEGA 16 МГц (ATmega2560) -------------------------------------
Таймер | Разрядность | Частоты | Периоды | Выходы | Пин Arduino | Пин МК|
--------|---------------|-------------------|-------------------|-----------|---------------|-------|
Timer0 | 8 бит | 61 Гц - 1 МГц | 16 384.. 1 мкс | CHANNEL_A | 13 | PB7 |
| | | | CHANNEL_B | 4 | PG5 |
--------|---------------|-------------------|-------------------|-----------|---------------|-------|
Timer1 | 16 бит | 0.24 Гц - 1 МГц | 4 200 000.. 1 мкс | CHANNEL_A | 11 | PB5 |
| | | | CHANNEL_B | 12 | PB6 |
| | | | CHANNEL_C | 13 | PB7 |
--------|---------------|-------------------|-------------------|-----------|---------------|-------|
Timer2 | 8 бит | 61 Гц - 1 МГц | 16 384.. 1 мкс | CHANNEL_A | 10 | PB4 |
| | | | CHANNEL_B | 9 | PH6 |
--------|---------------|-------------------|-------------------|-----------|---------------|-------|
Timer3 | 16 бит | 0.24 Гц - 1 МГц | 4 200 000.. 1 мкс | CHANNEL_A | 5 | PE3 |
| | | | CHANNEL_B | 2 | PE4 |
| | | | CHANNEL_C | 3 | PE5 |
--------|---------------|-------------------|-------------------|-----------|---------------|-------|
Timer4 | 16 бит | 0.24 Гц - 1 МГц | 4 200 000.. 1 мкс | CHANNEL_A | 6 | PH3 |
| | | | CHANNEL_B | 7 | PH4 |
| | | | CHANNEL_C | 8 | PH5 |
--------|---------------|-------------------|-------------------|-----------|---------------|-------|
Timer5 | 16 бит | 0.24 Гц - 1 МГц | 4 200 000.. 1 мкс | CHANNEL_A | 46 | PL3 |
| | | | CHANNEL_B | 45 | PL4 |
| | | | CHANNEL_C | 44 | PL5 |
----------------------------------------------------------------------------------------------------
*/
/*
setPeriod(период) - установка периода в микросекундах и запуск таймера. Возвращает реальный период (точность ограничена разрешением таймера).
setFrequency(частота) - установка частоты в Герцах и запуск таймера. Возвращает реальную частоту (точность ограничена разрешением таймера).
setFrequencyFloat(частота float) - установка частоты в Герцах и запуск таймера, разрешены десятичные дроби. Возвращает реальную частоту (точность ограничена разрешением таймера).
enableISR(источник) - включить прерывания, канал прерываний CHANNEL_A или CHANNEL_B (+ CHANNEL_C у Mega2560)
disableISR(источник) - выключить прерывания, канал CHANNEL_A или CHANNEL_B. Счёт таймера не останавливается (без указания параметров будет выключен канал А).
pause() - приостановить счёт таймера, не сбрасывая счётчик
resume() - продолжить счёт после паузы
stop() - остановить счёт и сбросить счётчик
restart() - перезапустить таймер (сбросить счётчик)
setDefault() - установить параметры таймера по умолчанию ("Ардуино-умолчания")
outputEnable(канал, режим) - канал: включить выход таймера CHANNEL_A или CHANNEL_B (+ CHANNEL_C у Mega2560). Режим: TOGGLE_PIN, CLEAR_PIN, SET_PIN (переключить/выключить/включить пин по прерыванию)
outputDisable(канал) - отключить выход таймера CHANNEL_A или CHANNEL_B (+ CHANNEL_C у Mega2560, см. такблицу таймеров)
outputState(канал, состояние) - сменить состояние канала: HIGH / LOW
phaseShift(источник, фаза) - сдвинуть фазу канала на 0-360 градусов (у 8 бит таймеров двигается только канал B)
*/
#define MAX_PERIOD_8 (1000000UL * 1024UL / F_CPU * 256UL) // 16384 (61 Гц) на 16 МГц
#define MAX_PERIOD_16 (1000000UL * 1024UL / F_CPU * 65536UL) // 4194304 (0.24 Гц) на 16 МГц
// #ifndef GyverTimers_h
// #define GyverTimers_h
// #include <Arduino.h>
/* ========== Константы ========== */
#define CHANNEL_A 0x00
#define CHANNEL_B 0x01
#define CHANNEL_C 0x02
#define TOGGLE_PIN 0x01
#define CLEAR_PIN 0x02
#define SET_PIN 0x03
#define TIMER0_A TIMER0_COMPA_vect
#define TIMER0_B TIMER0_COMPB_vect
#define TIMER1_A TIMER1_COMPA_vect
#define TIMER1_B TIMER1_COMPB_vect
#define TIMER2_A TIMER2_COMPA_vect
#define TIMER2_B TIMER2_COMPB_vect
#if defined(__AVR_ATmega2560__)
#define TIMER1_C TIMER1_COMPC_vect
#define TIMER3_A TIMER3_COMPA_vect
#define TIMER3_B TIMER3_COMPB_vect
#define TIMER3_C TIMER3_COMPC_vect
#define TIMER4_A TIMER4_COMPA_vect
#define TIMER4_B TIMER4_COMPB_vect
#define TIMER4_C TIMER4_COMPC_vect
#define TIMER5_A TIMER5_COMPA_vect
#define TIMER5_B TIMER5_COMPB_vect
#define TIMER5_C TIMER5_COMPC_vect
#endif
#define GYVERTIMERS_INLINE
/*inline __attribute__((always_inline))*/
/* ================ Сlasses of timers ================ */
class Timer_0 { // Timer 0
public:
uint32_t setPeriod(uint32_t _timer0_period); // Set timer period [us]
uint32_t setFrequency(uint32_t _timer0_frequency); // Set timer frequency [Hz]
float setFrequencyFloat(float _timer0_frequency); // Set timer float frequency [Hz]
GYVERTIMERS_INLINE
bool ready(uint8_t channel = CHANNEL_A); // Return true, is interrupt is ready, but not enabled
GYVERTIMERS_INLINE
void enableISR(uint8_t source = CHANNEL_A); // Enable timer interrupt , channel A or B
GYVERTIMERS_INLINE
void disableISR(uint8_t source = CHANNEL_A); // Disable timer interrupt , channel A or B
GYVERTIMERS_INLINE
void pause(void); // Disable timer clock , not cleaning the counter
GYVERTIMERS_INLINE
void resume(void); // Return clock timer settings
GYVERTIMERS_INLINE
void stop(void); // Disable timer clock , and cleaning the counter
GYVERTIMERS_INLINE
void restart(void); // Return clock timer settings & reset counter
GYVERTIMERS_INLINE
void setDefault(void); // Set default timer settings
GYVERTIMERS_INLINE
void outputEnable(uint8_t channel, uint8_t mode); // Enable and configurate timer hardware output
GYVERTIMERS_INLINE
void outputDisable(uint8_t channel); // Disable timer hardware output
GYVERTIMERS_INLINE
void outputState(uint8_t channel,bool state); // Set High / Low on the timer output
GYVERTIMERS_INLINE
void phaseShift(uint8_t source, uint16_t phase);
private:
uint8_t _timer0_clock = 0x00; // Variable to store timer clock settings
};
class Timer_1 { // Timer 1
public:
uint32_t setPeriod(uint32_t _timer1_period); // Set timer period [Hz]
uint32_t setFrequency(uint32_t _timer1_frequency); // Set timer frequency [Hz]
float setFrequencyFloat(float _timer1_frequency); // Set timer float frequency [Hz]
GYVERTIMERS_INLINE
bool ready(uint8_t channel = CHANNEL_A); // Return true, is interrupt is ready, but not enabled
GYVERTIMERS_INLINE
void enableISR(uint8_t source = CHANNEL_A); // Enable timer interrupt , channel A or B
GYVERTIMERS_INLINE
void disableISR(uint8_t source = CHANNEL_A); // Disable timer interrupt , channel A or B
GYVERTIMERS_INLINE
void pause(void); // Disable timer clock , not cleaning the counter
GYVERTIMERS_INLINE
void resume(void); // Return clock timer settings
GYVERTIMERS_INLINE
void stop(void); // Disable timer clock , and cleaning the counter
GYVERTIMERS_INLINE
void restart(void); // Return clock timer settings & reset counter
GYVERTIMERS_INLINE
void setDefault(void); // Set default timer settings
GYVERTIMERS_INLINE
void outputEnable(uint8_t channel, uint8_t mode); // Enable and configurate timer hardware output
GYVERTIMERS_INLINE
void outputDisable(uint8_t channel); // Disable timer hardware output
GYVERTIMERS_INLINE
void outputState(uint8_t channel,bool state); // Set High / Low on the timer output
GYVERTIMERS_INLINE
void phaseShift(uint8_t source, uint16_t phase);
private:
uint8_t _timer1_clock = 0x00; // Variable to store timer clock settings
};
class Timer_2 { // Timer 2
public:
uint32_t setPeriod(uint32_t _timer2_period); // Set timer period [Hz]
uint32_t setFrequency(uint32_t _timer2_frequency); // Set timer frequency [Hz]
float setFrequencyFloat(float _timer2_frequency); // Set timer float frequency [Hz]
GYVERTIMERS_INLINE
bool ready(uint8_t channel = CHANNEL_A); // Return true, is interrupt is ready, but not enabled
GYVERTIMERS_INLINE
void enableISR(uint8_t source = CHANNEL_A); // Enable timer interrupt , channel A or B
GYVERTIMERS_INLINE
void disableISR(uint8_t source = CHANNEL_A); // Disable timer interrupt , channel A or B
GYVERTIMERS_INLINE
void pause(void); // Disable timer clock , not cleaning the counter
GYVERTIMERS_INLINE
void resume(void); // Return clock timer settings
GYVERTIMERS_INLINE
void stop(void); // Disable timer clock , and cleaning the counter
GYVERTIMERS_INLINE
void restart(void); // Return clock timer settings & reset counter
GYVERTIMERS_INLINE
void setDefault(void); // Set default timer settings
GYVERTIMERS_INLINE
void outputEnable(uint8_t channel, uint8_t mode); // Enable and configurate timer hardware output
GYVERTIMERS_INLINE
void outputDisable(uint8_t channel); // Disable timer hardware output
GYVERTIMERS_INLINE
void outputState(uint8_t channel,bool state); // Set High / Low on the timer output
GYVERTIMERS_INLINE
void phaseShift(uint8_t source, uint16_t phase);
private:
uint8_t _timer2_clock = 0x00; // Variable to store timer clock settings
};
#if defined(__AVR_ATmega2560__)
class Timer_3 { // Timer 3
public:
uint32_t setPeriod(uint32_t _timer3_period); // Set timer period [Hz]
uint32_t setFrequency(uint32_t _timer3_frequency); // Set timer frequency [Hz]
float setFrequencyFloat(float _timer3_frequency); // Set timer float frequency [Hz]
GYVERTIMERS_INLINE
bool ready(uint8_t channel = CHANNEL_A); // Return true, is interrupt is ready, but not enabled
GYVERTIMERS_INLINE
void enableISR(uint8_t source = CHANNEL_A); // Enable timer interrupt , channel A or B
GYVERTIMERS_INLINE
void disableISR(uint8_t source = CHANNEL_A); // Disable timer interrupt , channel A or B
GYVERTIMERS_INLINE
void pause(void); // Disable timer clock , not cleaning the counter
GYVERTIMERS_INLINE
void resume(void); // Return clock timer settings
GYVERTIMERS_INLINE
void stop(void); // Disable timer clock , and cleaning the counter
GYVERTIMERS_INLINE
void restart(void); // Return clock timer settings & reset counter
GYVERTIMERS_INLINE
void setDefault(void); // Set default timer settings
GYVERTIMERS_INLINE
void outputEnable(uint8_t channel, uint8_t mode); // Enable and configurate timer hardware output
GYVERTIMERS_INLINE
void outputDisable(uint8_t channel); // Disable timer hardware output
GYVERTIMERS_INLINE
void outputState(uint8_t channel,bool state); // Set High / Low on the timer output
GYVERTIMERS_INLINE
void phaseShift(uint8_t source, uint16_t phase);
private:
uint8_t _timer3_clock = 0x00; // Variable to store timer clock settings
};
class Timer_4 { // Timer 4
public:
uint32_t setPeriod(uint32_t _timer4_period); // Set timer period [Hz]
uint32_t setFrequency(uint32_t _timer4_frequency); // Set timer frequency [Hz]
float setFrequencyFloat(float _timer4_frequency); // Set timer float frequency [Hz]
GYVERTIMERS_INLINE
bool ready(uint8_t channel = CHANNEL_A); // Return true, is interrupt is ready, but not enabled
GYVERTIMERS_INLINE
void enableISR(uint8_t source = CHANNEL_A); // Enable timer interrupt , channel A or B
GYVERTIMERS_INLINE
void disableISR(uint8_t source = CHANNEL_A); // Disable timer interrupt , channel A or B
GYVERTIMERS_INLINE
void pause(void); // Disable timer clock , not cleaning the counter
GYVERTIMERS_INLINE
void resume(void); // Return clock timer settings
GYVERTIMERS_INLINE
void stop(void); // Disable timer clock , and cleaning the counter
GYVERTIMERS_INLINE
void restart(void); // Return clock timer settings & reset counter
GYVERTIMERS_INLINE
void setDefault(void); // Set default timer settings
GYVERTIMERS_INLINE
void outputEnable(uint8_t channel, uint8_t mode); // Enable and configurate timer hardware output
GYVERTIMERS_INLINE
void outputDisable(uint8_t channel); // Disable timer hardware output
GYVERTIMERS_INLINE
void outputState(uint8_t channel,bool state); // Set High / Low on the timer output
GYVERTIMERS_INLINE
void phaseShift(uint8_t source, uint16_t phase);
private:
uint8_t _timer4_clock = 0x00; // Variable to store timer clock settings
};
class Timer_5 { // Timer 5
public:
uint32_t setPeriod(uint32_t _timer5_period); // Set timer period [Hz]
uint32_t setFrequency(uint32_t _timer5_frequency); // Set timer frequency [Hz]
float setFrequencyFloat(float _timer5_frequency); // Set timer float frequency [Hz]
GYVERTIMERS_INLINE
bool ready(uint8_t channel = CHANNEL_A); // Return true, is interrupt is ready, but not enabled
GYVERTIMERS_INLINE
void enableISR(uint8_t source = CHANNEL_A); // Enable timer interrupt , channel A or B
GYVERTIMERS_INLINE
void disableISR(uint8_t source = CHANNEL_A); // Disable timer interrupt , channel A or B
GYVERTIMERS_INLINE
void pause(void); // Disable timer clock , not cleaning the counter
GYVERTIMERS_INLINE
void resume(void); // Return clock timer settings
GYVERTIMERS_INLINE
void stop(void); // Disable timer clock , and cleaning the counter
GYVERTIMERS_INLINE
void restart(void); // Return clock timer settings & reset counter
GYVERTIMERS_INLINE
void setDefault(void); // Set default timer settings
GYVERTIMERS_INLINE
void outputEnable(uint8_t channel, uint8_t mode); // Enable and configurate timer hardware output
GYVERTIMERS_INLINE
void outputDisable(uint8_t channel); // Disable timer hardware output
GYVERTIMERS_INLINE
void outputState(uint8_t channel,bool state); // Set High / Low on the timer output
GYVERTIMERS_INLINE
void phaseShift(uint8_t source, uint16_t phase);
private:
uint8_t _timer5_clock = 0x00; // Variable to store timer clock settings
};
#endif
extern Timer_0 Timer0;
extern Timer_1 Timer1;
extern Timer_2 Timer2;
#if defined(__AVR_ATmega2560__)
extern Timer_3 Timer3;
extern Timer_4 Timer4;
extern Timer_5 Timer5;
#endif
// #endif
// #include "GyverTimers.h"
// ========================== READY ==========================
bool Timer_0::ready(uint8_t channel) {
bool flag = false;
switch (channel) {
case CHANNEL_A: flag = bitRead(TIFR0, OCF0A); if (flag)bitSet(TIFR0, OCF0A); break; // Return interrupt flag + clear flag
case CHANNEL_B: flag = bitRead(TIFR0, OCF0B); if (flag)bitSet(TIFR0, OCF0B); break;
}
return flag;
}
bool Timer_1::ready(uint8_t channel) {
bool flag = false;
switch (channel) {
case CHANNEL_A: flag = bitRead(TIFR1, OCF1A); if (flag)bitSet(TIFR1, OCF1A); break; // Return interrupt flag + clear flag
case CHANNEL_B: flag = bitRead(TIFR1, OCF1B); if (flag)bitSet(TIFR1, OCF1B); break;
#if defined(__AVR_ATmega2560__)
case CHANNEL_C: flag = bitRead(TIFR1, OCF1C); if (flag)bitSet(TIFR1, OCF1C); break;
#endif
}
return flag;
}
bool Timer_2::ready(uint8_t channel) {
bool flag = false;
switch (channel) {
case CHANNEL_A: flag = bitRead(TIFR2, OCF2A); if (flag)bitSet(TIFR2, OCF2A); break; // Return interrupt flag + clear flag
case CHANNEL_B: flag = bitRead(TIFR2, OCF2B); if (flag)bitSet(TIFR2, OCF2B); break;
}
return flag;
}
#if defined(__AVR_ATmega2560__)
bool Timer_3::ready(uint8_t channel) {
bool flag = false;
switch (channel) {
case CHANNEL_A: flag = bitRead(TIFR3, OCF3A); if (flag)bitSet(TIFR3, OCF3A); break; // Return interrupt flag + clear flag
case CHANNEL_B: flag = bitRead(TIFR3, OCF3B); if (flag)bitSet(TIFR3, OCF3B); break;
case CHANNEL_C: flag = bitRead(TIFR3, OCF3C); if (flag)bitSet(TIFR3, OCF3C); break;
}
return flag;
}
bool Timer_4::ready(uint8_t channel) {
bool flag = false;
switch (channel) {
case CHANNEL_A: flag = bitRead(TIFR4, OCF4A); if (flag)bitSet(TIFR4, OCF4A); break; // Return interrupt flag + clear flag
case CHANNEL_B: flag = bitRead(TIFR4, OCF4B); if (flag)bitSet(TIFR4, OCF4B); break;
case CHANNEL_C: flag = bitRead(TIFR4, OCF4C); if (flag)bitSet(TIFR4, OCF4C); break;
}
return flag;
}
bool Timer_5::ready(uint8_t channel) {
bool flag = false;
switch (channel) {
case CHANNEL_A: flag = bitRead(TIFR5, OCF5A); if (flag)bitSet(TIFR5, OCF5A); break; // Return interrupt flag + clear flag
case CHANNEL_B: flag = bitRead(TIFR5, OCF5B); if (flag)bitSet(TIFR5, OCF5B); break;
case CHANNEL_C: flag = bitRead(TIFR5, OCF5C); if (flag)bitSet(TIFR5, OCF5C); break;
}
return flag;
}
#endif
// ========================== OUTPUT STATE ==========================
void Timer_0::outputState(uint8_t channel, bool state) {
switch (channel) {
case CHANNEL_A: TCCR0B = (TCCR0B & 0x7F) | (state << FOC0A); break;
case CHANNEL_B: TCCR0B = (TCCR0B & 0xBF) | (state << FOC0B); break;
}
}
void Timer_1::outputState(uint8_t channel, bool state) {
switch (channel) {
case CHANNEL_A: TCCR1C = (TCCR1C & 0x7F) | (state << FOC1A); break;
case CHANNEL_B: TCCR1C = (TCCR1C & 0xBF) | (state << FOC1B); break;
#if defined(__AVR_ATmega2560__)
case CHANNEL_C: TCCR1C = (TCCR1C & 0xDF) | (state << FOC1C); break;
#endif
}
}
void Timer_2::outputState(uint8_t channel, bool state) {
switch (channel) {
case CHANNEL_A: TCCR2B = (TCCR2B & 0x7F) | (state << FOC2A); break;
case CHANNEL_B: TCCR2B = (TCCR2B & 0xBF) | (state << FOC2B); break;
}
}
#if defined(__AVR_ATmega2560__)
void Timer_3::outputState(uint8_t channel, bool state) {
switch (channel) {
case CHANNEL_A: TCCR3C = (TCCR3C & 0x7F) | (state << FOC3A); break;
case CHANNEL_B: TCCR3C = (TCCR3C & 0xBF) | (state << FOC3B); break;
case CHANNEL_C: TCCR3C = (TCCR3C & 0xDF) | (state << FOC3C); break;
}
}
void Timer_4::outputState(uint8_t channel, bool state) {
switch (channel) {
case CHANNEL_A: TCCR4C = (TCCR4C & 0x7F) | (state << FOC4A); break;
case CHANNEL_B: TCCR4C = (TCCR4C & 0xBF) | (state << FOC4B); break;
case CHANNEL_C: TCCR4C = (TCCR4C & 0xDF) | (state << FOC4C); break;
}
}
void Timer_5::outputState(uint8_t channel, bool state) {
switch (channel) {
case CHANNEL_A: TCCR5C = (TCCR5C & 0x7F) | (state << FOC5A); break;
case CHANNEL_B: TCCR5C = (TCCR5C & 0xBF) | (state << FOC5B); break;
case CHANNEL_C: TCCR5C = (TCCR5C & 0xDF) | (state << FOC5C); break;
}
}
#endif
// ========================== PAUSE ==========================
void Timer_0::pause(void) {
TCCR0B = (TCCR0B & 0xF8); // Clear timer clock bits
}
void Timer_1::pause(void) {
TCCR1B = (TCCR1B & 0xF8);
}
void Timer_2::pause(void) {
TCCR2B = (TCCR2B & 0xF8);
}
#if defined(__AVR_ATmega2560__)
void Timer_3::pause(void) {
TCCR3B = (TCCR3B & 0xF8);
}
void Timer_4::pause(void) {
TCCR4B = (TCCR4B & 0xF8);
}
void Timer_5::pause(void) {
TCCR5B = (TCCR5B & 0xF8);
}
#endif
// ========================== RESUME ==========================
void Timer_0::resume(void) {
TCCR0B = ((TCCR0B & 0xF8) | _timer0_clock); // Return clock timer settings
}
void Timer_1::resume(void) {
TCCR1B = ((TCCR1B & 0xF8) | _timer1_clock);
}
void Timer_2::resume(void) {
TCCR2B = ((TCCR2B & 0xF8) | _timer2_clock);
}
#if defined(__AVR_ATmega2560__)
void Timer_3::resume(void) {
TCCR3B = ((TCCR3B & 0xF8) | _timer3_clock);
}
void Timer_4::resume(void) {
TCCR4B = ((TCCR4B & 0xF8) | _timer4_clock);
}
void Timer_5::resume(void) {
TCCR5B = ((TCCR5B & 0xF8) | _timer5_clock);
}
#endif
// ========================== STOP ==========================
void Timer_0::stop(void) {
Timer_0::pause();
TCNT0 = 0x00; // Clear timer counter
}
void Timer_1::stop(void) {
Timer_1::pause();
TCNT1 = 0x00;
}
void Timer_2::stop(void) {
Timer_2::pause();
TCNT2 = 0x00;
}
#if defined(__AVR_ATmega2560__)
void Timer_3::stop(void) {
Timer_3::pause();
TCNT3 = 0x00;
}
void Timer_4::stop(void) {
Timer_4::pause();
TCNT4 = 0x00;
}
void Timer_5::stop(void) {
Timer_5::pause();
TCNT5 = 0x00;
}
#endif
// ========================== RESTART ==========================
void Timer_0::restart(void) {
Timer_0::resume();
TCNT0 = 0x00;
}
void Timer_1::restart(void) {
Timer_1::resume();
TCNT1 = 0x00;
}
void Timer_2::restart(void) {
Timer_2::resume();
TCNT2 = 0x00;
}
#if defined(__AVR_ATmega2560__)
void Timer_3::restart(void) {
Timer_3::resume();
TCNT3 = 0x00;
}
void Timer_4::restart(void) {
Timer_4::resume();
TCNT4 = 0x00;
}
void Timer_5::restart(void) {
Timer_5::resume();
TCNT5 = 0x00;
}
#endif
// ========================== DISABLE ISR ==========================
void Timer_0::disableISR(uint8_t source) {
TIMSK0 &= ~ (source ? (1 << OCIE0B) : (1 << OCIE0A));
}
void Timer_1::disableISR(uint8_t source) {
switch (source) {
case CHANNEL_A: TIMSK1 &= ~ (1 << OCIE1A); break;
case CHANNEL_B: TIMSK1 &= ~ (1 << OCIE1B); break;
#if defined(__AVR_ATmega2560__)
case CHANNEL_C: TIMSK1 &= ~ (1 << OCIE1C); break;
#endif
}
}
void Timer_2::disableISR(uint8_t source) {
TIMSK2 &= ~ (source ? (1 << OCIE2B) : (1 << OCIE2A));
}
#if defined(__AVR_ATmega2560__)
void Timer_3::disableISR(uint8_t source) {
switch (source) {
case CHANNEL_A: TIMSK3 &= ~ (1 << OCIE3A); break;
case CHANNEL_B: TIMSK3 &= ~ (1 << OCIE3B); break;
case CHANNEL_C: TIMSK3 &= ~ (1 << OCIE3C); break;
}
}
void Timer_4::disableISR(uint8_t source) {
switch (source) {
case CHANNEL_A: TIMSK4 &= ~ (1 << OCIE4A); break;
case CHANNEL_B: TIMSK4 &= ~ (1 << OCIE4B); break;
case CHANNEL_C: TIMSK4 &= ~ (1 << OCIE4C); break;
}
}
void Timer_5::disableISR(uint8_t source) {
switch (source) {
case CHANNEL_A: TIMSK5 &= ~ (1 << OCIE5A); break;
case CHANNEL_B: TIMSK5 &= ~ (1 << OCIE5B); break;
case CHANNEL_C: TIMSK5 &= ~ (1 << OCIE5C); break;
}
}
#endif
// ========================== DEFAULT ==========================
void Timer_0::setDefault(void) {
TCCR0A = 0x03; // Fast PWM , 8 bit
TCCR0B = 0x03; // Prescaler /64
OCR0B = 0x00; // Clear COMPA
OCR0A = 0x00; // Clear COMPB
TCNT0 = 0x00; // Clear counter
}
void Timer_1::setDefault(void) {
TCCR1A = 0x01; // Phasecorrect PWM , 8 bit
TCCR1B = 0x0B; // Prescaler /64
OCR1B = 0x00; // Clear COMPA
OCR1A = 0x00; // Clear COMPB
TCNT1 = 0x00; // Clear counter
}
void Timer_2::setDefault(void) {
TCCR2A = 0x01; // Phasecorrect PWM , 8 bit
TCCR2B = 0x04; // Prescaler /64
OCR2B = 0x00; // Clear COMPA
OCR2A = 0x00; // Clear COMPB
TCNT2 = 0x00; // Clear counter
}
#if defined(__AVR_ATmega2560__)
void Timer_3::setDefault(void) {
TCCR3A = 0x01; // Phasecorrect PWM , 8 bit
TCCR3B = 0x0B; // Prescaler /64
OCR3B = 0x00; // Clear COMPA
OCR3A = 0x00; // Clear COMPB
TCNT3 = 0x00; // Clear counter
}
void Timer_4::setDefault(void) {
TCCR4A = 0x01; // Phasecorrect PWM , 8 bit
TCCR4B = 0x0B; // Prescaler /64
OCR4B = 0x00; // Clear COMPA
OCR4A = 0x00; // Clear COMPB
TCNT4 = 0x00; // Clear counter
}
void Timer_5::setDefault(void) {
TCCR5A = 0x01; // Phasecorrect PWM , 8 bit
TCCR5B = 0x0B; // Prescaler /64
OCR5B = 0x00; // Clear COMPA
OCR5A = 0x00; // Clear COMPB
TCNT5 = 0x00; // Clear counter
}
#endif
// ========================== PHASE SHIFT ==========================
void Timer_0::phaseShift(uint8_t source, uint16_t phase) {
if (source) OCR0B = map(phase, 0, 360, 0, OCR0A);
}
void Timer_1::phaseShift(uint8_t source, uint16_t phase) {
switch (source) {
case CHANNEL_A: OCR1A = map(phase, 0, 360, 0, ICR1); break;
case CHANNEL_B: OCR1B = map(phase, 0, 360, 0, ICR1); break;
#if defined(__AVR_ATmega2560__)
case CHANNEL_C: OCR1C = map(phase, 0, 360, 0, ICR1); break;
#endif
}
}
void Timer_2::phaseShift(uint8_t source, uint16_t phase) {
if (source) OCR2B = map(phase, 0, 360, 0, OCR2A);
}
#if defined(__AVR_ATmega2560__)
void Timer_3::phaseShift(uint8_t source, uint16_t phase) {
switch (source) {
case CHANNEL_A: OCR3A = map(phase, 0, 360, 0, ICR3); break;
case CHANNEL_B: OCR3B = map(phase, 0, 360, 0, ICR3); break;
case CHANNEL_C: OCR3C = map(phase, 0, 360, 0, ICR3); break;
}
}
void Timer_4::phaseShift(uint8_t source, uint16_t phase) {
switch (source) {
case CHANNEL_A: OCR4A = map(phase, 0, 360, 0, ICR4); break;
case CHANNEL_B: OCR4B = map(phase, 0, 360, 0, ICR4); break;
case CHANNEL_C: OCR4C = map(phase, 0, 360, 0, ICR4); break;
}
}
void Timer_5::phaseShift(uint8_t source, uint16_t phase) {
switch (source) {
case CHANNEL_A: OCR5A = map(phase, 0, 360, 0, ICR5); break;
case CHANNEL_B: OCR5B = map(phase, 0, 360, 0, ICR5); break;
case CHANNEL_C: OCR5C = map(phase, 0, 360, 0, ICR5); break;
}
}
#endif
// ========================== ENABLE ISR ==========================
void Timer_0::enableISR(uint8_t source) {
if (!source) TIMSK0 |= (1 << OCIE0A);
else TIMSK0 |= (1 << OCIE0B);
}
void Timer_1::enableISR(uint8_t source) {
switch (source) {
case CHANNEL_A: TIMSK1 |= (1 << OCIE1A); break;
case CHANNEL_B: TIMSK1 |= (1 << OCIE1B); break;
#if defined(__AVR_ATmega2560__)
case CHANNEL_C: TIMSK1 |= (1 << OCIE1C); break;
#endif
}
}
void Timer_2::enableISR(uint8_t source) {
if (!source) TIMSK2 |= (1 << OCIE2A);
else TIMSK2 |= (1 << OCIE2B);
}
#if defined(__AVR_ATmega2560__)
void Timer_3::enableISR(uint8_t source) {
switch (source) {
case CHANNEL_A: TIMSK3 |= (1 << OCIE3A); break;
case CHANNEL_B: TIMSK3 |= (1 << OCIE3B); break;
case CHANNEL_C: TIMSK3 |= (1 << OCIE3C); break;
}
}
void Timer_4::enableISR(uint8_t source) {
switch (source) {
case CHANNEL_A: TIMSK4 |= (1 << OCIE4A); break;
case CHANNEL_B: TIMSK4 |= (1 << OCIE4B); break;
case CHANNEL_C: TIMSK4 |= (1 << OCIE4C); break;
}
}
void Timer_5::enableISR(uint8_t source) {
switch (source) {
case CHANNEL_A: TIMSK5 |= (1 << OCIE5A); break;
case CHANNEL_B: TIMSK5 |= (1 << OCIE5B); break;
case CHANNEL_C: TIMSK5 |= (1 << OCIE5C); break;
}
}
#endif
// ========================== SET FREQUENCY ==========================
uint32_t Timer_0::setFrequency(uint32_t _timer0_frequency) {
return 1000000UL / (Timer_0::setPeriod(1000000UL / _timer0_frequency));
}
uint32_t Timer_1::setFrequency(uint32_t _timer1_frequency) {
return 1000000UL / (Timer_1::setPeriod(1000000UL / _timer1_frequency));
}
uint32_t Timer_2::setFrequency(uint32_t _timer2_frequency) {
return 1000000UL / (Timer_2::setPeriod(1000000UL / _timer2_frequency));
}
#if defined(__AVR_ATmega2560__)
uint32_t Timer_3::setFrequency(uint32_t _timer3_frequency) {
return 1000000UL / (Timer_3::setPeriod(1000000UL / _timer3_frequency));
}
uint32_t Timer_4::setFrequency(uint32_t _timer4_frequency) {
return 1000000UL / (Timer_4::setPeriod(1000000UL / _timer4_frequency));
}
uint32_t Timer_5::setFrequency(uint32_t _timer5_frequency) {
return 1000000UL / (Timer_5::setPeriod(1000000UL / _timer5_frequency));
}
#endif
// ========================== SET FREQUENCY FLOAT ==========================
float Timer_0::setFrequencyFloat(float _timer0_frequency) {
return 1000000.0F / (Timer_0::setPeriod(1000000.0F / _timer0_frequency));
}
float Timer_1::setFrequencyFloat(float _timer1_frequency) {
return 1000000.0F / (Timer_1::setPeriod(1000000.0F / _timer1_frequency));
}
float Timer_2::setFrequencyFloat(float _timer2_frequency) {
return 1000000.0F / (Timer_2::setPeriod(1000000.0F / _timer2_frequency));
}
#if defined(__AVR_ATmega2560__)
float Timer_3::setFrequencyFloat(float _timer3_frequency) {
return 1000000.0F / (Timer_3::setPeriod(1000000.0F / _timer3_frequency));
}
float Timer_4::setFrequencyFloat(float _timer4_frequency) {
return 1000000.0F / (Timer_4::setPeriod(1000000.0F / _timer4_frequency));
}
float Timer_5::setFrequencyFloat(float _timer5_frequency) {
return 1000000.0F / (Timer_5::setPeriod(1000000.0F / _timer5_frequency));
}
#endif
// ========================== OUTPUT ENABLE ==========================
void Timer_0::outputEnable(uint8_t channel, uint8_t mode) {
switch (channel) {
case CHANNEL_A: TCCR0A = (TCCR0A & 0x3F) | (mode << 6); break;
case CHANNEL_B: TCCR0A = (TCCR0A & 0xCF) | (mode << 4); break;
}
}
void Timer_1::outputEnable(uint8_t channel, uint8_t mode) {
switch (channel) {
case CHANNEL_A: TCCR1A = (TCCR1A & 0x3F) | (mode << 6); break;
case CHANNEL_B: TCCR1A = (TCCR1A & 0xCF) | (mode << 4); break;
#if defined(__AVR_ATmega2560__)
case CHANNEL_C: TCCR1A = (TCCR1A & 0xF3) | (mode << 2); break;
#endif
}
}
void Timer_2::outputEnable(uint8_t channel, uint8_t mode) {
switch (channel) {
case CHANNEL_A: TCCR2A = (TCCR2A & 0x3F) | (mode << 6); break;
case CHANNEL_B: TCCR2A = (TCCR2A & 0xCF) | (mode << 4); break;
}
}
#if defined(__AVR_ATmega2560__)
void Timer_3::outputEnable(uint8_t channel, uint8_t mode) {
switch (channel) {
case CHANNEL_A: TCCR3A = (TCCR3A & 0x3F) | (mode << 6); break;
case CHANNEL_B: TCCR3A = (TCCR3A & 0xCF) | (mode << 4); break;
case CHANNEL_C: TCCR3A = (TCCR3A & 0xF3) | (mode << 2); break;
}
}
void Timer_4::outputEnable(uint8_t channel, uint8_t mode) {
switch (channel) {
case CHANNEL_A: TCCR4A = (TCCR4A & 0x3F) | (mode << 6); break;
case CHANNEL_B: TCCR4A = (TCCR4A & 0xCF) | (mode << 4); break;
case CHANNEL_C: TCCR4A = (TCCR4A & 0xF3) | (mode << 2); break;
}
}
void Timer_5::outputEnable(uint8_t channel, uint8_t mode) {
switch (channel) {
case CHANNEL_A: TCCR5A = (TCCR5A & 0x3F) | (mode << 6); break;
case CHANNEL_B: TCCR5A = (TCCR5A & 0xCF) | (mode << 4); break;
case CHANNEL_C: TCCR5A = (TCCR5A & 0xF3) | (mode << 2); break;
}
}
#endif
// ========================== OUTPUT DISABLE ==========================
void Timer_0::outputDisable(uint8_t channel) {
switch (channel) {
case CHANNEL_A: TCCR0A = (TCCR0A & 0x3F); break;
case CHANNEL_B: TCCR0A = (TCCR0A & 0xCF); break;
}
}
void Timer_1::outputDisable(uint8_t channel) {
switch (channel) {
case CHANNEL_A: TCCR1A = (TCCR1A & 0x3F); break;
case CHANNEL_B: TCCR1A = (TCCR1A & 0xCF); break;
#if defined(__AVR_ATmega2560__)
case CHANNEL_C: TCCR1A = (TCCR1A & 0xF3); break;
#endif
}
}
void Timer_2::outputDisable(uint8_t channel) {
switch (channel) {
case CHANNEL_A: TCCR2A = (TCCR2A & 0x3F); break;
case CHANNEL_B: TCCR2A = (TCCR2A & 0xCF); break;
}
}
#if defined(__AVR_ATmega2560__)
void Timer_3::outputDisable(uint8_t channel) {
switch (channel) {
case CHANNEL_A: TCCR3A = (TCCR3A & 0x3F); break;
case CHANNEL_B: TCCR3A = (TCCR3A & 0xCF); break;
case CHANNEL_C: TCCR3A = (TCCR3A & 0xF3); break;
}
}
void Timer_4::outputDisable(uint8_t channel) {
switch (channel) {
case CHANNEL_A: TCCR4A = (TCCR4A & 0x3F); break;
case CHANNEL_B: TCCR4A = (TCCR4A & 0xCF); break;
case CHANNEL_C: TCCR4A = (TCCR4A & 0xF3); break;
}
}
void Timer_5::outputDisable(uint8_t channel) {
switch (channel) {
case CHANNEL_A: TCCR5A = (TCCR5A & 0x3F); break;
case CHANNEL_B: TCCR5A = (TCCR5A & 0xCF); break;
case CHANNEL_C: TCCR5A = (TCCR5A & 0xF3); break;
}
}
#endif
// ========================== SET PERIOD ==========================
uint32_t Timer_0::setPeriod(uint32_t _timer0_period) {
_timer0_period = constrain(_timer0_period, 1, MAX_PERIOD_8);
uint32_t _timer0_cycles = F_CPU / 1000000 * _timer0_period; // Calculation of the number of timer cycles per period
uint8_t _timer0_prescaler = 0x00;
uint16_t _timer0_divider = 0x00;
if (_timer0_cycles < 256UL) { // Сhoose optimal divider for the timer
_timer0_prescaler = 0x01;
_timer0_divider = 1UL;
} else if (_timer0_cycles < 256UL * 8) {
_timer0_prescaler = 0x02;
_timer0_divider = 8UL;
} else if (_timer0_cycles < 256UL * 64) {
_timer0_prescaler = 0x03;
_timer0_divider = 64UL;
} else if (_timer0_cycles < 256UL * 256) {
_timer0_prescaler = 0x04;
_timer0_divider = 256UL;
} else {
_timer0_prescaler = 0x05;
_timer0_divider = 1024UL;
}
uint8_t _timer0_top = (_timer0_cycles < 256UL * 1024 ? (_timer0_cycles / _timer0_divider) : 256UL) ;
TCCR0A = (TCCR0A & 0xF0) | (1 << WGM21); // CTC - mode
TCCR0B = _timer0_prescaler; // Set timer prescaler
OCR0A = _timer0_top - 1; // Set timer top
_timer0_clock = (TCCR0B & 0x07); // Save timer clock settings
return (1000000UL / ((F_CPU / _timer0_divider) / _timer0_top)); // Return real timer period
}
uint32_t Timer_1::setPeriod(uint32_t _timer1_period) {
_timer1_period = constrain(_timer1_period, 1, MAX_PERIOD_16);
uint32_t _timer1_cycles = F_CPU / 1000000 * _timer1_period; // Calculation of the number of timer cycles per period
uint8_t _timer1_prescaler = 0x00;
uint16_t _timer1_divider = 0x00;
if (_timer1_cycles < 65536UL) { // Сhoose optimal divider for the timer
_timer1_prescaler = 0x01;
_timer1_divider = 1UL;
} else if (_timer1_cycles < 65536UL * 8) {
_timer1_prescaler = 0x02;
_timer1_divider = 8UL;
} else if (_timer1_cycles < 65536UL * 64) {
_timer1_prescaler = 0x03;
_timer1_divider = 64UL;
} else if (_timer1_cycles < 65536UL * 256) {
_timer1_prescaler = 0x04;
_timer1_divider = 256UL;
} else {
_timer1_prescaler = 0x05;
_timer1_divider = 1024UL;
}
uint16_t _timer1_top = (_timer1_cycles < 65536UL * 1024 ? (_timer1_cycles / _timer1_divider) : 65536UL) ;
#if defined(__AVR_ATmega2560__)
TCCR1A = (TCCR1A & 0xFC);
#else
TCCR1A = (TCCR1A & 0xF0);
#endif
TCCR1B = ((1 << WGM13) | (1 << WGM12) | _timer1_prescaler); // CTC mode + set prescaler
ICR1 = _timer1_top - 1; // Set timer top
_timer1_clock = (TCCR1B & 0x07); // Save timer clock settings
return (1000000UL / ((F_CPU / _timer1_divider) / _timer1_top)); // Return real timer period
}
uint32_t Timer_2::setPeriod(uint32_t _timer2_period) {
_timer2_period = constrain(_timer2_period, 1, MAX_PERIOD_8);
uint32_t _timer2_cycles = F_CPU / 1000000 * _timer2_period; // Calculation of the number of timer cycles per period
uint8_t _timer2_prescaler = 0x00;
uint16_t _timer2_divider = 0x00;
if (_timer2_cycles < 256UL) { // Сhoose optimal divider for the timer
_timer2_prescaler = 0x01;
_timer2_divider = 1UL;
} else if (_timer2_cycles < 256UL * 8) {
_timer2_prescaler = 0x02;
_timer2_divider = 8UL;
} else if (_timer2_cycles < 256UL * 32) {
_timer2_prescaler = 0x03;
_timer2_divider = 32UL;
} else if (_timer2_cycles < 256UL * 64) {
_timer2_prescaler = 0x04;
_timer2_divider = 64UL;
} else if (_timer2_cycles < 256UL * 128) {
_timer2_prescaler = 0x05;
_timer2_divider = 128UL;
} else if (_timer2_cycles < 256UL * 256) {
_timer2_prescaler = 0x06;
_timer2_divider = 256UL;
} else {
_timer2_prescaler = 0x07;
_timer2_divider = 1024UL;
}
uint8_t _timer2_top = (_timer2_cycles < 256UL * 1024 ? (_timer2_cycles / _timer2_divider) : 256UL);
TCCR2A = (TCCR2A & 0xF0) | (1 << WGM21); // CTC - mode
TCCR2B = _timer2_prescaler; // Set timer prescaler
OCR2A = _timer2_top - 1; // Set timer top
_timer2_clock = (TCCR2B & 0x07); // Save timer clock settings
return (1000000UL / ((F_CPU / _timer2_divider) / _timer2_top)); // Return real timer period
}
#if defined(__AVR_ATmega2560__)
uint32_t Timer_3::setPeriod(uint32_t _timer3_period) {
_timer3_period = constrain(_timer3_period, 1, MAX_PERIOD_16);
uint32_t _timer3_cycles = F_CPU / 1000000 * _timer3_period; // Calculation of the number of timer cycles per period
uint8_t _timer3_prescaler = 0x00;
uint16_t _timer3_divider = 0x00;
if (_timer3_cycles < 65536UL) { // Сhoose optimal divider for the timer
_timer3_prescaler = 0x01;
_timer3_divider = 1UL;
} else if (_timer3_cycles < 65536UL * 8) {
_timer3_prescaler = 0x02;
_timer3_divider = 8UL;
} else if (_timer3_cycles < 65536UL * 64) {
_timer3_prescaler = 0x03;
_timer3_divider = 64UL;
} else if (_timer3_cycles < 65536UL * 256) {
_timer3_prescaler = 0x04;
_timer3_divider = 256UL;
} else {
_timer3_prescaler = 0x05;
_timer3_divider = 1024UL;
}
uint16_t _timer3_top = (_timer3_cycles < 65536UL * 1024 ? (_timer3_cycles / _timer3_divider) : 65536UL) ;
TCCR3A = (TCCR3A & 0xFC);
TCCR3B = ((1 << WGM33) | (1 << WGM32) | _timer3_prescaler); // CTC mode + set prescaler
ICR3 = _timer3_top - 1; // Set timer top
_timer3_clock = (TCCR3B & 0x07); // Save timer clock settings
return (1000000UL / ((F_CPU / _timer3_divider) / _timer3_top)); // Return real timer period
}
uint32_t Timer_4::setPeriod(uint32_t _timer4_period) {
_timer4_period = constrain(_timer4_period, 1, MAX_PERIOD_16);
uint32_t _timer4_cycles = F_CPU / 1000000 * _timer4_period; // Calculation of the number of timer cycles per period
uint8_t _timer4_prescaler = 0x00;
uint16_t _timer4_divider = 0x00;
if (_timer4_cycles < 65536UL) { // Сhoose optimal divider for the timer
_timer4_prescaler = 0x01;
_timer4_divider = 1UL;
} else if (_timer4_cycles < 65536UL * 8) {
_timer4_prescaler = 0x02;
_timer4_divider = 8UL;
} else if (_timer4_cycles < 65536UL * 64) {
_timer4_prescaler = 0x03;
_timer4_divider = 64UL;
} else if (_timer4_cycles < 65536UL * 256) {
_timer4_prescaler = 0x04;
_timer4_divider = 256UL;
} else {
_timer4_prescaler = 0x05;
_timer4_divider = 1024UL;
}
uint16_t _timer4_top = (_timer4_cycles < 65536UL * 1024 ? (_timer4_cycles / _timer4_divider) : 65536UL) ;
TCCR4A = (TCCR4A & 0xFC);
TCCR4B = ((1 << WGM43) | (1 << WGM42) | _timer4_prescaler); // CTC mode + set prescaler
ICR4 = _timer4_top - 1; // Set timer top
_timer4_clock = (TCCR4B & 0x07); // Save timer clock settings
return (1000000UL / ((F_CPU / _timer4_divider) / _timer4_top)); // Return real timer period
}
uint32_t Timer_5::setPeriod(uint32_t _timer5_period) {
_timer5_period = constrain(_timer5_period, 1, MAX_PERIOD_16);
uint32_t _timer5_cycles = F_CPU / 1000000 * _timer5_period; // Calculation of the number of timer cycles per period
uint8_t _timer5_prescaler = 0x00;
uint16_t _timer5_divider = 0x00;
if (_timer5_cycles < 65536UL) { // Сhoose optimal divider for the timer
_timer5_prescaler = 0x01;
_timer5_divider = 1UL;
} else if (_timer5_cycles < 65536UL * 8) {
_timer5_prescaler = 0x02;
_timer5_divider = 8UL;
} else if (_timer5_cycles < 65536UL * 64) {
_timer5_prescaler = 0x03;
_timer5_divider = 64UL;
} else if (_timer5_cycles < 65536UL * 256) {
_timer5_prescaler = 0x04;
_timer5_divider = 256UL;
} else {
_timer5_prescaler = 0x05;
_timer5_divider = 1024UL;
}
uint16_t _timer5_top = (_timer5_cycles < 65536UL * 1024 ? (_timer5_cycles / _timer5_divider) : 65536UL) ;
TCCR5A = (TCCR5A & 0xFC);
TCCR5B = ((1 << WGM53) | (1 << WGM52) | _timer5_prescaler); // CTC mode + set prescaler
ICR5 = _timer5_top - 1; // Set timer top
_timer5_clock = (TCCR5B & 0x07); // Save timer clock settings
return (1000000UL / ((F_CPU / _timer5_divider) / _timer5_top)); // Return real timer period
}
#endif
Timer_0 Timer0 = Timer_0();
Timer_1 Timer1 = Timer_1();
Timer_2 Timer2 = Timer_2();
#if defined(__AVR_ATmega2560__)
Timer_3 Timer3 = Timer_3();
Timer_4 Timer4 = Timer_4();
Timer_5 Timer5 = Timer_5();
#endif
//конец библиотеки GyverTimers
template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; }
void setup() {
Serial.begin(9600);
if (EEPROM.read(STR_ADDR) != INIT_KEY) {
//установки для первого включения
Serial << "KEY is NOT equal (WOKWI ?) !!!" << '\n' << '\n';
EEPROM.write(STR_ADDR, INIT_KEY);
}
else { //если ключ совпадает, значит данные уже записывались в EEPROM
Serial << "KEY is Ok - Hard Board" << '\n' << '\n';
pause_soft *= 2;
pause_hard *= 2;
}
Serial.print("counter_cycles_PWM_max = "); Serial.println(counter_cycles_PWM_max);
Serial.print("PWM_front = "); Serial.println(PWM_front);
Serial.print("start front = "); Serial.println(PWM_start_front);
Serial.print("start fall = "); Serial.println(PWM_start_fall);
for (byte i=0; i < NUM_LINES; i++) {
pinMode(PIN_LED[i], OUTPUT);
} //for i
// Serial.print("sizeof(all_progs) = "); Serial.println(sizeof(all_progs));
// Serial.print("sizeof prog01 = "); Serial.println(sizeof(prog01));Serial.println();
int fr=Timer2.setFrequency(15000UL);
// // Serial.print("freq="); Serial.println(fr);
// Timer2.enableISR();
// attachInterrupt(pin, handler, mode)
//
// Serial.print("num_progs="); Serial.println(sizeof(all_progs)/sizeof(int));
// Serial.println(sizeof(prog01)/sizeof(prog01[0])); узнать количество строк в 2-мерном массиве
}
void loop() {
static bool w;
if (w) return;
// for (byte i=0; i < num_progs; i++) {
for (byte i=16; i <= 19; i++) {
// pause = i*200;
Serial.println();
Serial.print("program="); Serial.println(i);
// i=1;
main_program((uint32_t)all_progs[i]); // перебор программ
// cycle(4, (int)prog02); //это работает
// w = true; //чтобы цикл отработал только 1 раз
}
}
void main_program(const byte *arr) {
// Serial.println("point 3: main_program");
byte com = arr[0]; //режим
order = bitRead(com, 3); // Порядок выполнения
ignition = bitRead(com, 2); // Зажигание: 1 - плавное
if (ignition) {
pause = pause_soft;
}
else {
pause = pause_hard;
}
if (bitRead(com, 0)) {
BIT_mode(arr, 255); // Битовый режим. Яркость одна для всех
}
else {
BYTE_mode(arr); // поБайтный режим
}
}
void BIT_mode(const byte *arr, const byte brightness) {
// Serial.println("point BIT_mode");
byte repeat_this_prog = ((*(arr) & 0b11000000) >> 6) + 1;
Serial.print("repeat_this_prog="); Serial.println(repeat_this_prog);
byte num_bytes_prog = *(arr + 1); //кол. байтов программы (или нач. сост.)
byte data;
direction = 0;
if (num_bytes_prog > 253) {// RANDOM!!!
RANDOM_BIT_MODE(&num_bytes_prog);
return;
}
// Serial.print("repeats * repeat_this_prog * (order) ? 2: 1 = "); Serial.println(repeats * repeat_this_prog * (order) ? 2: 1);
for (byte rep=0; rep < repeats * repeat_this_prog * ((order) ? 2: 1); rep++) { // повторы
Serial.print("rep = "); Serial.println(rep);
if (!bitRead(*(arr), 1)) { //работа в Битовом режиме по байтам
if (!direction) {
for (byte i = (rep == 0) ? 0: 1; i < num_bytes_prog; i++) { // однократное выполнение всех байтов программы
data = *(arr + i + 2);
// Serial.print("data1 = "); Serial.println(data, BIN);
counter_PWM = 0;
counter_cycles_PWM = 65535;
LEDS_BITS_FILL(data, brightness);
Timer2.enableISR();
delay(pause);
if (ignition) {
delay(pause/5);
}
} // for
}
else { //direction = 1: реверс
// for (byte i = num_bytes_prog; i != 0; i--) {
for (byte i = num_bytes_prog - 1; i != 0; i--) { // однократное выполнение всех байтов программы
// в обратном направлении
data = *(arr + i + 2 - 1);
// Serial.print("data2 = "); Serial.println(data, BIN);
counter_PWM = 0;
counter_cycles_PWM = 65535;
LEDS_BITS_FILL(data, brightness);
Timer2.enableISR();
delay(pause);
if (ignition) {
delay(pause/5);
}
} // for
}
Serial.print("point 1. counter_cycles_PWM = "); Serial.println(counter_cycles_PWM);
if (order) { //выполнение, реверс, выполнение, реверс, …
direction = !direction;
}
}
else { // работа со сдвигом
Serial.println("Работа со сдвигом не реализована");
return;
// bool tetrade_mode = false; // работа в Битовом режиме ПО БАЙТАМ
byte begin_BYTES[num_bytes_prog];
for (byte i; i < num_bytes_prog; i++) { //заполнение массива нач. сост
begin_BYTES[i] = *(arr + i + 3); //т.к. байты нач. сост. передаются с 4-го элемента массива
Serial.print("begin_BYTES "); Serial.print(i); Serial.print(" = "); Serial.println(begin_BYTES[i], BIN);
}
}
} //for rep
LEDS_BITS_FILL(0, brightness); // гасим все
if (ignition) {
delay(pause/4);
}
else {
delay(pause);
}
} //BIT_mode
void RANDOM_BIT_MODE(byte* mode) {
byte num_bytes_prog = 8;
byte data;
// Serial.print("mode = "); Serial.println(*mode);
// for (byte i = (rep == 0) ? 0: 1; i < num_bytes_prog; i++) { // однократное выполнение всех байтов программы
for (byte i = 0; i < num_bytes_prog; i++) { // однократное выполнение всех байтов программы
if (*mode == 254) {
data = random(1, 8);
byte n = 0;
data = bitSet(n, data);
}
else { // если mode = 255
data = random(1, 255);
}
Serial.print("data_random = "); Serial.println(data, BIN);
counter_PWM = 0;
counter_cycles_PWM = 65535;
LEDS_BITS_FILL(data, brightness);
Timer2.enableISR();
delay(pause);
if (ignition) {
delay(pause/5);
}
}
}
void BYTE_mode(const byte *arr) {
Serial.println("Функция BYTE_mode не реализована");
return;
bool rising = bitRead(*(arr), 2); // зажигание
}
ISR(TIMER2_A) {
progPWMtick();
}
void progPWMtick() { //программная реализация ШИМ. Запускается по таймеру, из обработчика ISR(TIMER2_A)
static volatile uint16_t prev_counter_cycles_PWM; // !!! переменная специально для отладки
static volatile byte fill;
static volatile byte fill_prev = 55;
static volatile byte counter_PWM_fade_cycles;
static volatile byte fill_index;
static volatile byte prev_counter_PWM_fade_cycles;
// начальное зажигание с помощью PWM
if (counter_PWM == 0) {
counter_cycles_PWM++;
// if (fill_prev != fill & counter_cycles_PWM > 138) {
// Serial.println(counter_cycles_PWM);
// }
if (counter_cycles_PWM > counter_cycles_PWM_max) {
Timer2.disableISR();
return;
}
for (byte i=0; i < NUM_LINES; i++) {
if (LED_PWM_fill[i]) {
digitalWrite(PIN_LED[i], HIGH);
}
else {
digitalWrite(PIN_LED[i], LOW);
}
}
}
// задание значения fill для каждого значения counter_cycles_PWM
if (ignition) {
if (counter_cycles_PWM < PWM_start_front) { // плавное нарастание яркости
if (counter_PWM == 0) {
if (counter_cycles_PWM == 0) {
counter_PWM_fade_cycles = 0;
fill_index = 0;
fill = fill_array[fill_index];
// Serial.print("Point 0"); Serial.print(", counter_cycles_PWM = "); Serial.println(counter_cycles_PWM);
}
else { // если counter_cycles_PWM != 0
if (++counter_PWM_fade_cycles == step_PWM_front_cycles) {
// fill += 5;
fill_index++;
fill = fill_array[fill_index];
counter_PWM_fade_cycles = 0;
}
}
}
// if (fill_prev != fill && fill > 220) {
// if (fill_prev != fill) {
// Serial.print("fill rise = "); Serial.print(fill); Serial.print(", counter_cycles_PWM = "); Serial.println(counter_cycles_PWM);
// fill_prev = fill;
// }
}
else { // if (counter_cycles_PWM < PWM_start_front)
if (counter_cycles_PWM >= PWM_start_fall ) { // плавное угасание яркости
if (counter_PWM == 0) {
if (counter_cycles_PWM == PWM_start_fall) {
counter_PWM_fade_cycles = 0;
// fill = 255;
fill_index = sizeof(fill_array) - 1;
fill = fill_array[fill_index];
// Serial.print("fill_index = "); Serial.println(fill_index);
}
else { // если counter_cycles_PWM > PWM_start_fall
// if (++counter_PWM_fade_cycles == step_PWM_fall_cycles) {
if (++counter_PWM_fade_cycles == step_PWM_front_cycles) {
// fill -= 5;
fill_index--;
fill = fill_array[fill_index];
counter_PWM_fade_cycles = 0;
}
}
}
}
else { // if (PWM_start_front >= counter_cycles_PWM < PWM_start_fall ) // максимальная яркость
// между фронтом и спадом
fill = brightness;
}
}
// if (fill_prev != fill) {
// if (counter_cycles_PWM > 128 && prev_counter_PWM_fade_cycles != counter_PWM_fade_cycles ) {
// if (fill_prev != fill && counter_cycles_PWM > 138) {
// Serial.print("fill fall = "); Serial.print(fill); Serial.print(", counter_cycles_PWM = "); Serial.println(counter_cycles_PWM);
// }
// fill_prev = fill;
// prev_counter_PWM_fade_cycles = counter_PWM_fade_cycles;
}
else { // if ignition
fill = brightness;
} // конец задания значения fill
for (byte i=0; i < NUM_LINES; i++) {
if (LED_PWM_fill[i]) {
if (counter_PWM >= fill) { // заполнение ШИМ
// Serial.print("fill = "); Serial.println(fill);
digitalWrite(PIN_LED[i], LOW);
// Serial.print("Point 5. fill = "); Serial.print(fill);
// Serial.print(", counter_cycles_PWM = "); Serial.println(counter_cycles_PWM);
}
}
}
byte temp = counter_PWM;
// counter_PWM += 15;
counter_PWM += 5;
if (temp > 128 && counter_PWM < 128) { // при переходе счетчика через 0 - делаем равным 0
counter_PWM = 0;
}
}
void LEDS_BITS_FILL(byte b, byte brightness) {
// выдергиваем из байта данных биты, и рассовываем значение яркости по элементам массива LED_PWM_fill[],
// от 0 до 7. // если бит=1, этот LED будет светиться
for (byte k=0; k < NUM_LINES; k++) {
LED_PWM_fill[7-k] = bitRead(b, k) ? brightness: 0;
}
}
// сохраненная на всякий случай работающая функция progPWMtick()
// void progPWMtick() { //программная реализация ШИМ. Запускается по таймеру, из обработчика ISR(TIMER2_A)
// static volatile byte counter_PWM = 0;
// if (counter_PWM == 0) {
// for (byte i=0; i < NUM_LINES; i++) {
// if (LED_PWM_fill[i] > 0) {
// digitalWrite(PIN_LED[i], HIGH);
// }
// }
// }
// for (byte i=0; i < NUM_LINES; i++) {
// if (counter_PWM == LED_PWM_fill[i]) {
// digitalWrite(PIN_LED[i], LOW);
// }
// }
// counter_PWM++;
// }
//
// REM другие варианты отправки массива в функцию
// void cycle(uint8_t size_arr, const byte *arr) { ////этот вариант работает, вызов: (int)prog02
// for(byte j = 0; j < size_arr; j++) {
// for (byte i = 0; i < 6; i++) {
// byte * p = arr + j*6;
// byte * q = p + i;
// Serial.print("q="); Serial.println(*q);
// }
// } // for j
// }
// void cycle(uint8_t size_arr, const byte* arr) { //этот вариант работает, вызов: (int)prog02
// for(byte j = 0; j < size_arr; j++) {
// for (byte i = 0; i < 6; i++) {
// Serial.print("arr[]="); Serial.println(*( arr + j*6 + i));
// } // for i
// } // for j
// Serial.println();
// }
// void cycle(uint8_t size_arr, const byte* arr[6]) { //такой вариант не работает, выдает
// неправильные данные
//...
// Serial.print("q[]="); Serial.println(arr[j][i]);
// void cycle(uint8_t size_arr, const byte arr[][6]) { //этот вариант работает, вызов: (int)prog02
// for(byte j = 0; j < size_arr; j++) {
// for (byte i = 0; i < 6; i++) {
// Serial.print("q[]="); Serial.println(arr[j][i]);
// }
// } // for j
// Serial.println();
// }
// конец REM
//
// void cycle(uint8_t size_arr, const byte *arr) {
// for(byte j = 0; j < size_arr; j++) {
// LEDS_ON(arr + j*NUM_LINES); //так работает
// // Serial.print("arr!!="); Serial.println(*(arr + j*NUM_LINES)); //вывод значения строки с индексом 0
// delay(80);
// LEDS_OFF();
// delay(80);
// // for (byte i = 0; i < NUM_LINES; i++) {
// // Serial.print(*( arr + j*NUM_LINES + i)); Serial.print(" "); //так работает
// // // Serial.print("arr[]="); Serial.println(arr[j][i]); //так не работает
// // }
// // Serial.println();
// } // for j
// // Serial.println("===");
// }
// void LEDS_BITS_OFF() {
// for (byte k=0; k < 8; k++) {
// LED_PWM_fill[k] = 0;
// }
// }
// void LEDS_ON(byte* arr) {
// // analogWrite(PIN_LED1, arr[0]);
// for (byte k=0; k < NUM_LINES; k++) {
// LED_PWM_fill[k] = arr[k];
// }
// }
// void LEDS_OFF() {
// // analogWrite(PIN_LED1, 0);
// for (byte k=0; k < NUM_LINES; k++) {
// LED_PWM_fill[k] = 0;
// }
// }
// void example(uint8_t size_arr, const byte * arr) {
// Serial.println(sizeof(arr));
// Serial.println(sizeof(arr[0]));
// }
/*
// const byte prog01[][NUM_LINES] = {{255, 0, 0, 0, 0, 0, 0, 0},
// {0, 255, 0, 0, 0, 0, 0, 0},
// {0, 0, 255, 0, 0, 0, 0, 0},
// {0, 0, 0, 255, 0, 0, 0, 0},
// {0, 0, 0, 0, 255, 0, 0, 0},
// {0, 0, 0, 0, 0, 255, 0, 0},
// {0, 0, 0, 0, 0, 0, 255, 0},
// {0, 0, 0, 0, 0, 0, 0, 255},
// {0, 0, 0, 0, 0, 0, 255, 0},
// {0, 0, 0, 0, 0, 255, 0, 0},
// {0, 0, 0, 0, 255, 0, 0, 0},
// {0, 0, 0, 255, 0, 0, 0, 0},
// {0, 0, 255, 0, 0, 0, 0, 0},
// {0, 255, 0, 0, 0, 0, 0, 0}};
const byte prog01[][NUM_LINES] = {{40, 0, 0, 0, 0, 0, 0, 0},
{0, 40, 0, 0, 0, 0, 0, 0},
{0, 0, 80, 0, 0, 0, 0, 0},
{0, 0, 0, 120, 0, 0, 0, 0},
{0, 0, 0, 0, 160, 0, 0, 0},
{0, 0, 0, 0, 0, 200, 0, 0},
{0, 0, 0, 0, 0, 0, 230, 0},
{0, 0, 0, 0, 0, 0, 0, 255},
{0, 0, 0, 0, 0, 0, 230, 0},
{0, 0, 0, 0, 0, 200, 0, 0},
{0, 0, 0, 0, 160, 0, 0, 0},
{0, 0, 0, 120, 0, 0, 0, 0},
{0, 0, 80, 0, 0, 0, 0, 0},
{0, 40, 0, 0, 0, 0, 0, 0}};
const byte prog02[][NUM_LINES] = {{0, 255, 255, 255, 255, 255},
{255, 0, 255, 255, 255, 255},
{255, 255, 0, 255, 255, 255},
{255, 255, 255, 0, 255, 255},
{255, 255, 255, 255, 0, 255},
{255, 255, 255, 255, 255, 0},
{255, 255, 255, 255, 0, 255},
{255, 255, 255, 0, 255, 255},
{255, 255, 0, 255, 255, 255},
{255, 0, 255, 255, 255, 255}};
*/