ПредишенСледващото

Това често се случва, че програмата трябва да се държат по различен начин в зависимост от настъпването на събитие, времето, изминало от началото на работата и т.н.

Помислете например за подобие устройство венец а. Да кажем, че искаме да Arduino са свързани светодиоди режим, който може да се променя с натискане на един бутон светят. Mode може да бъде три:

Светодиодите са постоянно

Светодиодите са изключени, включеното всеки 2 секунди

Светодиоди постепенно набира яркост от нула до максимум 10 секунди, да излезем и да започне да расте отново яркост

Натиснете бутона, ние искаме да преминем към следващия режим: 1 → 2, 2 → 3, 3 → 1. Всъщност по същия начин, както това се случва в много елхи гирлянди.

Ние няма да се справят с контрола на всеки LED индивидуално. Просто се предположи, че всички те са пряко свързани с един от най-Ардуино чрез MOSFET-транзистор или друг ключ. За някои други щифт на часовника в същото време, свързан с бутона за промяна на режима.

В този сценарий на скицата, върши цялата работа, той може да изглежда така:

Резултатът не е най-лесният програмата. Но ние имаме много логика. Стъпка по стъпка, ние трябва да разберем какво е написано тук. Нека започнем с някои макроси.

Както вече споменахме, ние имаме 3 режима: непрекъсната светлина, мига, увеличаване на яркостта. Но тъй като те покаже на процесора да се каже кой е по-актуална, каква е следващата, и т.н. Както вече знаете, всичко, с която процесорът работи - числа. Знаейки това, ние можем да всички видове просто номерирани:

0 - постоянна светлина, ние кръстен на него STATE_SHINE

1 - мигащ режим, ние го наричаме STATE_BLINK

2 - режим Rise яркост, ние го наричаме STATE_FADE

Използването на общ префикс в имената, разбира се, не е необходимо - това е само макро - но за групиране на свързаните с тях ценности по смисъла на представки са доста удобни, и можете да ги посрещнат доста често.

Във всеки режим, нашето устройство прави нещо уникално, различно от това, което се случва в други режими. Токът може да бъде само един режим. Едно от възможните преходи са ясно дефинирани: всеки следващ активира при натискане на бутона. Такива системи се наричат ​​крайни автомати. и режима им се наричат ​​състояния (инж. държавни).

Говорейки формално, държавната машина - система с краен брой известни условия, условията на прехода между тях са фиксирани и познати, и токът винаги е точно една държава.

Е, ние правим държавна машина - отлично. Текущото състояние, т.е. Режим сияние ще се съхранява в променлива наречена ledState. който първоначално се установява стойността на STATE_SHINE. По този начин, когато системата Arduino ще бъде в постоянна светлина.

За съдбата на други макро променливи, и говори по протежение на пътя.

Верига преходи между държави

Нека разгледаме функцията на линия. Или по-скоро, първата си част, както и определенията, които се отнасят за нея:

Първо четем състоянието на бутоните в логическа променлива isButtonDown. И веднага след това ние проверяваме при условие, че той е бил натиснат само това, но не в това състояние, с течение на предходната повикването. Можете да научите типична техника за определяне на натискането на един бутон. Дали това, което е той, защо се забави поканата и назначаване wasButtonDown в края, което трябва да бъде ясно. Ние се фокусираме върху това, което се случва вътре условно, ако.

оператор на половете

Нейната същност е да се установи следното вместо текущото състояние. Използването на условията, определени от сегашното състояние, а в кодекса, vetkok съответстващ следващото състояние.

Имайте предвид, че в C ++ тест за символ на половете проведена ==. т.е. двоен знак за равенство. Така пише на оператора "равно". Стойността на логическия израз е вярно, ако стойностите на лявата и дясната страна на == равно.

Типична грешка програмиране - да обърка оператор равенство == с = по възлагане на оператора. Ако пишете:

програма е абсолютно правилно от гледна точка на C ++ компилатор, но мястото не е това, което се очаква, първо променлива ще бъде настроен на ledState STATE_SHINE. и само тогава тя ще бъде тествана истина дали нейната стойност.

Ето защо, например, в нашия случай, ако ние направихме грешка като мине този код ledState винаги да бъде пренаписан с STATE_SHINE на стойност. което от своя страна е обявен като 0. 0 е еквивалентно на фалшива състояние. и затова ние никога няма да вляза в даден блок от код.

