Счётчик для катушечного магнитофона

Всем присутствующим здоровья! Нашёл у немецких коллег скетч счётчика для катушечного магнитофона на Ардуино Нано.Собрал,работает.Немного не устраивает счёт и отсутствие одной функции.А именно:счёт идёт до 9 и потом переходит на следующий регистр,т.е в формате 99999.Как перевести в формат часов,минут и секунд,т.е. 95959 ,и добавить функцию переключения счёта в зависимости от скорости,т.е. сейчас он работает для скорости 19 см/с,а при 9 см/с показания должны удваиваться.Просьба не кидать помидорами,в программировании,я,чуть выше ноля.

/* Arduino OLED Tape Counter
* Copyright (C) 2020 by DIYLAB, v0.99, 28.04.2020
*
* This Software is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Arduino SSD1306Ascii Library.  If not, see
* <http://www.gnu.org/licenses/>.
* 
* Used libraries
* ~~~~~~~~~~~~~~
* SSD1306Ascii: <https://github.com/greiman/SSD1306Ascii>
* Arduino OneButton Library: <https://github.com/mathertel/OneButton>
*
* Used mikrocontroller
* ~~~~~~~~~~~~~~~~~~~~
* Arduino nano v3.0
*/
#include <LiquidCrystal.h>
#include <SSD1306Ascii.h>
#include <SSD1306AsciiAvrI2c.h>
#include <OneButton.h>
#include <EEPROM.h>

///////////////////////////////////////////////////////////////
// USER CONFIG SECTION (Only edit here!)                     //
///////////////////////////////////////////////////////////////
// Software configuration:
#define PULSESPERCOUNT    1    // Number of pulses for one count.
#define BRIGHTNESS        128    // Display brightness (0 to 255)

// Hardware pin configuration:
// *Only change if absolutely necessary!
#define SENSOR_A        3    // Controller PIN (Sensor-A)
#define SENSOR_B        2    // Controller PIN (Sensor-B)
#define BUTTON            5    // Controller PIN (RESET-Button)
#define ZEROPOINT        7    // Controller PIN ('00000' pulse)
///////////////////////////////////////////////////////////////

#define LED                13    // Onboard LED
#define LEFT            1    // left rotation
#define RIGHT            2    // right rotation
#define EEPROM_ADDRESS    0x0    // EEPROM address for data store
#define I2C_ADDRESS        0x3C // or 0x3D - depending on display

// Intervals
#define INTERVAL1 1000

OneButton btn(BUTTON, true, true);
SSD1306AsciiAvrI2c oled;

unsigned int loopCounter = 0;
unsigned long secondTick = 0;
unsigned long timeInterval1 = 0;
volatile long counter = 0;
volatile int sensor1 = 0;
volatile int sensor2 = 0;
volatile int direction = 0;
volatile int step = 0;
volatile int divider = 0;
volatile boolean stepFlag0, stepFlag1, stepFlag2, stepFlag3, onboardLEDFlag;

/**
* Setup
********/
void setup() {
    // Set inputs.
    pinMode(SENSOR_A, INPUT);
    pinMode(SENSOR_B, INPUT);

    // Set outputs.
    pinMode(LED, OUTPUT);
    pinMode(ZEROPOINT, OUTPUT);

    // Link the button functions.  
    btn.attachClick(ButtonClick);
    btn.attachDoubleClick(ButtonDoubleClick);
    btn.attachLongPressStart(ButtonLongPressStart);
    btn.attachLongPressStop(ButtonLongPressStop);

// Initialize Timer 1.
    setupTimer1();

    // Set PinChange Interrupts.
    attachInterrupt(0, CheckState, CHANGE);
    attachInterrupt(1, CheckState, CHANGE);

    // Initialize display.
    oled.begin(&Adafruit128x32, I2C_ADDRESS);

    // Set font.
    oled.setFont(lcdnums12x16);

    // Set display brightness.
    oled.setContrast(BRIGHTNESS);

    // Clear display.
    oled.clear();

    // Set magnification of the font.
    oled.set2X();

    // Get last counter reading from the EEPROM.
    counter = EEPROMReadlong(EEPROM_ADDRESS);

    // Initial settings on the Display from EEPROM.
    WriteOled((counter == -1) ? 0 : counter);
}

