stab_usart.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. #include "usart.h"
  2. #ifdef USE_USART
  3. /**
  4. * @brief USART initialization
  5. * Если задействовано управление регулятором ТЭНа через UART, инициализируем оный
  6. */
  7. void USART_start(void) {
  8. Serial.begin(9600, SERIAL_8N1); // Инициализируем USART
  9. #ifdef Debug
  10. Serial.println("Started");
  11. #endif
  12. }
  13. /**
  14. * @brief Функция возвращает значение текущей мощности с учетом режима "Разгон"
  15. */
  16. static uint16_t get_Power(void) {
  17. if (fl.stab_off || fl.Udown || fl.NotZero) { // Если авария или сеть в дауне - передаем ноль
  18. return 0;
  19. }
  20. else if (fl.razg_on || fl.Ulow) { // В разгоне и при недостаточном сетевом передаем расчетную текущую мощность
  21. uint32_t tmp_u = (long)U_sum * U_sum;
  22. tmp_u /= 100;
  23. tmp_u *= Pnom;
  24. tmp_u /= U_LINE_Q;
  25. return tmp_u;
  26. } else { // В рабочем режиме - передаем уставку
  27. return Pust;
  28. }
  29. }
  30. /**
  31. * @brief Функция установки текущей мощности по запросу
  32. */
  33. static void set_newPDM(uint16_t power) {
  34. if (power >= Pnom) { // Если параметр превышает максимально возможное значение,
  35. PDMust = CICLE; // значит ставим максимально возможное значение.
  36. } else {
  37. PDMust = calc_proportion(power, CICLE, Pnom);
  38. }
  39. set_Pust(); // Пересчитаем Pust
  40. fl.dspNewData = 1; // Обновление информации на дисплее
  41. }
  42. #endif /* USE_USART */
  43. #ifdef USE_ADprotocol
  44. /* USART */
  45. /**
  46. * Байт "состав данных" b00010111 (основной параметр - мощность в нагрузке,
  47. * доп. параметр - напряжение сети) в HEX-формате 0x17
  48. */
  49. static char USART_InfoData[14] = {'T','1','7','0','0','0','0','0','0','0','0','0','0',0x0D}; // Массив готовых данных для передачи внешнему контроллеру
  50. static char USART_SetData[6]; // Массив управляющих символов от внешнего контроллера
  51. /**
  52. * @brief Парсим управляющую последовательность по универсальному протоколу
  53. */
  54. void USART_parser(void) {
  55. static uint8_t index = 0;
  56. static uint8_t data_size;
  57. while (Serial.available() > 0) {
  58. if (fl.stab_off) {
  59. Serial.read(); // Вычитываем очередной байт, чтобы не засирать буфер
  60. } else if ( !index || fl.uartTimeout ) { // Начало
  61. USART_SetData[0] = Serial.read(); // Вычитываем очередной байт
  62. fl.uartTimeout = 0; // Сбросим флаг таймаута ожидания окончания посылки
  63. cnt_uartWDT = 0; // Сбросим таймер ожидания окончания посылки
  64. switch ( USART_SetData[0] ) { // Ждём первый символ...
  65. case 'M':
  66. case 'm': { // ...запроса на изменение режима работы
  67. data_size = 2;
  68. index=1;
  69. break;
  70. }
  71. case 'P':
  72. case 'p': { // ...запроса на изменение уставки
  73. data_size = 5;
  74. index=1;
  75. break;
  76. }
  77. default: {
  78. // break;
  79. }
  80. }
  81. } else {
  82. USART_SetData[index] = Serial.read(); // Вычитываем очередной байт
  83. if ( USART_SetData[index] == 0x0D ) { // Ждем последнего символа посылки <CR>
  84. if ( index == data_size ) {
  85. switch (index) {
  86. case 2: { // Парсим запрос на смену режима
  87. switch ( USART_SetData[1] ) {
  88. case '0': { // Переход в рабочий режим
  89. if ( fl.razg_on ) {
  90. stop_razgon();
  91. }
  92. break;
  93. }
  94. case '1': { // Переход в режим разгона
  95. if ((!fl.NotZero) & (!fl.Udown) & (!fl.razg_off)) { // Если электросеть в дауне или разгон запрещен - не разгонишься
  96. fl.razg_on = 1;
  97. fl.razg = 1;
  98. }
  99. break;
  100. }
  101. case '2': { // Отключение нагрузки
  102. PDMust = 0;
  103. stop_razgon();
  104. Pust = 0;
  105. break;
  106. }
  107. default: {
  108. break;
  109. }
  110. }
  111. break;
  112. }
  113. case 5: { // Парсим запрос на смену уставки
  114. uint16_t tmp_p = 0;
  115. uint8_t b;
  116. for (uint8_t x=1; x <= 4; x++ ) {
  117. tmp_p *= 16;
  118. b = A_to_HEX (USART_SetData[x]);
  119. if (b == 255) {
  120. break;
  121. }
  122. tmp_p += b;
  123. }
  124. if (b != 255) {
  125. set_newPDM (tmp_p); // Установим новую уставку мощности;
  126. }
  127. break;
  128. }
  129. }
  130. index = 0;
  131. fl.dspNewData = 1; //Обновление информации на дисплее
  132. } else index = 0;
  133. } else if ( index++ == data_size ) {
  134. index = 0;
  135. }
  136. }
  137. }
  138. }
  139. /**
  140. * @brief Отчет внешнему контроллеру по универсальному протоколу
  141. */
  142. void USART_report(void) {
  143. uint16_t b;
  144. if (fl.stab_off) {
  145. b = 3; // b000000(11) - аварийное отключение нагрузки (удаленное включение невозможно)
  146. } else if (fl.Udown || fl.NotZero) {
  147. b = 6; // b000001(10) - отсутствие сетевого напряжения, нагрузка отключена
  148. } else if (fl.razg_on) {
  149. b = 1; // b(000000)(01) - разгон
  150. } else if (PDMust == 0) {
  151. b = 2; // b000000(10) - нагрузка отключена
  152. } else if (fl.Ulow) {
  153. b = 8; // b000010(00) - напряжения сети недостаточно для достижения уставки
  154. } else {
  155. b = 0; // b000000(00) - режим рабочий, ошибок нет
  156. }
  157. // Закодируем состав данных
  158. USART_InfoData[3] = HEX_to_A ( b / 16 ); // Старший разряд байта "Режим + ошибки"
  159. USART_InfoData[4] = HEX_to_A ( b % 16 ); // Младший разряд байта "Режим + ошибки"
  160. // Закодируем основной параметр - мощность на выходе
  161. b = get_Power(); // Получим текущую мощщу
  162. USART_InfoData[8] = HEX_to_A ( b % 16 ); // 0 разряд основного параметра
  163. b /= 16;
  164. USART_InfoData[7] = HEX_to_A ( b % 16 ); // 1 разряд основного параметра
  165. b /= 16;
  166. USART_InfoData[6] = HEX_to_A ( b % 16 ); // 2 разряд основного параметра
  167. USART_InfoData[5] = HEX_to_A ( b / 16 ); // 3 разряд основного параметра
  168. // Закодируем доп.параметр - напряжение сети
  169. if (fl.NotZero) { // Если сети нет, то и на выходе пусто
  170. USART_InfoData[12] = '0'; // 0 разряд основного параметра
  171. USART_InfoData[11] = '0'; // 1 разряд основного параметра
  172. USART_InfoData[10] = '0'; // 2 разряд основного параметра
  173. USART_InfoData[9] = '0'; // 3 разряд основного параметра
  174. } else {
  175. b = U_sum;
  176. USART_InfoData[12] = HEX_to_A ( b % 16 ); // 0 разряд основного параметра
  177. b /= 16;
  178. USART_InfoData[11] = HEX_to_A ( b % 16 ); // 1 разряд основного параметра
  179. b /= 16;
  180. USART_InfoData[10] = HEX_to_A ( b % 16 ); // 2 разряд основного параметра
  181. USART_InfoData[9] = HEX_to_A ( b / 16 ); // 3 разряд основного параметра
  182. }
  183. // Отправим
  184. Serial.write(USART_InfoData, 14);
  185. }
  186. #endif /* USE_ADprotocol */
  187. #ifdef USE_RMVK
  188. /* RMVK_/_Samovar */
  189. /**
  190. * @brief Функция возвращает значение текущего напряжения без десятичного знака
  191. */
  192. uint16_t get_Uin(void) {
  193. return ((U_real_dec < 5)? U_real : (U_real + 1));
  194. }
  195. /**
  196. * @brief Функция возвращает расчетное значение текущего (если getReal=true)
  197. * или желаемого (если getReal=false) напряжения
  198. */
  199. uint16_t get_Uout(const bool getReal) {
  200. if ( fl.Udown || fl.NotZero || (PDMust == 0) ) { // Если сеть в дауне или стаб в стопе - передаем ноль
  201. return 0;
  202. } else if ( getReal && ( fl.razg_on || fl.Ulow ) ) { // В разгоне и при недостаточном сетевом передаем текущее сетевое, если надо
  203. return get_Uin();
  204. } else { // В рабочем режиме - передаем уставку
  205. return calc_proportion(PDMust, U_LINE);
  206. }
  207. }
  208. /**
  209. * @brief Парсим управляющую последовательность от RMVK_/_Samovar
  210. */
  211. void USART_parser(void) {
  212. static String inoutString;
  213. static uint8_t index = 0;
  214. while (Serial.available() > 0) {
  215. char inChar = (char)Serial.read();// Вычитываем очередной байт
  216. if ( !index || fl.uartTimeout ) { // Начало посылки
  217. if ((inChar == 'A') || ((uint8_t)(inChar) == 0xD0)) { // Ждём первый символ посылки "A" или первый байт UTF-кириллицы из протокола Samovar'a
  218. inoutString = inChar;
  219. index=1;
  220. fl.uartTimeout = 0; // Сбросим флаг таймаута ожидания окончания посылки
  221. cnt_uartWDT = 0; // Сбросим таймер ожидания окончания посылки
  222. }
  223. } else if ( index++ < 13 ) { // Пока посылка не длиннее 13 символов, считаем её корректной
  224. if ( inChar == 0x0D ) { // Ждем последнего символа посылки <CR>
  225. index = 0;
  226. // Парсим строку, поскольку кончилась
  227. // В протоколе Samovar стандартное начало посылки "АТ" пересылается русскими символами в Юникоде. Баг или фича?
  228. if (( inoutString == ("AT+VI?")) || // Запрос текущего напряжения сети
  229. ( inoutString == ("АТ+VI?"))) { // В этой строке "АТ" - русскими символами!
  230. if (fl.NotZero) { // Если сети нет, то и на выходе пусто
  231. inoutString = String(0);
  232. } else {
  233. inoutString = String(get_Uin());
  234. }
  235. } else if (( inoutString == F("АТ+VO?")) || ( inoutString == F("АТ+VS?"))) { // Запрос текущей мощности от Samovar. В этой строке "АТ" - русскими символами!
  236. inoutString = String(get_Power());
  237. } else if ( inoutString == F("AT+VO?") ) { // Запрос текущего напряжения на выходе от РМВ-К
  238. inoutString = String(get_Uout(true));
  239. } else if ( inoutString == F("AT+VS?") ) { // Запрос напряжения уставки на выходе от РМВ-К
  240. inoutString = String(get_Uout(false));
  241. } else if ( inoutString == F("AT+ON?") ) { // Запрос состояния выхода от РМВ-К
  242. if ((PDMust == 0) || (fl.NotZero) || (fl.Udown)) { // Если на выходе 0
  243. inoutString = String("OFF");
  244. } else {
  245. inoutString = String("ON");
  246. }
  247. } else if (( inoutString == F("AT+SS?")) || // Запрос режима от Samovar
  248. ( inoutString == F("АТ+SS?"))) { // В этой строке "АТ" - русскими символами!
  249. if (fl.stab_off || fl.Udown || fl.NotZero) { // При аварии, сильно пониженном напряжении сети или его отсутствии - передаем ошибку
  250. inoutString = String(3);
  251. } else if (fl.razg_on) { // Передаем "Разгон"
  252. inoutString = String(1);
  253. } else if (PDMust == 0) { // Передаем "Стоп"
  254. inoutString = String(2);
  255. } else { // Передаем "Рабочий режим"
  256. inoutString = String(0);
  257. }
  258. } else if (( inoutString == F("AT+ON=0")) || // Запрос на выключение стабилизатора
  259. ( inoutString == F("АТ+ON=0"))) { // В этой строке "АТ" - русскими символами!
  260. if (!fl.stab_off) { // Если стаб не выключен аварийно...
  261. PDMust = 0;
  262. stop_razgon();
  263. Pust = 0;
  264. fl.dspNewData = 1; //Обновление информации на дисплее
  265. inoutString = "";
  266. }
  267. } else if (( inoutString == F("AT+ON=1")) || // Запрос на включение режима "Разгон"
  268. ( inoutString == F("АТ+ON=1"))) { // В этой строке "АТ" - русскими символами!
  269. if ((!fl.stab_off) && (!fl.NotZero) && (!fl.Udown) && (!fl.razg_off)) { // Если авария, электросеть в дауне или разгон запрещен - не разгонишься
  270. fl.razg_on = 1;
  271. fl.razg = 1;
  272. fl.dspNewData = 1; //Обновление информации на дисплее
  273. }
  274. inoutString = "";
  275. } else if ( inoutString.substring(0,8) == F("АТ+VS=") ) { // Запрос на изменение уставки от Samovar. В этой строке "АТ" - русскими символами!
  276. if (!fl.stab_off) { // Если стаб не выключен аварийно...
  277. //выключаем разгон, на всякий случай
  278. stop_razgon();
  279. set_newPDM (inoutString.substring(8).toInt()); // Установим новую уставку мощности
  280. inoutString = "";
  281. }
  282. } else if ( inoutString.substring(0,6) == F("AT+VS=") ) { // Запрос на изменение уставки от РМВ-К
  283. if (fl.stab_off || fl.Udown || fl.NotZero) { // Если авария или сеть в дауне - ничего не меняем, передаем ошибку
  284. inoutString = String(F("error"));
  285. } else {
  286. uint16_t tmp_u = inoutString.substring(6).toInt();
  287. if ( tmp_u < U_LINE ) {
  288. tmp_u *= CICLE;
  289. PDMust = tmp_u / U_LINE;
  290. } else PDMust = CICLE;
  291. //выключаем разгон, на всякий случай
  292. stop_razgon();
  293. set_Pust(); // Посчитаем Pust
  294. fl.dspNewData = 1; // Обновление информации на дисплее
  295. inoutString = String(get_Uout(false));
  296. }
  297. } else { // Неизвестная или закосяченная команда
  298. #ifdef Debug
  299. inoutString = String(F("(o_O unknown!)"));
  300. #else
  301. inoutString = "";
  302. #endif
  303. }
  304. if ( inoutString != "" ) { // Если строка не пустая
  305. inoutString += char(0x0D); // Добавляем в конец <CR>
  306. Serial.print( inoutString ); // Шлём!
  307. }
  308. } else { // Еще не конец
  309. inoutString += inChar; // Добавляем и это лыко в строку
  310. }
  311. } else { // Посылка длинновата, а значит - некорректна, начинаем сначала
  312. index = 0;
  313. }
  314. }
  315. }
  316. #endif /* RMVK_/_Samovar */