Параллельные задачи исключают любые циклы?
- Войдите на сайт для отправки комментариев
Пнд, 27/01/2020 - 07:25
Есть два участка программы которые должны работать параллельно. По отдельности они выполняют свои функции на отлично. Решил использовать библиотеку <Thread.h>, но она исключает delay. Тогда решил использовать millis для задержек. Сделал, но в части кода есть цикл do while, во время выполнения которого все равно ничего другого не работает. Неужели нельзя написать более-менее сложную программу с несколькими потоками вычислений?
Программа меряет Вольтаж и усредняет за промежуток времени, после записывает на флешку (пока не выводит, т.к. настраиваю через монитор порта).
Moderator : пожалуйста, вставьте код правильно (возможно, новым сообщением в тему),
если ты задачу опишешь внятно, да код вставишь правильно, то мошт чо и придумаеца.
http://arduino.ru/forum/obshchii/vstavka-programmnogo-koda-v-temukommentarii
Неужели нельзя написать более-менее сложную программу с несколькими потоками вычислений?
Неужели нельзя написать более-менее сложную программу с несколькими потоками вычислений?
Можно... наверное.
Дурдуина с несколькими потоками вычислений??? Поржал!
Сделал, но в части кода есть цикл do while, во время выполнения которого все равно ничего другого не работает. Неужели нельзя написать более-менее сложную программу с несколькими потоками вычислений?
можно, но от цикла while , скорее всего, придется отказаться. Все это отлично пишется на одних миллис, без всяких потоков
Спасибо, извините, первый день тут
#include <SPI.h> //Подключаем библиотеки #include <SD.h> #include <Thread.h> Thread Razbavlenie = Thread(); Thread Data = Thread(); #define Vremya_izmereniya_min 0.5 //Параметры для управления времени запси данных и количества измерений #define Kolichestvo_izmereniy 100 #define Uslovie_zakr 4.4 //Параметры работы клапана #define Uslovie_otkr 2.8 float Uphre = A0; //Присваиваем имя и аналоговым и цифровым контактам и задаем тип данных int SDled = 9; int Rele = 8; const int chipSelect = 4; float Uanalog = 0; //Присваиваем имя переменным и задаем тип данных float Udigital[Kolichestvo_izmereniy]; float Uavgdigital = 0; int i = 0; int ledblink = 0; float UdigitalKlap = 0; float sum = 0; void setup(){ Serial.begin(9600); //Инициируем последовательное соединение и задаем скорость передачи данных между ПК и Ардуино в бит/c pinMode(Rele, OUTPUT); pinMode(SDled, OUTPUT); Data.onRun(Dannie); // назначаем потоку задачу Data.setInterval(100); Razbavlenie.onRun(Klapan); // назначаем потоку задачу Razbavlenie.setInterval(10000); // задаём интервал срабатывания, мсек } void loop() { if (Razbavlenie.shouldRun()) Razbavlenie.run(); // запускаем поток if (Data.shouldRun()) Data.run(); // запускаем поток } void Dannie() { for(i=0; i<Kolichestvo_izmereniy; i++){ Uanalog = analogRead(Uphre); //Считываем значение с указанного аналогового входа Udigital[i] = Uanalog*5.0/1023.0; //Преобразуем поток аналоговых данных в цифровые данные Uavgdigital += Udigital[i]; //Serial.print("SumSD =\t"); //Serial.print(i); //Serial.print("\t"); //Serial.println(Uavgdigital); delay(Vremya_izmereniya_min*60000/Kolichestvo_izmereniy);//расчет разрыва измерений = время измерений (мин) * 60000 (кол-во милисекунд в минуте) / количество измерений } //Serial.print("UavgSD =\t"); //Serial.println(Uavgdigital/Kolichestvo_izmereniy);//Производим вывод данных в монитор последовательного интерфейса File dataFile = SD.open("lite.txt", FILE_WRITE); //Запись на флешку данных в фаил лайт if (dataFile) { dataFile.println(Uavgdigital/Kolichestvo_izmereniy); dataFile.close(); } Uavgdigital = 0; //обнуление среднего значения после записи } void Klapan() { Uanalog = analogRead(Uphre); UdigitalKlap = Uanalog*5.0/1023.0; //Serial.print("UdigitalKlap =\t"); //Serial.println(UdigitalKlap); if (UdigitalKlap <= Uslovie_otkr) { Uavgdigital = 0; sum = 0; for(i=0; i<100; i++){ Uavgdigital = 0.0; Uanalog = analogRead(Uphre); Udigital[i] = Uanalog*5.0/1024.0; sum += Udigital[i]; //Serial.print("SUM1C =\t"); //Serial.print(i); //Serial.print("\t"); //Serial.println(sum); delay(100); } Uavgdigital = sum/100; //Serial.print("UavgD1C =\t"); //Serial.println(Uavgdigital); if (Uavgdigital <= Uslovie_otkr) { do { Uavgdigital = 0; sum = 0; digitalWrite(Rele, HIGH); delay(5000); digitalWrite(Rele, LOW); delay(10000); for(i=0; i<99; i++){ Uanalog = analogRead(Uphre); Udigital[i] = Uanalog*5.0/1024.0; sum += Udigital[i]; //Serial.print("SUM2C =\t"); //Serial.print(i); //Serial.print("\t"); //Serial.println(sum); delay(100); } Uavgdigital = sum/100; //Serial.print("UavgD2C =\t"); //Serial.println(Uavgdigital); } while(Uavgdigital <= Uslovie_zakr); digitalWrite(Rele, LOW); } } }и где вы "переписали на миллис"? Сплошные делеи в коде, такое никакими потоками не вылечить
Сплошные делеи в коде, такое никакими потоками не вылечить
Я пытался сделать потоки с делеями на специально для этого предназначенном языке - получил эпичный облом :-(
Потоки с делеями есть на rtos. Которая прожорлива по памяти, но для мелких задач помещается в уно.
да, это старый участок кода, сейчас поделюсь миллис, но он не доделан. Вторая часть кода отключена, т.к. проблема в первом участке, т.к. пока крутится do while ничего другого не происходит. Суть - есть два потока - один записывает данные вольтметра (фоторезистор стоит напротив светодиода, а между ними протекает жидкость, которая со временем пропускает все меньше света (загрязняется), и когда напряжение достигает нижнего порога Uslovie_otkr происходит открытие клапана, который эту жидкость разбавляет уже до верхнего предела Uslovie_zakr) на SD с усреднением за установленный параметрами период времени Vremya_izmereniya_min с установленным шагом Kolichestvo_izmereniy. Второй поток поверяет вольтаж уже чаще и если он меньше нижнего порога Uslovie_otkr то начинает усреднять вольтаж - 100 измерений с задержкой 100 мс. Если условие уже усредненного значения вольтажа все еще меньше Uslovie_otkr, то программа запускает открытие клапана на 5 секунд, ждет 10 секунд (пока идет перемешивание), затем опять измеряет вольтаж, усредняет его и опять сравнивает условие уже этого усреднения с Uslovie_zakr, если оно выполняется, то выходит из цикла. По сути пол получается пилообразный график.
#include <SPI.h> //Подключаем библиотеки #include <SD.h> #define Vremya_izmereniya_min 0.2 //Параметры для управления времени запси данных и количества измерений #define Kolichestvo_izmereniy 10 #define Uslovie_zakr 4.4 //Параметры работы клапана #define Uslovie_otkr 2.8 float Uphre = A0; //Присваиваем имя и аналоговым и цифровым контактам и задаем тип данных int SDled = 9; int Rele = 8; const int chipSelect = 4; float Uanalog = 0; //Присваиваем имя переменным и задаем тип данных float Udigital[Kolichestvo_izmereniy]; float Uavgdigital = 0; int i = 0; int k = 0; int m = 0; int ledblink = 0; float UdigitalKlap = 0; float sum = 0; unsigned long Time1; unsigned long Time2; unsigned long Time3; unsigned long Time4; void setup(){ Serial.begin(9600); //Инициируем последовательное соединение и задаем скорость передачи данных между ПК и Ардуино в бит/c pinMode(Rele, OUTPUT); pinMode(SDled, OUTPUT); } void loop() { if (millis()- Time1 > 100) { Time1 = millis(); do{ if( millis()- Time2 > Vremya_izmereniya_min*60000/Kolichestvo_izmereniy) //расчет разрыва измерений = время измерений (мин) * 60000 (кол-во милисекунд в минуте) / количество измерений { Time2 = millis(); for(i=0; i<1; i++){ Uanalog = analogRead(Uphre); //Считываем значение с указанного аналогового входа Udigital[i] = Uanalog*5.0/1023.0; //Преобразуем поток аналоговых данных в цифровые данные Uavgdigital += Udigital[i]; k++; Serial.print("SumSD =\t"); Serial.print(k); Serial.print("\t"); Serial.println(Uavgdigital); } } }while (k<Kolichestvo_izmereniy); //Serial.print("UavgSD =\t"); //Производим вывод данных в монитор последовательного интерфейса //Serial.println(Uavgdigital/Kolichestvo_izmereniy); File dataFile = SD.open("lite.txt", FILE_WRITE); //Запись на флешку данных на SD карту if (dataFile) { dataFile.println(Uavgdigital/Kolichestvo_izmereniy); dataFile.close(); } Uavgdigital = 0; k = 0; } if (millis()- Time3 > 1000) { Time3 = millis (); Serial.println(1111); } /* Uanalog = analogRead(Uphre); //Считываем значение с указанного аналогового входа UdigitalKlap = Uanalog*5.0/1023.0; Serial.print("UdigitalKlap =\t"); Serial.println(UdigitalKlap); if (UdigitalKlap <= Uslovie_otkr) { do { Uavgdigital = 0; sum = 0; if(millis()- Time1 > 100) { for(i=0; i<1; i++){ Uanalog = analogRead(Uphre); Udigital[i] = Uanalog*5.0/1024.0; sum += Udigital[i]; m++; Serial.print("SUM1C =\t"); Serial.print(m); Serial.print("\t"); Serial.println(sum); } } }while (m<100); Uavgdigital = sum/100; //Serial.print("UavgD1C =\t"); //Serial.println(Uavgdigital); if (Uavgdigital <= Uslovie_otkr) { do { Uavgdigital = 0; sum = 0; digitalWrite(Rele, HIGH); delay(5000); digitalWrite(Rele, LOW); delay(10000); for(i=0; i<99; i++){ Uanalog = analogRead(Uphre); Udigital[i] = Uanalog*5.0/1024.0; sum += Udigital[i]; //Serial.print("SUM2C =\t"); //Serial.print(i); //Serial.print("\t"); //Serial.println(sum); delay(100); } Uavgdigital = sum/100; //Serial.print("UavgD2C =\t"); //Serial.println(Uavgdigital); } while(Uavgdigital <= Uslovie_zakr); digitalWrite(Rele, LOW); } } }*/ }Кроме лупа и прочих циклов, в ардуине, и не только, существуют функции, заглядывать в них разрешается из любого места.
Artas - конкретно в ваши обьяснения я не вчитывался, но по коду могу рассказать. что вам нужно изменить.
Если вы хотите работать в несколько потоков на однопроцессорной системе, все длинные циклы. где программа проводит десятки секунд - все эти while и for - должны быть безжалостно выкинуты. Программу надо кардинально переписать.
Общий принцип - возьмем для примера ваш цикл for. который делает 100 измерений с интервалом 100мс. У вас в программе он написан в блокирующем стиле - то есть программа заходит в цикл и сидит в нем, пока не сделает все измерения - то есть 100 * 0.1 сек = 10 сек. По меркам мира электроники 10 сек - это вечность.
Вместо цикла делаем так: - пишем коротенькую процедуру, которая делает один замер (а не 100!) и без всяких задержек заканчивает работу, позволяя программе перейти к работе с другим потоком. Делаем что-то во втором потоке, а через 100мс (отмеряем с помощью миллис )- снова заходим в процедуру и снова делаем один замер. И так, пока не сделаем все 100 измерений.
естесственно, второй поток, все ваши бесконечные while - тоже должен быть переписан так, чтобы система делала одно короткое действие и выходила из процедуры в основной цикл.
таким образом можно делать параллельно и два дела. и три, больше... и без всяких тяжелых библиотек типа Threads или RTOS- которые, в общем-то - работают ровно на том же принципе переключения
Вместо цикла делаем так: - пишем коротенькую процедуру, которая делает один замер (а не 100!) и без всяких задержек заканчивает работу, позволяя программе перейти к работе с другим потоком. Делаем что-то во втором потоке, а через 100мс (отмеряем с помощью миллис )- снова заходим в процедуру и снова делаем один замер. И так, пока не сделаем все 100 измерений.
Естественно, второй поток, все ваши бесконечные while - тоже должен быть переписан так, чтобы система делала одно короткое действие и выходила из процедуры в основной цикл.
Действительно помогло, Спасибо. Мне, как человеку, который занимается этим ок. месяца было очень трудно, странно, что нет никаких реально работающих библиотек. В общем с кучей костылей все работает, спасибо большое)
Действительно помогло, Спасибо. Мне, как человеку, который занимается этим ок. месяца было очень трудно, странно, что нет никаких реально работающих библиотек. В общем с кучей костылей все работает, спасибо большое)
Конечно, когда уже есть готовый код и надо весь перекорежить - это непрсото. А вот если сразу писать в этом стиле - будет легче, и костылей не понадобится.