- Какво е многозадачност?
- Защо да пропуснете закъснението () в Arduino?
- Защо да използвам милис ()?
- Необходими компоненти
- Електрическа схема
- Програмиране на Arduino UNO за многозадачност
В многозадачността е довело до компютрите революция, където една или повече програми могат да работят едновременно, което увеличава ефективността, гъвкавост, адаптивност и производителността. Във вградени системи микроконтролерите също могат да се справят с многозадачност и изпълняват едновременно две или повече задачи, без да спират текущите инструкции.
Тук в този урок ще научим как Arduino изпълнява многозадачност с функцията Arduino millis. Обикновено функцията за забавяне () се използва в Arduino за периодична задача като LED мига, но тази функция за забавяне () спира програмата за известно време и не позволява извършването на други операции. Така че тази статия обяснява как можем да избегнем използването на функцията delay () и да я заменим с millis (), за да изпълняваме повече от една задача едновременно и да направим Arduino многозадачен контролер. Преди да влезем в подробности, нека започнем с подценяване на многозадачността.
Какво е многозадачност?
Многозадачността просто означава едновременно изпълнение на повече от една задача или програма. Почти всички операционни системи се отличават с многозадачност. Този вид операционни системи са известни като MOS (многозадачна операционна система). MOS може да бъде мобилна или настолна операционна система за компютър. Добрият пример за многозадачност в компютрите е, когато потребителите изпълняват едновременно приложението за електронна поща, интернет браузъра, медийния плейър, игрите и ако потребителите не искат да използват приложението, то работи във фонов режим, ако не е затворено. Крайният потребител използва всички тези приложения едновременно, но ОС приема тази концепция малко по-различно. Нека да обсъдим как ОС управлява многозадачност.
Както се вижда на снимката, процесорът разделя времето на трите равни части и присвоява всяка част на всяка задача / приложение. По този начин се извършва многозадачността в повечето системи. Концепцията ще бъде почти еднаква за Arduino Multitasking, с изключение на това, че разпределението на времето ще бъде малко по-различно. Тъй като Arduino работи с ниска честота и RAM в сравнение с Laptop / Mobile / PC, така че времето, дадено на всяка задача, също ще бъде различно. Arduino също има функция за забавяне (), която се използва широко. Но преди да започнем, нека обсъдим защо не трябва да използваме функцията delay () във всеки проект.
Защо да пропуснете закъснението () в Arduino?
Ако се разглежда референтната документация на Arduino, тогава има два типа функции за забавяне, първата е delay (), а втората delayMicroseconds (). И двете функции са идентични по отношение на генерирането на забавяне. Единствената разлика е, че при функцията delay () цялото число на параметъра е в милисекунди, т.е. ако напишем delay (1000), тогава забавянето ще бъде от 1000 милисекунди, т.е. 1 секунда. По подобен начин във функцията delayMicroseconds (), параметърът е предаден в микросекунди, т.е. ако напишем delayMicroseconds (1000), тогава забавянето ще бъде от 1000 микросекунди, т.е. 1 милисекунди.
Тук идва въпросът, и двете функции поставят програмата на пауза за времето, изминало във функцията за забавяне. Така че, ако даваме закъснение от 1 секунда, тогава процесорът не може да премине към следващата инструкция, докато не премине 1 секунда. По същия начин, ако закъснението е 10 секунди, програмата ще спре за 10 секунди и процесорът няма да позволи да следва следващите инструкции, докато не изтекат 10 секунди. Това затруднява работата на микроконтролера по отношение на скоростта и изпълнението на инструкциите.
Най-добрият пример за обяснение на недостатъка на функцията за забавяне е използването на два бутона. Помислете, че искаме да превключваме два светодиода с помощта на два бутона. Така че, ако се натисне един бутон, тогава съответният светодиод трябва да свети за 2 секунди, по същия начин, ако се натисне втори, тогава светодиодът трябва да свети за 4 секунди. Но когато използваме delay (), ако потребителят натиска първия бутон, програмата ще спре за 2 секунди и ако потребителят натисне втория бутон преди 2 секунди закъснение, тогава микроконтролерът няма да приеме входа, тъй като програмата е в етап на спиране.
Официалната документация на Arduino ясно споменава това в своето описание на функцията Бележки и предупреждения за забавяне (). Можете да преминете и да проверите това, за да стане по-ясно.
Защо да използвам милис ()?
За да преодолее проблема, причинен от използването на забавяне, разработчикът трябва да използва функцията millis (), която е лесна за използване, след като станете обичайна и тя ще използва 100% производителност на процесора, без да генерира забавяне при изпълнението на инструкциите. millis () е функция, която просто връща количеството милисекунди, изминали откакто платката Arduino започна да изпълнява текущата програма, без да замрази програмата. Този номер на времето ще прелее (т.е. ще се върне на нула), след приблизително 50 дни.
Точно както Arduino има delayMicroseconds (), той също има микро версията на milis () като микро (). Разликата между микро и мили е, че микро () ще прелее след приблизително 70 минути, в сравнение с милис (), което е 50 дни. Така че в зависимост от приложението можете да използвате милис () или микро ().
Използване на милис () вместо забавяне ():
За да използвате милиса () за синхронизиране и забавяне, трябва да запишете и съхраните времето, в което се е извършило действието, за да започнете часа и след това да проверите на интервали дали определеното време е изтекло. Така че, както е посочено, съхранявайте текущото време в променлива.
неподписан дълъг токMillis = милис ();
Нуждаем се от още две променливи, за да разберем дали е изминало необходимото време. Съхранили сме текущото време в променливата currentMillis, но също така трябва да знаем, кога е започнал периодът на времето и колко е периодът. Така се декларира Interval и previousMillis . Интервалът ще ни покаже закъснението и previosMillis ще съхрани последния път, когато е настъпило събитието.
неподписан дълъг предишенMillis; неподписан дълъг период = 1000;
За да разберем това, нека вземем пример за обикновен мигащ светодиод. Периодът = 1000 ще ни каже, че светодиодът ще мига за 1 секунда или 1000ms.
const int ledPin = 4; // номерът на LED щифта е свързан int ledState = LOW; // използва се за задаване на светодиодно състояние без знак дълго предишенMillis = 0; // ще съхранява последния път, когато светодиодът е мигал const дълъг период = 1000; // период, през който да мига в ms void setup () { pinMode (ledPin, OUTPUT); // задаваме ledpin като изход } void loop () { unsigned long currentMillis = millis (); // съхраняваме текущото време if (currentMillis - previousMillis> = period) {// проверяваме дали 1000ms са преминали previousMillis = currentMillis; // запазваме последния път, когато сте мигали светодиода, ако (ledState == LOW) {// ако светодиодът е изключен, включете го и обратно ledState = HIGH; } else { ledState = LOW; } digitalWrite (ledPin, ledState); // задайте LED с ledState да мига отново } }
Ето, изявлението
Прекъсванията в Arduino работят както при другите микроконтролери. Платката Arduino UNO има два отделни щифта за закрепване на прекъсвания на GPIO пин 2 и 3. Ние сме го разгледали подробно в Arduino Interrupts Tutorial, където можете да научите повече за прекъсванията и как да ги използвате.
Тук ще покажем Arduino Multitasking, като обработваме две задачи едновременно. Задачите ще включват мигане на два светодиода с различно времезакъснение, заедно с бутон, който ще се използва за управление на състоянието за включване / изключване на светодиода. Така че три задачи ще бъдат изпълнени едновременно.
Необходими компоненти
- Arduino UNO
- Три светодиода (всеки цвят)
- Съпротивления (470, 10k)
- Джъмпери
- Макет
Електрическа схема
Схемата на схемата за демонстриране на използването на Arduino Millis () е много лесна и няма много компоненти, които да се прикрепят, както е показано по-долу.
Програмиране на Arduino UNO за многозадачност
Програмирането на Arduino UNO за многозадачност ще изисква само логиката, която стои зад начина, по който работи milis (), която е обяснена по-горе. Препоръчително е да упражнявате мигащ светодиод с помощта на милиони отново и отново, за да направите логиката ясна и да се почувствате удобно с милис (), преди да започнете да програмирате Arduino UNO за многозадачност. В този урок прекъсването се използва и с millis () едновременно за многозадачност. Бутонът ще бъде прекъсване. Така че, когато се генерира прекъсване, т.е. натискане на бутон, светодиодът ще превключи в състояние ВКЛ.Програмирането започва с деклариране на номера на пинове, където са свързани светодиоди и бутон.
int led1 = 6; int led2 = 7; int toggleLed = 5; int pushButton = 2;
След това пишем променлива, за да съхраним състоянието на светодиодите за бъдеща употреба.
int ledState1 = LOW; int ledState2 = LOW;
Точно както е обяснено по-горе в примера за мигане, променливите за период и предишен милилис са декларирани за сравнение и генериране на забавяне за светодиодите. Първият светодиод мига на всеки 1 секунда, а друг светодиод мига след 200 ms.
неподписан дълъг предишенMillis1 = 0; const дълъг период1 = 1000; неподписан дълъг предишенMillis2 = 0; const дълъг период2 = 200;
Друга функция за милис ще бъде използвана за генериране на забавяне на дебюнса, за да се избегнат многократните натискания на бутона. Ще има подобен подход, както по-горе.
int debouncePeriod = 20; int debounceMillis = 0;
На трите променливи ще бъдат използвани за съхранение на статута на бутон като прекъсване, превключване LED и натискане на бутон състояние.
bool buttonPushed = false; int ledChange = LOW; int lastState = HIGH;
Дефинирайте действието на щифта, който щифт ще работи като ВХОД или ИЗХОД.
pinMode (led1, OUTPUT); pinMode (led2, OUTPUT); pinMode (toggleLed, OUTPUT); pinMode (pushButton, INPUT);
Сега дефинирайте щифта за прекъсване, като прикачите прекъсване с дефиниция на ISR и режим на прекъсване. Имайте предвид, че се препоръчва да се използва digitalPinToInterrupt (pin_number) при деклариране на функцията attachInterrupt (), за да се преведе действителният цифров щифт към конкретния номер на прекъсване.
attachInterrupt (digitalPinToInterrupt (pushButton), pushButton_ISR, CHANGE);
Подпрограмата за прекъсване е написана и тя ще промени само флага buttonPushed. Имайте предвид, че подпрограмата за прекъсване трябва да бъде възможно най-кратка, затова се опитайте да я напишете и да намалите допълнителните инструкции.
void pushButton_ISR () { buttonPushed = true; }
Цикълът започва със съхраняване на стойността на милиса в променлива currentMillis, която ще съхранява стойността на времето, изминало всеки път, когато цикълът се повтори.
неподписан дълъг токMillis = милис ();
Има общо три функции в многозадачност, мига един светодиод на 1 секунда, мига втори светодиод на 200ms и Ако бутонът е натиснат, изключете / включете светодиода. Така че ще напишем три части, за да изпълним тази задача.
В първата е превключва LED състояние след всеки един секунди чрез сравняване на милисекунди изтекли.
if (currentMillis - previousMillis1> = period1) { previousMillis1 = currentMillis; ако (ledState1 == LOW) { ledState1 = HIGH; } else { ledState1 = LOW; } digitalWrite (led1, ledState1); }
По същия начин второто превключва светодиода след всеки 200ms чрез сравняване на изминалите мили. Обяснението вече е обяснено по-рано в тази статия.
if (currentMillis - previousMillis2> = period2) { previousMillis2 = currentMillis; ако (ledState2 == LOW) { ledState2 = HIGH; } else { ledState2 = LOW; } digitalWrite (led2, ledState2); }
И накрая, флагът buttonPushed се наблюдава и след генериране на забавяне на отпадане от 20ms той просто превключва състоянието на светодиода съответства на бутон, прикрепен като прекъсване.
if (buttonPushed = true) // проверяваме дали ISR се извиква { if ((currentMillis - debounceMillis)> debouncePeriod && buttonPushed) // генерира 20ms забавяне на дебюнса, за да се избегнат множество натискания { debounceMillis = currentMillis; // запаметяваме последното време за забавяне на дебюнса, ако (digitalRead (pushButton) == LOW && lastState == HIGH) // променяме led след натискане на бутон { ledChange =! ledChange; digitalWrite (toggleLed, ledChange); lastState = LOW; } иначе ако (digitalRead (pushButton) == HIGH && lastState == LOW) { lastState = HIGH; } buttonPushed = false; } }
Това завършва урока по Arduino millis (). Имайте предвид, че за да станете обичайни с milis (), просто се упражнявайте да прилагате тази логика в някои други приложения. Можете също да го разширите, за да използвате двигатели, серво мотори, сензор и други периферни устройства. В случай на съмнение, моля, пишете на нашия форум или коментирайте по-долу.
Пълният код и видео за демонстриране на използването на функцията милис в Arduino са предоставени по-долу.