/**
* MainLoop
***********/
void loop() {
    // Watching the push button.
    btn.tick();

    // Turn ZEROPOINT output pin off after INTERVAL1 if was on.
    if (millis() > timeInterval1 + INTERVAL1) {
        timeInterval1 = millis();
        if (digitalRead(ZEROPOINT))
            digitalWrite(ZEROPOINT, LOW);
    }

    // Is the edge sequence complete?
    if (stepFlag0 && stepFlag1 && stepFlag2 && stepFlag3)
    {
        // Reset all edge flags.
        stepFlag0 = stepFlag1 = stepFlag2 = stepFlag3 = false;

        // Increase the loop-counter.
        loopCounter++;

        // Count only after reaching the target 'PULSESPERCOUNT'.
        if (loopCounter == PULSESPERCOUNT)
        {
            // Reset the loopCounter.
            loopCounter = 0;

            // Counter up or down, depending on the direction.
            (direction == LEFT) ? counter++ : counter--;

            // Output on the display.
            WriteOled(counter);

            // '00000" Pulse.
            if (counter == 0)
                digitalWrite(ZEROPOINT, HIGH);
        }

        // As long as the sensors provide data,
        // reset timer1 regularly before the timer overflow
        // to avoid unnecessary writing to the EEPROM.
        TCNT1 = 0;
    }
}

/**
 * This function will be called when the button was pressed 1 time.
*******************************************************************/
void ButtonClick() {
    WriteOled(counter = 0);
}

/**
* This function will be called when the button was
* pressed 2 times in a short timeframe.
***************************************************/
void ButtonDoubleClick() {
    // Intended for later use!
}

/**
* This function will be called once, when the button is
* pressed for a long time.
*********************************************************/
void ButtonLongPressStart() {
    // Intended for later use!
}

/**
* This function will be called once, when the button is
* released after beeing pressed for a long time.
*********************************************************/
void ButtonLongPressStop() {
    // Intended for later use!
}

/**
* Write OLED Display
*********************/
void WriteOled(unsigned long val) {
    // Buffer for all five digits.
    char buffer[5];

    // Formatting the output.
    sprintf(buffer, "%05ld", val);

    // Output on the display.
    oled.println(buffer);
}

/**
* Check Sensor State after Interrupt
*************************************/
void CheckState() {
    // Interrogate sensors.
    sensor1 = digitalRead(SENSOR_A);
    sensor2 = digitalRead(SENSOR_B);

// Edge Detector
    if (sensor1 == 1 && sensor2 == 1)
    {
        if (step == 1) { direction = LEFT; }
        if (step == 3) { direction = RIGHT; }
        step = 0;
        stepFlag0 = true;
    }
    if (sensor1 == 0 && sensor2 == 1)
    {
        if (step == 2) { direction = LEFT; }
        if (step == 0) { direction = RIGHT; }
        step = 1;
        stepFlag1 = true;
    }
    if (sensor1 == 0 && sensor2 == 0)
    {
        if (step == 3) { direction = LEFT; }
        if (step == 1) { direction = RIGHT; }
        step = 2;
        stepFlag2 = true;
    }
    if (sensor1 == 1 && sensor2 == 0)
    {
        if (step == 0) { direction = LEFT; }
        if (step == 2) { direction = RIGHT; }
        step = 3;
        stepFlag3 = true;
    }
}

/**
* Timer overflow interrupt.
****************************/
ISR(TIMER1_COMPA_vect) {
    // Increase second counter.
    secondTick++;

    // If LED on, turn LED off.
    if (onboardLEDFlag)
        digitalWrite(LED, LOW);

    if (divider == 0)
    {
      // Only store in EEPROM if the data differ!
        if (EEPROMReadlong(0) != counter)
        {
            // Turn LED on, set flag.
            digitalWrite(LED, HIGH);
            onboardLEDFlag = HIGH;

            // Write counter data to EEPROM.
            EEPROMWritelong(EEPROM_ADDRESS, counter);
        }
    }
    divider++;
    divider %= 5;
}

/**
* Initialize Timer1.
*********************/
void setupTimer1() {
    noInterrupts();
    // Clear registers
    TCCR1A = 0;
    TCCR1B = 0;
    TCNT1 = 0;

    // 1 Hz (16000000/((15624+1)*1024)).
    OCR1A = 15624;
    // CTC
    TCCR1B |= (1 << WGM12);
    // Prescaler 1024.
    TCCR1B |= (1 << CS12) | (1 << CS10);
    // Output Compare Match A Interrupt Enable.
    TIMSK1 |= (1 << OCIE1A);
    interrupts();
}

/**
* Write a 4 byte (32bit) long to the eeprom
* at the specified address to adress + 3.
*********************************************/
void EEPROMWritelong(int address, long value) {
    // Decomposition from a long to 4 bytes by using bitshift.
    byte four = (value & 0xFF);
    byte three = ((value >> 8) & 0xFF);
    byte two = ((value >> 16) & 0xFF);
    byte one = ((value >> 24) & 0xFF);

    // Write the 4 bytes into the eeprom memory.
    EEPROM.write(address, four);
    EEPROM.write(address + 1, three);
    EEPROM.write(address + 2, two);
    EEPROM.write(address + 3, one);
}

/**
* return a 4 byte (32bit) long from the eeprom
* at the specified address to adress + 3.
* returns: long
*********************************************/
long EEPROMReadlong(long address) {
    // Read the 4 bytes from the eeprom memory.
    long four = EEPROM.read(address);
    long three = EEPROM.read(address + 1);
    long two = EEPROM.read(address + 2);
    long one = EEPROM.read(address + 3);

    // Return the recomposed long by using bitshift.
    return ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + ((two << 16) & 0xFFFFFF) + ((one << 24) & 0xFFFFFFFF);
}

А ничего , что единица счета в данном случае, она как бы немного , совсем чуточку, нифига не линейная ?

Представить, что это секунды и при выводе на дисплей перевести секунды в ЧЧ:ММ:СС.

Не надо лукавить.
Вы что, не знаете, как перевести, скажем 983 секунды в минуты:секунды?

Еще: необходима схема.

И последнее: если Вы хотите что-то сделать самостоятельно, нужно привести код с собственными попытками. Если же Вы хотите, чтобы сделали за Вас, тему следовало размещать в разделе “Иу исполнителя”.

там немцы уже всё за него сделали

В смысле-не линейная? Обводной ролик вращается с постоянной скоростью.

Я,не прошу сделать за меня,я прошу подсказать где менять значения.


Два оптодатчика на D2-D3,для подсчёта импульсов и определения направления счёта,дисплей,и кнопка сброса на ноль.

А чо у авторов кода не спросишь?

У них эта тема давно в архиве,ещё за 2020 год.

Ну, значить, не судьба.

Т.е. именно в вывод на дисплей нужно ввести поправку?

Я бы так делал.

Спасибо за подсказку,попробую.

Надо же как то еще сообщать/узнавать что включилась вторая скорость …

Так не делают счётчик, через обводной ролик.
Это не работает как минимум в трёх случаях:
1.перемотка вперёд
2.перемотка назад
3.пауза

Сколько раз сталкивался, всегда счётчик привязан или к передней или к задней бобине.
Хотя не исключаю, что есть какие то другие конструкции.

видимо тут:

* Write OLED Display
*********************/
void WriteOled(unsigned long val) {
    // Buffer for all five digits.
    char buffer[5];

    // Formatting the output.
    sprintf(buffer, "%05ld", val);

    // Output on the display.
    oled.println(buffer);
}

/**

5 на 6 тока поменяй.

а не 8?

5 цифр с ведущими нулями + 0х00 в оконцовке

так функцию всю переписывать надо, я думал ты об этом, а ты об ошибках )))