- Шта је Семафор?
- Како користити Семапхоре у ФрееРТОС-у?
- Објашњење Семафор кода
- Кружни дијаграм
- Шта је Мутек?
- Како користити Мутек у ФрееРТОС-у?
- Објашњење Мутек кода
У претходним водичима покривали смо основе ФрееРТОС-а са Ардуином и објектом језгра Куеуе у ФрееРТОС Ардуино. Сада ћемо у овом трећем водичу за ФрееРТОС научити више о ФрееРТОС-у и његовим напредним АПИ-јевима, што вам може помоћи да дубље разумете платформу са више задатака.
Семафор и Мутек (узајамно искључивање) су објекти језгра који се користе за синхронизацију, управљање ресурсима и заштиту ресурса од корупције. У првој половини овог водича видећемо идеју која стоји иза Семафора, како и где га користити. У другом полувремену ћемо наставити са Мутексом.
Шта је Семафор?
У претходним водичима разговарали смо о приоритетима задатка, а такође смо упознати да задатак већег приоритета преузима задатак нижег приоритета, па док извршавање задатка високог приоритета може постојати могућност да се у задатку нижег приоритета догоди оштећење података још увек није извршено и подаци непрекидно долазе на овај задатак са сензора који узрокује губитак података и неисправан рад целе апликације.
Дакле, постоји потреба за заштитом ресурса од губитка података и овде Семафор игра важну улогу.
Семафор је сигнални механизам у којем задатак у стању чекања сигнализира други задатак за извршење. Другим речима, када задатак1 заврши са радом, тада ће приказати заставицу или повећати заставицу за 1, а затим ће ову заставу примити други задатак (задатак2) показујући да сада може да обавља свој посао. Када задатак2 заврши са радом, застава ће се смањити за 1.
У основи, то је механизам „Дај“ и „Узми“, а семафор је целобројна променљива која се користи за синхронизацију приступа ресурсима.
Врсте семафора у ФрееРТОС-у:
Семафор је две врсте.
- Бинарни семафор
- Бројање Семафора
1. Бинарни семафор: Има две целобројне вредности 0 и 1. Нешто је сличан реду дужине 1. На пример, имамо два задатка, задатак1 и задатак2. Задатак1 шаље податке на задатак2, тако да задатак2 континуирано провјерава ставку реда ако их има 1, а затим може прочитати податке у супротном мора причекати док не постане 1. Након преузимања података, задатак2 смањује ред и чини га 0 То значи да задатак1 поново може податке послати на таск2.
Из горњег примера може се рећи да се бинарни семафор користи за синхронизацију између задатака или између задатака и за прекид.
2. Бројање семафора: има вредности веће од 0 и може се сматрати редом дужине већим од 1. Овај семафор се користи за бројање догађаја. У овом сценарију употребе, руковатељ догађајима ће „дати“ семафор сваки пут када се догоди догађај (повећање вредности броја семафора), а задатак руковаоца ће „узети“ семафор сваки пут када обради догађај (смањење вредности броја семафора).
Вредност бројања је, дакле, разлика између броја догађаја који су се догодили и броја обрађених.
Сада, да видимо како да користимо Семапхоре у нашем ФрееРТОС коду.
Како користити Семапхоре у ФрееРТОС-у?
ФрееРТОС подржава различите АПИ-је за стварање семафора, узимање семафора и давање семафора.
Сада могу постојати две врсте АПИ-ја за исти објект језгра. Ако морамо да дамо семафор са ИСР-а, тада се не може користити уобичајени АПИ за семафор. Требали бисте користити АПИ-је заштићене прекидима.
У овом упутству користићемо бинарни семафор јер га је лако разумети и применити. Како се овде користи функционалност прекида, у ИСР функцији морате користити АПИ-је заштићене прекидима. Када кажемо синхронизација задатка с прекидом, то значи стављање задатка у стање Руннинг одмах након ИСР-а.
Креирање семафора:
Да бисмо користили било који објект језгра, прво га морамо створити. За стварање бинарног семафора користите вСемапхореЦреатеБинари ().
Овај АПИ не узима ниједан параметар и враћа променљиву типа СемапхореХандле_т. Глобално име променљиве сема_в је креирано за чување семафора.
СемапхореХандле_т сема_в; сема_в = кСемапхореЦреатеБинари ();
Давање семафора:
За давање семафора постоје две верзије - једна за прекид и друга за уобичајени задатак.
- кСемапхореГиве (): Овај АПИ узима само један аргумент који је име променљиве семафора попут сема_в као што је дато горе приликом креирања семафора. Може се позвати из било ког уобичајеног задатка који желите да синхронизујете.
- кСемапхореГивеФромИСР (): Ово је АПИ верзија кСемапхореГиве () заштићена од прекида. Када треба да синхронизујемо ИСР и уобичајени задатак, тада из функције ИСР треба користити кСемапхореГивеФромИСР ().
Узимање семафора:
Да бисте узели семафор, користите АПИ функцију кСемапхореТаке (). Овај АПИ узима два параметра.
кСемапхореТаке (СемапхореХандле_т кСемапхоре, ТицкТипе_т кТицксТоВаит);
кСемапхоре: Назив семафора који се узима у нашем случају сема_в.
кТицксТоВаит: Ово је максимално време које ће задатак чекати у Блокираном стању да семафор постане доступан. У нашем пројекту поставићемо кТицксТоВаит на портМАКС_ДЕЛАИ како би задатак_1 неограничено чекао у Блокираном стању док сема_в не буде доступан.
Хајде да сада користимо ове АПИ-је и напишемо код за обављање неких задатака.
Овде су повезани један тастер и две ЛЕД диоде. Тастер ће деловати као прекидач који је причвршћен на пин 2 Ардуино Уно-а. Када се притисне ово дугме, генерисаће се прекид и ЛЕД лампица која је повезана на пин 8 УКЉУЧИТ ће се и када га притиснете поново ИСКЉУЧИТИ.
Дакле, када се притисне дугме, кСемапхореГивеФромИСР () биће позвано из функције ИСР, а функција кСемапхореТаке () из функције ТаскЛЕД.
Да би систем изгледао вишезадаћно, повежите друге ЛЕД диоде помоћу пина 7 који ће увек трептати.
Објашњење Семафор кода
Почнимо са писањем кода за отварање Ардуино ИДЕ-а
1. Прво укључите датотеку заглавља Ардуино_ФрееРТОС.х . Сада, ако се користи било који објекат језгра као семафор у реду, за њега мора бити укључена и датотека заглавља.
# инцлуде # инцлуде
2. Прогласите променљиву типа СемапхореХандле_т за чување вредности семафора.
СемапхореХандле_т интерруптСемапхоре;
3. У воид сетуп (), креирајте два задатка (ТаскЛЕД и ТаскБлинк) користећи кТаскЦреате () АПИ, а затим креирајте семафор помоћу кСемапхореЦреатеБинари (). Направите задатак са једнаким приоритетима и касније покушајте да се играте са овим бројем. Такође, конфигуришите пин 2 као улаз и омогућите унутрашњи отпорник на извлачење и причврстите прекидач. Коначно, покрените роковник као што је приказано доле.
воид сетуп () { пинМоде (2, ИНПУТ_ПУЛЛУП); кТаскЦреате (ТаскЛед, "Лед", 128, НУЛЛ, 0, НУЛЛ); кТаскЦреате (ТаскБлинк, "ЛедБлинк", 128, НУЛЛ, 0, НУЛЛ); интерруптСемапхоре = кСемапхореЦреатеБинари (); иф (интерруптСемапхоре! = НУЛЛ) { аттацхИнтеррупт (дигиталПинТоИнтеррупт (2), дебоунцеИнтеррупт, ЛОВ); } }
4. Сада имплементирајте ИСР функцију. Направите функцију и дајте јој име исто као и други аргумент функције аттацхИнтеррупт () . Да би прекид правилно функционисао, потребно је да уклоните проблем са опозивом дугмета помоћу функције милис или микро и подешавањем времена опозива. Из ове функције позовите функцију интерруптХандлер () како је приказано доле.
дуго дебоунцинг_тиме = 150; волатиле унсигнед лонг ласт_мицрос; воид дебоунцеИнтеррупт () { иф ((лонг) (мицрос () - ласт_мицрос)> = дебоунцинг_тиме * 1000) { интерруптХандлер (); ласт_мицрос = мицрос (); } }
У функцији интерруптХандлер () позовите АПИ кСемапхореГивеФромИСР () .
воид интерруптХандлер () { кСемапхореГивеФромИСР (интерруптСемапхоре, НУЛЛ); }
Ова функција ће дати семафор ТаскЛед-у да укључи ЛЕД.
5. Направите ТаскЛед функцију и унутар вхиле петље, позовите кСемапхореТаке () АПИ и проверите да ли је семафор успешно узима или не. Ако је једнако пдПАСС (тј. 1), подесите ЛЕД да се пребацује како је приказано доле.
воид ТаскЛед (воид * пвПараметерс) { (воид) пвПараметерс; пинМоде (8, ИЗЛАЗ); вхиле (1) { иф (кСемапхореТаке (интерруптСемапхоре, портМАКС_ДЕЛАИ) == пдПАСС) { дигиталВрите (8,! дигиталРеад (8)); } } }
6. Такође, креирајте функцију да трепће друге ЛЕД диоде повезане на пин 7.
воид ТаскЛед1 (воид * пвПараметерс) { (воид) пвПараметерс; пинМоде (7, ИЗЛАЗ); вхиле (1) { дигиталВрите (7, ХИГХ); вТаскДелаи (200 / портТИЦК_ПЕРИОД_МС); дигиталВрите (7, ЛОВ); вТаскДелаи (200 / портТИЦК_ПЕРИОД_МС); } }
7. Функција воид лооп ће остати празна. Не заборави то.
воид лооп () {}
То је то, комплетни код се може наћи на крају овог водича. Сада отпремите овај код и спојите ЛЕД диоде и тастер са Ардуино УНО у складу са шемом кола.
Кружни дијаграм
Након отпремања кода, видећете да ЛЕД трепће након 200 мс и када се притисне дугме, одмах ће засветлети друга ЛЕД лампица као што је приказано у видеу датом на крају.
На овај начин, семафори се могу користити у ФрееРТОС-у са Ардуином, где треба да преносе податке са једног задатка на други без икаквог губитка.
Сада, да видимо шта је Мутек и како се користи ФрееРТОС.
Шта је Мутек?
Као што је горе објашњено, семафор је сигнални механизам, слично томе, Мутек је механизам закључавања за разлику од семафора који има одвојене функције за повећавање и смањивање, али у Мутеку функција узима и даје у себи. То је техника за избегавање корупције заједничких ресурса.
Да би се заштитио заједнички ресурс, ресурсу се додељује токен картица (мутек). Ко год има ову картицу може приступити другом ресурсу. Остали би требали сачекати док се картица не врати. На тај начин само један ресурс може приступити задатку, а други чекају своју прилику.
Хајде да разумемо Мутек у ФрееРТОС- у помоћу примера.
Овде имамо три задатка, један за штампање података на ЛЦД-у, други за слање ЛДР података на ЛЦД задатак и последњи задатак за слање података о температури на ЛЦД-у. Дакле, овде два задатка деле исти ресурс, тј. ЛЦД. Ако ЛДР задатак и задатак температуре истовремено шаљу податке, онда један од података може бити оштећен или изгубљен.
Да бисмо заштитили губитак података, морамо закључати ЛЦД ресурс за задатак1 док не заврши задатак приказа. Тада ће се задатак ЛЦД-а откључати и тада задатак2 може обавити свој посао.
Можете видети рад Мутека и семафора на доњем дијаграму.
Како користити Мутек у ФрееРТОС-у?
Мутекси се такође користе на исти начин као и семафори. Прво га креирајте, а затим дајте и узмите користећи одговарајуће АПИ-је.
Стварање мутека:
Да бисте креирали Мутек, користите кСемапхореЦреатеМутек () АПИ . Као што му само име говори да је Мутек врста Бинарног семафора. Користе се у различитим контекстима и сврхама. Бинарни семафор служи за синхронизацију задатака, док се Мутек користи за заштиту дељеног ресурса.
Овај АПИ не узима ниједан аргумент и враћа променљиву типа СемапхореХандле_т . Ако мутек не може да се креира, кСемапхореЦреатеМутек () враћа НУЛЛ.
СемапхореХандле_т мутек_в; мутек_в = кСемапхореЦреатеМутек ();
Узимање мутекса:
Када задатак жели да приступи ресурсу, узеће Мутек користећи кСемапхореТаке () АПИ. То је исто као бинарни семафор. Потребна су и два параметра.
кСемапхоре: Име Мутека који се узима у нашем случају мутек_в .
кТицксТоВаит: Ово је максимално време које ће задатак чекати у Блокираном стању да Мутек постане доступан. У нашем пројекту поставићемо кТицксТоВаит на портМАКС_ДЕЛАИ како би задатак_1 неограничено чекао у Блокираном стању док мутек_в не постане доступан.
Давање мутекса:
Након приступа дељеном ресурсу, задатак би требао вратити Мутек како би му други задаци могли приступити. АПИ кСемапхореГиве () се користи за враћање Мутека.
Функција кСемапхореГиве () узима само један аргумент који је Мутек који се даје у нашем случају мутек_в.
Користећи горње АПИ-је, имплементирамо Мутек у ФрееРТОС код помоћу Ардуино ИДЕ-а.
Објашњење Мутек кода
Овде је циљ овог дела употреба серијског монитора као заједничког ресурса и два различита задатка за приступ серијском монитору за штампање неке поруке.
1. Датотеке заглавља остаће исте као семафор.
# инцлуде # инцлуде
2. Прогласите променљиву типа СемапхореХандле_т за чување вредности Мутека.
СемапхореХандле_т мутек_в;
3. У воид сетуп (), иницијализујте серијски монитор брзином од 9600 бауд и креирајте два задатка (Таск1 и Таск2) помоћу АПИ-ја кТаскЦреате () . Затим креирајте Мутек користећи кСемапхореЦреатеМутек (). Направите задатак са једнаким приоритетима, а касније покушајте да се играте овим бројем.
воид сетуп () { Сериал.бегин (9600); мутек_в = кСемапхореЦреатеМутек (); иф (мутек_в == НУЛЛ) { Сериал.принтлн ("Мутек не може бити креиран"); } кТаскЦреате (Таск1, "Таск 1", 128, НУЛЛ, 1, НУЛЛ); кТаскЦреате (Таск2, "Таск 2", 128, НУЛЛ, 1, НУЛЛ); }
4. Сада направите функције задатка за Таск1 и Таск2. За кратко време функције задатка, пре штампања поруке на серијском монитору, морамо узети Мутек користећи кСемапхореТаке (), затим одштампати поруку и вратити Мутек помоћу кСемапхореГиве (). Онда одложите мало.
воид Таск1 (воид * пвПараметерс) {вхиле (1) { кСемапхореТаке (мутек_в, портМАКС_ДЕЛАИ); Сериал.принтлн ("Здраво из задатка1"); кСемапхореГиве (мутек_в); вТаскДелаи (пдМС_ТО_ТИЦКС (1000)); } }
Слично томе, имплементирајте функцију Таск2 са кашњењем од 500мс.
5. Воид лооп () остаће празан.
Сада отпремите овај код на Ардуино УНО и отворите серијски монитор.
Видећете да се поруке штампају из задатака1 и задатка2.
Да бисте тестирали рад Мутека, само коментаришите кСемапхореГиве (мутек_в); из било ког задатка. Можете видети да програм виси на последњој поруци за штампање .
Тако се Семапхоре и Мутек могу применити у ФрееРТОС-у са Ардуином. За више информација о Семафору и Мутексу можете посетити званичну документацију ФрееРТОС-а.
Комплетни кодови и видео за Семапхоре и Мутес дати су у наставку.