#include "usart.h" #ifdef USE_USART /** * @brief USART initialization * Если задействовано управление регулятором ТЭНа через UART, инициализируем оный */ void USART_start(void) { Serial.begin(9600, SERIAL_8N1); // Инициализируем USART #ifdef Debug Serial.println("Started"); #endif } /** * @brief Функция возвращает значение текущей мощности с учетом режима "Разгон" */ static uint16_t get_Power(void) { if (fl.stab_off || fl.Udown || fl.NotZero) { // Если авария или сеть в дауне - передаем ноль return 0; } else if (fl.razg_on || fl.Ulow) { // В разгоне и при недостаточном сетевом передаем расчетную текущую мощность uint32_t tmp_u = (long)U_sum * U_sum; tmp_u /= 100; tmp_u *= Pnom; tmp_u /= U_LINE_Q; return tmp_u; } else { // В рабочем режиме - передаем уставку return Pust; } } /** * @brief Функция установки текущей мощности по запросу */ static void set_newPDM(uint16_t power) { if (power >= Pnom) { // Если параметр превышает максимально возможное значение, PDMust = CICLE; // значит ставим максимально возможное значение. } else { PDMust = calc_proportion(power, CICLE, Pnom); } set_Pust(); // Пересчитаем Pust fl.dspNewData = 1; // Обновление информации на дисплее } #endif /* USE_USART */ #ifdef USE_ADprotocol /* USART */ /** * Байт "состав данных" b00010111 (основной параметр - мощность в нагрузке, * доп. параметр - напряжение сети) в HEX-формате 0x17 */ static char USART_InfoData[14] = {'T','1','7','0','0','0','0','0','0','0','0','0','0',0x0D}; // Массив готовых данных для передачи внешнему контроллеру static char USART_SetData[6]; // Массив управляющих символов от внешнего контроллера /** * @brief Парсим управляющую последовательность по универсальному протоколу */ void USART_parser(void) { static uint8_t index = 0; static uint8_t data_size; while (Serial.available() > 0) { if (fl.stab_off) { Serial.read(); // Вычитываем очередной байт, чтобы не засирать буфер } else if ( !index || fl.uartTimeout ) { // Начало USART_SetData[0] = Serial.read(); // Вычитываем очередной байт fl.uartTimeout = 0; // Сбросим флаг таймаута ожидания окончания посылки cnt_uartWDT = 0; // Сбросим таймер ожидания окончания посылки switch ( USART_SetData[0] ) { // Ждём первый символ... case 'M': case 'm': { // ...запроса на изменение режима работы data_size = 2; index=1; break; } case 'P': case 'p': { // ...запроса на изменение уставки data_size = 5; index=1; break; } default: { // break; } } } else { USART_SetData[index] = Serial.read(); // Вычитываем очередной байт if ( USART_SetData[index] == 0x0D ) { // Ждем последнего символа посылки if ( index == data_size ) { switch (index) { case 2: { // Парсим запрос на смену режима switch ( USART_SetData[1] ) { case '0': { // Переход в рабочий режим if ( fl.razg_on ) { stop_razgon(); } break; } case '1': { // Переход в режим разгона if ((!fl.NotZero) & (!fl.Udown) & (!fl.razg_off)) { // Если электросеть в дауне или разгон запрещен - не разгонишься fl.razg_on = 1; fl.razg = 1; } break; } case '2': { // Отключение нагрузки PDMust = 0; stop_razgon(); Pust = 0; break; } default: { break; } } break; } case 5: { // Парсим запрос на смену уставки uint16_t tmp_p = 0; uint8_t b; for (uint8_t x=1; x <= 4; x++ ) { tmp_p *= 16; b = A_to_HEX (USART_SetData[x]); if (b == 255) { break; } tmp_p += b; } if (b != 255) { set_newPDM (tmp_p); // Установим новую уставку мощности; } break; } } index = 0; fl.dspNewData = 1; //Обновление информации на дисплее } else index = 0; } else if ( index++ == data_size ) { index = 0; } } } } /** * @brief Отчет внешнему контроллеру по универсальному протоколу */ void USART_report(void) { uint16_t b; if (fl.stab_off) { b = 3; // b000000(11) - аварийное отключение нагрузки (удаленное включение невозможно) } else if (fl.Udown || fl.NotZero) { b = 6; // b000001(10) - отсутствие сетевого напряжения, нагрузка отключена } else if (fl.razg_on) { b = 1; // b(000000)(01) - разгон } else if (PDMust == 0) { b = 2; // b000000(10) - нагрузка отключена } else if (fl.Ulow) { b = 8; // b000010(00) - напряжения сети недостаточно для достижения уставки } else { b = 0; // b000000(00) - режим рабочий, ошибок нет } // Закодируем состав данных USART_InfoData[3] = HEX_to_A ( b / 16 ); // Старший разряд байта "Режим + ошибки" USART_InfoData[4] = HEX_to_A ( b % 16 ); // Младший разряд байта "Режим + ошибки" // Закодируем основной параметр - мощность на выходе b = get_Power(); // Получим текущую мощщу USART_InfoData[8] = HEX_to_A ( b % 16 ); // 0 разряд основного параметра b /= 16; USART_InfoData[7] = HEX_to_A ( b % 16 ); // 1 разряд основного параметра b /= 16; USART_InfoData[6] = HEX_to_A ( b % 16 ); // 2 разряд основного параметра USART_InfoData[5] = HEX_to_A ( b / 16 ); // 3 разряд основного параметра // Закодируем доп.параметр - напряжение сети if (fl.NotZero) { // Если сети нет, то и на выходе пусто USART_InfoData[12] = '0'; // 0 разряд основного параметра USART_InfoData[11] = '0'; // 1 разряд основного параметра USART_InfoData[10] = '0'; // 2 разряд основного параметра USART_InfoData[9] = '0'; // 3 разряд основного параметра } else { b = U_sum; USART_InfoData[12] = HEX_to_A ( b % 16 ); // 0 разряд основного параметра b /= 16; USART_InfoData[11] = HEX_to_A ( b % 16 ); // 1 разряд основного параметра b /= 16; USART_InfoData[10] = HEX_to_A ( b % 16 ); // 2 разряд основного параметра USART_InfoData[9] = HEX_to_A ( b / 16 ); // 3 разряд основного параметра } // Отправим Serial.write(USART_InfoData, 14); } #endif /* USE_ADprotocol */ #ifdef USE_RMVK /* RMVK_/_Samovar */ /** * @brief Функция возвращает значение текущего напряжения без десятичного знака */ uint16_t get_Uin(void) { return ((U_real_dec < 5)? U_real : (U_real + 1)); } /** * @brief Функция возвращает расчетное значение текущего (если getReal=true) * или желаемого (если getReal=false) напряжения */ uint16_t get_Uout(const bool getReal) { if ( fl.Udown || fl.NotZero || (PDMust == 0) ) { // Если сеть в дауне или стаб в стопе - передаем ноль return 0; } else if ( getReal && ( fl.razg_on || fl.Ulow ) ) { // В разгоне и при недостаточном сетевом передаем текущее сетевое, если надо return get_Uin(); } else { // В рабочем режиме - передаем уставку return calc_proportion(PDMust, U_LINE); } } /** * @brief Парсим управляющую последовательность от RMVK_/_Samovar */ void USART_parser(void) { static String inoutString; static uint8_t index = 0; while (Serial.available() > 0) { char inChar = (char)Serial.read();// Вычитываем очередной байт if ( !index || fl.uartTimeout ) { // Начало посылки if ((inChar == 'A') || ((uint8_t)(inChar) == 0xD0)) { // Ждём первый символ посылки "A" или первый байт UTF-кириллицы из протокола Samovar'a inoutString = inChar; index=1; fl.uartTimeout = 0; // Сбросим флаг таймаута ожидания окончания посылки cnt_uartWDT = 0; // Сбросим таймер ожидания окончания посылки } } else if ( index++ < 13 ) { // Пока посылка не длиннее 13 символов, считаем её корректной if ( inChar == 0x0D ) { // Ждем последнего символа посылки index = 0; // Парсим строку, поскольку кончилась // В протоколе Samovar стандартное начало посылки "АТ" пересылается русскими символами в Юникоде. Баг или фича? if (( inoutString == ("AT+VI?")) || // Запрос текущего напряжения сети ( inoutString == ("АТ+VI?"))) { // В этой строке "АТ" - русскими символами! if (fl.NotZero) { // Если сети нет, то и на выходе пусто inoutString = String(0); } else { inoutString = String(get_Uin()); } } else if (( inoutString == F("АТ+VO?")) || ( inoutString == F("АТ+VS?"))) { // Запрос текущей мощности от Samovar. В этой строке "АТ" - русскими символами! inoutString = String(get_Power()); } else if ( inoutString == F("AT+VO?") ) { // Запрос текущего напряжения на выходе от РМВ-К inoutString = String(get_Uout(true)); } else if ( inoutString == F("AT+VS?") ) { // Запрос напряжения уставки на выходе от РМВ-К inoutString = String(get_Uout(false)); } else if ( inoutString == F("AT+ON?") ) { // Запрос состояния выхода от РМВ-К if ((PDMust == 0) || (fl.NotZero) || (fl.Udown)) { // Если на выходе 0 inoutString = String("OFF"); } else { inoutString = String("ON"); } } else if (( inoutString == F("AT+SS?")) || // Запрос режима от Samovar ( inoutString == F("АТ+SS?"))) { // В этой строке "АТ" - русскими символами! if (fl.stab_off || fl.Udown || fl.NotZero) { // При аварии, сильно пониженном напряжении сети или его отсутствии - передаем ошибку inoutString = String(3); } else if (fl.razg_on) { // Передаем "Разгон" inoutString = String(1); } else if (PDMust == 0) { // Передаем "Стоп" inoutString = String(2); } else { // Передаем "Рабочий режим" inoutString = String(0); } } else if (( inoutString == F("AT+ON=0")) || // Запрос на выключение стабилизатора ( inoutString == F("АТ+ON=0"))) { // В этой строке "АТ" - русскими символами! if (!fl.stab_off) { // Если стаб не выключен аварийно... PDMust = 0; stop_razgon(); Pust = 0; fl.dspNewData = 1; //Обновление информации на дисплее inoutString = ""; } } else if (( inoutString == F("AT+ON=1")) || // Запрос на включение режима "Разгон" ( inoutString == F("АТ+ON=1"))) { // В этой строке "АТ" - русскими символами! if ((!fl.stab_off) && (!fl.NotZero) && (!fl.Udown) && (!fl.razg_off)) { // Если авария, электросеть в дауне или разгон запрещен - не разгонишься fl.razg_on = 1; fl.razg = 1; fl.dspNewData = 1; //Обновление информации на дисплее } inoutString = ""; } else if ( inoutString.substring(0,8) == F("АТ+VS=") ) { // Запрос на изменение уставки от Samovar. В этой строке "АТ" - русскими символами! if (!fl.stab_off) { // Если стаб не выключен аварийно... //выключаем разгон, на всякий случай stop_razgon(); set_newPDM (inoutString.substring(8).toInt()); // Установим новую уставку мощности inoutString = ""; } } else if ( inoutString.substring(0,6) == F("AT+VS=") ) { // Запрос на изменение уставки от РМВ-К if (fl.stab_off || fl.Udown || fl.NotZero) { // Если авария или сеть в дауне - ничего не меняем, передаем ошибку inoutString = String(F("error")); } else { uint16_t tmp_u = inoutString.substring(6).toInt(); if ( tmp_u < U_LINE ) { tmp_u *= CICLE; PDMust = tmp_u / U_LINE; } else PDMust = CICLE; //выключаем разгон, на всякий случай stop_razgon(); set_Pust(); // Посчитаем Pust fl.dspNewData = 1; // Обновление информации на дисплее inoutString = String(get_Uout(false)); } } else { // Неизвестная или закосяченная команда #ifdef Debug inoutString = String(F("(o_O unknown!)")); #else inoutString = ""; #endif } if ( inoutString != "" ) { // Если строка не пустая inoutString += char(0x0D); // Добавляем в конец Serial.print( inoutString ); // Шлём! } } else { // Еще не конец inoutString += inChar; // Добавляем и это лыко в строку } } else { // Посылка длинновата, а значит - некорректна, начинаем сначала index = 0; } } } #endif /* RMVK_/_Samovar */