Така че, ако ние считаме нашата верига, ако като цяло, можем да видим, че ние се опитваме да разберем условията, в които държавата е настроен сега, и въз основа на това, актуализирайте ledState на стойност. да го поставите в следващия ни беше планирано от режим.

Нейната логика във всяка държава

Ние сме направили всичко, което е необходимо, за да се гарантира, че променливата ledState можах да разбера какво точно трябва да се направи със светодиоди сега. Остава само да приложат тази логика на практика.

Помислете за втората половина на функциите кодовите контур и определения, които се използват в нея.

Тялото на цикъла, виждаме верига от условни изрази, в които всеки от условията, ние сравни сегашното състояние на ledState последователно с всички възможни. Долната линия е точно същата, както беше по-рано, при превключване на държави с натискането на един бутон: В зависимост от текущата стойност ledState изпълнението на конкретна блок от код.

По-горе можете да видите ясно 3-те блока на код: един за всяка от режима на светлина. Първият от тях е изпълнена, ако все още ledState STATE_SHINE. т.е. Ако текущия режим - непрекъснат блясък. Блокът на код в този случай, е примитивен, ние просто трябва да се уверите, че светодиодите на:

Ясно е, че късата линия следващия път, процесорът отново попадат в този бранш и отново да се превърне в светодиодите които вече са включени. Но това няма нищо лошо, това е съвсем нормално, без никакви странични ефекти.

мигащ режим

По-интересно. Ако текущото състояние е създадена през STATE_BLINK. т.е. мигащ режим на всеки 2 секунди, се извършва с код клон:

Вие знаете, че за да се само примигна неговия светодиод Arduino достатъчно последователно, за да предизвика digitalWrite и забавяне. включително след деактивация:

Но ние действал по различен начин и по-сложно. Защо?

Фактът, че забавянето на повикване води до Спете процесор, и то просто "замръзва" в призив за определено време. Той не може да направи нищо друго, освен сън. Сега нека си припомним, че нашият венец винаги "едновременно" прави 2 неща:

Контроли светещите светодиоди

Улавя и в момента на натискане на бутона, за да превключите режима

По този начин, ако режимът на мига процесора спеше в продължение на 2 секунди, а през това време ние щракнете върху бутона, натискане, че ще остане незабелязана и прехода към следващия режим няма да се случи. И ние няма да го искам напълно.

Как да се реши проблема? Да не се използва незабавно на всички! Вместо това, всеки път, когато става в нашия бранш може да се преизчисли дали Гарланд трябва да се включи или изключи е в момента.

За да направите това, ние използваме една малка аритметичен израз. (Милисекунди () / BLINK_DELAY) 2%.

След това, ние просто ще вземе остатъка от деление с 2 на междинния резултат на. Така получената стойност е след 0, след това преминаване към 1 на всеки 2 секунди. Това, което трябва! Ние просто преминават изчислената стойност като аргумент, когато се обаждате digitalWrite.

Режим на яркостта покачване

Ако сегашното състояние на нашите гирлянди - STATE_FADE. на третия блок ще бъде изпълнена, което ще доведе до светодиодите постепенно придобиват по яркост в продължение на 10 секунди, гаси, а печалбата на яркост отново:

Долната линия е почти същото като за мига. Ние просто използвайте малко по-различен израз за изчисляване и се обадете analogWrite вместо digitalWrite.

Нашата цел е да направим яркостта на светодиодите да получат от нула до максимум 10 секунди точно, или това, което е същото, 10000 милисекунди. analogWrite функция като параметър яркост поема стойности от 0 до 255, т.е. само 256 градации. Следователно, за да се увеличи яркостта с едно деление трябва да премине 10000 мс ÷ 256 ≈ 39 милисекунди. Именно тези ценности, които дефинирахме в началото на програмата:

Тъй като експресионни милисекунди на () / FADE_STEP_DELAY единица ще станат по-големи всеки път 39 мсек проходи.

Забележка скобите в FADE_STEP_DELAY на дефиниция. Тъй като стойностите са заместени в макро програма, както е, получаваме милисекунди () / (10000/256); и ако скобите не биха били, че ще се превърне милисекунди () / 10000/256, което абсолютно не е едно и също нещо от гледна точка на математиката на. Ето защо, добави скоби около някакви аритметични изрази, когато ги използват като макроси ценности.

И накрая, междинните стойности в милисекунди () / FADE_STEP_DELAY стигнем до края на разделението от 256. По този начин, всичко ще започне отначало всеки път, когато някаква междинна стойност ще стане кратно на 256. Какво ви трябва!

