- Mikä on semafori?
- Kuinka käyttää semaforia FreeRTOS: ssa?
- Semaforikoodien selitys
- Piirikaavio
- Mikä on Mutex?
- Kuinka käyttää Mutexia FreeRTOSissa?
- Mutex-koodin selitys
Aikaisemmissa opetusohjelmissa olemme käsitelleet FreeRTOSin perusteet Arduinolla ja Queue-ytimen objektilla FreeRTOS Arduinossa. Tässä kolmannessa FreeRTOS-opetusohjelmassa opimme lisää FreeRTOS: sta ja sen etukäteen suunnitelluista sovellusliittymistä, mikä voi saada sinut ymmärtämään monitoimialustaa syvemmin.
Semafori ja Mutex (keskinäinen poissulkeminen) ovat ytimen objekteja, joita käytetään synkronointiin, resurssien hallintaan ja resurssien suojaamiseen korruptiolta. Tämän opetusohjelman ensimmäisellä puoliskolla näemme semaforin taustalla olevan idean, miten ja missä sitä käytetään. Toisella puoliskolla jatkamme Mutexin kanssa.
Mikä on semafori?
Aikaisemmissa opetusohjelmissa olemme keskustelleet tehtävien prioriteeteista ja saaneet myös tietää, että korkeamman prioriteetin tehtävä ennalta tyhjentää matalamman prioriteetin tehtävän, joten samalla kun korkean prioriteetin tehtävä voidaan suorittaa, korruptio voi tapahtua matalamman prioriteetin tehtävässä, koska se ei ole vielä suoritettu ja data saapuu tähän tehtävään jatkuvasti anturista, mikä aiheuttaa tietojen menetystä ja toimintahäiriöitä koko sovelluksessa.
Joten on tarpeen suojata resursseja tietojen menetykseltä, ja tässä semaforilla on tärkeä rooli.
Semafori on signalointimekanismi, jossa toinen tehtävä signaloi odotustilassa olevan tehtävän suoritettavaksi. Toisin sanoen, kun tehtävä1 on saanut työnsä päätökseen, se näyttää lipun tai lisää lippua yhdellä ja sitten toinen tehtävä (tehtävä2) vastaanottaa tämän lipun osoittaen, että se voi suorittaa työnsä nyt. Kun tehtävä 2 on valmis, lippua pienennetään yhdellä.
Joten se on periaatteessa "Anna" ja "Ota" -mekanismi ja semafori on kokonaislukumuuttuja, jota käytetään synkronoimaan resurssien käyttöoikeus.
Semaforityypit FreeRTOSissa:
Semaforeja on kahta tyyppiä.
- Binaarinen semafori
- Lasketaan semaforia
1. Binaarinen semafori: Siinä on kaksi kokonaislukua 0 ja 1. Se on jonkin verran samanlainen kuin jonon pituus 1. Esimerkiksi meillä on kaksi tehtävää, task1 ja task2. Tehtävä1 lähettää tietoja tehtävään2, joten tehtävä2 tarkistaa jatkuvasti jonokohteen, jos sellaista on 1, sitten se voi lukea tiedot, joita sen on odotettava, kunnes niistä tulee 1. Kun data on otettu, tehtävä2 vähentää jonoa ja tekee siitä 0. Tämä tarkoittaa taas tehtävää1. voi lähettää tiedot tehtävään2.
Edellä olevasta esimerkistä voidaan sanoa, että binaarista semaforia käytetään tehtävien tai tehtävien ja keskeytysten väliseen synkronointiin.
2. Semaforin laskeminen: Sen arvot ovat suurempia kuin 0, ja sen voidaan ajatella olevan jonon, jonka pituus on yli 1. Tätä semaforia käytetään tapahtumien laskemiseen. Tässä käyttötilanteessa tapahtumankäsittelijä 'antaa' semaforin aina, kun tapahtuma tapahtuu (kasvaa semaforien määrän arvoa), ja käsittelijän tehtävä 'ottaa' semaforin joka kerta, kun se käsittelee tapahtumaa (vähentää semaforien määrän arvoa).
Laskenta-arvo on siis tapahtuneiden tapahtumien ja käsitellyn lukumäärän välinen ero.
Katsotaan nyt, kuinka semaforia käytetään FreeRTOS-koodissamme.
Kuinka käyttää semaforia FreeRTOS: ssa?
FreeRTOS tukee erilaisia sovellusliittymiä semaforin luomiseen, semaforin ottamiseen ja semaforin antamiseen.
Nyt samalle ytimen objektille voi olla kahden tyyppisiä sovellusliittymiä. Jos joudumme antamaan semaforia ISR: stä, normaalia semaforin sovellusliittymää ei voida käyttää. Käytä keskeytyksellä suojattuja sovellusliittymiä.
Tässä opetusohjelmassa käytämme binaarista semaforia, koska se on helppo ymmärtää ja toteuttaa. Koska tässä käytetään keskeytystoimintoa, sinun on käytettävä keskeytyksellä suojattuja sovellusliittymiä ISR-toiminnossa. Kun sanomme tehtävän synkronoinnin keskeytyksen kanssa, se tarkoittaa tehtävän asettamista Juoksutilaan heti ISR: n jälkeen.
Semaforin luominen:
Jos haluat käyttää mitä tahansa ytimen objektia, meidän on ensin luotava se. Luo binaarinen semafori käyttämällä vSemaphoreCreateBinary ().
Tämä sovellusliittymä ei ota mitään parametria ja palauttaa tyypin SemaphoreHandle_t muuttujan. Semaforin tallentamiseksi luodaan yleinen muuttujan nimi sema_v.
SemaforiHandle_t sema_v; sema_v = xSemaphoreCreateBinary ();
Semaforin antaminen:
Semaforin antamiseksi on olemassa kaksi versiota - yksi keskeytykselle ja toinen normaalille tehtävälle.
- xSemaphoreGive (): Tämä sovellusliittymä vie vain yhden argumentin, joka on semaforin muuttujan nimi, kuten sema_v, kuten yllä on annettu, samalla kun luodaan semaforia. Sitä voidaan kutsua mistä tahansa normaalista tehtävästä, jonka haluat synkronoida.
- xSemaphoreGiveFromISR (): Tämä on xSemaphoreGive (): n keskeytyksellä suojattu API-versio. Kun meidän on synkronoitava ISR ja normaali tehtävä, xSemaphoreGiveFromISR (): ää tulisi käyttää ISR-funktiosta.
Semaforin ottaminen:
Jos haluat ottaa semaforin, käytä API-toimintoa xSemaphoreTake (). Tässä sovellusliittymässä on kaksi parametria.
xSemaphoreTake (SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait);
xSemafori: Meidän tapauksessamme otettavan semaforin nimi sema_v.
xTicksToWait: Tämä on enimmäisaika, jonka tehtävä odottaa estetyssä tilassa semaforin saataville. Projektissamme asetamme xTicksToWait arvoksi portMAX_DELAY , jotta tehtävä_1 odottaa loputtomasti estetyssä tilassa, kunnes sema_v on käytettävissä.
Käytetään nyt näitä sovellusliittymiä ja kirjoitetaan koodi joidenkin tehtävien suorittamiseen.
Tässä yksi painike ja kaksi LEDiä ovat liitettyinä. Painike toimii keskeytyspainikkeena, joka on kiinnitetty Arduino Unon tapiin 2. Kun tätä painiketta painetaan, syntyy keskeytys ja napaan 8 kytketty LED syttyy ja kun painat sitä uudelleen, se sammuu.
Joten kun painiketta painetaan, xSemaphoreGiveFromISR () kutsutaan ISR-toiminnosta ja xSemaphoreTake () -toiminto kutsutaan TaskLED-funktiosta.
Jotta järjestelmä näyttää monitoimittaiselta, kytke muut LEDit napaan 7, joka on aina vilkkuva.
Semaforikoodien selitys
Aloitetaan koodin kirjoittaminen avaamalla Arduino IDE
1. Lisää ensin Arduino_FreeRTOS.h- otsikkotiedosto. Jos jotakin ytimen objektia käytetään kuten jonosemaforia, sille on myös sisällytettävä otsikkotiedosto.
# sisällyttää # sisällytä
2. Ilmoita muuttuja tyyppiä SemaphoreHandle_t tallentamaan semaforin arvot.
SemaphoreHandle_t keskeytäSemaaphore;
3. Luo tyhjässä asetuksessa () kaksi tehtävää (TaskLED ja TaskBlink) xTaskCreate () -sovellusliittymän avulla ja luo sitten semafori käyttämällä xSemaphoreCreateBinary () -työkalua. Määritä myös tappi 2 tuloksi ja ota käyttöön sisäinen vetovastus ja kiinnitä keskeytystappi. Käynnistä lopuksi ajastin alla olevan kuvan mukaisesti.
void setup () { pinMode (2, INPUT_PULLUP); xTaskCreate (TaskLed, "Led", 128, NULL, 0, NULL); xTaskCreate (TaskBlink, "LedBlink", 128, NULL, 0, NULL); keskeytäSemaphore = xSemaphoreCreateBinary (); if (keskeytäSemaphore! = NULL) { liitäInterrupt (digitalPinToInterrupt (2), debounceInterrupt, LOW); } }
4. Ota nyt käyttöön ISR-toiminto. Tee funktio ja nimeä se samaksi kuin attachInterrupt () -funktion toinen argumentti. Jotta keskeytys toimisi kunnolla, sinun on poistettava painikkeen purkamisongelma millis- tai mikrotoiminnolla ja säätämällä poistoaikaa. Tämän toiminnon kautta soita keskeytyskäyttäjä () -toiminto alla olevan kuvan mukaisesti.
pitkä debouncing_time = 150; haihtumaton allekirjoittamaton pitkä lastimikro; void debounceInterrupt () { if ((long) (micros () - last_micros)> = debouncing_time * 1000) { keskeytäKäyttäjä (); last_mikros = mikros (); } }
In interruptHandler () funktio, soita xSemaphoreGiveFromISR () API.
void keskeytäKäyttäjä () { xSemaphoreGiveFromISR (keskeytäSemafori, NULL); }
Tämä toiminto antaa semaforin TaskLedille LEDin kytkemiseksi päälle.
5. Luo TaskLed- toiminto ja kutsu while- silmukan sisään xSemaphoreTake () -sovellusliittymää ja tarkista, onko semafori otettu onnistuneesti vai ei. Jos se on yhtä suuri kuin pdPASS (eli 1), tee LED-merkkivalo alla olevan kuvan mukaisesti.
void TaskLed (void * pvParameters) { (void) pvParameters; pinMode (8, OUTPUT); while (1) { if (xSemaphoreTake (keskeytäSemaFore, portMAX_DELAY) == pdPASS) { digitalWrite (8,! digitalRead (8)); } } }
6. Luo myös toiminto, joka vilkuttaa muita LEDiin kytkettyjä LEDejä.
void TaskLed1 (void * pvParameters) { (void) pvParameters; pinMode (7, OUTPUT); kun taas (1) { digitalWrite (7, HIGH); vTaskDelay (200 / portTICK_PERIOD_MS); digitalWrite (7, LOW); vTaskDelay (200 / portTICK_PERIOD_MS); } }
7. Void loop -toiminto pysyy tyhjänä. Älä unohda sitä.
void loop () {}
Se on, täydellinen koodi löytyy tämän opetusohjelman lopusta. Lataa nyt tämä koodi ja kytke LEDit ja painike Arduino UNO: iin piirikaavion mukaisesti.
Piirikaavio
Koodin lataamisen jälkeen näet LED-merkkivalon vilkkuvan 200 ms: n kuluttua ja kun painiketta painetaan, toinen LED palaa heti, kuten lopussa olevassa videossa näkyy.
Tällä tavalla semaforeja voidaan käyttää FreeRTOS: ssa Arduinon kanssa, jossa sen on siirrettävä tiedot tehtävästä toiseen häviöttömästi.
Katsotaan nyt, mikä on Mutex ja miten sitä käytetään FreeRTOS.
Mikä on Mutex?
Kuten yllä selitettiin, semafori on signalointimekanismi, samoin Mutex on lukitusmekanismi toisin kuin semafori, jolla on erilliset toiminnot lisäystä ja vähennystä varten, mutta Mutexissa funktio ottaa ja antaa itsensä. Se on tekniikka, jolla vältetään jaettujen resurssien korruptio.
Jaetun resurssin suojaamiseksi määritetään resurssille tunnuskortti (mutex). Kuka tahansa, jolla on tämä kortti, voi käyttää toista resurssia. Toisten tulisi odottaa, kunnes kortti palautuu. Tällä tavoin vain yksi resurssi pääsee tehtävään ja muut odottavat mahdollisuuttaan.
Ymmärretään Mutex FreeRTOS: ssa esimerkin avulla.
Tässä meillä on kolme tehtävää, yksi tietojen tulostamiseen LCD-näytölle, toinen LDR-tietojen lähettämiseen LCD-tehtävään ja viimeinen tehtävä lämpötilatietojen lähettämiseen LCD-näytölle. Joten tässä kaksi tehtävää jakaa saman resurssin eli nestekidenäytön. Jos LDR- ja lämpötilatehtävä lähettävät tietoja samanaikaisesti, yksi tiedoista voi olla vioittunut tai kadonnut.
Joten tietohäviön suojaamiseksi meidän on lukittava task1: n LCD-resurssi, kunnes se on suorittanut näyttötehtävän. Sitten LCD-tehtävä avautuu ja tehtävä2 voi suorittaa työnsä.
Voit tarkkailla Mutexin ja semaforien toimintaa alla olevasta kaaviosta.
Kuinka käyttää Mutexia FreeRTOSissa?
Mutexeja käytetään myös samalla tavalla kuin semaforeja. Luo ensin, anna ja ota vastaavien sovellusliittymien avulla.
Mutexin luominen:
Luo Mutex käyttämällä xSemaphoreCreateMutex () -sovellusliittymää . Nimensä mukaan Mutex on eräänlainen binäärisemafori. Niitä käytetään erilaisissa yhteyksissä ja tarkoituksissa. Binaarinen semafori on tehtävien synkronointiin, kun taas Mutexia käytetään jaetun resurssin suojaamiseen.
Tämä sovellusliittymä ei ota argumenttia ja palauttaa muuttujan, jonka tyyppi on SemaphoreHandle_t . Jos mutexia ei voida luoda, xSemaphoreCreateMutex () palauttaa arvon NULL.
SemaforiHandle_t mutex_v; mutex_v = xSemaphoreCreateMutex ();
Mutexin ottaminen:
Kun tehtävä haluaa käyttää resurssia, se vie Mutexin käyttämällä xSemaphoreTake () -sovellusliittymää. Se on sama kuin binäärisemafori. Se vaatii myös kaksi parametria.
xSemaphore: Tapauksessamme käytettävän Mutexin nimi mutex_v .
xTicksToWait: Tämä on enimmäisaika, jonka tehtävä odottaa estetyssä tilassa, kunnes Mutex on käytettävissä. Projektissamme asetamme xTicksToWait arvoksi portMAX_DELAY , jotta tehtävä_1 odottaa loputtomasti estetyssä tilassa, kunnes mutex_v on käytettävissä.
Mutexin antaminen:
Kun olet käyttänyt jaettua resurssia, tehtävän tulisi palauttaa Mutex, jotta muut tehtävät voivat käyttää sitä. xSemaphoreGive () -sovellusliittymää käytetään antamaan Mutex takaisin.
XSemaphoreGive () -funktio vie vain yhden argumentin, joka on tapauksessamme mutex_v annettava Mutex.
Yllä olevien sovellusliittymien avulla toteutetaan Mutex FreeRTOS-koodissa Arduino IDE: n avulla.
Mutex-koodin selitys
Tässä osassa tavoitteena on käyttää sarjamonitoria jaettuna resurssina ja kahta erilaista tehtävää käyttääksesi sarjamonitoria jonkin viestin tulostamiseen.
1. Otsikkotiedostot pysyvät samoina kuin semafori.
# sisällyttää # sisällytä
2. Ilmoita muuttuja tyyppiä SemaphoreHandle_t tallentamaan Mutex-arvot.
SemaforiHandle_t mutex_v;
3. Alusta tyhjästä asennuksesta () alustamalla sarjavalvonta 9600 baudinopeudella ja luomalla kaksi tehtävää (Tehtävä1 ja Tehtävä2) xTaskCreate () -sovellusliittymän avulla. Luo sitten Mutex käyttämällä xSemaphoreCreateMutex (). Luo tehtävä, jolla on samat prioriteetit ja yritä myöhemmin pelata tällä numerolla.
void setup () { Sarja.alku (9600); mutex_v = xSemaphoreCreateMutex (); if (mutex_v == NULL) { Serial.println ("Mutexia ei voi luoda"); } xTaskCreate (Tehtävä1, "Tehtävä 1", 128, NULL, 1, NULL); xTaskCreate (tehtävä 2, "tehtävä 2", 128, NULL, 1, NULL); }
4. Tee nyt tehtävän tehtävät tehtäville Task1 ja Task2. Kun taas silmukka tehtävän toiminnon, ennen tulostamista viestin Serial Monitor meidän täytyy ottaa Mutex käyttäen xSemaphoreTake () tulosta viesti sitten ja sitten palauttaa Mutex käyttäen xSemaphoreGive (). Anna sitten viive.
void Task1 (void * pvParameters) { while (1) { xSemaphoreTake (mutex_v, portMAX_DELAY); Serial.println ("Hei tehtävästä1"); xSemaphoreGive (mutex_v); vTaskDelay (pdMS_TO_TICKS (1000)); } }
Vastaavasti Task2-toiminto toteutetaan 500 ms: n viiveellä.
5. Void-silmukka () jää tyhjäksi.
Lataa nyt tämä koodi Arduino UNO -palveluun ja avaa sarjamonitori.
Näet viestit tulostuvat tehtävistä1 ja tehtävä2.
Voit testata Mutexin toimintaa kommentoimalla vain xSemaphoreGive (mutex_v); mistä tahansa tehtävästä. Voit nähdä, että ohjelma jumittuu viimeiseen tulostusviestiin .
Näin Semaphore ja Mutex voidaan toteuttaa FreeRTOS: ssa Arduinon kanssa. Lisätietoja Semaphoresta ja Mutexista saat käymällä FreeRTOSin virallisessa dokumentaatiossa.
Täydelliset koodit ja video semaforeille ja mykistyksille on annettu alla.