Доброго времени суток! Написал код для удаленного управления Вебастой на авто в АрдуиноИДЕ.
На ардуино НАНО 328чип, код работает как надо с аппаратным плюс программным последовательным портом. Но мне нужно два аппаратных порта, так как на програмном не нашел как включить бит проверки четности, поэтому глаз пал на ATtiny841. К сожалению код на тиньке не работает так как на НАНО.
Программирую тиньку USBasp без бутлоудера, резонатор использовал 8 и 16 МГц. Ядро для тиньки разные пробывал, результат одинаков. Проблема в том что код на тиньки как то теряет данные котрые необходимо отправлять по первому порту, да и с приемом то же проблемы.
1. //#include <SoftwareSerial.h> // Библиотека програмной реализации обмена по UART-протоколу для ардуино
2. //SoftwareSerial Serial1(5, 6); // RX, TX
3. uint32_t time_call = 0; // переменная для запоминания времени кода был начат вызов
4. String _response = ""; // Переменная для хранения ответов модуля
5. uint8_t countTry = 0; // переменная хранения количество неудачных попыток ввода кода
6. uint8_t countByte_Rx = 0; // переменная хранящая количество принятых байт
7. uint8_t countByte_Tx = 0; // переменная хранящая количество переданных байт
8. bool set_call = 0; // флаг установки вызова
9. bool act_call = 0; // флаг активного вызова
10. byte recive[15]; // массив для хранения и обработки приходящих сообщений от Вебасты
11. #define sec 10000 // уставка периуда отпраки сообщения поддержания работы
12. #define sec_call 20000 // уставка максимального времени вызова
13. #define timeOUT 5000 // таймаут ожидания ответа от модема
14. #define NumberPhone "ATD+79775559988;" // номер телефона на который будут совершаться звонки
15. #define PASSWORD_USER 99 // пароль (для евеличения кол-во символов пароля требуется изменить допустимое кол-во введенных \
16. // символов в строке кода:"else if (result.length() <= 3) {" и используемые символы для пароля \
17. // в "if (result.substring(2, 4).toInt() == PASSWORD) {")
18. // для ATtiny841:
19. #define LED_GREEN PA0 // пин для подключения сетодиода индикатора что МК не завис
20. #define LED_PIN_1 PA7 // пин для подключения сетодиода индикатора что что команда вкл Вебасты прошла
21. #define RESET_PIN_SIM800 PA6 // пин для сброса сим800
22. // для Ардуино:
23. /*
24. #define LED_GREEN 12 // пин для подключения сетодиода индикатора что МК не завис
25. #define LED_PIN_1 13 // пин для подключения сетодиода индикатора что что команда вкл Вебасты прошла
26. #define RESET_PIN_SIM800 11 // пин для сброса сим800
27. */
28. #define per_proverki_sim800 3000 // период отправки сообщения модему для проверки что он не завис, ожидаем ответ
29. #define per_indikaci 3000 // период между индикацией сколько раз модем был перезагружен
30. byte requestON[5] = { 0x34, 0x03, 0x21, 0x00, 0x00 };
31. String result = ""; // Переменная для хранения вводимых данных
32. uint32_t time_proverki_sim800 = 0; //переменная для периода отправки сообщения модему для проверки что он не завис
33. uint32_t time_LED_GREEN = 0;
34. int count_reset = 0; // счетчик перезагрузок модема
35. void setup() {
36. pinMode(RESET_PIN_SIM800, OUTPUT);
37. digitalWrite(RESET_PIN_SIM800, HIGH);
38. pinMode(LED_PIN_1, OUTPUT); // Настройка пина подключения светодиода на выxод
39. pinMode(LED_GREEN, OUTPUT);
40. digitalWrite(LED_GREEN, HIGH);
41. Serial.begin(9600);
42. Serial1.begin(2400);
43. Serial.println("Start");
44. Serial.setTimeout(300);
45. //delay(6000);
46. digitalWrite(LED_GREEN, LOW);
47. _response = sendATCommand("AT", true); // Проверка общего статуса
48. _response = sendATCommand("AT+DDET=1,0,0", true); // Включаем DTMF
49. Serial.println("END Setup");
50. }
51. void loop() {
52. if (time_LED_GREEN <= millis()) {
53. for (int i = 1; i <= count_reset; i++) {
54. digitalWrite(LED_GREEN, HIGH);
55. delay(300);
56. digitalWrite(LED_GREEN, LOW);
57. delay(300);
58. }
59. time_LED_GREEN = millis() + per_indikaci;
60. }
61. if (time_proverki_sim800 <= millis()) {
62. _response = sendATCommand("AT Proverka", true); // Проверка общего статуса
63. if (_response == 0) {
64. count_reset++;
65. digitalWrite(RESET_PIN_SIM800, LOW);
66. delay(100);
67. digitalWrite(RESET_PIN_SIM800, HIGH);
68. //delay(6000); // даем время GSM модулю начать работу
69. _response = sendATCommand("AT reset", true); // Проверка общего статуса
70. _response = sendATCommand("AT+DDET=1,0,0", true); // Включаем DTMF
71. }
72. time_proverki_sim800 = millis() + per_proverki_sim800;
73. }
74. if (Serial.available()) { // Если модем, что-то отправил...
75. _response = waitResponse(); // Получаем ответ от модема для анализа
76. int index = -1;
77. do { // Перебираем построчно каждый пришедший ответ
78. index = _response.indexOf("\r\n"); // Получаем идекс переноса строки
79. String submsg = "";
80. if (index > -1) { // Если перенос строки есть, значит
81. submsg = _response.substring(0, index); // Получаем первую строку
82. _response = _response.substring(index + 2); // И убираем её из пачки
83. } else { // Если больше переносов нет
84. submsg = _response; // Последняя строка - это все, что осталось от пачки
85. _response = ""; // Пачку обнуляем
86. }
87. submsg.trim(); // Убираем пробельные символы справа и слева
88. if (submsg != "") { // Если строка значимая (не пустая), то распознаем уже её
89. if (submsg.startsWith("+DTMF:")) { // Если ответ начинается с "+DTMF:" тогда:
90. String symbol = submsg.substring(7, 8); // Выдергиваем символ с 7 позиции длиной 1 (по 8)
91. //Serial.println(symbol);
92. processingDTMF(symbol); // Логику выносим для удобства в отдельную функцию
93. } else if (submsg.startsWith("RING")) { // При входящем звонке...
94. sendATCommand("ATA", true); // ...отвечаем (поднимаем трубку)
95. result = ""; // очищаем строку от возможных данных
96. set_call = 1; // устанавливаем флаг установки вызова
97. countTry = 0; // При каждом звонке, сбрасываем счетчик попыток
98. }
99. }
100. } while (index > -1); // Пока индекс переноса строки действителен
101. }
102. if (set_call == 1) {
103. time_call = millis() + sec_call; // установка максимального времени вызова
104. set_call = 0; // устанавливаем флаг неактивный вызов*
105. act_call = 1; // устанавливаем флаг активного вызова
106. }
107. if ((time_call <= millis()) && (act_call == 1)) { // если вызов превысил установленное время и был активным
108. act_call = 0;
109. result = "";
110. Serial.println("ATH"); // кладем трубку(прекращаем вызов)
111. }
112. data_Rx(0);
113. if (((recive[7] == 0xA1) && (recive[9] == 0xEE)) || ((recive[8] == 0xC4) && (recive[10] == 0x84))) {
114. static uint32_t p_tx_podd = 0; // переменная для запоминания времени когда было отправлено сообщение поддерж раб Вебасто
115. if (p_tx_podd < millis()) {
116. memset(recive, 0x00, countByte_Rx);
117. podderzhanie();
118. p_tx_podd = millis() + sec;
119. }
120. } else if (((recive[8] == 0xFF) && (recive[9] == 0x7B)) || ((recive[9] == 0xFF) && (recive[10] == 0x7B)) || ((recive[6] == 0x90) && (recive[7] == 0xD1))) {
121. digitalWrite(LED_PIN_1, LOW);
122. delay(400);
123. memset(recive, 0x00, countByte_Rx);
124. sendATCommand(NumberPhone, true); // набираем свой номер телефона
125. set_call = 1; // устанавливаем флаг установки звонка
126. }
127. }
128. String sendATCommand(String cmd_GSM, bool waiting) {
129. //String sendATCommand(String cmd_GSM) {
130. String _resp = ""; // Переменная для хранения результата
131. Serial.println("1");
132. Serial.println(cmd_GSM); // Отправляем команду модулю
133. Serial.println("2");
134. if (waiting) { // Если необходимо дождаться ответа...
135. _resp = waitResponse(); // ... ждем, когда будет передан ответ
136. // Если Echo Mode выключен (ATE0), то эти 3 строки можно закомментировать
137. //if (_resp.startsWith(cmd_GSM)) { // Убираем из ответа дублирующуюся команду
138. // _resp = _resp.substring(_resp.indexOf("\r\n", cmd_GSM.length()) + 2);
139. //}
140. }
141. return _resp; // Возвращаем результат. Пусто, если проблема
142. }
143. String waitResponse() { // Функция ожидания ответа и возврата полученного результата
144. String _resp = ""; // Переменная для хранения результата
145. uint32_t _timeout = millis() + timeOUT; // Переменная для отслеживания таймаута (10 секунд)
146. while (!Serial.available() && (millis() < _timeout)) {}; // Ждем ответа 10 секунд, если пришел ответ или наступил таймаут, то...
147. if (Serial.available() > 0) { // Если есть, что считывать...
148. _resp = Serial.readString(); // ... считываем и запоминаем
149. //Serial.println("1" + _resp);
150. }
151. // else { // Если пришел таймаут, то...
152. // FROGI.println("Timeout..."); // ... оповещаем об этом и...
153. // }
154. return _resp; // ... возвращаем результат. Пусто, если проблема
155. }
156. // Отдельная функция для логики DTMF
157. void processingDTMF(String symbol) {
158. if (symbol == "#") { // если введен символ #, то проверяем введенный код
159. if (result.substring(2, 4).toInt() == PASSWORD_USER) { //преобразуем 2 и 3 символ из пришедшей строки в целочисленный тип данных и сверяем с паролем, далее если пароль верный
160. byte val_time = result.substring(0, 2).toInt(); // преобразуем 0 и 1 символ из пришедшей строки в целочисленный тип данных
161. if ((val_time > 14) && (val_time < 100)) { // сравниваем больше оно 14 и меньше ли 100, так как это время для работы Вебасты
162. setWBSTState(HIGH, val_time); // отправляем в функцию состояния вебасты флаг на включение и запрошенное время работы
163. countTry = 0; // Обнуляем счетчик неудачных попыток ввода кода
164. } else if (val_time == 0) { // если введенное значение равно 0, то
165. Serial.println("ATH"); // кладем трубку(прекращаем вызов)
166. act_call = 0; // выключаем флаг активного звонка
167. setWBSTState(LOW, 0x00); // отправляем в функцию состояния вебасты флаг на вЫключение
168. countTry = 0; // Обнуляем счетчик неудачных попыток ввода кода
169. }
170. } else { // если пароль неверный
171. countTry += 1; // Увеличиваем счетчик неудачных попыток на 1
172. if (countTry == 3) { // если счетчик неуд.попыток равен 3
173. Serial.println("ATH"); // кладем трубку(прекращаем вызов)
174. act_call = 0; // выключаем флаг активного звонка
175. countTry = 0; // Обнуляем счетчик неудачных попыток ввода кода
176. }
177. }
178. result = ""; // После каждой решетки сбрасываем вводимую комбинацию
179. }
180. else if (result.length() <= 6) { //если количество символов в result <= 6
181. result += symbol; // Все, что приходит, собираем в одну строку
182. } else {
183. result = ""; // Сбрасываем вводимую комбинацию при вводе большем кол-ве чем кол-во разрешенных символов(это блокировка против роста строки) и при введенной решетки
184. }
185. }
186. void data_Rx(int o) { // функция приема сообщений от Вебасты
187. if (Serial1.available()) { // Если есть, что считывать...
188. delay(100); // ждем пока все придет
189. countByte_Rx = Serial1.available(); // запоминаем сколько байт в буфере
190. Serial1.readBytes(recive, countByte_Rx); // считываем из буфера приема
191. byte checksum = 0x00;
192. for (uint8_t i = countByte_Tx; i < countByte_Rx - 1; i++) {
193. checksum = checksum ^ recive[i]; // расчет чексуммы ксор входных данных
194. }
195. if (checksum != recive[countByte_Rx - 1]) { // если расчитанная КС не равно последнему байту сообщения, то данные повреждены и мы их стираем
196. memset(recive, 0x00, countByte_Rx);
197. switch (o) {
198. case 1:
199. ON_Wbst();
200. break;
201. case 2:
202. podderzhanie();
203. break;
204. case 3:
205. OFF_Wbst();
206. break;
207. //default:
208. // выполняется, если не выбрана ни одна альтернатива
209. // default необязателен
210. }
211. }
212. }
213. }
214. void podderzhanie() {
215. byte msg_podd[6] = { 0x34, 0x04, 0x44, 0x21, 0x00, 0x55 }; // Сообщение для поддержания работы, без него котел отключится, отправлять не реже 15 секунд
216. Serial1.write(msg_podd, 6);
217. memset(recive, 0x00, countByte_Rx);
218. countByte_Tx = 6;
219. delay(400);
220. data_Rx(2);
221. }
222. void setWBSTState(bool state, byte request_TimerWork) { // Функция изменения состояния Вебасты (ВКЛ\ВЫКЛ)
223. digitalWrite(LED_PIN_1, state);
224. if (state == LOW) {
225. OFF_Wbst();
226. }
227. if (state == HIGH) {
228. requestON[3] = request_TimerWork; // Сообщение запроса на работу где request_TimerWork это время (0x0F = 15 мин)(0x0E = 14) и т.д.
229. requestON[4] = requestON[0] xor requestON[1] xor requestON[2] xor requestON[3]; // расчитываем КС в четвертый байт(последний)
230. Serial.println("ATH"); // кладем трубку(прекращаем вызов)
231. act_call = 0;
232. ON_Wbst();
233. }
234. }
235. void ON_Wbst() {
236. //Serial1.begin(300);
237. //Serial1.write(0x0);
238. //Serial1.begin(2400);
239. Serial1.write(requestON, 5);
240. countByte_Tx = 5;
241. delay(400);
242. data_Rx(1);
243. }
244. void OFF_Wbst() {
245. byte requestOFF[5] = { 0x34, 0x02, 0x10, 0x26 }; // сообщение на вЫключение Вебасты
246. Serial1.write(requestOFF, 4);
247. countByte_Tx = 4;
248. delay(400);
249. data_Rx(3);
250. }