Advertisement
Guest User

Consumption meter

a guest
Feb 12th, 2013
69
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 15.25 KB | None | 0 0
  1. #include <EEPROM.h>
  2. #include <LiquidCrystal.h>
  3.  
  4. #define LCD_RS_PIN 5
  5. #define LCD_ENABLE_PIN 6
  6. #define LCD_D4_PIN 7
  7. #define LCD_D5_PIN 8
  8. #define LCD_D6_PIN 9
  9. #define LCD_D7_PIN 10
  10.  
  11. #define LED_PIN 13 // Вывод со светодиодом
  12. #define BANDAP_PIN 14 // Эталонный вход АЦП
  13.  
  14. #define RESET_GLOBAL_PIN 2 // Номер ноги для кнопки сброса расхода
  15. #define SPEED_PIN 2 // Номер ноги для датчика скорости
  16. #define INJECTOR_PIN 3 // Номер ноги для форсунки
  17. #define CHECK_VOLTAGE_PIN A0 // Номер ноги, на которой измеряем напряжение для засекания отключения питания
  18.  
  19. #define PERIOD 1000000 // Период усреднения текущего расхода и обновления дисплея (микросекунды) - секунда
  20.  
  21. #define BANDAP_VOLTAGE 1.1 // Эталонное напряжение на 14 входе АЦП
  22. #define CRITICAL_VOLTAGE 3.0 // Напряжение, при котором начинаем быстренько записывать в EEPROM
  23.  
  24. #define IDLE_STROKE_DURATION 20000 // Суммарное время открытия форсунок (милисекунды) за период на холостом ходу
  25. #define IDLE_STROKE_HOUR_CONSUMPTION 0.7 // Часовой расход топлива на холостом ходу (литры в час)
  26. #define TEST_SPEED 60.0 // Контрольная скорость (километры в час) для расчёта коэффициента пробега
  27. #define TEST_TICKS 84 // Число импульсов с датчика скорости за период на контрольной скорости
  28.  
  29. #define HOUR_PERIODS ( 3600000000.0 / PERIOD ) // Число периодов в часу
  30. #define FUEL_FACTOR ( IDLE_STROKE_HOUR_CONSUMPTION / HOUR_PERIODS / IDLE_STROKE_DURATION ) // Коэффициент расхода топлива (литры) за период
  31. #define RANGE_FACTOR ( TEST_SPEED / TEST_TICKS / HOUR_PERIODS ) // Коэффициент пробега (километры) за период
  32. #define CONSUMPTION_FACTOR ( 100.0 * FUEL_FACTOR / RANGE_FACTOR ) // Коэффициент километрового расхода топлива (литры на 100 км)
  33.  
  34. #define TICKS_TRESHOLD 1 // Порог (импульсы датчика скорости) за период, выше которого можно считать километровый расход
  35. #define DURATION_CORR 0 // Поправка при измерении длительности времени открытия одной форсунки (микросекунды)
  36. #define AVG_LENGTH 10 // Число периодов для усреднения
  37.  
  38. #define AVG_REFRESH_TIME 1 // Время в часах, после которого сбрасывается усреднённый километровый расход, если не было сброса по расстоянию (1 час)
  39. #define AVG_REFRESH_LENGTH 0.1 // Расстояние в километрах, после которого сбрасывается усреднённый километровый расход (100 м)
  40. // #define AVG_REFRESH_PERIODS ( AVG_REFRESH_TIME * HOUR_PERIODS ) // Число периодов между обновлениями среднего расхода
  41. #define AVG_REFRESH_PERIODS 60 // Число периодов между обновлениями среднего расхода
  42. #define AVG_REFRESH_TICKS ( AVG_REFRESH_LENGTH / RANGE_FACTOR ) // Число импульсов датчика скорости между обновлениями среднего расхода
  43. #define SHOW_GLOBAL_PERIODS 3 // Число периодов между переключениями общего и среднего (за 10 минут) расхода
  44.  
  45. // Строковые константы
  46. // #define STR_AVG String(" Cp:")
  47. // #define STR_CUR String("M\xB4\xBD:")
  48.  
  49. // #define STR_HR String("\xAB\x61\x63:")
  50. #define STR_KM String(" K\xBC:")
  51.  
  52. #define STR_AVG String("Cp:")
  53. #define STR_CUR String("M\xB4:")
  54. #define STR_HR String(" \xAB:")
  55. #define STR_GLOB String("O\xB2:")
  56.  
  57. #define STR_NA String(" \xBD/\xE3")
  58. #define STR_KMH String("\xBA\xBC/\xC0")
  59.  
  60. LiquidCrystal lcd(LCD_RS_PIN, LCD_ENABLE_PIN, LCD_D4_PIN, LCD_D5_PIN, LCD_D6_PIN, LCD_D7_PIN);
  61.  
  62. unsigned long dur;
  63. unsigned long dur_t;
  64. unsigned long t;
  65.  
  66. boolean last_injector_state;
  67. boolean last_speed_state;
  68. boolean last_reset_global_state;
  69.  
  70. unsigned long total_duration;
  71. unsigned long total_ticks;
  72. unsigned long total_avg_duration;
  73. unsigned long total_avg_ticks;
  74. unsigned long d_avg_duration;
  75. unsigned long d_avg_ticks;
  76. unsigned long global_avg_duration;
  77. unsigned long global_avg_ticks;
  78. int period_counter;
  79. // int period_counter2;
  80.  
  81. boolean eeprom_already_written;
  82. boolean show_global;
  83. int show_global_counter;
  84.  
  85. // Структура, описывающая данные для усреднения
  86. struct consumption_data {
  87.   unsigned long duration;
  88.   unsigned long ticks;
  89. };
  90.  
  91. byte gauge_0[] = {
  92.   B00000000,
  93.   B00000000,
  94.   B00000000,
  95.   B00000000,
  96.   B00000000,
  97.   B00000000,
  98.   B00000000,
  99.   B11111111
  100. };
  101.  
  102. byte gauge_1[] = {
  103.   B00000000,
  104.   B00000000,
  105.   B00000000,
  106.   B00000000,
  107.   B00000000,
  108.   B00000000,
  109.   B11111111,
  110.   B11111111
  111. };
  112.  
  113. byte gauge_2[] = {
  114.   B00000000,
  115.   B00000000,
  116.   B00000000,
  117.   B00000000,
  118.   B00000000,
  119.   B11111111,
  120.   B11111111,
  121.   B11111111
  122. };
  123.  
  124. byte gauge_3[] = {
  125.   B00000000,
  126.   B00000000,
  127.   B00000000,
  128.   B00000000,
  129.   B11111111,
  130.   B11111111,
  131.   B11111111,
  132.   B11111111
  133. };
  134.  
  135. byte gauge_4[] = {
  136.   B00000000,
  137.   B00000000,
  138.   B00000000,
  139.   B11111111,
  140.   B11111111,
  141.   B11111111,
  142.   B11111111,
  143.   B11111111
  144. };
  145.  
  146. byte gauge_5[] = {
  147.   B00000000,
  148.   B00000000,
  149.   B11111111,
  150.   B11111111,
  151.   B11111111,
  152.   B11111111,
  153.   B11111111,
  154.   B11111111
  155. };
  156.  
  157. byte gauge_6[] = {
  158.   B00000000,
  159.   B11111111,
  160.   B11111111,
  161.   B11111111,
  162.   B11111111,
  163.   B11111111,
  164.   B11111111,
  165.   B11111111
  166. };
  167.  
  168. byte gauge_7[] = {
  169.   B11111111,
  170.   B11111111,
  171.   B11111111,
  172.   B11111111,
  173.   B11111111,
  174.   B11111111,
  175.   B11111111,
  176.   B11111111
  177. };
  178.  
  179. struct consumption_data data[AVG_LENGTH];
  180. int avg_counter;
  181.  
  182. void setup() {
  183.   // Serial.begin(9600);
  184.  
  185.   // Инициализация дисплея
  186.   lcd.begin(8, 2);
  187.  
  188.   // Загрузка пользовательских символов для отрисовки шкалы
  189.   lcd.createChar(0, gauge_0);
  190.   lcd.createChar(1, gauge_1);
  191.   lcd.createChar(2, gauge_2);
  192.   lcd.createChar(3, gauge_3);
  193.   lcd.createChar(4, gauge_4);
  194.   lcd.createChar(5, gauge_5);
  195.   lcd.createChar(6, gauge_6);
  196.   lcd.createChar(7, gauge_7);
  197.  
  198.   pinMode(INJECTOR_PIN, INPUT);
  199.   pinMode(SPEED_PIN, INPUT);
  200.   pinMode(RESET_GLOBAL_PIN, INPUT);
  201.   pinMode(CHECK_VOLTAGE_PIN, INPUT);
  202.   pinMode(LED_PIN, OUTPUT);
  203.  
  204.   digitalWrite(SPEED_PIN, HIGH);
  205.   digitalWrite(INJECTOR_PIN, HIGH);  
  206.   digitalWrite(RESET_GLOBAL_PIN, HIGH);
  207.  
  208.   last_injector_state = analogRead(INJECTOR_PIN) < 500;
  209.   last_speed_state = analogRead(SPEED_PIN) < 500;
  210.   last_reset_global_state = digitalRead(RESET_GLOBAL_PIN);
  211.  
  212.   // Инициализация данных для усреднения
  213.   for (int i=0; i < AVG_LENGTH; ++i) {
  214.     data[i].duration = 0;
  215.     data[i].ticks = 0;
  216.   }
  217.  
  218.   dur = 0;
  219.   dur_t = micros();
  220.   t = dur_t + PERIOD;
  221.  
  222.   total_duration = 0;
  223.   total_ticks = 0;
  224.   total_avg_duration = total_duration;
  225.   total_avg_ticks = total_ticks;
  226.   d_avg_duration = total_duration;
  227.   d_avg_ticks = total_ticks;
  228.  
  229.   for (int i = 0; i < sizeof(unsigned long int); ++i) {
  230.     *( (byte*)(&global_avg_duration) + i ) = EEPROM.read(i);
  231.   }
  232.  
  233.   int addr = sizeof(unsigned long int);
  234.  
  235.   for (int i = 0; i < sizeof(unsigned long int); ++i) {
  236.     *( (byte*)(&global_avg_ticks) + i ) = EEPROM.read(addr + i);
  237.   }
  238.  
  239.   /* global_avg_duration = 0;
  240.   global_avg_ticks = 0; */
  241.    
  242.   period_counter = 0;
  243. //   period_counter2 = 0;
  244.   avg_counter = 0;
  245.   show_global = false;
  246.   show_global_counter = 0;
  247.  
  248.   eeprom_already_written = true;
  249. }
  250.  
  251. void loop() {
  252.   float vcc_voltage = BANDAP_VOLTAGE * 1024 / analogRead(BANDAP_PIN);
  253.   float check_voltage = 5.0 * analogRead(CHECK_VOLTAGE_PIN) / 1024;
  254.  
  255. /*  boolean injector_state = analogRead(INJECTOR_PIN) < 500;
  256.   boolean speed_state = analogRead(SPEED_PIN) < 500;*/
  257.  
  258.   boolean injector_state = !digitalRead(INJECTOR_PIN);
  259.   boolean speed_state = digitalRead(SPEED_PIN);
  260.  
  261.   boolean reset_global_state = digitalRead(RESET_GLOBAL_PIN);
  262.   unsigned long new_t = micros();
  263.  
  264.   // if (vcc_voltage < CRITICAL_VOLTAGE) {
  265.   if (check_voltage < CRITICAL_VOLTAGE) {
  266.     if (!eeprom_already_written) {
  267.       digitalWrite(LED_PIN, HIGH);
  268.      
  269.       // Быстренько записываем в ПЗУ данные о среднем расходе
  270.      
  271.       for ( int i = 0; i < sizeof(unsigned long int); ++i ) {
  272.         EEPROM.write(i, *( (byte*)(&global_avg_duration) + i) );
  273.       }
  274.      
  275.       int addr = sizeof(unsigned long int);
  276.  
  277.       for ( int i = 0; i < sizeof(unsigned long int); ++i ) {
  278.         EEPROM.write(addr + i, *( (byte*)(&global_avg_ticks) + i) );
  279.       }
  280.      
  281.       eeprom_already_written = true;
  282.      
  283.       digitalWrite(LED_PIN, LOW);
  284.     }
  285.    
  286.   } else {
  287.     eeprom_already_written = false;
  288.   }
  289.  
  290.   // Вычисление мгновенных значений
  291.  
  292.   if (injector_state != last_injector_state) {
  293.     if (injector_state) {
  294.       dur = new_t - dur_t;
  295.       if (dur) dur += DURATION_CORR; // Поправочка
  296.       total_duration += dur;
  297.     } else {
  298.       dur_t = new_t;
  299.       dur = 0;
  300.     }
  301.    
  302.     last_injector_state = injector_state;
  303.   }
  304.  
  305.   if (speed_state != last_speed_state) {
  306.     total_ticks++;
  307.    
  308.     last_speed_state = speed_state;
  309.   }
  310.  
  311.   if (last_reset_global_state == HIGH && reset_global_state == LOW) {
  312.     global_avg_duration = 0;
  313.     global_avg_ticks = 0;
  314.    
  315.     digitalWrite(LED_PIN, HIGH);
  316.   }
  317.  
  318.   if (last_reset_global_state == LOW && reset_global_state == HIGH) {
  319.     digitalWrite(LED_PIN, LOW);
  320.   }
  321.  
  322.   last_reset_global_state = reset_global_state;
  323.  
  324.   // Действия, которые выполняются раз в секунду
  325.  
  326.   if (new_t >= t) {
  327.     if (!dur) {
  328.       dur = new_t - dur_t;
  329.       if (dur) dur += DURATION_CORR; // Поправочка
  330.       total_duration += dur;
  331.     }
  332.    
  333.     // Отладочная установка значений
  334.    
  335.     // total_duration = 100000;
  336.     // total_ticks = 56;
  337.    
  338.     d_avg_duration += total_duration;
  339.     d_avg_ticks += total_ticks;
  340.    
  341.     global_avg_duration += total_duration / 1000;
  342.     global_avg_ticks += total_ticks;
  343.    
  344.     ++period_counter;
  345.     // ++period_counter2;
  346.    
  347.     // if (d_avg_ticks >= AVG_REFRESH_TICKS || period_counter >= AVG_REFRESH_PERIODS) {
  348.     if (period_counter >= AVG_REFRESH_PERIODS) {
  349.       // Вычисление средних значений
  350.      
  351.       total_avg_duration += d_avg_duration;
  352.       total_avg_duration -= data[avg_counter].duration;
  353.      
  354.       total_avg_ticks += d_avg_ticks;
  355.       total_avg_ticks -= data[avg_counter].ticks;
  356.            
  357.       data[avg_counter].duration = d_avg_duration;
  358.       data[avg_counter].ticks = d_avg_ticks;
  359.  
  360. //      total_avg_duration = 0;
  361. //      total_avg_ticks = 0;
  362.      
  363. //      for (int i = 0; i < AVG_LENGTH; ++i) {
  364. //        total_avg_duration += data[i].duration;
  365. //        total_avg_ticks += data[i].ticks;
  366. //      }
  367.      
  368.       // Отладочный вывод
  369.       // Serial.println(total_duration, DEC);
  370.       // Serial.println(total_ticks, DEC);
  371.       // Serial.println(d_avg_duration, DEC);
  372.       // Serial.println(d_avg_ticks, DEC);
  373.       // Serial.println(total_avg_duration, DEC);
  374.       // Serial.println(total_avg_ticks, DEC);
  375.      
  376.       period_counter = 0;
  377.       d_avg_duration = 0;
  378.       d_avg_ticks = 0;
  379.  
  380.       ++avg_counter;
  381.       if (avg_counter >= AVG_LENGTH)
  382.         avg_counter = 0;
  383.     }
  384.    
  385.     // Конвертация значений в физические единицы и вывод на экран
  386.  
  387.     String s1, s2, s3, s4;
  388.     unsigned int consumption = 0;
  389.     unsigned int avg_consumption = 0;
  390.     unsigned int global_avg_consumption = 0;
  391.    
  392.     if (total_ticks > TICKS_TRESHOLD) {
  393.       consumption = 10.0 * CONSUMPTION_FACTOR * total_duration / total_ticks;
  394.     }
  395.  
  396.     if (total_avg_ticks > TICKS_TRESHOLD) {
  397.       avg_consumption = 10.0 * CONSUMPTION_FACTOR * total_avg_duration / total_avg_ticks;
  398.     }
  399.  
  400.     if (global_avg_ticks > TICKS_TRESHOLD) {
  401.       global_avg_consumption = 10000.0 * CONSUMPTION_FACTOR * global_avg_duration / global_avg_ticks;
  402.     }
  403.    
  404.     unsigned int hour_consumption = 10.0 * FUEL_FACTOR * total_duration * HOUR_PERIODS;
  405.     unsigned int spd = RANGE_FACTOR * total_ticks * HOUR_PERIODS;
  406.    
  407.     s1 = String(total_duration, DEC);
  408.  
  409.     if (total_ticks > TICKS_TRESHOLD) {
  410.       s1 = STR_CUR + format(consumption);
  411.       // s1 = STR_HR + format(hour_consumption);
  412.       // s1 = format(consumption);
  413.     } else {
  414.       // s1 = STR_CUR + STR_NA;
  415.       // s1 = STR_HR + STR_NA;
  416.       // s1 = "n/a ";
  417.       s1 = STR_HR + format(hour_consumption);
  418.     }
  419.  
  420.     if (total_avg_ticks > TICKS_TRESHOLD) {
  421.       s2 = STR_AVG + format(avg_consumption);
  422.       // s2 = STR_KM + format(avg_consumption);
  423.       // s2 = format(avg_consumption);
  424.     } else {
  425.       s2 = STR_AVG + STR_NA;
  426.       // s2 = STR_KM + STR_NA;
  427.       // s2 = "n/a ";
  428.     }
  429.  
  430.     if (global_avg_ticks > TICKS_TRESHOLD) {
  431.       s4 = STR_GLOB + format(global_avg_consumption);
  432.     } else {
  433.       s4 = STR_GLOB + STR_NA;
  434.     }
  435.    
  436.     byte gauge_level = round(float(hour_consumption) / 10.0);
  437.     byte c1;
  438.     byte c2;
  439.    
  440.     if (gauge_level > 8) {
  441.        c1 = 7;
  442.        c2 = gauge_level - 9;
  443.        if (c2 > 7) c2 = 7;
  444.     } else if (gauge_level > 0) {
  445.       c1 = gauge_level - 1;
  446.       c2 = ' ';
  447.     } else {
  448.       c1 = ' ';
  449.       c2 = ' ';
  450.     }
  451.    
  452.     // s2 = "hr: " + format(hour_consumption);
  453.     // s2 = format(hour_consumption);
  454.    
  455.     // s3 = "sp: " + String(spd, DEC);
  456.     // s3 = String(spd, DEC);
  457.     // s3 = String(total_ticks, DEC);
  458.    
  459.     // int iters = 3 - s3.length();
  460.     // int iters = 8 - s3.length();
  461.    
  462.     // for(int i = 0; i < iters; ++i)
  463.     //  s3 = " " + s3;
  464.      
  465.     // int iters2 = 8 - s1.length();
  466.    
  467.     // for(int i = 0; i < iters2; ++i)
  468.     //  s1 = " " + s1;
  469.    
  470.     // s3 += STR_KMH;
  471.    
  472.     lcd.setCursor(1,0);
  473.     lcd.print( show_global ? s4 : s2 );
  474.    
  475.     if (show_global_counter > SHOW_GLOBAL_PERIODS) {
  476.       show_global = !show_global;
  477.       show_global_counter = 0;
  478.     }
  479.    
  480.     show_global_counter++;
  481.    
  482.     lcd.setCursor(1,1);
  483.     lcd.print(s1);
  484.    
  485.     lcd.setCursor(0, 1);
  486.     lcd.print(c1);
  487.  
  488.     lcd.setCursor(0, 0);
  489.     lcd.print(c2);
  490.        
  491.     total_duration = 0;
  492.     total_ticks = 0;
  493.     t = new_t + PERIOD;
  494.   }
  495. }
  496.  
  497. String format(unsigned int dec) {
  498.   if (dec > 1000) return String("##.#");
  499.  
  500.   unsigned int intPart = dec / 10;
  501.   unsigned int fracPart = dec % 10;
  502.   String result = String(intPart, DEC) + "," + String(fracPart, DEC);
  503.  
  504.   int iters = 4 - result.length();  
  505.   for(int i = 0; i < iters; ++i)
  506.     result = " " + result;
  507.  
  508.   return result;
  509. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement