Добрый день! Суть такая, у меня есть одна мега и нано. В будущем будет температурный контроллер китайского производства. Хочу мегу подрубить к нане через RS485, а на нано повесить некоторое оборудование. Так же, уже написал часть программы на Qt , Мегу хочу держать подключенной к USB и общаться. Например с программы на PC выставили значения, они уходят в большем пакете в Мегу, В меге этот пакет обрабатывается и отсылается на китайский контроллер или на ардуино нано. Начал пока с общение мега-нано. Но проблема такая, я с меги отсылаю пакет, на нано он читается хорошо. Нано как прочитала пакет, должна скопировать значения, заполнить свой пакет и отправить на мегу. Но мега вообще не читает ничего, как будто ничего не приходит!! ПРошу помочь! Так же с лампочкой которой управляет нано по команде меги, есть проблемы, не очень корректно работет. ПРошу помочь, посмотреть мой код и навести на мысль Ардуино Мега: Код (C++): #include <SoftwareSerial.h> #define DIR 8 // переключатель прием\передача #define BUT 49 struct packet_big //пакет PC { byte start_byte_one;//в длинном пакете равен 254 byte start_byte_two;//в длинном пакете равен 232 byte temp_pomp;//температура охлаждения byte on_of_pomp;//on-off насоса (1 или 0) byte ex_temp_reactor;//текущая температура в реакторе byte current_temp_reactor;//выставленная температура в реакторе byte timer_ex;//таймер byte tmp;//пока не трогаем byte crv;//пока не трогаем }; struct packet_arduino_pomp //пакет Arduino nano { byte start_byte_one;//в коротком пакете равен 212 byte start_byte_two;//в коротком пакете равен 211 byte temp_pomp;//температура охлаждения byte on_of_pomp;//on-off насоса (1 или 0) byte tmp;//пока не трогаем byte CRC8;//пока не трогаем /*упаковать*/ void pask() { CRC8 = (start_byte_one + start_byte_two + temp_pomp + on_of_pomp + tmp) / 10; } /*проверка упаковки*/ bool test_pask() { if (CRC8 == (start_byte_one + start_byte_two + temp_pomp + on_of_pomp + tmp) / 10) return 0; //ОК return -1; // ошибка } }; packet_big one = {254, 232, 0, 0, 0, 0, 0, 0, 0}; packet_arduino_pomp one_pomp = {212, 211, 0, 0, 0, 0}; byte buttonState = 0; void setup() { Serial.begin(9600);//на PC Serial2.begin(9600); // SoftwareSerial на Arduino nano pinMode(BUT, INPUT); pinMode(DIR, OUTPUT); } void loop() { digitalWrite(DIR, HIGH); // включаем передачу buttonState = digitalRead(BUT); //кнопка byte* ptr28 = (byte* )&one; byte *ptr_pomp = (byte*)&one_pomp; if (buttonState == HIGH) //вкл/выкл от кнопки { if (one.on_of_pomp == 0) //если выключен , то перезаписываем в пакете (включаем) one.on_of_pomp = 1; else if (one.on_of_pomp == 1) //если включен, то перезаписываем в пакете (выключаем) one.on_of_pomp = 0; } one_pomp.on_of_pomp = one.on_of_pomp; // Serial.write(ptr28,sizeof(packet_big)); //передаем на PC one_pomp.pask(); Serial2.write(ptr_pomp, sizeof(packet_arduino_pomp)); //передаем на Arduino nano delay(200); digitalWrite(DIR, LOW); // включаем прием //прием с PC данных всех команд, включая информацию о температуре с реактора if (Serial.available() > sizeof(packet_big)) //возможно установить колличество байт { byte buf_big = Serial.read(); if (buf_big == 254) { buf_big = Serial.read(); if (buf_big == 232) { ptr28[0] = 254; ptr28[1] = buf_big; for (size_t i = 2; i < sizeof(packet_big); i++) { buf_big = Serial.read(); ptr28[i] = buf_big ; } } } } //возможно нужно повторно записать стартовый бит. //прием с ардуино nano данных о вкл/ вкл насоса и температуры охлаждения if (Serial2.available() >= sizeof(packet_arduino_pomp)) { byte buf_pump = 0; for (size_t i = 0; i < sizeof(packet_arduino_pomp); i++) { Serial.println("1"); if (i == 0 && (buf_pump = Serial2.read()) != 212) { Serial.println("2"); i = 0; continue; } if (i == 1 && (buf_pump = Serial2.read()) != 211) { Serial.println("3"); i = 0; continue; } if (i >= 2) { Serial.println("4"); buf_pump = Serial2.read(); ptr_pomp[i] = buf_pump; if (i == sizeof(packet_arduino_pomp) - 1) { Serial.println("5"); if (one_pomp.test_pask()) //проверяем контрольную сумму { Serial.println("6"); i = 0; continue; } } } } Serial.println("ON"); for (size_t i = 0; i < sizeof(packet_arduino_pomp); i++) { Serial.println( ptr_pomp[i]); } Serial.println("END"); } // запись данных из пакета от PC в пакет от ардуино и наобарот. // one.temp_pomp = one_pomp.temp_pomp; } Ардуино нано: Код (C++): #include <SoftwareSerial.h> #define DIR 8 // переключатель прием\передача #define ON 1 // вкл. клапан #define OFF 0 // вкл. клапан struct packet_arduino_pomp //пакет Arduino nano { byte start_byte_one;//в коротком пакете равен 212 byte start_byte_two;//в коротком пакете равен 211 byte temp_pomp;//температура охлаждения byte on_of_pomp;//on-off насоса (1 или 0) byte tmp;//пока не трогаем byte CRC8;//пока не трогаем /*упаковать*/ void pask() { CRC8 = (start_byte_one + start_byte_two + temp_pomp+on_of_pomp+tmp)/10; } /*проверка упаковки*/ bool test_pask() { if (CRC8 == (start_byte_one + start_byte_two + temp_pomp+on_of_pomp+tmp)/10) return 0; //ОК return -1; // ошибка } }; static packet_arduino_pomp one = {212,211,0,0,0,0};//пакет с данными byte temp_pomp = 0;//переменная для хранения температуры SoftwareSerial RS485 (2, 6); // RX, TX void setup() { Serial.begin(9600); RS485.begin(9600); // SoftwareSerial pinMode(DIR, OUTPUT); pinMode(3, OUTPUT); } void loop() { byte* ptr28 = (byte* )&one; digitalWrite(DIR, LOW); // включаем прием delay(200); if (RS485.available()>= sizeof(packet_arduino_pomp)) { byte buf_pump=0; for (size_t i = 0; i < sizeof(packet_arduino_pomp); i++) { Serial.println("1"); if(i==0&&(buf_pump = RS485.read())!=212) { Serial.println("2"); i=0; continue; } if(i==1&&(buf_pump = RS485.read())!=211) { Serial.println("3"); i=0; continue; } if(i>=2) { Serial.println("4"); buf_pump = RS485.read(); ptr28[i] = buf_pump; if(i==sizeof(packet_arduino_pomp)-1) { Serial.println("5"); if(one.test_pask())//проверяем контрольную сумму { Serial.println("6"); i=0; continue; } } } } Serial.println("ON"); for(size_t i = 0; i < sizeof(packet_arduino_pomp); i++) { Serial.println(ptr28[i]); } Serial.println("END"); if(one.on_of_pomp==ON) // включим клапан { digitalWrite(3, HIGH); // включим клапан } else if (one.on_of_pomp==OFF) digitalWrite(3, LOW); } one.temp_pomp = 55;//записываем значение температуры охлаждения в пакет на отправку one.pask();//формируем контрольную сумму delay(50); digitalWrite(DIR, HIGH); // включаем передачу RS485.write(ptr28,sizeof(packet_arduino_pomp)); delay(50); }
не вполне понятно, почему вы называете обычный сериал именем Rs485. Это совершенно разные протоколы. При беглом проглядывании кода ошибок не видно ( если считать, что там нет rs485, а есть обычный сериал). Думаю, ошибки проще всего искать вам самому - напихайте в код побольше отладочного вывода и смотрите.
Убераю все delay, все работает, но не долго, быстро уходит в штопор и начинает зацикливатся тчо на меге, что на нано в условии чтения : Код (C++): if (i == 1 && (buf_pump = Serial2.read()) != 211) { Serial.println("3"); i = 0; continue; } Что это могла быть?
Ну так и должно быть... В этом куске кода может и даже ДОЛЖНО зацикливаться. Условием выхода из цикла у вас является последовательное появление байт 211 и 212, верно? - Но вы же не проверяете, есть ли еще символы в Сериале... Когда буфер сериала исчерпан, функция read() начинает возвращать -1, а программа бесконечно читает пустой сериал и ищет значение 211
Обычная практика при работе с RS-485, помимо правильного переключения приём/передача - это ОБЯЗАТЕЛЬНО дожидаться завершения передачи по UART, например, так: Код (C++): // ждём завершения передачи по UART Serial3 while(!(UCSR3A & _BV(TXC3) ));
Дык DIYman вроде напсал, флажек TXC3 в регистре UCSR3A, для третьего сериала.... Для других заменить цифирьку 3 на соответствующий номер 0 или 1 или 2. Можно использовать и такую гадость как: Код (C++): // переключиться на передачу Serial.print("Blablablabla"); Serial.flush(); delay(1); // задержка должна быть равна времени передачи одного байта на текущей скорости // тут переключиться на прием Еще вариант: Код (C++): uint16_t temp=Serial.availableForWrite(); // переключиться на передачу Serial.print("Blablablabla"); while (Serial.availableForWrite()>=temp); delay(1); // задержка должна быть равна времени передачи одного байта на текущей скорости // тут переключиться на прием
Совсем не гадость, я просто забыл упомянуть - помимо флага очистки буфера в нужном UART - я ишшо жду таймаута при чтении, равного времени передачи нескольких байт (зависит от специфики). Т.е. по завершению передачи сразу переключаюсь на приём - ну а там в цикле - таймаут ловлю уже. Ту же фишку можно проделать и при помощи delay, как вы и описали - просто она не обеспечивает всей гибкости - мало ли что там надо ещё сделать, ожидаючи - ответил ли клиент. И хотя я и активно юзаю yield для критичных ко времени задач - всё равно находятся дела, которые можно поделать в цикле, ждучи, пока либо ведомый просрётся пакетом в шину, либо - наступит звездец в виде таймаута.