Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <EEPROM.h>
- #include <LiquidCrystal.h>
- #define LCD_RS_PIN 5
- #define LCD_ENABLE_PIN 6
- #define LCD_D4_PIN 7
- #define LCD_D5_PIN 8
- #define LCD_D6_PIN 9
- #define LCD_D7_PIN 10
- #define LED_PIN 13 // Вывод со светодиодом
- #define BANDAP_PIN 14 // Эталонный вход АЦП
- #define RESET_GLOBAL_PIN 2 // Номер ноги для кнопки сброса расхода
- #define SPEED_PIN 2 // Номер ноги для датчика скорости
- #define INJECTOR_PIN 3 // Номер ноги для форсунки
- #define CHECK_VOLTAGE_PIN A0 // Номер ноги, на которой измеряем напряжение для засекания отключения питания
- #define PERIOD 1000000 // Период усреднения текущего расхода и обновления дисплея (микросекунды) - секунда
- #define BANDAP_VOLTAGE 1.1 // Эталонное напряжение на 14 входе АЦП
- #define CRITICAL_VOLTAGE 3.0 // Напряжение, при котором начинаем быстренько записывать в EEPROM
- #define IDLE_STROKE_DURATION 20000 // Суммарное время открытия форсунок (милисекунды) за период на холостом ходу
- #define IDLE_STROKE_HOUR_CONSUMPTION 0.7 // Часовой расход топлива на холостом ходу (литры в час)
- #define TEST_SPEED 60.0 // Контрольная скорость (километры в час) для расчёта коэффициента пробега
- #define TEST_TICKS 84 // Число импульсов с датчика скорости за период на контрольной скорости
- #define HOUR_PERIODS ( 3600000000.0 / PERIOD ) // Число периодов в часу
- #define FUEL_FACTOR ( IDLE_STROKE_HOUR_CONSUMPTION / HOUR_PERIODS / IDLE_STROKE_DURATION ) // Коэффициент расхода топлива (литры) за период
- #define RANGE_FACTOR ( TEST_SPEED / TEST_TICKS / HOUR_PERIODS ) // Коэффициент пробега (километры) за период
- #define CONSUMPTION_FACTOR ( 100.0 * FUEL_FACTOR / RANGE_FACTOR ) // Коэффициент километрового расхода топлива (литры на 100 км)
- #define TICKS_TRESHOLD 1 // Порог (импульсы датчика скорости) за период, выше которого можно считать километровый расход
- #define DURATION_CORR 0 // Поправка при измерении длительности времени открытия одной форсунки (микросекунды)
- #define AVG_LENGTH 10 // Число периодов для усреднения
- #define AVG_REFRESH_TIME 1 // Время в часах, после которого сбрасывается усреднённый километровый расход, если не было сброса по расстоянию (1 час)
- #define AVG_REFRESH_LENGTH 0.1 // Расстояние в километрах, после которого сбрасывается усреднённый километровый расход (100 м)
- // #define AVG_REFRESH_PERIODS ( AVG_REFRESH_TIME * HOUR_PERIODS ) // Число периодов между обновлениями среднего расхода
- #define AVG_REFRESH_PERIODS 60 // Число периодов между обновлениями среднего расхода
- #define AVG_REFRESH_TICKS ( AVG_REFRESH_LENGTH / RANGE_FACTOR ) // Число импульсов датчика скорости между обновлениями среднего расхода
- #define SHOW_GLOBAL_PERIODS 3 // Число периодов между переключениями общего и среднего (за 10 минут) расхода
- // Строковые константы
- // #define STR_AVG String(" Cp:")
- // #define STR_CUR String("M\xB4\xBD:")
- // #define STR_HR String("\xAB\x61\x63:")
- #define STR_KM String(" K\xBC:")
- #define STR_AVG String("Cp:")
- #define STR_CUR String("M\xB4:")
- #define STR_HR String(" \xAB:")
- #define STR_GLOB String("O\xB2:")
- #define STR_NA String(" \xBD/\xE3")
- #define STR_KMH String("\xBA\xBC/\xC0")
- LiquidCrystal lcd(LCD_RS_PIN, LCD_ENABLE_PIN, LCD_D4_PIN, LCD_D5_PIN, LCD_D6_PIN, LCD_D7_PIN);
- unsigned long dur;
- unsigned long dur_t;
- unsigned long t;
- boolean last_injector_state;
- boolean last_speed_state;
- boolean last_reset_global_state;
- unsigned long total_duration;
- unsigned long total_ticks;
- unsigned long total_avg_duration;
- unsigned long total_avg_ticks;
- unsigned long d_avg_duration;
- unsigned long d_avg_ticks;
- unsigned long global_avg_duration;
- unsigned long global_avg_ticks;
- int period_counter;
- // int period_counter2;
- boolean eeprom_already_written;
- boolean show_global;
- int show_global_counter;
- // Структура, описывающая данные для усреднения
- struct consumption_data {
- unsigned long duration;
- unsigned long ticks;
- };
- byte gauge_0[] = {
- B00000000,
- B00000000,
- B00000000,
- B00000000,
- B00000000,
- B00000000,
- B00000000,
- B11111111
- };
- byte gauge_1[] = {
- B00000000,
- B00000000,
- B00000000,
- B00000000,
- B00000000,
- B00000000,
- B11111111,
- B11111111
- };
- byte gauge_2[] = {
- B00000000,
- B00000000,
- B00000000,
- B00000000,
- B00000000,
- B11111111,
- B11111111,
- B11111111
- };
- byte gauge_3[] = {
- B00000000,
- B00000000,
- B00000000,
- B00000000,
- B11111111,
- B11111111,
- B11111111,
- B11111111
- };
- byte gauge_4[] = {
- B00000000,
- B00000000,
- B00000000,
- B11111111,
- B11111111,
- B11111111,
- B11111111,
- B11111111
- };
- byte gauge_5[] = {
- B00000000,
- B00000000,
- B11111111,
- B11111111,
- B11111111,
- B11111111,
- B11111111,
- B11111111
- };
- byte gauge_6[] = {
- B00000000,
- B11111111,
- B11111111,
- B11111111,
- B11111111,
- B11111111,
- B11111111,
- B11111111
- };
- byte gauge_7[] = {
- B11111111,
- B11111111,
- B11111111,
- B11111111,
- B11111111,
- B11111111,
- B11111111,
- B11111111
- };
- struct consumption_data data[AVG_LENGTH];
- int avg_counter;
- void setup() {
- // Serial.begin(9600);
- // Инициализация дисплея
- lcd.begin(8, 2);
- // Загрузка пользовательских символов для отрисовки шкалы
- lcd.createChar(0, gauge_0);
- lcd.createChar(1, gauge_1);
- lcd.createChar(2, gauge_2);
- lcd.createChar(3, gauge_3);
- lcd.createChar(4, gauge_4);
- lcd.createChar(5, gauge_5);
- lcd.createChar(6, gauge_6);
- lcd.createChar(7, gauge_7);
- pinMode(INJECTOR_PIN, INPUT);
- pinMode(SPEED_PIN, INPUT);
- pinMode(RESET_GLOBAL_PIN, INPUT);
- pinMode(CHECK_VOLTAGE_PIN, INPUT);
- pinMode(LED_PIN, OUTPUT);
- digitalWrite(SPEED_PIN, HIGH);
- digitalWrite(INJECTOR_PIN, HIGH);
- digitalWrite(RESET_GLOBAL_PIN, HIGH);
- last_injector_state = analogRead(INJECTOR_PIN) < 500;
- last_speed_state = analogRead(SPEED_PIN) < 500;
- last_reset_global_state = digitalRead(RESET_GLOBAL_PIN);
- // Инициализация данных для усреднения
- for (int i=0; i < AVG_LENGTH; ++i) {
- data[i].duration = 0;
- data[i].ticks = 0;
- }
- dur = 0;
- dur_t = micros();
- t = dur_t + PERIOD;
- total_duration = 0;
- total_ticks = 0;
- total_avg_duration = total_duration;
- total_avg_ticks = total_ticks;
- d_avg_duration = total_duration;
- d_avg_ticks = total_ticks;
- for (int i = 0; i < sizeof(unsigned long int); ++i) {
- *( (byte*)(&global_avg_duration) + i ) = EEPROM.read(i);
- }
- int addr = sizeof(unsigned long int);
- for (int i = 0; i < sizeof(unsigned long int); ++i) {
- *( (byte*)(&global_avg_ticks) + i ) = EEPROM.read(addr + i);
- }
- /* global_avg_duration = 0;
- global_avg_ticks = 0; */
- period_counter = 0;
- // period_counter2 = 0;
- avg_counter = 0;
- show_global = false;
- show_global_counter = 0;
- eeprom_already_written = true;
- }
- void loop() {
- float vcc_voltage = BANDAP_VOLTAGE * 1024 / analogRead(BANDAP_PIN);
- float check_voltage = 5.0 * analogRead(CHECK_VOLTAGE_PIN) / 1024;
- /* boolean injector_state = analogRead(INJECTOR_PIN) < 500;
- boolean speed_state = analogRead(SPEED_PIN) < 500;*/
- boolean injector_state = !digitalRead(INJECTOR_PIN);
- boolean speed_state = digitalRead(SPEED_PIN);
- boolean reset_global_state = digitalRead(RESET_GLOBAL_PIN);
- unsigned long new_t = micros();
- // if (vcc_voltage < CRITICAL_VOLTAGE) {
- if (check_voltage < CRITICAL_VOLTAGE) {
- if (!eeprom_already_written) {
- digitalWrite(LED_PIN, HIGH);
- // Быстренько записываем в ПЗУ данные о среднем расходе
- for ( int i = 0; i < sizeof(unsigned long int); ++i ) {
- EEPROM.write(i, *( (byte*)(&global_avg_duration) + i) );
- }
- int addr = sizeof(unsigned long int);
- for ( int i = 0; i < sizeof(unsigned long int); ++i ) {
- EEPROM.write(addr + i, *( (byte*)(&global_avg_ticks) + i) );
- }
- eeprom_already_written = true;
- digitalWrite(LED_PIN, LOW);
- }
- } else {
- eeprom_already_written = false;
- }
- // Вычисление мгновенных значений
- if (injector_state != last_injector_state) {
- if (injector_state) {
- dur = new_t - dur_t;
- if (dur) dur += DURATION_CORR; // Поправочка
- total_duration += dur;
- } else {
- dur_t = new_t;
- dur = 0;
- }
- last_injector_state = injector_state;
- }
- if (speed_state != last_speed_state) {
- total_ticks++;
- last_speed_state = speed_state;
- }
- if (last_reset_global_state == HIGH && reset_global_state == LOW) {
- global_avg_duration = 0;
- global_avg_ticks = 0;
- digitalWrite(LED_PIN, HIGH);
- }
- if (last_reset_global_state == LOW && reset_global_state == HIGH) {
- digitalWrite(LED_PIN, LOW);
- }
- last_reset_global_state = reset_global_state;
- // Действия, которые выполняются раз в секунду
- if (new_t >= t) {
- if (!dur) {
- dur = new_t - dur_t;
- if (dur) dur += DURATION_CORR; // Поправочка
- total_duration += dur;
- }
- // Отладочная установка значений
- // total_duration = 100000;
- // total_ticks = 56;
- d_avg_duration += total_duration;
- d_avg_ticks += total_ticks;
- global_avg_duration += total_duration / 1000;
- global_avg_ticks += total_ticks;
- ++period_counter;
- // ++period_counter2;
- // if (d_avg_ticks >= AVG_REFRESH_TICKS || period_counter >= AVG_REFRESH_PERIODS) {
- if (period_counter >= AVG_REFRESH_PERIODS) {
- // Вычисление средних значений
- total_avg_duration += d_avg_duration;
- total_avg_duration -= data[avg_counter].duration;
- total_avg_ticks += d_avg_ticks;
- total_avg_ticks -= data[avg_counter].ticks;
- data[avg_counter].duration = d_avg_duration;
- data[avg_counter].ticks = d_avg_ticks;
- // total_avg_duration = 0;
- // total_avg_ticks = 0;
- // for (int i = 0; i < AVG_LENGTH; ++i) {
- // total_avg_duration += data[i].duration;
- // total_avg_ticks += data[i].ticks;
- // }
- // Отладочный вывод
- // Serial.println(total_duration, DEC);
- // Serial.println(total_ticks, DEC);
- // Serial.println(d_avg_duration, DEC);
- // Serial.println(d_avg_ticks, DEC);
- // Serial.println(total_avg_duration, DEC);
- // Serial.println(total_avg_ticks, DEC);
- period_counter = 0;
- d_avg_duration = 0;
- d_avg_ticks = 0;
- ++avg_counter;
- if (avg_counter >= AVG_LENGTH)
- avg_counter = 0;
- }
- // Конвертация значений в физические единицы и вывод на экран
- String s1, s2, s3, s4;
- unsigned int consumption = 0;
- unsigned int avg_consumption = 0;
- unsigned int global_avg_consumption = 0;
- if (total_ticks > TICKS_TRESHOLD) {
- consumption = 10.0 * CONSUMPTION_FACTOR * total_duration / total_ticks;
- }
- if (total_avg_ticks > TICKS_TRESHOLD) {
- avg_consumption = 10.0 * CONSUMPTION_FACTOR * total_avg_duration / total_avg_ticks;
- }
- if (global_avg_ticks > TICKS_TRESHOLD) {
- global_avg_consumption = 10000.0 * CONSUMPTION_FACTOR * global_avg_duration / global_avg_ticks;
- }
- unsigned int hour_consumption = 10.0 * FUEL_FACTOR * total_duration * HOUR_PERIODS;
- unsigned int spd = RANGE_FACTOR * total_ticks * HOUR_PERIODS;
- s1 = String(total_duration, DEC);
- if (total_ticks > TICKS_TRESHOLD) {
- s1 = STR_CUR + format(consumption);
- // s1 = STR_HR + format(hour_consumption);
- // s1 = format(consumption);
- } else {
- // s1 = STR_CUR + STR_NA;
- // s1 = STR_HR + STR_NA;
- // s1 = "n/a ";
- s1 = STR_HR + format(hour_consumption);
- }
- if (total_avg_ticks > TICKS_TRESHOLD) {
- s2 = STR_AVG + format(avg_consumption);
- // s2 = STR_KM + format(avg_consumption);
- // s2 = format(avg_consumption);
- } else {
- s2 = STR_AVG + STR_NA;
- // s2 = STR_KM + STR_NA;
- // s2 = "n/a ";
- }
- if (global_avg_ticks > TICKS_TRESHOLD) {
- s4 = STR_GLOB + format(global_avg_consumption);
- } else {
- s4 = STR_GLOB + STR_NA;
- }
- byte gauge_level = round(float(hour_consumption) / 10.0);
- byte c1;
- byte c2;
- if (gauge_level > 8) {
- c1 = 7;
- c2 = gauge_level - 9;
- if (c2 > 7) c2 = 7;
- } else if (gauge_level > 0) {
- c1 = gauge_level - 1;
- c2 = ' ';
- } else {
- c1 = ' ';
- c2 = ' ';
- }
- // s2 = "hr: " + format(hour_consumption);
- // s2 = format(hour_consumption);
- // s3 = "sp: " + String(spd, DEC);
- // s3 = String(spd, DEC);
- // s3 = String(total_ticks, DEC);
- // int iters = 3 - s3.length();
- // int iters = 8 - s3.length();
- // for(int i = 0; i < iters; ++i)
- // s3 = " " + s3;
- // int iters2 = 8 - s1.length();
- // for(int i = 0; i < iters2; ++i)
- // s1 = " " + s1;
- // s3 += STR_KMH;
- lcd.setCursor(1,0);
- lcd.print( show_global ? s4 : s2 );
- if (show_global_counter > SHOW_GLOBAL_PERIODS) {
- show_global = !show_global;
- show_global_counter = 0;
- }
- show_global_counter++;
- lcd.setCursor(1,1);
- lcd.print(s1);
- lcd.setCursor(0, 1);
- lcd.print(c1);
- lcd.setCursor(0, 0);
- lcd.print(c2);
- total_duration = 0;
- total_ticks = 0;
- t = new_t + PERIOD;
- }
- }
- String format(unsigned int dec) {
- if (dec > 1000) return String("##.#");
- unsigned int intPart = dec / 10;
- unsigned int fracPart = dec % 10;
- String result = String(intPart, DEC) + "," + String(fracPart, DEC);
- int iters = 4 - result.length();
- for(int i = 0; i < iters; ++i)
- result = " " + result;
- return result;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement