summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.cpp337
-rw-r--r--src/pin.cpp44
-rw-r--r--src/pin.h64
3 files changed, 445 insertions, 0 deletions
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..ab09cd5
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,337 @@
+/* ===============================================
+ Тахометр-мотометр - мои изыскания
+ 20250108 ... 20250206
+ v.041
+
+ tiny2313, 16MHz, Общий Катод - ОК
+
+ = FUSES = Low - 0xFF; High - 0xDB; Ext - 0xFF
+
+================================================== */
+
+#include <avr/interrupt.h>
+#include <util/delay.h>
+#include <avr/eeprom.h>
+#include <avr/wdt.h>
+#include "pin.h"
+
+// =======================================
+// ОПРЕДЕЛЯЕМ КОНСТАНТЫ:
+#define F_QUARTZ 16000000UL // частота кварца
+#define DIVIDER 64 // делитель таймера T1, задается в инициализации Т1
+#define PART_SEC 60000000 / (1000000 / (F_QUARTZ / DIVIDER)) // часть секунды (для пересчета оборотов)
+
+// Количество импульсов на 1 оборот коленвала:
+#define REV_RATED_POWER 3600 // обороты при номинальной мощности (введите свои)
+#define COUNT_PULSE 1 // 4 - импульса на оборот; 2 - 2 импульса; 1 - 1 импульс
+
+// 8ми сегментный 4х разрядный индикатор:
+#define LEVEL 0 // (1) - Общий Анод, (0) - Общий Катод
+#define RAZR 4 // количество разрядов индикатора
+#define BRIGHT 0x7F // яркость свечения сегментов (больше значение - ярче)
+
+// Минимальный учетный интервал Моточасов:
+#define TIME 3600 // 3600=1минута; 216000=1час (60 * 60 * 60 (1сек * 1мин * 1час)
+#define MEM_CELL 8 // начальная ячейка памяти в которой будут храниться моточасы
+#define MEANING 0x0A0A0A0A // контрольное слово для проверки памяти
+#define DELAY_VISIBLE 100 // пауза для визуального отображения
+#define KOEFF 3 // коэффициент усреднения
+#define TIME_RESET_MOTO 5000 // задержка сброса моточасов
+
+// =======================================
+// Рабочие переменные:
+// Отображаемые на индикаторе символы:
+uint8_t seg[19] = {
+ 0b11111100, // 0
+ 0b01100000, // 1
+ 0b11011010, // 2
+ 0b11110010, // 3
+ 0b01100110, // 4
+ 0b10110110, // 5
+ 0b10111110, // 6
+ 0b11100000, // 7
+ 0b11111110, // 8
+ 0b11110110, // 9
+ 0b11101110, // A
+ 0b00111110, // B
+ 0b00011010, // C
+ 0b01111010, // D
+ 0b10011110, // E
+ 0b10001110, // F
+ 0b00000000, // 16 - пусто
+ 0b00000010, // 17 - минус
+ 0b11000110, // 18 - градус
+};
+uint8_t data[RAZR]; // ячейки данных разрядов индикатора
+uint32_t countMoto = 0; // счетчик моточасов (накопитель оборотов)
+uint16_t temp = 0; // счетчик оборотов
+bool flagRev = false; // флаг для индикации
+bool flagDot = false; // флаг для отображения точки в моточасах
+uint16_t revOld = 0; // предыдущие обороты двигателя
+uint32_t myMillis = 0; // счетчик миллисекунд
+uint32_t myMillisOld = 0; // старый счетчик миллисекунд
+
+// ################################################################
+// Усредняем показания оборотов:
+uint16_t filtr(uint16_t rev)
+{
+ static uint8_t a = pow(2, KOEFF) - 1;
+ (revOld > rev / KOEFF) ? revOld = (a * revOld + rev) >> KOEFF : revOld = rev;
+ return revOld;
+}
+
+//================================================================
+// Инициализация прерываний:
+void INTERRUPT_Init()
+{
+ // Инициализация T0:
+ TCCR0B |= (1 << CS01) | (1 << CS00); // делитель = 64
+ OCR0A = BRIGHT;
+ OCR0B = 250;
+ TIMSK |= (1 << TOIE0) | (1 << OCIE0A);
+ // Инициализация T1:
+ TCCR1B |= (1 << CS11) | (1 << CS10); // делитель = 64
+ // Инициализация INT0:
+ MCUCR |= (1 << ISC01) | (1 << ISC00); //-по фронту//(1 << ISC01);//-по спаду //
+ GIMSK |= (1 << INT0);
+}
+
+//================================================================
+// Включение сегментов:
+void segWork(uint8_t sTem)
+{
+ uint8_t segments = seg[sTem];
+ (LEVEL) ? segments = ~segments : segments = segments;
+ (segments & (1 << 7)) ? PORT_A |= (1 << SEG_A) : PORT_A &= ~(1 << SEG_A);
+ (segments & (1 << 6)) ? PORT_B |= (1 << SEG_B) : PORT_B &= ~(1 << SEG_B);
+ (segments & (1 << 5)) ? PORT_C |= (1 << SEG_C) : PORT_C &= ~(1 << SEG_C);
+ (segments & (1 << 4)) ? PORT_D |= (1 << SEG_D) : PORT_D &= ~(1 << SEG_D);
+ (segments & (1 << 3)) ? PORT_E |= (1 << SEG_E) : PORT_E &= ~(1 << SEG_E);
+ (segments & (1 << 2)) ? PORT_F |= (1 << SEG_F) : PORT_F &= ~(1 << SEG_F);
+ (segments & (1 << 1)) ? PORT_G |= (1 << SEG_G) : PORT_G &= ~(1 << SEG_G);
+ (segments & (1 << 0)) ? PORT_H |= (1 << SEG_H) : PORT_H &= ~(1 << SEG_H);
+}
+
+//================================================================
+// Гашение всех разрядов перед установкой сегментов:
+ISR(TIMER0_COMPA_vect)
+{
+ (LEVEL) ? PORT_RAZ1 &= ~(1 << RAZ_1) : PORT_RAZ1 |= (1 << RAZ_1);
+ (LEVEL) ? PORT_RAZ2 &= ~(1 << RAZ_2) : PORT_RAZ2 |= (1 << RAZ_2);
+ (LEVEL) ? PORT_RAZ3 &= ~(1 << RAZ_3) : PORT_RAZ3 |= (1 << RAZ_3);
+ (LEVEL) ? PORT_RAZ4 &= ~(1 << RAZ_4) : PORT_RAZ4 |= (1 << RAZ_4);
+}
+
+//================================================================
+// Основная индикация:
+ISR(TIMER0_OVF_vect)
+{
+ static uint8_t s = 0;
+
+ switch (s)
+ {
+ case 0:
+ segWork(data[0]);
+ (LEVEL) ? PORT_RAZ1 |= (1 << RAZ_1) : PORT_RAZ1 &= ~(1 << RAZ_1);
+ break;
+
+ case 1:
+ segWork(data[1]);
+ (flagDot && !LEVEL) ? PORT_H |= (1 << SEG_H) : PORT_H &= ~(1 << SEG_H);
+ (LEVEL) ? PORT_RAZ2 |= (1 << RAZ_2) : PORT_RAZ2 &= ~(1 << RAZ_2);
+ break;
+
+ case 2:
+ segWork(data[2]);
+ (LEVEL) ? PORT_RAZ3 |= (1 << RAZ_3) : PORT_RAZ3 &= ~(1 << RAZ_3);
+ break;
+
+ case 3:
+ segWork(data[3]);
+ (LEVEL) ? PORT_RAZ4 |= (1 << RAZ_4) : PORT_RAZ4 &= ~(1 << RAZ_4);
+ break;
+ }
+ (s == 3) ? s = 0 : s++; // крутим активный разряд
+
+ // почти = 1мс (976 мкс)
+ myMillis++;
+}
+
+//================================================================
+// Запись данных в массив для отображения:
+void visible(uint16_t vis)
+{
+ for (uint8_t c = 4; c > 0; c--)
+ {
+ data[c - 1] = vis % 10;
+ vis /= 10;
+
+ // Гасим "левый" ноль:
+ if (data[0] == 0)
+ {
+ data[0] = 16;
+ }
+ }
+}
+
+//===============================================================
+// Подсчет оборотов (по таймеру T1):
+ISR(INT0_vect)
+{
+ temp = TCNT1 * COUNT_PULSE;
+ TCNT1 = 0;
+ temp = PART_SEC / temp;
+ countMoto += temp;
+ // flagRev = true;
+}
+
+//===============================================================
+// Проверяем включено-ли зажигание:
+void onIgnition()
+{
+ if (!(PIN_IGN_ON & (1 << IGN_ON)))
+ {
+ // если - нет, то сохраняем моточасы в EEPROM:
+ eeprom_update_dword((uint32_t *)MEM_CELL + 1, countMoto);
+ // и выключаемся:
+ while (1)
+ ;
+ }
+}
+
+//===============================================================
+// Сброс моточасов:
+void resEeprom()
+{
+ eeprom_update_dword((uint32_t *)MEM_CELL, MEANING);
+ eeprom_update_dword((uint32_t *)MEM_CELL + 1, 0);
+}
+
+//===============================================================
+// Проверка нажатия кнопки сброса моточасов:
+// void checkPinRes()
+// {
+// if (!(PIN_BTN & (1 << BTN)))
+// {
+// _delay_ms(5000);
+// if (!(PIN_BTN & (1 << BTN)))
+// {
+// // если 3сек еще нажата, то сброс моточасов
+// countMoto = 0;
+// resEeprom();
+// }
+// }
+// }
+
+//===============================================================
+// Проверка нажатия кнопки сброса моточасов:
+void checkPinMode()
+{
+ static bool pinCondition = false;
+ static bool flagResEeprom = true;
+ static uint32_t pinCount = 0;
+ if (!(PIN_BTN & (1 << BTN)) && !pinCondition)
+ {
+ flagRev = !flagRev;
+ pinCondition = 1;
+ pinCount = myMillis;
+ }
+
+ if (!(PIN_BTN & (1 << BTN)) && pinCondition)
+ {
+ if (myMillis <= pinCount + TIME_RESET_MOTO)
+ {
+ pinCount++;
+ visible(pinCount);
+ }
+ else
+ {
+ countMoto = 0;
+ if (flagResEeprom)
+ {
+ resEeprom();
+ }
+ else
+ {
+ flagResEeprom = false;
+ }
+ }
+ }
+ else
+ {
+ pinCondition = false;
+ pinCount = 0;
+ flagResEeprom = true;
+ }
+}
+
+//===============================================================
+int main(void)
+{
+ wdt_reset();
+ init_pin();
+
+ wdt_enable(WDTO_1S);
+ wdt_reset();
+
+ //---------------------------------------------------------
+ // Читаем моточасы из EEPROM:
+ if (eeprom_read_dword((uint32_t *)MEM_CELL) == MEANING)
+ {
+ countMoto = eeprom_read_dword((uint32_t *)MEM_CELL + 1);
+ }
+ else
+ {
+ resEeprom();
+ }
+
+ // Инициализируем прерывания:
+ INTERRUPT_Init();
+ // Разрешаем прерывания:
+ wdt_reset();
+ sei();
+ //---------------------------------------------------------
+ while (1)
+ {
+ checkPinMode();
+ // Если включен режим тахометра:
+ if (flagRev)
+ {
+ // то отображаем тахометр (и "убиваем" младший разряд)
+ visible(filtr(temp) / 10 * 10);
+ // flagRev = false;
+ flagDot = false;
+ myMillisOld = myMillis;
+ }
+ else
+ {
+ revOld = 0;
+ // если нет - отображаем моточасы
+ uint16_t data;
+ // Если меньше 100 мото/часов - отображаем с минутами:
+ if ((countMoto / REV_RATED_POWER / TIME) < 100)
+ {
+ data = countMoto / REV_RATED_POWER / TIME * 100;
+ data += countMoto / REV_RATED_POWER / (TIME / 60) % 60;
+ flagDot = true;
+ }
+ // если больше или равно 100 мото/часов - отображаем только часы:
+ else
+ {
+ data = countMoto / REV_RATED_POWER / TIME;
+ flagDot = false;
+ }
+ if ((countMoto / REV_RATED_POWER / TIME) >= 1000)
+ countMoto = 0;
+ visible(data);
+ myMillisOld = myMillis;
+ }
+
+ // задержка для отображения цифр
+ while (myMillis <= myMillisOld + DELAY_VISIBLE)
+ {
+ onIgnition();
+ wdt_reset();
+ }
+ }
+} \ No newline at end of file
diff --git a/src/pin.cpp b/src/pin.cpp
new file mode 100644
index 0000000..d0e1e98
--- /dev/null
+++ b/src/pin.cpp
@@ -0,0 +1,44 @@
+#include <avr/io.h>
+#include "pin.h"
+
+//===============================================================
+// Инициализация всех ПИНов:
+void init_pin()
+{
+ DDR_A |= (1 << SEG_A);
+ PORT_A |= (1 << SEG_A);
+ DDR_B |= (1 << SEG_B);
+ PORT_B |= (1 << SEG_B);
+ DDR_C |= (1 << SEG_C);
+ PORT_C |= (1 << SEG_C);
+ DDR_D |= (1 << SEG_D);
+ PORT_D |= (1 << SEG_D);
+ DDR_E |= (1 << SEG_E);
+ PORT_E |= (1 << SEG_E);
+ DDR_F |= (1 << SEG_F);
+ PORT_F |= (1 << SEG_F);
+ DDR_G |= (1 << SEG_G);
+ PORT_G |= (1 << SEG_G);
+ DDR_H |= (1 << SEG_H);
+ PORT_H |= (1 << SEG_H);
+
+ DDR_RAZ1 |= (1 << RAZ_1);
+ PORT_RAZ1 |= (1 << RAZ_1);
+ DDR_RAZ2 |= (1 << RAZ_2);
+ PORT_RAZ2 |= (1 << RAZ_2);
+ DDR_RAZ3 |= (1 << RAZ_3);
+ PORT_RAZ3 |= (1 << RAZ_3);
+ DDR_RAZ4 |= (1 << RAZ_4);
+ PORT_RAZ4 |= (1 << RAZ_4);
+
+ DDR_TAHO &= ~(1 << BTN);
+ PORT_TAHO |= (1 << BTN);
+
+ DDR_BTN &= ~(1 << BTN);
+ PORT_BTN |= (1 << BTN);
+
+ DDR_IGN_ON &= ~(1 << IGN_ON);
+ PORT_IGN_ON |= (1 << IGN_ON);
+}
+
+//===============================================================
diff --git a/src/pin.h b/src/pin.h
new file mode 100644
index 0000000..5343e8c
--- /dev/null
+++ b/src/pin.h
@@ -0,0 +1,64 @@
+#ifndef PIN_H_
+#define PIN_H_
+
+// ЗАДАЕМ ИСПОЛЬЗУЕМЫЕ ПИНы:
+// СЕГМЕНТЫ:
+#define SEG_A PB3
+#define DDR_A DDRB
+#define PORT_A PORTB
+#define SEG_B PB7
+#define DDR_B DDRB
+#define PORT_B PORTB
+#define SEG_C PD6
+#define DDR_C DDRD
+#define PORT_C PORTD
+#define SEG_D PD4
+#define DDR_D DDRD
+#define PORT_D PORTD
+#define SEG_E PD5
+#define DDR_E DDRD
+#define PORT_E PORTD
+#define SEG_F PB4
+#define DDR_F DDRB
+#define PORT_F PORTB
+#define SEG_G PB0
+#define DDR_G DDRB
+#define PORT_G PORTB
+#define SEG_H PD3
+#define DDR_H DDRD
+#define PORT_H PORTD
+// РАЗРЯДЫ:
+#define RAZ_1 PB2
+#define DDR_RAZ1 DDRB
+#define PORT_RAZ1 PORTB
+#define RAZ_2 PB5
+#define DDR_RAZ2 DDRB
+#define PORT_RAZ2 PORTB
+#define RAZ_3 PB6
+#define DDR_RAZ3 DDRB
+#define PORT_RAZ3 PORTB
+#define RAZ_4 PB1
+#define DDR_RAZ4 DDRB
+#define PORT_RAZ4 PORTB
+
+// КНОПКА:
+#define BTN PD0
+#define DDR_BTN DDRD
+#define PORT_BTN PORTD
+#define PIN_BTN PIND
+
+// ЗАЖИГАНИЕ:
+#define IGN_ON PD1
+#define DDR_IGN_ON DDRD
+#define PORT_IGN_ON PORTD
+#define PIN_IGN_ON PIND
+
+// ВХОД ТАХОМЕТРА:
+#define PIN_TAHO PD2
+#define DDR_TAHO DDRD
+#define PORT_TAHO PORTD
+
+//-----------------------------------
+void init_pin(void);
+
+#endif \ No newline at end of file