/
baxneo
/
test3
Обзор
Документация
Войти
/
baxneo
/
test3
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
src/z_function.ino
999 строк
38 KB
Viktor Leontev
1_50_1
16 сен 2025, 23:18
16 сен 2025, 23:18
1e90660
Код
Авторство
О чём код?
// постоянно работающие функции void sensor_survey(void) { butt.Tick(); // опрос кнопок и энкодера if (ina.sample()) { dcdc.Control(); // регулировка тока и напряжения #if (VOLTIN == 1) VoltINcheck(); // проверить напряжение БП на наличие и на превышение check_Q1(); //проверка на то что силовой транзистор пробит #endif } #if (VOLTIN == 1) // замер напряжения БП adc_v.sample(); // считываем данные с АЦП с накоплением и усреднением #endif #if (SENSTEMP1 == 2) // датчик температуры NTC транзистора ntc_q.sample(); // считываем данные с АЦП с накоплением и усреднением #endif #if (SENSTEMP2 == 2) // датчик температуры NTC аккумулятора ntc_akb.sample(); // считываем данные с АЦП с накоплением и усреднением #endif if (second_flag) { // выполняются раз в секунду second_flag = false; second = true; ina.calc(); // преобразование промежуточных средних значений тока и напряжения в реальные значения #if (SENSTEMP1 > 0) temp_Q1_read(); // чтение температуры транзистора, вызывать раз в секунду #endif #if (SENSTEMP2 > 0) temp_akb_read(); // чтение температуры акб, вызывать раз в секунду #endif #if (FAN) kul.fan(); // управение кулером #endif #if (POWPIN == 1) Relay(); // функция управления реле подключения к сети 220В #endif #if (LOGGER) Sout.Serial_out(); // вывод данных в серийный порт Sout.create(); // сбросить данные #endif } } // функция хранения акб и буферного режима void Storage(void) { bool ext = true; bool vvmin = true; // флаг отключения нагрузки uint8_t sig = 0; // время отстчета сигнала буферного режима const uint16_t vbc = (bat.Volt(volt_cell_discharge) / 100) * 100; // расчет напряжения - снижение до 12В #if (GUARDA0) Guard(); // принудительная блокировка модуля защиты при напряжении заряда или разряда акб менее 5 Вольт. #endif #if (POWPIN == 1) // Relay_on(true); // включить сеть 220В #endif Freq(get_epprom_servise(FREQCHARGE)); // установить частоту работы силового модуля do { uint16_t vlt = (pam.Mode == STORAGE) ? pam.Volt_storage : pam.Volt_buffer; int16_t amp = (pam.Mode == STORAGE) ? (int16_t)pam.Capacity << 3 : pam.Current_charge; // максимальный ток заряда PrintVA(vlt, amp, 0, 0, 2); // вывод напряжения и тока заряда ina.start(); // старт замеров INA if (pam.Mode == BUFER) { gio::high(BUFERPIN); // включить пин 13. Включить реле нагрузки dcdc.start(DCDC_CHARGE); } Delay(3000); dcdc.begin(vlt, amp); // задать максимальные значения напряжения и тока заряда } while (false); start_second_usr(); // старт счета секунд while (ext) { // цикл работы sensor_survey(); // опрос кнопок, INA226, напря. от БП., контроль dcdc. if (butt.tick == ENCHELD or butt.tick == STOPHELD) ext = false; // завершить работу режима // если прошла секунда if (second) { second = false; if (pam.Mode == STORAGE and dcdc.get_pause() == LOW and (ina.volt_aver < pam.Volt_storage - 30)) dcdc.start(DCDC_CHARGE); // включить заряд когда напряжение на акб снизится ниже напряжения Хранения #if (GUARDA0) Guard(); // принудительная блокировка модуля защиты при напряжении заряда или разряда акб менее 5 Вольт. #endif Print_time(get_second_usr(), DISPLAYx - 8, 0); // *Storage 12:10:36* setCursory(); // *13.10V 6.12A 25C* PrintVA(ina.voltsec, ina.ampersec, 0, 0, 2); // вывод на дисплей во float - напряжение, ток, ампер-часы, ватт-часы, кол. разрядов после запятой. #if (SENSTEMP1 or SENSTEMP2) print_tr(); // температура транзистора или акб #endif // сигнализация о снижении напряжения акб ниже предела (12V) if (ina.volt_aver < vbc) { if (--sig == 0) { sig = 60; // сигнал раз в 60 секунд #if (TIME_LIGHT) disp.Light_high(); // включение подсветки #endif Speaker(300); // функция звукового сигнала (время в миллисекундах) } if (pam.Mode == BUFER) { // включен буферный режим if (vvmin and ina.volt_aver < bat.Volt(volt_cell_discharge)) { // если нагрузка подключена и напряжение снизилось менее напряжения разряда то Speaker(300); // функция звукового сигнала (время в миллисекундах) vvmin = false; gio::low(BUFERPIN); // отключить пин 13. отключить реле нагрузки } } } if (!vvmin and ina.volt_aver > pam.Volt_buffer - 50) { // когда реле нагрузки отключено и напряжение увеличилось до максимального то Speaker(300); // функция звукового сигнала (время в миллисекундах) vvmin = true; gio::high(BUFERPIN); // включить пин 13. включить реле нагрузки } #if (TIME_LIGHT) if (pam.Mode == BUFER) disp.Light_low(); // отключение подсветки через 3 минуты в буферном режиме, если разрешено отключение #endif } // если прошла секунда } // цикл работы gio::low(BUFERPIN); // отключить пин 13. отключить реле нагрузки dcdc.Off(); // отключить заряд, разряд. #if (GUARDA0) gio::low(PROTECTBLOCK); // отключить блокировку модуля защиты #endif } // расчет токов и напряжений void calculate(uint8_t i) { switch (i) { case 1: pam.Current_charge = constrain(bat.Cur(curr_cell_charge), CUR_CHARGE_MIN, CURRMAXINT - 500); // ток заряда pam.Current_charge_min = constrain((int16_t)pam.Capacity << 1, CURMIN, 200); // ток завершения заряда pam.Current_discharge = constrain(bat.Cur(2), 50, CURRMAXINT - 500); // ток разряда pam.Current_discharge_min = pam.Current_discharge; // ток завершения разряда pam.Current_add_charge = constrain(bat.Cur(curr_cell_addcharge), CUR_CHARGE_MIN, pam.Current_charge); // ток дозаряда pam.Current_add_charge_min = pam.Current_add_charge / 3; // минимальный ток дозаряда pam.Current_pre_charge = constrain(pam.Current_charge >> 1, 200, pam.Current_charge); // ток предзаряда ChargeTimeCalc(); // расчет времени заряда pam.Round = 1; // 1 раунд break; case 2: // расчет напряжений { pam.Volt_charge = bat.Volt(volt_cell_charge); // напряжение заряда, напряжение заряда ячейки на количество ячеек pam.Volt_decrCur = Volt_DCur(); // напряжение при котором начинается снижение тока заряда pam.Volt_discharge = bat.Volt(volt_cell_discharge); // напряжение разряда uint32_t vbc = bat.Volt(volt_cell); #if defined(__LGT8FX8P__) pam.Volt_storage = DSC_DIV_get((uint32_t)(vbc * 104 + 50), (uint16_t)100); pam.Volt_buffer = DSC_DIV_get((uint32_t)(vbc * 110 + 50), (uint16_t)100); #else pam.Volt_storage = (vbc * 104 + 50) / 100; // pam.Volt_storage = (uint16_t)(vbc * 1.04); // напряжение хранения pam.Volt_buffer = (vbc * 110 + 50) / 100; // pam.Volt_buffer = (uint16_t)(vbc * 1.1); // напряжение буферного режима #endif if (pam.typeAkb < 5) { // расчет для свинцово кислотных Акб pam.Volt_add_charge = bat.Volt(volt_cell_add_charge); // напряжение дозаряда pam.Volt_pre_charge = pam.Volt_buffer; // pam.Volt_pre_charge = (uint16_t)(vbc * 1.1f); // напряжение предзаряда } } break; } } #if (POWPIN == 1) //uint16_t timer_bp = 0; // функция управления реле подключения к сети 220В. Вызывать раз в секунду void Relay(void) { if (ina.voltsec < VOLT_AKB_RELE_ON and timer_bp == 0) { gio::high(RELAY220); // включить реле bitClear(flag_global, RELEY_OFF); // запрещено отключать реле } else if (ina.voltsec > VOLT_AKB_RELE_OFF) bitSet(flag_global, RELEY_OFF); // разрешено отключать реле // отключить БП если не включен ни какой режим и акб отключен. if (BitIsClear(pam.MyFlag, ACTIVITI) and ina.voltsec < 2000) { if (timer_bp) { if (butt.tick) timer_bp = POW_TIME * 60; // сбросить время в секундах при каждом нажатии if (--timer_bp == 1) gio::low(RELAY220); // отключить реле - зарядник отключится } else timer_bp = POW_TIME * 60; // задать время в секундах } else timer_bp = 0; } // (true - включить реле, false - отключить реле) void Relay_on(bool vkl) { if (vkl) gio::high(RELAY220); // включить реле else if (bitRead(flag_global, RELEY_OFF)) gio::low(RELAY220); // отключать реле если включен флаг разрешающий отключать реле } #endif // функция расчета Ач и Втч int32_t aw_ch(int32_t i) { #if defined(__LGT8FX8P__) return DSC_DIV_get((int32_t)(i * 5 + 9), (uint16_t)18); #else return (i * 5 + 9) / 18; // эквивалент round(i*0.277777f) с округлением //return (int32_t)round(i * 0.277777f); #endif } // функция включения блокировки модуля защиты в зависимости от напряжения акб // включает блокировку при напряжении акб менее 5 Вольт и отключает при напр. более 6 Вольт #if (GUARDA0) void Guard(void) { if (ina.voltsec < 5000) gio::high(PROTECTBLOCK); else if (ina.voltsec > 6000) gio::low(PROTECTBLOCK); } #endif // функция сброса значений заряда void Res_mem_char(void) { pam.Ah_charge = 1; // единица для того чтобы Ач и Вт сразу отображались на дисплее pam.Wh_charge = 1; pam.Time_charge = 0; pam.Time_addcharge = 0; pam.Ah_addcharge = 0; pam.Wh_addcharge = 0; #if (BRRANIMIR == 1) bitClear(pam.MyFlag, BRANIM); bitClear(pam.MyFlag, BRANIMBOIL); #endif } // функция сброса значений разряда void Res_mem_dischar(void) { pam.Ah_discharge = 1; // емкость разряда Ah // единица для того чтобы Ач и Вт сразу отображались на дисплее pam.Wh_discharge = 1; // емкость разряда Вт/ч pam.Time_discharge = 0; // время разряда pam.Ah_addcharge = 0; // емкость разряда до напряжения аккумулятора pam.Wh_addcharge = 0; // емкость до напряжения аккумулятора Вт/ч } // очистить память значений КТЦ #if defined(__LGT8FX8P__) void Res_ktc(void) { lgt_eeprom_update_byte(MEM_ROUNDi, pam.Round); // сохранить количество циклов for (uint16_t i = MEM_KTC; i <= 1019; i++) lgt_eeprom_update_byte(i, 0); // очистить память КТЦ } #else void Res_ktc(void) { EEPROM.update(MEM_ROUNDi, pam.Round); // сохранить количество циклов for (uint16_t i = MEM_KTC; i <= 1019; i++) EEPROM.update(i, 0); // очистить память КТЦ } #endif // функция ожидания (t - милисекунды) void Delay(uint16_t t) { uint32_t r = millis_my(); do { sensor_survey(); // опрос кнопок, INA226, напря. от БП., контроль dcdc. // and !butt.tick } while ((millis_my() - r < t) and !butt.tick); } // пауза до нажатия void pauses(void) { do { sensor_survey(); // опрос кнопок, INA226, напря. от БП., контроль dcdc. } while (!butt.tick); } // напряжение при котором начинается снижение тока заряда uint16_t Volt_DCur(void) { return (pam.Volt_charge + bat.Volt(0)) >> 1; } #if (KALIBROVKA == 1) // калибровка падения напряжения при токе нагрузки, напряжения от БП void Korrect(uint8_t kof) { if (kof == 1 and VOLTIN == 0) return; // если выбрана калибровка напряжения от БП и не установлен делитель напряжения на входе то выйти из функции #if (TIME_LIGHT) disp.Light_high(); // включение подсветки #endif if (kof == 0 or kof == 2) { ina.start(); // старт замеров INA Delay(500); while (ina.voltsec < 9000) { lcd.clear(); lcd.print(F(txt11)); // Подключи АКБ lcd.print(F(" >9V")); // Delay(200); if (butt.tick == STOPCLICK or butt.tick == OKCLICK) { dcdc.Off(); return; } } if (kof == 0) { Freq(get_epprom_servise(FREQDISCHAR)); // установить частоту работы разрядного модуля (4 кГц по умолчанию) bitSet(pam.MyFlag, ACTIVITI); // старт работы режима dcdc.start(DCDC_DISCHARGE); // настройка разряда // dcdc.Smooth_off(); // отключить плавный пуск dcdc.begin((ina.voltsec >> 1), 2100); // задает напряжение и ток разряда } } lcd.clear(); bool x = false; bool ext = true; do { // установка напряжения do { // ожидание действий пользователя sensor_survey(); // опрос кнопок, INA226, напря. от БП., контроль dcdc. if (kof == 0 and ina.ampersec < -2000) bitClear(pam.MyFlag, ACTIVITI); // отключить стабилизацию тока if (second or butt.tick) { second = false; // вывод на дисплей switch (kof) { case 0: setCursorx(); // 0, 0 PrintVA(ina.voltsec, ina.ampersec, 0, 0, 3); if (BitIsClear(pam.MyFlag, ACTIVITI)) { setCursory(); // *12.365V 3.254А * Write_x(x); // > or пробел // *>80 >55 * lcd.print(vkr.Ohms); if (vkr.Ohms > 120) lcd.write('!'); printSimb(); lcd.setCursor(8, 1); Write_x(!x); // > or пробел lcd.print(((float)vkr.shunt / 100)); lcd.print(F("mOm ")); } break; #ifdef VKORRECT #if (VOLTIN == 1) case 1: // замер напряжения блока питания setCursorx(); PrintVA(adc_v.volt); lcd.write('<'); lcd.print(vkr.Vref); lcd.write('>'); printSimb(); break; #endif #endif case 2: // замер напряжения акб setCursorx(); PrintVA(ina.voltsec, 0, 0, 0, 3); lcd.write('<'); lcd.print(vkr.inaKoof); lcd.write('>'); printSimb(); break; } } } while (!butt.tick); switch (butt.tick) { case OKCLICK: x = !x; break; case RIGHT: case LEFT: switch (kof) { case 0: if (x) vkr.Ohms = constrain_my(vkr.Ohms, 0, 255, butt.tick); else vkr.shunt = constrain_my(vkr.shunt, 10, 11000, butt.tick); ina.start(); // старт замеров INA break; #ifdef VKORRECT // замер напряжения блока питания #if (VOLTIN) case 1: vkr.Vref = constrain_my(vkr.Vref, 500, 1500, butt.tick); break; #endif #endif case 2: // замер напряжения акб vkr.inaKoof = constrain_my(vkr.inaKoof, 10000, 15000, butt.tick); break; } break; case ENCHELD: case STOPCLICK: ext = false; break; } } while (ext); // установка напряжения dcdc.Off(); // отключить заряд, разряд. bitClear(pam.MyFlag, ACTIVITI); #if defined(__LGT8FX8P__) lgt_eeprom_update_block(((uint8_t *)&vkr), MEM_VKR, sizeof(vkr)); #else EEPROM.put(MEM_VKR, vkr); #endif } #elif (KALIBROVKA == 2) // калибровка падения напряжения при токе нагрузки, напряжения от БП void Korrect(const uint8_t kof) { if (kof == 1 and VOLTIN == 0) return; // если выбрана калибровка напряжения от БП и не установлен делитель напряжения на входе то выйти из функции #if (TIME_LIGHT) disp.Light_high(); // включение подсветки #endif if (kof == 0 or kof == 2) { ina.start(); // старт замеров INA Delay(500); while (ina.voltsec < 9000) { lcd.clear(); lcd.print(F(txt11)); // Подключи АКБ lcd.print(F(" 12V 2А")); Delay(200); if (butt.tick == STOPCLICK or butt.tick == OKCLICK) return; } if (kof == 0) gio::high(PWMDCH); // включить разряд } lcd.clear(); bool x = false; bool ext = true; do { // установка напряжения do { // ожидание действий пользователя sensor_survey(); // опрос кнопок, INA226, напря. от БП., контроль dcdc. if (second or butt.tick) { second = false; // вывод на дисплей switch (kof) { case 0: setCursorx(); // 0, 0 PrintVA(ina.voltsec, ina.ampersec, 0, 0, 3); if (BitIsClear(pam.MyFlag, CHARGE)) { setCursory(); // *12.365V 3.254А * Write_x(x); // > or пробел // *>80 >55 * lcd.print(vkr.Ohms); if (vkr.Ohms > 120) lcd.write('!'); printSimb(); lcd.setCursor(8, 1); Write_x(!x); // > or пробел lcd.print(((float)vkr.shunt / 100)); lcd.print(F("mOm ")); } break; #ifdef VKORRECT #if (VOLTIN == 1) case 1: // замер напряжения блока питания setCursorx(); PrintVA(adc_v.volt); lcd.write('<'); // < lcd.print(vkr.Vref); lcd.write('>'); // > printSimb(); break; #endif #endif case 2: // замер напряжения акб setCursorx(); PrintVA(ina.voltsec, 0, 0, 0, 3); lcd.write('<'); lcd.print(vkr.inaKoof); lcd.write('>'); printSimb(); break; } } } while (!butt.tick); switch (butt.tick) { if (BitIsClear(pam.MyFlag, CHARGE)) { case OKCLICK: x = !x; break; case RIGHT: case LEFT: switch (kof) { case 0: if (x) vkr.Ohms = constrain_my(vkr.Ohms, 0, 255, butt.tick); else vkr.shunt = constrain_my(vkr.shunt, 10, 11000, butt.tick); ina.start(); // старт замеров INA break; #ifdef VKORRECT // замер напряжения блока питания #if (VOLTIN) case 1: vkr.Vref = constrain_my(vkr.Vref, 500, 1500, butt.tick); break; #endif #endif case 2: // замер напряжения акб vkr.inaKoof = constrain_my(vkr.inaKoof, 10000, 15000, butt.tick); break; } break; } case ENCHELD: case STOPCLICK: ext = false; break; } } while (ext); // установка напряжения gio::low(PWMDCH); // отключить разряд #if defined(__LGT8FX8P__) lgt_eeprom_update_block(((uint8_t *)&vkr), MEM_VKR, sizeof(vkr)); #else EEPROM.put(MEM_VKR, vkr); #endif } #endif // Функция ожидания time_charge - минут void Wait(uint16_t time_min) { lcd.clear(); lcd.print(F(txt16)); // Pause / start_second_usr(); // старт счета секунд do { sensor_survey(); // опрос кнопок, INA226, напря. от БП., контроль dcdc. // если прошла секунда вывод на дисплей if (second) { second = false; setCursory(); PrintVA(ina.voltsec); lcd.print(time_min); lcd.print(F(txt20)); // "мин" if (get_second_usr() >= 60) { // когда прошла минута start_second_usr(); // старт счета секунд time_min--; } #if (TIME_LIGHT) disp.Light_low(); // отключение подсветки через 3 минуты, если разрешено отключение #endif } } while (time_min and butt.tick != STOPHELD and butt.tick != ENCHELD); // цикл в минутах или долгово нажатия OK } // Функция завершения заряда void End(void) { lcd.clear(); lcd.print(regim_end); // вывод причины завершения работы. printSimb(); // пробел print_mode(MODE); // вывод режима setCursory(); int32_t Ah = 0; uint32_t tm = 0; switch (pam.Mode) { case CHARGE: // Заряд Ah = pam.Ah_charge; tm = pam.Time_charge; break; case CHARGE_ADDCHARGE: case BRANIMIR: case KTCycle: // Заряд-Дозаряд , Бранимир, КТЦ Ah = pam.Ah_charge + pam.Ah_addcharge; tm = pam.Time_charge + pam.Time_addcharge; break; case ADDCHARGE: // Дозаряд Ah = pam.Ah_addcharge; tm = pam.Time_addcharge; break; case DISCHARGE: // Разряд Ah = pam.Ah_discharge; tm = pam.Time_discharge; break; case STORAGE: case BUFER: // Хранение, Буфер. Ah = 0; tm = 0; break; } PrintVA(0, 0, Ah, 0); #if (DISPLAYx == 16) Print_time(tm, DISPLAYx - 5, 1); #elif (DISPLAYx == 20) Print_time(tm, DISPLAYx - 11, 1); #endif #if (DISPLAYy == 4) lcd.setCursor(0, 2); ClearStr(3); #endif regim_end = beg; Speaker(1000); // функция звукового сигнала (время в миллисекундах) Delay(1000); // подождать pauses(); // пауза до нажатия lcd.clear(); // очистить дисплей Delay(500); // подождать } // функция выбора Stop/OK. (timer - секунд, время через которое возвращается false. Если timer = 0 то возврат из функции по нажатию кнопок/енкодера) bool Choice(uint8_t secund, bool rez) { // sensor_survey(); // опрос кнопок, INA226, напря. от БП., контроль dcdc. butt.tick = 0; do { switch (butt.tick) { case LEFT: case RIGHT: rez = !rez; break; case OKCLICK: case STOPCLICK: return rez; break; } lcd.setCursor(4, 1); lcd.print((rez ? F(txt17) : F(txt19))); // OK / Stop do { // цикл ожидания действий пользователя sensor_survey(); // опрос кнопок, INA226, напря. от БП., контроль dcdc. if (second) { second = false; // если прошла секунда вывод на дисплей lcd.setCursor(DISPLAYx - 2, 1); lcd.print(secund); printSimb(); secund--; } } while (!butt.tick and secund); // цикл ожидания действий пользователя } while (secund); // ожидание истечения времени return rez; } // функция звукового сигнала (n - время в миллисекундах) void Speaker(uint16_t n) { // активный звукового сигнала #if (SPEAKER == 2) gio::high(BUZER); // включить сигнал Delay(n); // подождать n - миллисекунд gio::low(BUZER); // отключить сигнал #elif (SPEAKER == 1) // пассивный звукового сигнала uint32_t time2 = millis_my(); // звуковой сигнал в течении n миллисекунд while (millis_my() - time2 < n) { gio::high(BUZER); // HIGH delayMicroseconds(300); // 2314 - частота 432Гц; 1157 - частота 864Гц; 771 - частота 1296Гц gio::low(BUZER); // LOW delayMicroseconds(471); } #endif return; } // расчет времени заряда void ChargeTimeCalc(void) { #if defined(__LGT8FX8P__) DSC_MUL((uint16_t)pam.Capacity, (uint16_t)1000); uint16_t v = DA_DIV_get((uint16_t)pam.Current_charge); #else uint16_t v = ((uint32_t)pam.Capacity * 1000 / pam.Current_charge); #endif v += ((v + 2 - 1) >> 1); pam.Time_charge_h = (uint8_t)constrain(v, 1, 48); // расчет времени заряда } // вычисление процента заряда uint8_t Percentage(int16_t curr_min) { uint16_t vmin = bat.Volt(volt_cell_discharge); // миним напряжение (напряжение разряда) if (ina.volt_aver <= vmin) return 0; auto v = map_my(ina.volt_aver, vmin, dcdc.getVolt_charge(), 0, 100); // процент по напряжению auto c = map_my(ina.curr_aver, curr_min, dcdc.getCur_charge(), 0, 100); // процент по току c >>= 1; uint8_t prc = v - c; // процент общий return constrain(prc, 0, 100); } #if (CORRECTCUR and SENSTEMP2) // контроль температуры Акб void Control_trAkb(void) { if (bitRead(flag_global, TEMP_AKB)) { if (temp_akb > 40) bitClear(flag_global, TEMP_AKB); else if (pam.typeAkb <= 4 and temp_akb < -15) bitClear(flag_global, TEMP_AKB); else if ((pam.typeAkb <= 6 or pam.typeAkb == 8) and temp_akb < 10) bitClear(flag_global, TEMP_AKB); } if (BitIsClear(flag_global, TEMP_AKB)) { dcdc.Off(); // остановить заряд #if (TIME_LIGHT) disp.Light_high(); // включение подсветки #endif lcd.clear(); lcd.print(F(txt9)); // "Temp akb:" Speaker(1000); // функция звукового сигнала (время в миллисекундах) uint32_t sek = 0; do { sensor_survey(); // опрос кнопок, INA226, напря. от БП., контроль dcdc. // and !butt.tick if (butt.tick == ENCHELD or butt.tick == STOPHELD) { bitClear(pam.MyFlag, ACTIVITI); bitSet(flag_global, TEMP_AKB); return; } if (millis_my() - sek >= 3000) { sek = millis_my(); lcd.setCursor(9, 0); lcd.print(temp_akb); printSimb(); // пробел setCursory(); PrintVA(ina.voltsec, ina.ampersec, 0, 0, 3); if (temp_akb < 37) { if (pam.typeAkb <= 4 and temp_akb > -14) bitSet(flag_global, TEMP_AKB); else if ((pam.typeAkb <= 6 or pam.typeAkb == 8) and temp_akb > 11) bitSet(flag_global, TEMP_AKB); dcdc.pause(bitRead(flag_global, TEMP_AKB)); // включить заряд } } } while (BitIsClear(flag_global, TEMP_AKB)); lcd.clear(); Speaker(1000); // функция звукового сигнала (время в миллисекундах) } } #endif #if (VOLTIN == 1) // напряжение от БП //проверка на то что силовой транзистор пробит inline void check_Q1(void) { auto vt = difference(ina.voltms, adc_v.volt); if ((abs(vt) < 100) and abs(ina.amperms) > 500 and dcdc.getTok() == 0) { #if (TIME_LIGHT) disp.Light_high(); // включение подсветки #endif // bitSet(vkr.GlobFlag, TRQ1); dcdc.Off(); #if (GUARDA0) gio::low(PROTECTBLOCK); // разблокировать защитный модуль #endif #if (PROT == 1) gio::high(PROTECT); //закрыть защитный транзистор #endif #if (POWPIN == 1) gio::low(RELAY220); // отключить сеть 220В #endif Saved(); // сохранить настройки lcd.clear(); lcd.print(F(txt24)); //"!!-BROKEN Q1-!!" pauses(); // bitClear(vkr.GlobFlag, TRQ1); // при нажатии записать в память что транзистор исправен Saved(); // сохранить настройки #if (PROT == 1) gio::low(PROTECT); // открыть защитный транзистор #endif #if (POWPIN == 1) Relay_on(true); // включить сеть 220В #endif #if (GUARDA0) Guard(); // принудительная блокировка модуля защиты при напряжении заряда или разряда акб менее 5 Вольт. #endif lcd.clear(); } } #endif // функция быстрого переключения "ног" void digitalWrite_speed(uint8_t pin, bool x) { // PWM disable switch (pin) { case 3: bitClear(TCCR2A, COM2B1); break; case 5: bitClear(TCCR0A, COM0B1); break; case 6: bitClear(TCCR0A, COM0A1); break; case 9: bitClear(TCCR1A, COM1A1); break; case 10: bitClear(TCCR1A, COM1B1); break; case 11: bitClear(TCCR2A, COM2A1); break; } gio::write(pin, x); } void analogWrite_my(uint8_t pin, uint16_t duty) { if (!duty) { digitalWrite_speed(pin, LOW); // Disable PWM and set pin to LOW return; // Skip next code } switch (pin) { case 5: bitSet(TCCR0A, COM0B1); // Enable hardware timer output OCR0B = duty; // Load duty to compare register return; case 6: bitSet(TCCR0A, COM0A1); OCR0A = duty; return; case 10: bitSet(TCCR1A, COM1B1); OCR1B = duty; return; case 9: bitSet(TCCR1A, COM1A1); OCR1A = duty; return; case 3: bitSet(TCCR2A, COM2B1); OCR2B = duty; return; case 11: bitSet(TCCR2A, COM2A1); OCR2A = duty; return; } } #if defined(__LGT8FX8P__) int16_t map_my(int16_t x, int16_t in_min, int16_t in_max, int16_t out_min, int16_t out_max) { return uDSC_map_int(x, in_min, in_max, out_min, out_max); } #else int16_t map_my(int32_t x, int16_t in_min, int16_t in_max, int16_t out_min, int16_t out_max) { if (x >= in_max) return out_max; if (x <= in_min) return out_min; int32_t diff = ((x - in_min) * (out_max - out_min)); // Предварительное масштабирование int16_t range = (in_max - in_min); // Диапазон исходных значений return (int16_t)(diff / range + out_min); // Итоговая формула } #endif int16_t difference(int32_t diff_1, int32_t diff_2) { return (int16_t)(diff_1 - diff_2); } // функция блока питания /* Вызывается из меню на экране датчиков, удержанием кнопки ПУСК. */ void BP_vvcc(void) { uint16_t bp_volt = BP_volt; // начальное напряжение БП int16_t bp_curr = BP_curr; // начальный ток БП bool x = true; // изменение напряжения или тока #if (GUARDA0) gio::high(PROTECTBLOCK); // принудительная блокировка модуля защиты при напряжении заряда или разряда акб менее 5 Вольт. #endif lcd.clear(); bitSet(pam.MyFlag, ACTIVITI); // запустить работу режима Freq(get_epprom_servise(FREQCHARGE)); // установить частоту работы силового модуля dcdc.start(DCDC_CHARGE); // режим работы DCDC dcdc.begin(bp_volt, bp_curr); // задает напряжение и ток заряда while (true) { sensor_survey(); if (butt.tick) { // если кнопка нажата // производится корректировка напряжения и тока заряда switch (butt.tick) { case RIGHT: // энкодер вправо case LEFT: // энкодер влево // изменение напряжения или тока if (x) bp_volt = volt_step(bp_volt, butt.tick); else bp_curr = constrain_my(bp_curr, CUR_CHARGE_MIN, CURRMAXINT, butt.tick * STEP_CURR); dcdc.begin(bp_volt, bp_curr); break; // выбор напряжения или тока case OKCLICK: // клик Пуск x = !x; break; case STOPHELD: case ENCHELD: dcdc.Off(); bitClear(pam.MyFlag, ACTIVITI); lcd.clear(); #if (GUARDA0) gio::low(PROTECTBLOCK); // принудительная блокировка модуля защиты #endif return; // выход из режима БП break; } } // если прошла секунда или кнопки/энкодер if (second or butt.tick) { second = false; // вывод на дисплей setCursorx(); // первая строка PrintVA(ina.voltsec, ina.ampersec, 0, 0, 3); // напряжение и ток setCursory(); // вторая строка Write_x(x); // > or пробел lcd.print(bp_volt); printSimb(); lcd.setCursor(8, 1); Write_x(!x); // > or пробел lcd.print(bp_curr); printSimb(); } } } /* #if defined(__LGT8FX8P__) #else #endif */ /* int16_t map_my(long x, int16_t in_min, int16_t in_max, int16_t out_min, int16_t out_max) { if (in_min >= in_max) return out_min; return (int16_t)((x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min); } */ /* template<typename T> T map_my(T x, T in_min, T in_max, T out_min, T out_max) { return ((int32_t)x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } */ /* // диспетчер ошибок void ErrorManager(void) { #if (VOLTIN == 1) // превышение напряжения БП if (BitIsClear(flag_global, POWERHIGH)) { lcd.clear(); lcd.print(F(txt4)); // "Power " PrintVA(adc_v.volt, 0, 0, 0, 1); print_mode(ERROR); // error } #endif // превышена температура на силовом транзисторе if (bitRead(flag_global, TR_Q1_ERR)) {} // температура акб за пределами нормы if (BitIsClear(flag_global, TR_Q1_ERR)) {} } */ /* // ===================== FLAGS Button====================== #define EB_PRESS (1 << 0) 1 // нажатие на кнопку #define EB_HOLD (1 << 1) 2 // кнопка удержана #define EB_STEP (1 << 2) 4 // импульсное удержание #define EB_RELEASE (1 << 3) 8 // кнопка отпущена #define EB_CLICK (1 << 4) 16 // одиночный клик #define EB_CLICKS (1 << 5) 32 // сигнал о нескольких кликах #define EB_TURN (1 << 6) 64 // поворот энкодера #define EB_REL_HOLD (1 << 7) 128 // кнопка отпущена после удержания #define EB_REL_HOLD_C (1 << 8) 256 // кнопка отпущена после удержания с предв. кликами #define EB_REL_STEP (1 << 9) 512 // кнопка отпущена после степа #define EB_REL_STEP_C (1 << 10) 1024 // кнопка отпущена после степа с предв. кликами // ===================== FLAGS Encoder====================== #define EB_TYPE (1 << 0) #define EB_REV (1 << 2) #define EB_FAST (1 << 3) #define EB_EHLD_M (1 << 4) #define EB_DIR (1 << 5) #define EB_ETRN_R (1 << 6) #define EB_ISR_F (1 << 7) */