Всем присутствующим здоровья! Нашёл у немецких коллег скетч счётчика для катушечного магнитофона на Ардуино Нано.Собрал,работает.Немного не устраивает счёт и отсутствие одной функции.А именно:счёт идёт до 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);
}