аритметични държави

Още веднъж, да погледнем в кода, което ни е предвидено включването на друга държава, когато щракнете върху бутона:

Ако условията, които имахме № 3 и 33, кодът ще бъде издигната на много линии, но това не е нищо ново и уникално нямаше да добавя към програмата: той щеше да остане един и същ тип. Ако сте в писането на скицата изглежда, че някои от неговите места са намалени до монотонен набор от инструкции, малко по-различно от друг, почти сигурно има начин да се опрости кода, за да го прости, ясни, по-компактен. Човек трябва само да се мисли.

Какво може да се направи с нашата верига? Спомнете си, че състоянието на процесора - това е просто числа. Ние ги определили при използването на макроси.

Тези числа, ние определят последователността. Така че преминаването ledState на друг смисъл - това е нищо като добавяне на единица. Единственият проблем - преминаването от последното състояние на първия. Но ние вече знаем оператора до края на разделението, и да го използвате, е лесно да се помисли за този сценарий. Тогава целият код, за да включва следните държави могат да бъдат запис без разклонения, както следва:

Къде TOTAL_STATES - общият брой на държави, които можем да определим като:

изброяване ENUM

От гледна точка на съставяне не се различава от:

Но в случай на Enum ние не трябва да се предписва изрично стойностите 0, 1, 2, 3, и т.н. В обяви, първата константа автоматично се настройва на 0, и всеки следващ една по-голяма.

И колкото по-добре изброяването: ние можем да използваме името му (държава в този случай) като тип данни, като вътр. булев т.н. Това означава, че можем да се определи състоянието на променливата, както следва:

Зад кулисите ledState остава едно и също число, както и преди, но самата програма се превръща в малко по-ясна: ние, са ясно определени, че ще трябва да се съхраняват в нашата променлива.

Събрани заедно, ние получаваме актуализирана версия на нашата програма:

изявление избор ключ

За да се разбере какво да прави с LED гирлянди в този момент, ние използвахме верига от изрази, ако. което от своя страна ledState в сравнение с всички възможни състояния. Това е доста често срещан сценарий за него в ++ превключвател отчета за C има възможност за избор. Можем да го използваме за нашите цели:

Не казвам, че кодът е станал по-компактен, но тя е станала малко по-ясни.

Същността на изразяването на превключване е. На първо място, да се изчисли стойността на аритметичен израз, написан в скоби. В нашия случай - това е само за да се ledState на стойност. След това, в код блок се търси между етикета на скоби случай. чиято стойност се изчислява. изпълнение на код започва и преминава от това последователно до крайния блок (не до следващия случай). Изпълнение единица може да бъде завършена в началото израз почивка.

Често срещана грешка на невнимание - да забрави да се сложи на почивката. В този случай, то той ще се изпълни кода, принадлежащи към други марки, и това е най-важното - не това, което трябва. Да, това е една неприятна особеност на C ++, но имаше толкова много история. Първоначално това е било направено, за да бъде в състояние да се изброят няколко стойности на един клон. Например, ако условията за STATE_FADE STATE_BLINK и ние, като дизайн, ще трябва да направи същото, бихме могли да напишете:

Също така в ключа. на последно място, можете да зададете етикет със специален име подразбиране. Тя ще се провали, ако няма друг етикет случай не се достига стойност.

Така че, се запознахте с крайни автомати, държави, преходи, принципите на многозадачност. В нашия пример за различни състояния, ние използвахме сравнително проста логика: един digitalWrite разговор с обикновен аритметичен израз; и да преминете щатите и всички използват серийния бутон на кликване.

Нищо не пречи да се развива тази тема, за да се направи много по-умен устройство. Например, стая робот може да има патрули състояние за откриване на котка, котка състояние дисплей преследване състояние на батерията е изтощена. Превключване ще се появят на сигналите от датчиците и няма да бъде толкова просто. Logic се посочва, в този случай може да бъде доста сложно: вие трябва да получите стойностите от множество сензори, изберете посоката на движение, спирални мотори и т.н.

Точно както с всичко останало, нищо не пречи да се направи вложени държавни машини: тоест, държавата, които сами по себе са крайни автомати. Основна подкрепа код тънък и чете, а след това вие ще успеете!

Освен ако не е посочено друго, съдържанието на този уики е лицензирано под следния лиценз: CC Признание-Некомерсиално-Споделяне на споделеното 3.0 Нелокализиран

Инструменти на страницата

Подкрепете проекта - споделете линка, благодаря!