Skip to content
168 changes: 168 additions & 0 deletions firmware/nixieClock_2_v2.6/0_data.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
// библиотеки
#include "timer2Minim.h"
#include <GyverButton.h>
#include <RTClib.h>
#include <EEPROM.h>

RTC_DS3231 rtc;

// таймеры
timerMinim dotTimer(500); // полсекундный таймер для часов
timerMinim dotBrightTimer(DOT_TIMER); // таймер шага яркости точки
timerMinim backlBrightTimer(30); // таймер шага яркости подсветки//?
timerMinim almTimer(ALM_TIMEOUT * 1000); // таймер времени писка будильника
//timerMinim almTimer(600000); // таймер времени писка будильника
timerMinim flipTimer(FLIP_SPEED[FLIP_EFFECT]);
timerMinim glitchTimer(1000);
timerMinim blinkTimer(500);

// кнопки
GButton btnSet(BTN1, HIGH_PULL, NORM_OPEN);
GButton btnL(BTN2, HIGH_PULL, NORM_OPEN);
GButton btnR(BTN3, HIGH_PULL, NORM_OPEN);

// переменные
volatile int8_t indiDimm[4]; // величина диммирования (0-24)
volatile int8_t indiCounter[4]; // счётчик каждого индикатора (0-24)
volatile int8_t indiDigits[4]; // цифры, которые должны показать индикаторы (0-10)
volatile int8_t curIndi; // текущий индикатор (0-3)
boolean ALARM_POWER; // 1 - включить, 0 -выключить будильник. Кнопка 1

volatile boolean isBeeping = false;

boolean alm_flag;
boolean dotFlag;
int8_t hrs, mins, secs;
int8_t alm_hrs=9, alm_mins=30;//Часы и минуты будильника (При первом включении устанавливается время срабатывания)
byte indiMaxBright = INDI_BRIGHT, dotMaxBright = DOT_BRIGHT, backlMaxBright = BACKL_BRIGHT;
boolean dotBrightFlag, dotBrightDirection, backlBrightFlag, backlBrightDirection, indiBrightDirection;
int dotBrightCounter, backlBrightCounter, indiBrightCounter;
byte dotBrightStep;
boolean newTimeFlag;
boolean flipIndics[4];
byte newTime[4];
boolean flipInit;
byte startCathode[4], endCathode[4];
byte glitchCounter, glitchMax, glitchIndic;
boolean glitchFlag, indiState;
boolean curMode = 0;

byte currentDigit;

int8_t changeHrs, changeMins;
int8_t changeHrs2, changeMins2;
boolean lampState = false;
boolean anodeStates[] = {1, 1, 1, 1};
byte currentLamp, flipEffectStages;
bool trainLeaving;

const uint8_t CRTgamma[256] PROGMEM = {
0, 0, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 4, 4,
4, 4, 4, 5, 5, 5, 5, 6,
6, 6, 7, 7, 7, 8, 8, 8,
9, 9, 9, 10, 10, 10, 11, 11,
12, 12, 12, 13, 13, 14, 14, 15,
15, 16, 16, 17, 17, 18, 18, 19,
19, 20, 20, 21, 22, 22, 23, 23,
24, 25, 25, 26, 26, 27, 28, 28,
29, 30, 30, 31, 32, 33, 33, 34,
35, 35, 36, 37, 38, 39, 39, 40,
41, 42, 43, 43, 44, 45, 46, 47,
48, 49, 49, 50, 51, 52, 53, 54,
55, 56, 57, 58, 59, 60, 61, 62,
63, 64, 65, 66, 67, 68, 69, 70,
71, 72, 73, 74, 75, 76, 77, 79,
80, 81, 82, 83, 84, 85, 87, 88,
89, 90, 91, 93, 94, 95, 96, 98,
99, 100, 101, 103, 104, 105, 107, 108,
109, 110, 112, 113, 115, 116, 117, 119,
120, 121, 123, 124, 126, 127, 129, 130,
131, 133, 134, 136, 137, 139, 140, 142,
143, 145, 146, 148, 149, 151, 153, 154,
156, 157, 159, 161, 162, 164, 165, 167,
169, 170, 172, 174, 175, 177, 179, 180,
182, 184, 186, 187, 189, 191, 193, 194,
196, 198, 200, 202, 203, 205, 207, 209,
211, 213, 214, 216, 218, 220, 222, 224,
226, 228, 230, 232, 233, 235, 237, 239,
241, 243, 245, 247, 249, 251, 253, 255,
};

byte getPWM_CRT(byte val) {
return pgm_read_byte(&(CRTgamma[val]));
}

