Спасибо.
Подправил
Спасибо.
Подправил
11111
Последний раз редактировалось Oleg_33; 07.11.2015 в 18:54.
Итак...нынче закончил с индикатором включённой передачи, работать он будет с резистивным датчиком (ДПДЗ от ВАЗа) если кому интересно есть одна из записок сумашедшего по этому поводу, хоть как то поясняющая как это работает. https://yadi.sk/i/ZHWqcPxlkJozf
Аналогичное меню калибровки изображенное на мятом листе, предстанет взору на LCD дисплее если всё таки начать калибровку ...
Так же индикатор передачи имеет блинкер, который начинает блинковыть через заданное время, напоминая, что пора бы переключить передачу, активирован на 3 и 4 передаче. С этим блинкером было не всё так просто, отдельный код с таймером написаный отдельно прекрасно работал, однако если его добавить в основной код получались тормоза - слишком много было вызовов millis в разных участках кода. Решил переделать и сделать один таймер для всего, изменить пришлось не маленькую часть кода. Индикатор резерва (мигающий прямоугольник, видно на видео) тоже мигает через отдельный вызов таймера
Видео - https://youtu.be/P9oFztnLAIU
Вот с этим кодом воевал дня 4 по вечерам , это конечно вершина айсберга, сами таймеры работаю тихо себе не заметно.
PHP код:
void _gear_switch_send(){
if (gear_first_start == 1) {
static byte g;
switch (GEAR_CURENT) {
case GEAR_3:
if (g != GEAR_3) {
time_gear_blinker = 0;
g = GEAR_3;
}
if (time_gear_blinker > timer_gear3) {
_Wire_Send(GEAR_3_BLINK);
}
else _Wire_Send(GEAR_3);
break;
case GEAR_4:
if (g != GEAR_4) {
time_gear_blinker = 0;
g = GEAR_4;
}
if (time_gear_blinker > timer_gear4) {
_Wire_Send(GEAR_4_BLINK);
}
else _Wire_Send(GEAR_4);
break;
default:
_Wire_Send(GEAR_CURENT);
g = GEAR_CURENT;
}
}
}
Последний раз редактировалось Chip; 09.11.2015 в 20:36.
Возник нюанс с классами, как мне это провернуть ?
PHP код:
class CppStudio {
public:
void message() {
byte numder = numder ++;
}
};
void setup() {}
void loop() {
CppStudio objMessage;
objMessage.message();
// Как получить значение numder, не декларируя переменную в глобальную ?
}
Что именно нужно провернуть?
В коде комментарий, как в этом месте кода получить значение numder, не декларируя переменную в глобальную ?
Компилятор выдаёт ошибку error: 'numder' was not declared in this scope 'numder' was not declared in this scope
Кстати код готов, остались не значительные мелочи, можно лицезреть ... объективная критика приветствуется
PHP код:
#include <EEPROM.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "RTClib.h"
// Префикс ( с )-const означает константы только в разделе настроек, далее в коде ( d )-define, остальные префиксы образованы от первой буквы
// или аббревиатуры типа данных переменной.
// Пины Ардуины не имеют прификса, принадлежность к пинам отражена в названии
//
// Настройки
#define cADDRESS_OF_SLAVE 0x7d // адрес ардуины - SLAVE, индикатор включённой скорости. У обоих ардуино обязательно должно быть общее питание +5В!
#define cTIME_MAIN_LOOP 2000 //mc, таймер запуска функций мониторинга
#define cARITHMETIC_AVERAGE_RATIO 10 // Средне арифметический коэффициент, уровня топлива в баке.
// интервал считывания уровня топлива в мили секундах = cTIME_MAIN_LOOP * cARITHMETIC_AVERAGE_RATIO
#define cTIMER_BLINK_FUEL 250 //мс, время одного соcтояния индикатора резерва
#define cTIMER_BLINK_TRIP 500 //
#define cTIMER_GEAR3 10 /2 // сек/2 блинкер третьей передачи, через сколько секунд индикатор начнёт мигать
#define cTIMER_GEAR4 15 /2 // сек/2 блинкер четвертой передачи, через сколько секунд индикатор начнёт мигать
#define cMIN_ABC_FUEL_LEVEL 0 // АЦП минимального показания датчика уровня топлива (устанавливается подстроеччным резистором) можно расчитать Uдатчика / 0.0048828125
#define cMAX_ABC_FUEL_LEVEL 1010// 238 // АЦП максимального показания датчика уровня топлива, расчитывается: Uдатчика / 0.0048828125
#define cADC_LIMIT_FUEL_LEVEL 1000 // Максимальный лимит АЦП датчика уровня топлива!
#define cTEMP_SNOW 4 // Tемпература при которой появится снежинка вместо градусника на дисплее
#define cCOEF_ABC_VOLT 0.03107 // Коэфициент АЦП контроля напряжения бортовой сети
#define cLOW_VOLTAGE 12 // Минимальное напряжение в борт сети до предупреждения
#define cHIGH_VOLTAGE 15 // Максимальное напряжение в борт сети до предупреждения
#define cSTART_ODOMETR 2000 // По истечения скольки импульсов ничинает считать время в пути, максимальное значение в dPULSES_TO_METERS
#define cENGINE_COLD 40 // Температура при которой с дисплея исчезнет символ " ! ", означающий что двигатель прогрелся
#define cTIMER_DELAY_EXIT 1000 * 1 // Сколько секунд микроконтроллер остаётся включённым, после отключения питания с IGN_ON__ANALOG_PIN
#define cERROR_TEMP_OIL 100 // Максимальная температура масла до предумпреждения
//
//
// Выводы платы ************************************************************************************************
// 0 Внешнее прерывание, датчик скорости 5 вольт *
// 1 *
// 2 // I2C *
// 3 // I2C *
#define GEAR_NEITRAL__DIGITAL_PIN 4 // Минус при включении нейтрали *
#define FAN_CONTROL_RUN__DIGITAL_PIN 5 // Минус при включении вентилятора *
// 6 *
// 7 Внещнее прерывание *
// 8 *
#define MONITOR_BRIGHTNESS__DIGITAL_PIN 9 // Яркость дисплея, ШИМ *
#define DS18B20_TEMP 10 // Сигнальный провод датчиков DS18B20 *
#define FAN_RELAY__DIGITAL_PIN 11 // Реле CH1 - включение реле вентилятора охлаждения *
#define RELAY_DELAY__DIGITAL_PIN 12 // Реле CH2 - задержка выключения *
#define LED_ERROR__DIGITAL_PIN 13 // Светодиод неисправности *
// *
#define FUEL_LEVEL__ANALOG_PIN 0 // Датчик уровня топлива *
#define GEAR__ANALOG_PIN 1 // Датчик положения передачи *
#define MONITOR_5VDC__ANALOG_PIN 2 // Контроль DC преобразователя, 5В *
// 3 // *
#define MENU_BUTTON__ANALOG_PIN 4 // Делитель напряжения *
#define IGN_ON__ANALOG_PIN 5 // Плюс при включении зажигания,контроль напряжения *
// *************************************************************************************************************
// Внешнее прерывание
//**********************************************************
//Leonardo-Pin * 3 * 2 * 0 * 1 * 7 *
//Номер прерывания * int.0 * int.1 * int.2 * int.3 * int.4 *
//**********************************************************
#define dINTERRUPT_SPEED 2
#define dINTERRUPT_BUTTON 4
// Массив с настройками для сохраниения в панять
#define UBOUND_EEPROM_ARRAY 14
int aEEPROM_DATA[UBOUND_EEPROM_ARRAY];
/*
0 - вентилятор отключение,
1 - вентилятор включение
2 - перегрев
3 - по температуре окр. воздуха
4 - уровень топлива проценты или литры
5 - ? температура включения вентилятора в зависимости от температуры [7]
6 - яркость дисплея
7 - коррекция температуры окр. воздуха
8 - коррекция темературы двигателя
9 - ацп нейтрали
10 - ацп верхней точки
11 - ацп нижней точки
12 - коррекция темературы масла
13 - ?
*/
int aExpon[UBOUND_EEPROM_ARRAY] = {
2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28};
//Дисплей
//Кастомные символы
uint8_t temp_ico[8] = {
B00100, B01010, B01010, B01110, B11111, B11111, B01110};
uint8_t akb1[8] = {
B00100, B11111, B10010, B10111, B10010, B10000, B11111};
uint8_t akb2[8] = {
B00100, B11111, B00001, B11101, B00001, B00001, B11111};
uint8_t fuel_empty[8] = {
B11111, B00000, B00000, B00000, B00000, B00000, B11111};
uint8_t fuel[8] = {
B11111, B11111, B11111, B11111, B11111, B11111, B11111};
uint8_t temp[8] = {
B00110, B01001, B01001, B00110, B00000, B00000, B00000};
#if defined(ARDUINO) && ARDUINO >= 100
#define printByte(args) write(args);
#else
#define printByte(args) print(args,BYTE);
#endif
//
LiquidCrystal_I2C lcd(0x27, 16, 2);
// RTC timer
RTC_DS1307 RTC;
//System Timer
unsigned long ulTimer_one_trip;
byte bDelay_exit;
unsigned long ulMillis_delay_exit;
byte bTimer_first_action;
//FAN, OUT_TEMP - DALLAS TEMPERATYRE
byte bRELAY_CURENT; // Текущее состояние реле
int iTEMP_CURENT_ENGIN; // Температура двигателя
int iOUT_TEMP_CURENT; // Температура наружного воздуха
int iOIL_TEMP_CURENT; // Температура масла
int tO, tE, tOil; // Промежуточные значения
OneWire oneWire(DS18B20_TEMP);
DallasTemperature ds(&oneWire);
DeviceAddress Thermometer1 = {
0x28, 0xFF, 0x34, 0x17, 0x52, 0x14, 0x00, 0x8E};
DeviceAddress Thermometer2 = {
0x28, 0xFF, 0xF9, 0x8B, 0x52, 0x14, 0x00, 0xB3};
DeviceAddress Thermometer3 = {
0x28, 0xFF, 0xF9, 0x8B, 0x52, 0x14, 0x00, 0xB3}; // Масло
// Константы для вывода ошибки на дисплей
#define dSYSTEM_ERROR_LOW_VOLTAGE 1
#define dSYSTEM_ERROR_HIGH_VOLTAGE 2
#define dSYSTEM_ERROR_HIGH_TEMPERARURE 3
#define dSYSTEM_ERROR_HIGH_TEMPERARURE_OIL 4
byte bSYSTEM_ERROR = 0; // прерывание цикла дисплея если ошибка в системе, 0 - нет ошибок
// Меню
#define dBUTTON_RESET_ERROR 670 // АЦП кнопок меню
#define dBUTTON_MENU 400
#define dBUTTON_DUBLE 337
#define dBUTTON_NOT_PRESSED 1023
byte bBOUNCE_BUTTON_RESET_ERROR, bBOUNCE_BUTTON_MENU; // Для исключения переключения меню при удержании кнопки, дребезга контактов.
byte bKEY; // Код нажатой клавиши, срабатыввает при отпускании кнопки
byte bMENU_ACTIV; // При нажатии на кнопку KEY_MENU_LIST - bMENU_ACTIV = 1, KEY_MENU_OK - bMENU_ACTIV = 0
byte bDISPLAY_2;
//
byte bINDEX_MENU; // Номер страницы меню
#define dMENU_ITEM_OIL_TEMP 1
#define dMENU_ITEM_ENG_TEMP 2
#define dMENU_ITEM_BATT 3
#define dMENU_ITEM_FAN_MANUAL 4 // 1 - 4 Выход из меню двумя кнопками без сохранения в eeprom
#define dMENU_ITEM_DISPLAY_BRIGHTNESS 5 // 5 ... Выход из меню двумя кнопками c сохранением в eeprom
#define dMENU_ITEM_COR_OIL_TEMP 6
#define dMENU_ITEM_COR_OUT_TEMP 7
#define dMENU_ITEM_COR_ENG_TEMP 8
#define dMENU_ITEM_FAN_ON 9
#define dMENU_ITEM_FAN_OFF 10
#define dMENU_ITEM_ERROR_TEMP 11
#define dMENU_ITEM_FUEL_PERSENT_AND_LITER 12
#define dMENU_ITEM_CALIBR_GEAR_POS 13
//#define 14
#define dMENU_ITEM_END 15
byte menu_gear_calibration; // Многоуровневое меню калибровки передач
byte fan_manual = 0; // Ручное включение вентилятора из меню
byte persent_and_liter; // Проценты или литры на главном экране
byte DISPLAY_BRIGHTNESS; // Яркость дисплея 0 - 255
//Контроль напряжения
byte bSYSTEM_VOLTAGE;
float fDIS_SYSTEM_VOLTAGE; // Вывод на дисплей
byte bDC_VOLTAGE; // Контроль напряжения 5в линии DC преобразователя
// Константы вентилятора охлаждения
#define dLOW_COLING_FAN 2
#define dHIGH_COLING_FAN 3
#define dERROR_COLING_FAN 4
// Уровень топлива
byte bFUEL_LEVEL = 101, bIndex_mean;
int iArithmetic_mean; // Средне арифметическое уровня топлива
// Пройдения дистанция
boolean bolOdometr_menu_blink; // Мигание пустых делений, времени в пути
byte bOdometr_one_run;
volatile word vwDistance_one_trip; // +1 с каждым внешним прерыванием
#define dPULSES_TO_METERS 5625 // 5625 импульсов - 100 метров
volatile word vwInteger, vwAfter_point; // Делим число TRIP на две части (vwInteger.vwAfter_point)
//Индикатор включенной передачи
int iUP_GEAR, iN_GEAR, iDOWN_GEAR;
byte bGEAR_CURENT = 1;
int iUp_or_down = 1;
byte bGear_first_start = 0;
boolean fb;
byte time_gear_blinker;
// Константы для передачи значения включённой передачи по i2c шине.
#define dGEAR_H 0
#define dGEAR_1 1
#define dGEAR_2 2
#define dGEAR_3 3
#define dGEAR_4 4
#define dGEAR_5 5
#define dGEAR_H_BLINK 6
#define dGEAR_3_BLINK 7
#define dGEAR_4_BLINK 8
#define dGEAR_5_BLINK 9
//_______________________________________________________________________________________________________________
boolean bolTimer_state1, bolTimer_state2, bolTimer_state3, bolTimer_state4;
class _ClassTimer
{
// Переменные - члены класса
// Инициализируются при запуске
int number_timer; // номер таймера
long OnTime; // время включения в миллисекундах
long OffTime; // время, когда светодиод выключен
// Текущее состояние
int timer_state; // состояние ВКЛ/ВЫКЛ
unsigned long previousMillis; // последний момент смены состояния
// Конструктор создает экземпляр _ClassTimer и инициализирует
// переменные-члены класса и состояние
public:
_ClassTimer(int timer, long on, long off)
{
number_timer = timer;
pinMode(number_timer, OUTPUT);
OnTime = on;
OffTime = off;
timer_state = LOW;
previousMillis = 0;
}
int Update()
{
unsigned long currentMillis = millis(); // текущее время в миллисекундах
if ((timer_state == HIGH) && (currentMillis - previousMillis >= OnTime))
{
timer_state = LOW; // выключаем
previousMillis = currentMillis; // запоминаем момент времени
if (number_timer == 1) bolTimer_state1 = !bolTimer_state1;
else if (number_timer == 2) bolTimer_state2 = !bolTimer_state2;
else if (number_timer == 3) bolTimer_state3 = !bolTimer_state3;
else if (number_timer == 4) bolTimer_state4 = !bolTimer_state4;
}
else if ((timer_state == LOW) && (currentMillis - previousMillis >= OffTime))
{
timer_state = HIGH; // выключаем
previousMillis = currentMillis ; // запоминаем момент времени
}
}
};
// Устанавливаем параметры для таймера
_ClassTimer TimeR1(1, cTIME_MAIN_LOOP, cTIME_MAIN_LOOP); // Таймер считывания функций мониторинга
_ClassTimer Timer2(2, cTIMER_BLINK_TRIP, cTIMER_BLINK_TRIP); // TRIP мигание пустых делений
_ClassTimer Timer3(3, cTIMER_BLINK_FUEL, cTIMER_BLINK_FUEL); // Резерв топлива
_ClassTimer Timer4(4, 1000, 1000); // Таймер блинкера передач, счётчик приращения (time_gear_blinker) работает только по ВКЛЮЧЕНИЮ таймера
void setup() {
attachInterrupt(dINTERRUPT_SPEED, _Interrupt_Speed, FALLING); // FALLING HIGH -> LOW
//attachInterrupt(dINTERRUPT_BUTTON, _Interrupt_Button, FALLING ); // FALLING HIGH -> LOW
pinMode(FAN_RELAY__DIGITAL_PIN, OUTPUT);
digitalWrite(FAN_RELAY__DIGITAL_PIN, !LOW);
pinMode(RELAY_DELAY__DIGITAL_PIN, OUTPUT);
digitalWrite(RELAY_DELAY__DIGITAL_PIN, LOW);
pinMode(GEAR_NEITRAL__DIGITAL_PIN, INPUT); // Минус при включении нейтрали
digitalWrite(GEAR_NEITRAL__DIGITAL_PIN, HIGH);
pinMode(FAN_CONTROL_RUN__DIGITAL_PIN, INPUT); // Минус при включении вентилятора
digitalWrite(FAN_CONTROL_RUN__DIGITAL_PIN, HIGH);
pinMode(MONITOR_BRIGHTNESS__DIGITAL_PIN, OUTPUT); // Яркость дисплея
pinMode(LED_ERROR__DIGITAL_PIN, OUTPUT); // Светодиод неисправности
pinMode(FUEL_LEVEL__ANALOG_PIN, INPUT);
Serial.begin(9600);
Wire.begin();
RTC.begin();
lcd.init();
lcd.backlight();
lcd.createChar(1, temp_ico);
lcd.createChar(2, akb1);
lcd.createChar(3, akb2);
lcd.createChar(4, fuel);
lcd.createChar(5, temp);
lcd.createChar(6, fuel_empty);
for (int i = 0; i <= (UBOUND_EEPROM_ARRAY - 1); i++)aEEPROM_DATA[i] = _eeprom_read(aExpon[i]);
//Заполняем переменные из памяти
persent_and_liter = aEEPROM_DATA[4];
iUP_GEAR = aEEPROM_DATA[13];
iN_GEAR = aEEPROM_DATA[9];
iDOWN_GEAR = aEEPROM_DATA[11];
if (aEEPROM_DATA[6] < 10) DISPLAY_BRIGHTNESS = 255;
else DISPLAY_BRIGHTNESS = aEEPROM_DATA[6];
}
void loop() {
TimeR1.Update();
Timer2.Update();
Timer3.Update();
Timer4.Update();
if (bolTimer_state1 == false) { // Таймер считывания функций мониторинга
//Serial.println("bolTimer_state1");
if (bTimer_first_action == 0) { // Первый запуск
bTimer_first_action = 1;
for (int i = 0; i <= cARITHMETIC_AVERAGE_RATIO + 1; i++) _fuel_level();
}
_delay_read_sensor();
bolTimer_state1 = !bolTimer_state1;
}
if (bolTimer_state2 == false) {
//Serial.println("bolTimer_state2"); // TRIP мигание пустых делений
bolTimer_state2 = !bolTimer_state2;
}
if (bolTimer_state3 == false) { // Резерв топлива
fb = !fb;
//_fuel_level_blink();
//Serial.println("bolTimer_state3");
bolTimer_state3 = !bolTimer_state3;
}
if (bolTimer_state4 == false) { // Таймер блинкера передач
time_gear_blinker ++;
bolTimer_state4 = !bolTimer_state4;
}
if (! RTC.isrunning()) {
//Serial.println("RTC is NOT running!");
RTC.adjust(DateTime(__DATE__, __TIME__));
}
analogWrite(MONITOR_BRIGHTNESS__DIGITAL_PIN, DISPLAY_BRIGHTNESS);
ds.requestTemperatures(); // считываем температуру с датчиков температуры
iOUT_TEMP_CURENT = ds.getTempC(Thermometer2) - aEEPROM_DATA[7] + 5; // Температуру окр.воздуха
iTEMP_CURENT_ENGIN = ds.getTempC(Thermometer1) - aEEPROM_DATA[8] + 5; // Температуру двигателя
iOIL_TEMP_CURENT = ds.getTempC(Thermometer1) - aEEPROM_DATA[12] + 5; // Температуру масла
bSYSTEM_VOLTAGE = analogRead(IGN_ON__ANALOG_PIN) * cCOEF_ABC_VOLT ;
//bDC_VOLTAGE = analogRead(MONITOR_5VDC__ANALOG_PIN);
if (bMENU_ACTIV == 0) _input_dusplay_SUSTEM_ERROR(bSYSTEM_ERROR);// Обрабатываем переменную bSYSTEM_ERROR, выводим сообщение на дисплей
_gear_switch(); // записываем в bGEAR_CURENT текущую передачу
if (vwDistance_one_trip > cSTART_ODOMETR) bOdometr_one_run = 1;
DateTime now = RTC.now();
if (ulTimer_one_trip == 0 && vwDistance_one_trip > cSTART_ODOMETR) ulTimer_one_trip = ( ((23 - now.hour()) * 3600) + ((59 - now.minute()) * 60) + (60 - now.second()) );
DateTime future (now.unixtime() + ulTimer_one_trip);
static long g = 100500; // Зачем здесь это ? +100500 баллов за внимательность :)!
// Включённая передача
// Нейтральная передача не изменяет номер передачи в bGEAR_CURENT, она является лишь "маской"
if (bGear_first_start == 0 && digitalRead(GEAR_NEITRAL__DIGITAL_PIN) == HIGH) _Wire_Send(dGEAR_H_BLINK);
if (digitalRead(GEAR_NEITRAL__DIGITAL_PIN) == LOW) {
_Wire_Send(dGEAR_H);
g = dGEAR_H;
bGear_first_start = 1; // Сигнал к началу индикации передач
}
else {
if (g == dGEAR_H && bGEAR_CURENT == dGEAR_3) bGEAR_CURENT = 2; // Эмулируем выход из нейтрали на вторую передачу.
else {
_gear_switch_send(); // запускаем счётчик передач, отправляем в порт номер передачи
g = 100500;
}
}
_treat_abc_button(); //Считываем нажатую клавишу
_delay_exit(); // Задержка выключения
_menu_lcd();
// ------------------------------------------------------------ Главный экран --------------------------------------------------------
if (bSYSTEM_ERROR == 0 && bMENU_ACTIV == 0) { // Если нет ошибок и статус меню не активно! выводм текшие данные на дисплей
if (bDISPLAY_2 == 1) { // Дисплей 2
char ch_trip[15], ch_time[10];
sprintf(ch_time, "%i:%02i:%02i ", now.hour(), now.minute(), now.second());
lcd.setCursor(0, 0);
lcd.print(ch_time);
lcd.setCursor(0, 1);
sprintf(ch_trip, "%s - %i.%i ", "Trip", vwInteger, vwAfter_point);
lcd.print(ch_trip);
for (int i = 0; i <= cARITHMETIC_AVERAGE_RATIO + 1; i++) _fuel_level(); // Обновляем уровень топлива без задержки
}
else { // Основной дисплей
char ch_ch[5];
lcd.setCursor(12, 1);
if (aEEPROM_DATA[4] == 1) { // Литры
sprintf(ch_ch, "%01i%s", _persent_to_liter(), "L");
lcd.print(ch_ch);
_Fuel_Progress_Bar();
}
else { // Проценты
sprintf(ch_ch, "%03i%s", bFUEL_LEVEL, "%");
lcd.print(ch_ch);
_Fuel_Progress_Bar();
}
char ch_time[10];
//if (bOdometr_one_run == 0 && stat_timer1 == !LOW) { // Отображаем на дисплее пустые деления
// if (bolOdometr_menu_blink == true) {lcd.setCursor(0, 0);lcd.print("-:--:--");}
// else if (bolOdometr_menu_blink == false) {lcd.setCursor(0, 0); lcd.print(" ");}
// bolOdometr_menu_blink = !bolOdometr_menu_blink;
// stat_timer1 = !stat_timer1;
// }
//else
if (bOdometr_one_run == 1) { // Запускаем таймер
sprintf(ch_time, "%i:%02i:%02i", future.hour(), future.minute(), future.second());
lcd.setCursor(0, 0);
lcd.print(ch_time);
_voltage_scan(bSYSTEM_VOLTAGE); // Считываем напряжение, записываем в переменную bSYSTEM_ERROR статус системы
}
lcd.setCursor(10, 0); // 10 символ, если включен вентилятор
if (digitalRead(FAN_CONTROL_RUN__DIGITAL_PIN) == LOW) lcd.print("F");
else lcd.print(" ");
lcd.setCursor(11, 0); // 11 символ, двигатель не прогрет
if (iTEMP_CURENT_ENGIN < cENGINE_COLD) lcd.print("!");
else lcd.print(" ");
lcd.setCursor(12, 0); // 12 ... символ, температура наружного воздуха
if (tO > cTEMP_SNOW) lcd.write(1); //t
else if (tO <= cTEMP_SNOW) lcd.print("*"); //*
lcd.print(tO);
lcd.write(5);
}
}
}
//Функции ****************************************************************************************************************************************************************
// Функции состоящие из прописных букв запускаются только в одном участке кода
//void _Interrupt_Button() {
//}
void _delay_read_sensor() {
tE = iTEMP_CURENT_ENGIN;
tO = iOUT_TEMP_CURENT;
tOil = iOIL_TEMP_CURENT;
if (bINDEX_MENU != dMENU_ITEM_FAN_MANUAL) _engine_temp_monitoring(iTEMP_CURENT_ENGIN);// Считываем температуру, включаем или выключаем реле- функцией _RelayColingFan
// Если активен пунк меню dMENU_ITEM_FAN_MANUAL не запускаем функцию, во избежании постоянного переключения реле!
_oil_temp_monitoring(iOIL_TEMP_CURENT);
fDIS_SYSTEM_VOLTAGE = analogRead(IGN_ON__ANALOG_PIN) * cCOEF_ABC_VOLT ; // Считываем для дисплея напряжение в формате 10.00
_fuel_level();
}
void _treat_abc_button() {
bKEY = _read_button_key(analogRead(MENU_BUTTON__ANALOG_PIN)); // Считываем АЦП входа, обрабатываем нажатую кнопку
Serial.println(analogRead(MENU_BUTTON__ANALOG_PIN));
if (bKEY == 1) { // dBUTTON_RESET_ERROR кнопка сброса ошибок
if (bSYSTEM_ERROR) { // Если была ошибка, сбрасываем
bSYSTEM_ERROR = 0;
digitalWrite(LED_ERROR__DIGITAL_PIN, LOW); // Выключаем светодиод ошибки
lcd.clear();
bDISPLAY_2 = 0;
}
else if (bSYSTEM_ERROR == 0 && bMENU_ACTIV == 0) { // Отображаем дополнительное меню
bDISPLAY_2 = 1;
lcd.clear();
}
}
else if (bKEY == 2) { // dBUTTON_MENU
if (bDISPLAY_2 == 1) {
bMENU_ACTIV = 0;
bDISPLAY_2 = 0;
lcd.clear();
}
else if (bDISPLAY_2 == 0) {
bMENU_ACTIV = 1;
lcd.clear();
bDISPLAY_2 = 0;
}
}
}
int _read_button_key(int key) {
if (key > dBUTTON_RESET_ERROR && key < dBUTTON_RESET_ERROR + 40) bBOUNCE_BUTTON_RESET_ERROR = 1;
else if (key > dBUTTON_MENU && key < dBUTTON_MENU + 40) bBOUNCE_BUTTON_MENU = 1;
else if (key > dBUTTON_DUBLE && key < dBUTTON_DUBLE + 40) {
bBOUNCE_BUTTON_RESET_ERROR = 0;
return 3;
}
if (analogRead(MENU_BUTTON__ANALOG_PIN) == dBUTTON_NOT_PRESSED && bBOUNCE_BUTTON_RESET_ERROR + bBOUNCE_BUTTON_MENU == 1) { // Исли ацп = 1023 и нажата хоть одна кнопка
if (bBOUNCE_BUTTON_RESET_ERROR == 1) {
bBOUNCE_BUTTON_RESET_ERROR = 0;
return 1;
}
else if (bBOUNCE_BUTTON_MENU == 1) {
bBOUNCE_BUTTON_MENU = 0;
return 2;
}
}
}
void _delay_exit() {
if (analogRead(IGN_ON__ANALOG_PIN) > 100 && bDelay_exit == 2) {
bDelay_exit == 0;
ulMillis_delay_exit = millis() + cTIMER_DELAY_EXIT;
lcd.setCursor(9, 0);
lcd.print(" ");
}
if (analogRead(IGN_ON__ANALOG_PIN) < 100) { // Напряжение на контрольном пине упало до нуля
if (bSYSTEM_ERROR == 0 && bMENU_ACTIV == 0) {
lcd.setCursor(9, 0);
lcd.print("E");
}
if (bDelay_exit == 0) {
bDelay_exit = 2; // Значение 2 возможно только из этой строки
ulMillis_delay_exit = millis() + cTIMER_DELAY_EXIT;
Serial.println(ulMillis_delay_exit);
}
if (millis() > ulMillis_delay_exit && bDelay_exit == 2) digitalWrite(RELAY_DELAY__DIGITAL_PIN, HIGH); // выключаем реле
}
}
void _Wire_Send(byte data) {
Wire.beginTransmission(cADDRESS_OF_SLAVE);
Wire.write(data);
Wire.endTransmission();
}
void _gear_switch_send() {
if (bGear_first_start == 1) {
static byte g;
switch (bGEAR_CURENT) {
case dGEAR_3:
if (g != dGEAR_3) {
time_gear_blinker = 0;
g = dGEAR_3;
}
if (time_gear_blinker > cTIMER_GEAR3) {
_Wire_Send(dGEAR_3_BLINK);
}
else _Wire_Send(dGEAR_3);
break;
case dGEAR_4:
if (g != dGEAR_4) {
time_gear_blinker = 0;
g = dGEAR_4;
}
if (time_gear_blinker > cTIMER_GEAR4) {
_Wire_Send(dGEAR_4_BLINK);
}
else _Wire_Send(dGEAR_4);
break;
default:
_Wire_Send(bGEAR_CURENT);
g = bGEAR_CURENT;
}
}
}
void _Interrupt_Speed() {
vwDistance_one_trip++;
if (vwDistance_one_trip >= dPULSES_TO_METERS) {
vwDistance_one_trip = 0;
vwAfter_point ++;
if (vwAfter_point > 9) {
vwAfter_point = 0;
vwInteger ++;
}
}
}
void _gear_switch() {
int adc = analogRead(GEAR__ANALOG_PIN);
if (adc <= iDOWN_GEAR) iUp_or_down = iDOWN_GEAR;
if (adc >= iUP_GEAR) iUp_or_down = iUP_GEAR;
int diap = constrain(adc, aEEPROM_DATA[9] - 10, aEEPROM_DATA[9] + 10); // диапазон нейтральной передачи, считываем из памяти
if (adc == diap && iUp_or_down == iDOWN_GEAR && bGEAR_CURENT != 1) {
bGEAR_CURENT--;
iUp_or_down = 1;
}
else if (adc == diap && iUp_or_down == iUP_GEAR && bGEAR_CURENT < 5) {
bGEAR_CURENT++;
iUp_or_down = 1;
}
}
void _Save_Settings_in_Eeprom() {
if (bINDEX_MENU > dMENU_ITEM_FAN_MANUAL) {
for (int i = 0; i <= (UBOUND_EEPROM_ARRAY - 1); i++) _eeprom_write(aEEPROM_DATA[i], aExpon[i]); // Пишем в память настройки.
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Save settings");
fan_manual = 0;
delay(2000);
}
bMENU_ACTIV = 0;
bINDEX_MENU = 0;
bDISPLAY_2 = 0;
lcd.clear();
}
byte _persent_to_liter() { // Перерасчёт из процентов в литры
#define UBOUND 15 // Колличество элементов в массиве
byte ArrayLiterTank[UBOUND] = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
byte ArrayPersent[UBOUND] = {
4, 8, 15, 20, 20, 35, 48, 55, 65, 70, 72, 78, 82, 93, 100 };
for (int i = 0; i <= UBOUND; i++) {
if (ArrayPersent[i] >= bFUEL_LEVEL) return ArrayLiterTank[i];
}
}
void _Fuel_Progress_Bar() { // Прогресс бар
#define INDEX 10 // количество делений уровня топлива
int f = bFUEL_LEVEL / INDEX;
if (bFUEL_LEVEL <= INDEX) {
if (fb == false) {
lcd.setCursor(0, 1);
lcd.write(4);
}
else {
lcd.setCursor(0, 1);
lcd.print(" ");
}
for (int ii = 1; ii <= 9; ii++) { // пустые деления
lcd.setCursor(ii, 1);
lcd.write(6);
}
}
else if (bFUEL_LEVEL > INDEX) {
for (int i = 0; i <= f; i++) { // Цикл целые деления
lcd.setCursor(i - 1, 1);
lcd.write(4);
}
for (int ii = f; ii <= 9; ii++) { // пустые деления
lcd.setCursor(ii, 1);
lcd.write(6);
}
}
}
void _fuel_level() {
int val = analogRead(FUEL_LEVEL__ANALOG_PIN);
if (val > cADC_LIMIT_FUEL_LEVEL) val = cADC_LIMIT_FUEL_LEVEL; // ограничение уровня напряжения АЦП
iArithmetic_mean += map(val, cMIN_ABC_FUEL_LEVEL, cMAX_ABC_FUEL_LEVEL, 100, 0);
bIndex_mean ++;
if (bIndex_mean >= cARITHMETIC_AVERAGE_RATIO) {
bFUEL_LEVEL = iArithmetic_mean / cARITHMETIC_AVERAGE_RATIO;
bIndex_mean = 0;
iArithmetic_mean = 0;
}
}
byte _input_dusplay_SUSTEM_ERROR(byte e) { // Обрабытываем переменную bSYSTEM_ERROR, выводим сообщение на дисплей
switch (e) {
case dSYSTEM_ERROR_LOW_VOLTAGE:
lcd.clear();
digitalWrite(LED_ERROR__DIGITAL_PIN, HIGH);
lcd.clear();
lcd.setCursor(2, 1);
lcd.print("LOW VOLTAGE");
break;
case dSYSTEM_ERROR_HIGH_VOLTAGE:
lcd.clear();
digitalWrite(LED_ERROR__DIGITAL_PIN, HIGH);
lcd.clear();
lcd.setCursor(2, 1);
lcd.print("HIGH VOLTAGE") ;
break;
case dSYSTEM_ERROR_HIGH_TEMPERARURE:
lcd.clear();
digitalWrite(LED_ERROR__DIGITAL_PIN, HIGH);
lcd.clear();
lcd.setCursor(2, 1);
lcd.print("HIGH TEMP") ;
break;
case dSYSTEM_ERROR_HIGH_TEMPERARURE_OIL:
lcd.clear();
digitalWrite(LED_ERROR__DIGITAL_PIN, HIGH);
lcd.clear();
lcd.setCursor(2, 1);
lcd.print("OIL HIGH TEMP") ;
break;
}
}
byte _voltage_scan(byte volt) { // Считываем напряжение, записываем в переменную bSYSTEM_ERROR статус системы
if (volt <= cLOW_VOLTAGE && volt > 2) {
bSYSTEM_ERROR = dSYSTEM_ERROR_LOW_VOLTAGE;
return 0;
}
if (volt >= cHIGH_VOLTAGE) {
bSYSTEM_ERROR = dSYSTEM_ERROR_HIGH_VOLTAGE;
return 0;
}
if (volt < cHIGH_VOLTAGE && volt > cLOW_VOLTAGE) {
return 0;
}
}
int _engine_temp_monitoring(int adc) { // Считываем температуру, включаем или выключаем реле- функцией _RelayColingFan
if (adc > aEEPROM_DATA[2] ) { // Если перегрев двигателя записываем в переменную bSYSTEM_ERROR статус системы
_RelayColingFan(dERROR_COLING_FAN);
bSYSTEM_ERROR = dSYSTEM_ERROR_HIGH_TEMPERARURE;
return dERROR_COLING_FAN;
}
if (adc > aEEPROM_DATA[1]) {
_RelayColingFan(dHIGH_COLING_FAN); // Включаем
return dHIGH_COLING_FAN;
}
if (adc < aEEPROM_DATA[0]) {
_RelayColingFan(dLOW_COLING_FAN); // Выключаем
return dLOW_COLING_FAN;
}
}
int _oil_temp_monitoring(int adc) { // Считываем температуру масла
if (adc > cERROR_TEMP_OIL) { // Если перегрев масла записываем в переменную bSYSTEM_ERROR статус системы
//_RelayColingFan(dERROR_COLING_FAN);
bSYSTEM_ERROR = dSYSTEM_ERROR_HIGH_TEMPERARURE_OIL;
return 1;
}
}
int _RelayColingFan(int atr) { // Включение реле согласно принятому значению температуры
switch (atr)
{
case dLOW_COLING_FAN:
digitalWrite(FAN_RELAY__DIGITAL_PIN, !LOW); // Выключено
bRELAY_CURENT = digitalRead(FAN_RELAY__DIGITAL_PIN);
break;
case dHIGH_COLING_FAN:
digitalWrite(FAN_RELAY__DIGITAL_PIN, !HIGH); // Включено
bRELAY_CURENT = digitalRead(FAN_RELAY__DIGITAL_PIN);
break;
case dERROR_COLING_FAN:
digitalWrite(FAN_RELAY__DIGITAL_PIN, !HIGH); // Включено
bRELAY_CURENT = digitalRead(FAN_RELAY__DIGITAL_PIN);
break;
default: //
//
break;
}
}
unsigned int _eeprom_read(int cell) { // Чтение из еепром
unsigned int res = 0;
res = (EEPROM.read(cell) << 8) | EEPROM.read(cell - 1);
return res;
}
void _eeprom_write(unsigned int val, int cell) { // Запись в еепром
EEPROM.write(cell - 1, (val & 0xFF)); //пишем младший байт
EEPROM.write(cell, ((val & 0xFF00) >> 8));//пишем старший байт
}
void _menu_lcd() {
if (bMENU_ACTIV == 1) { // ----------------------------------------- Mеню 1 --------------------------------------------------------------------------
if (bKEY == 3) _Save_Settings_in_Eeprom(); // dBUTTON_DUBLE выходим из меню НАСТРОЕК, двойное нажатие клавиш
if (bKEY == 2) bINDEX_MENU += 1; // dBUTTON_MENU, листаем страницы меню
lcd.setCursor(0, 0);
if (bINDEX_MENU == dMENU_ITEM_OIL_TEMP) { // Текушие данные без настроек
lcd.print(bINDEX_MENU + String("Oil temp" ));
lcd.setCursor(0, 1);
lcd.write(1);
lcd.print(tOil);
lcd.write(5);
lcd.setCursor(0, 1);
}
else if (bINDEX_MENU == dMENU_ITEM_ENG_TEMP) {
lcd.print(bINDEX_MENU + String(":Engine temp"));
lcd.setCursor(0, 1);
lcd.write(1);
lcd.print(tE);
lcd.write(5);
lcd.setCursor(7, 1);
}
else if (bINDEX_MENU == dMENU_ITEM_BATT) {
lcd.print(bINDEX_MENU + String("BATT"));
lcd.setCursor(0, 1);
lcd.write(2);
lcd.write(3);
lcd.print(fDIS_SYSTEM_VOLTAGE);
lcd.print("V");
}
else if (bINDEX_MENU == dMENU_ITEM_FAN_MANUAL) { // Управление вентилятором
if (bKEY == 1) {
fan_manual++;
if (fan_manual == 2) fan_manual = 0;
lcd.clear();
}
lcd.print(bINDEX_MENU + String(":Fan manual" ));
lcd.setCursor(0, 1);
if (fan_manual == 1) {
lcd.print("[ON]");
_RelayColingFan(dHIGH_COLING_FAN);
if (digitalRead(FAN_CONTROL_RUN__DIGITAL_PIN) == LOW ) {
lcd.setCursor(7, 1);
lcd.print("<Run>");
}
else lcd.setCursor(7, 1);
lcd.print(" ");
}
if (fan_manual == 0) {
lcd.print("[OFF]");
_RelayColingFan(dLOW_COLING_FAN);
}
}
else if (bINDEX_MENU == dMENU_ITEM_DISPLAY_BRIGHTNESS) { // ------------------------------------------------------------
if (bKEY == 1) {
DISPLAY_BRIGHTNESS += 16 ;
if (DISPLAY_BRIGHTNESS > 255) DISPLAY_BRIGHTNESS = 16;
analogWrite(MONITOR_BRIGHTNESS__DIGITAL_PIN, DISPLAY_BRIGHTNESS);
aEEPROM_DATA[6] = DISPLAY_BRIGHTNESS;
lcd.clear();
}
lcd.print(bINDEX_MENU + String(":BRIGHTNESS"));
lcd.setCursor(0, 1);
int f = map(DISPLAY_BRIGHTNESS, 0, 255, 0, 16);
for (int i = 0; i <= f; i++) { // Цикл целые деления
lcd.setCursor(i, 1);
lcd.write(4);
}
for (int ii = f; ii <= 16; ii++) { // пустые деления
lcd.setCursor(ii, 1);
lcd.write(6);
}
}
else if (bINDEX_MENU == dMENU_ITEM_COR_OIL_TEMP) {
if (bKEY == 1) {
aEEPROM_DATA[12]++;
if (aEEPROM_DATA[12] > 10) aEEPROM_DATA[12] = 0;
lcd.clear();
}
lcd.print(bINDEX_MENU + String(":Oil temp correct" ));
lcd.setCursor(0, 1);
lcd.write(1);
lcd.print(String(" +[") + aEEPROM_DATA[12] + String("]-" ));
}
else if (bINDEX_MENU == dMENU_ITEM_COR_OUT_TEMP) {
if (bKEY == 1) {
aEEPROM_DATA[7]++;
if (aEEPROM_DATA[7] > 10) aEEPROM_DATA[7] = 0;
lcd.clear();
}
lcd.print(bINDEX_MENU + String(":Outdoor temp" ));
lcd.setCursor(0, 1);
lcd.write(1);
lcd.print(String(" +[") + aEEPROM_DATA[7] + String("]-" ));
}
else if (bINDEX_MENU == dMENU_ITEM_COR_ENG_TEMP) {
if (bKEY == 1) {
aEEPROM_DATA[8]++;
if (aEEPROM_DATA[8] > 10) aEEPROM_DATA[8] = 0;
lcd.clear();
}
lcd.print(bINDEX_MENU + String(":Engine temp" ));
lcd.setCursor(0, 1);
lcd.write(1);
lcd.print(String(" +[") + aEEPROM_DATA[8] + String("]-"));
}
else if (bINDEX_MENU == dMENU_ITEM_FAN_ON) {
if (bKEY == 1) {
aEEPROM_DATA[1]++;
if (aEEPROM_DATA[1] < 80) aEEPROM_DATA[1] = 80;
if (aEEPROM_DATA[1] > 106) aEEPROM_DATA[1] = 80;
lcd.clear();
}
lcd.print(bINDEX_MENU + String(":Fan on"));
lcd.setCursor(0, 1);
lcd.write(1);
lcd.print(String(" +[") + aEEPROM_DATA[1] + String("]-"));
}
else if (bINDEX_MENU == dMENU_ITEM_FAN_OFF) {
if (bKEY == 1) {
aEEPROM_DATA[0]++;
if (aEEPROM_DATA[0] < 80) aEEPROM_DATA[0] = 80;
if (aEEPROM_DATA[0] > 100) aEEPROM_DATA[0] = 80;
lcd.clear();
}
lcd.print(bINDEX_MENU + String(":Fan off"));
lcd.setCursor(0, 1);
lcd.write(1);
lcd.print(String(" -[") + aEEPROM_DATA[0] + String("]-"));
}
else if (bINDEX_MENU == dMENU_ITEM_ERROR_TEMP) {
if (bKEY == 1) {
aEEPROM_DATA[2]++;
if (aEEPROM_DATA[2] < 80) aEEPROM_DATA[2] = 80;
if (aEEPROM_DATA[2] > 120) aEEPROM_DATA[2] = 100;
lcd.clear();
}
lcd.print(bINDEX_MENU + String(":Error temp")); // PROGMEM !
lcd.setCursor(0, 1);
lcd.write(1);
lcd.print(String(" +[") + aEEPROM_DATA[2] + String("]"));
}
else if (bINDEX_MENU == dMENU_ITEM_FUEL_PERSENT_AND_LITER) {
if (bKEY == 1) {
persent_and_liter++;
if (persent_and_liter == 2) persent_and_liter = 0;
lcd.clear();
}
lcd.print(bINDEX_MENU + String(":Persent/liter"));
lcd.setCursor(0, 1);
if (persent_and_liter == 1) {
aEEPROM_DATA[4] = persent_and_liter;
lcd.print("[L]");
}
else if (persent_and_liter == 0) {
aEEPROM_DATA[4] = persent_and_liter;
lcd.print("[%]");
}
lcd.setCursor(11, 1) ; // Выводим реальный уровень топлива без задержки
lcd.print(map(analogRead(FUEL_LEVEL__ANALOG_PIN), 0, 1023, 0, 100));
}
else if (bINDEX_MENU == dMENU_ITEM_CALIBR_GEAR_POS) {
if (menu_gear_calibration == 0) { // -------- 0 <<<<< ----- первый шаг, спрашиваем - калибровать ?
//lcd.setCursor(0, 0);
lcd.print(bINDEX_MENU + String(":Calibrate gear"));
lcd.setCursor(0, 1);
lcd.print("[Calibrate]");
lcd.setCursor(13, 1);
lcd.print( String("G:") + bGEAR_CURENT );
if (bKEY == 1) {
menu_gear_calibration = 1;
lcd.clear();
return;
}
} // -------- 0
if (menu_gear_calibration == 1) { // -------- 1 <<<<< ----- второй шаг, просим установить коробу в N ?
//lcd.setCursor(0, 0);
lcd.print("Set gear - N");
if ( digitalRead(GEAR_NEITRAL__DIGITAL_PIN) == LOW) {
lcd.setCursor(0, 1);
lcd.print("[Ok]" + String(analogRead(GEAR__ANALOG_PIN)));
if (bKEY == 1) {
menu_gear_calibration = 2; // <<<<< ----- третий шаг, сохраняем ацп средней точки
aEEPROM_DATA[9] = analogRead(GEAR__ANALOG_PIN);
Serial.println(aEEPROM_DATA[9] + String("- N save"));
lcd.clear();
return;
}
}
else {
lcd.setCursor(0, 1);
lcd.print(" ");
}
} // -------- 1
if (menu_gear_calibration == 2) { // -------- 2
//lcd.setCursor(0, 0);
lcd.print("Hold gear - Up");
lcd.setCursor(0, 1);
lcd.print("[Ok]" + String(analogRead(GEAR__ANALOG_PIN)));
if (bKEY == 1) {
menu_gear_calibration = 3; // <<<<< ----- четвёртый шаг, сохраняем ацп верхней точки
aEEPROM_DATA[13] = analogRead(GEAR__ANALOG_PIN);
Serial.println(aEEPROM_DATA[13] + String("- Up save"));
lcd.clear();
return;
}
} // -------- 2
if (menu_gear_calibration == 3) { // -------- 3
//lcd.setCursor(0, 0);
lcd.print("Hold gear - Down");
lcd.setCursor(0, 1);
lcd.print("[Ok]" + String(analogRead(GEAR__ANALOG_PIN)));
if (bKEY == 1) {
menu_gear_calibration = 4; // <<<<< ----- пятый шаг, сохраняем ацп нижней точки
aEEPROM_DATA[11] = analogRead(GEAR__ANALOG_PIN);
Serial.println(aEEPROM_DATA[11] + String("- Down save"));
lcd.clear();
return;
}
} // -------- 3
if (menu_gear_calibration == 4) { // -------- 4
//lcd.setCursor(0, 0);
lcd.print("Save in eeprom ?");
lcd.setCursor(0, 1);
lcd.print("[Ok]");
if (bKEY == 1) {
Serial.println("Eeprom save"); // <<<<< ----- пятый шаг, сохраняем в память
menu_gear_calibration = 0;
_Save_Settings_in_Eeprom();
}
} // -------- 4
} // -------- dMENU_ITEM_CALIBR_GEAR_POS
else if (bINDEX_MENU == dMENU_ITEM_END) {
bINDEX_MENU = 0;
fan_manual = 0;
menu_gear_calibration = 0;
}
} // Конец - bMENU_ACTIV = 1
}
Последний раз редактировалось Oleg_33; 15.11.2016 в 02:06.
Для рисования схем рекомендую Fritzing, очень просто, удобно и красиво.
Эту тему просматривают: 5 (пользователей: 0 , гостей: 5)