// быстрый digitalWrite
void setPin(uint8_t pin, uint8_t x) {
switch (pin) { // откл pwm
case 3: // 2B
bitClear(TCCR2A, COM2B1);
break;
case 5: // 0B
bitClear(TCCR0A, COM0B1);
break;
case 6: // 0A
bitClear(TCCR0A, COM0A1);
break;
case 9: // 1A
bitClear(TCCR1A, COM1A1);
break;
case 10: // 1B
bitClear(TCCR1A, COM1B1);
break;
case 11: // 2A
bitClear(TCCR2A, COM2A1);
break;
}

if (pin < 8) bitWrite(PORTD, pin, x);
else if (pin < 14) bitWrite(PORTB, (pin - 8), x);
else if (pin < 20) bitWrite(PORTC, (pin - 14), x);
else return;
}

// быстрый analogWrite
void setPWM(uint8_t pin, uint16_t duty) {
if (duty == 0) setPin(pin, LOW);
else {
switch (pin) {
case 5:
bitSet(TCCR0A, COM0B1);
OCR0B = duty;
break;
case 6:
bitSet(TCCR0A, COM0A1);
OCR0A = duty;
break;
case 10:
bitSet(TCCR1A, COM1B1);
OCR1B = duty;
break;
case 9:
bitSet(TCCR1A, COM1A1);
OCR1A = duty;
break;
case 3:
bitSet(TCCR2A, COM2B1);
OCR2B = duty;
break;
case 11:
bitSet(TCCR2A, COM2A1);
OCR2A = duty;
break;
default:
break;
}
}
}

void beep(boolean on) {
#if (BEEPER_TYPE == 0)
isBeeping = on;
#elif (BEEPER_TYPE == 1)
setPin(PIEZO, on);
#endif
}
86 changes: 86 additions & 0 deletions firmware/nixieClock_2_v2.6/1_setup.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
void setup() {
//Serial.begin(9600);
// случайное зерно для генератора случайных чисел
randomSeed(analogRead(6) + analogRead(7));

// настройка пинов на выход
pinMode(DECODER0, OUTPUT);
pinMode(DECODER1, OUTPUT);
pinMode(DECODER2, OUTPUT);
pinMode(DECODER3, OUTPUT);
pinMode(KEY0, OUTPUT);
pinMode(KEY1, OUTPUT);
pinMode(KEY2, OUTPUT);
pinMode(KEY3, OUTPUT);
pinMode(PIEZO, OUTPUT);
pinMode(GEN, OUTPUT);
pinMode(DOT, OUTPUT);
pinMode(BACKL, OUTPUT);

// задаем частоту ШИМ на 9 и 10 выводах 31 кГц
TCCR1B = TCCR1B & 0b11111000 | 1; // ставим делитель 1

// включаем ШИМ
setPWM(9, DUTY);

// перенастраиваем частоту ШИМ на пинах 3 и 11 на 7.8 кГц и разрешаем прерывания COMPA
TCCR2B = (TCCR2B & B11111000) | 1; // делитель 8
TCCR2A |= (1 << WGM21); // включить CTC режим для COMPA
TIMSK2 |= (1 << OCIE2A); // включить прерывания по совпадению COMPA

// ---------- RTC -----------
rtc.begin();
if (rtc.lostPower()) {
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
DateTime now = rtc.now();
secs = now.second();
mins = now.minute();
hrs = now.hour();

// EEPROM
if (EEPROM.read(1023) != 0) // первый запуск и установка переменных
{
EEPROM.put(1023, 0);
EEPROM.put(10, FLIP_EFFECT);
EEPROM.put(1, BACKL_MODE);
EEPROM.put(2, GLITCH_ALLOWED);
EEPROM.put(3, ALARM_POWER);
}
EEPROM.get(10, FLIP_EFFECT);
EEPROM.get(1, BACKL_MODE);
EEPROM.get(2, GLITCH_ALLOWED);
EEPROM.get(3, ALARM_POWER);


if (EEPROM.read(1022) != 0) // первый запуск и установка начального времени срабатывания будильника
{
EEPROM.put(1022, 0);
EEPROM.put(4, alm_hrs); // часы будильника
EEPROM.put(5, alm_mins); //минуты будильника
}
EEPROM.get(4, alm_hrs); //Читаем часы будильника из памяти
EEPROM.get(5, alm_mins); //Читаем минуты будильника из памяти

sendTime(hrs, mins); // отправить время на индикаторы
changeBright(); // изменить яркость согласно времени суток

// установить яркость на индикаторы
for (byte i = 0; i < 4; i++)
indiDimm[i] = indiMaxBright;

// расчёт шага яркости точки
dotBrightStep = ceil((float)dotMaxBright * 2 / DOT_TIME * DOT_TIMER);
if (dotBrightStep == 0) dotBrightStep = 1;

// дыхание подсветки
if (backlMaxBright > 0)
backlBrightTimer.setInterval((float)BACKL_STEP / backlMaxBright / 2 * BACKL_TIME);

// стартовый период глюков
glitchTimer.setInterval(random(GLITCH_MIN * 1000L, GLITCH_MAX * 1000L));
indiBrightCounter = indiMaxBright;

// скорость режима при запуске
flipTimer.setInterval(FLIP_SPEED[FLIP_EFFECT]);
}
13 changes: 13 additions & 0 deletions firmware/nixieClock_2_v2.6/2_loop.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
void loop() {
if (dotTimer.isReady())
{calculateTime();} // каждые 500 мс пересчёт и отправка времени
if (newTimeFlag && curMode == 0)
{flipTick();} // перелистывание цифр
dotBrightTick(); // плавное мигание точки
backlBrightTick(); // плавное мигание подсветки ламп
if (GLITCH_ALLOWED && curMode == 0)
{glitchTick();} // глюки
buttonsTick(); // кнопки
settingsTick(); // настройки
Alarm();
}
83 changes: 83 additions & 0 deletions firmware/nixieClock_2_v2.6/bright.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
void backlBrightTick() {
if (BACKL_MODE == 0 && backlBrightTimer.isReady()) {
if (backlMaxBright > 0) {
if (backlBrightDirection) {
if (!backlBrightFlag) {
backlBrightFlag = true;
backlBrightTimer.setInterval((float)BACKL_STEP / backlMaxBright / 2 * BACKL_TIME);
}
backlBrightCounter += BACKL_STEP;
if (backlBrightCounter >= backlMaxBright) {
backlBrightDirection = false;
backlBrightCounter = backlMaxBright;
}
} else {
backlBrightCounter -= BACKL_STEP;
if (backlBrightCounter <= BACKL_MIN_BRIGHT) {
backlBrightDirection = true;
backlBrightCounter = BACKL_MIN_BRIGHT;
backlBrightTimer.setInterval(BACKL_PAUSE);
backlBrightFlag = false;
}
}
setPWM(BACKL, getPWM_CRT(backlBrightCounter));
} else {
digitalWrite(BACKL, 0);
}
}
}

void dotBrightTick() {
if (dotBrightFlag && dotBrightTimer.isReady()) {
if (dotBrightDirection) {
dotBrightCounter += dotBrightStep;
if (dotBrightCounter >= dotMaxBright) {
#if (DOT_TICK_STYLE == 0)
dotBrightDirection = false;
#elif (DOT_TICK_STYLE == 1)
dotBrightFlag = false;
#endif
dotBrightCounter = dotMaxBright;
}
} else {
dotBrightCounter -= dotBrightStep;
if (dotBrightCounter <= 0) {
#if (DOT_TICK_STYLE == 0)
dotBrightDirection = true;
#endif
dotBrightFlag = false;
dotBrightCounter = 0;
}
}
setPWM(DOT, getPWM_CRT(dotBrightCounter));
}
}

void changeBright() {
#if (NIGHT_LIGHT == 1)
// установка яркости всех светилок от времени суток
if ( (hrs >= NIGHT_START && hrs <= 23)
|| (hrs >= 0 && hrs < NIGHT_END) ) {
indiMaxBright = INDI_BRIGHT_N;
dotMaxBright = DOT_BRIGHT_N;
backlMaxBright = BACKL_BRIGHT_N;
} else {
indiMaxBright = INDI_BRIGHT;
dotMaxBright = DOT_BRIGHT;
backlMaxBright = BACKL_BRIGHT;
}
for (byte i = 0; i < 4; i++) {
indiDimm[i] = indiMaxBright;
}

dotBrightStep = ceil((float)dotMaxBright * 2 / DOT_TIME * DOT_TIMER);
if (dotBrightStep == 0) dotBrightStep = 1;

if (backlMaxBright > 0)
backlBrightTimer.setInterval((float)BACKL_STEP / backlMaxBright / 2 * BACKL_TIME);
indiBrightCounter = indiMaxBright;

//change PWM to apply backlMaxBright in case of maximum bright mode
if (BACKL_MODE == 1) setPWM(BACKL, backlMaxBright);
#endif
}
Loading