- Hur fungerar RTOS?
- Ofta använda termer i RTOS
- Installerar Arduino FreeRTOS-bibliotek
- Kretsschema
- Arduino FreeRTOS Exempel - Skapa FreeRTOS-uppgifter i Arduino IDE
- FreeRTOS uppgiftsimplementering i Arduino IDE
Operativsystemet som finns i de inbäddade enheterna kallas ett RTOS (operativsystem i realtid). I inbäddade enheter är realtidsuppgifter kritiska där timing spelar en mycket viktig roll. Realtids uppgifter är Time Deterministic innebär svarstiden till ett evenemang är alltid konstant, så att det kan garanteras att en viss händelse inträffar vid en bestämd tidpunkt. RTOS är utformat för att köra applikationer med mycket exakt timing och hög tillförlitlighet. RTOS hjälper också till multitasking med en enda kärna.
Vi har redan täckt en handledning om hur man använder RTOS i inbäddade system där man kan veta mer om RTOS, skillnaden mellan allmänt operativsystem och RTOS, olika typer av RTOS, etc.
I den här handledningen börjar vi med FreeRTOS. FreeRTOS är en klass av RTOS för inbäddade enheter som är tillräckligt små för att köras på 8/16-bitars mikrokontroller, även om dess användning inte är begränsad till dessa mikrokontroller. Det är en helt öppen källkod och koden finns på github. Om vi känner till några grundläggande begrepp för RTOS är det väldigt enkelt att använda FreeRTOS eftersom det har väldokumenterade API: er som kan användas direkt i koden utan att känna till backend-delen av kodningen. Komplett FreeRTOS-dokumentation finns här.
Eftersom FreeRTOS kan köras på 8-bitars MCU så kan det också köras på Arduino Uno-kort. Vi måste bara ladda ner FreeRTOS-biblioteket och sedan börja implementera koden med API: er. Denna handledning är avsedd för en komplett nybörjare, nedan är ämnena som vi kommer att täcka i denna Arduino FreeRTOS-handledning:
- Hur RTOS fungerar
- Några ofta använda termer i RTOS
- Installerar FreeRTOS i Arduino IDE
- Hur man skapar FreeRTOS-uppgifter med exempel
Hur fungerar RTOS?
Innan vi börjar med RTOS-arbete, låt oss se vad som är en uppgift. Uppgift är en kodkod som kan schemaläggas att CPU ska köras. Så om du vill utföra en uppgift ska den schemaläggas med hjälp av kärnfördröjning eller med avbrott. Detta arbete utförs av Scheduler som är närvarande i kärnan. I en processor med en enda kärna hjälper schemaläggaren uppgifter att utföras i en viss tidsskiva men det verkar som att olika uppgifter körs samtidigt. Varje uppgift körs enligt den prioritet som ges till den.
Låt oss nu se vad som händer i RTOS-kärnan om vi vill skapa en uppgift för LED-blinkning med ett sekunders intervall och sätta den här uppgiften på högsta prioritet.
Förutom LED-uppgiften kommer det att finnas ytterligare en uppgift som skapas av kärnan, den kallas en ledig uppgift. Tomgångsuppgiften skapas när ingen uppgift är tillgänglig för körning. Denna uppgift körs alltid med lägsta prioritet, dvs. 0 prioritet. Om vi analyserar tidtagningsdiagrammet ovan kan det ses att körningen börjar med en LED-uppgift och den körs under en viss tid och sedan för återstående tid körs tomgångsuppgiften tills ett kryssavbrott inträffar. Därefter bestämmer kärnan vilken uppgift som ska utföras enligt uppgifternas prioritet och den sammanlagda tiden för LED-uppgiften. När en sekund är klar väljer kärnan den ledade uppgiften igen för att utföra eftersom den har en högre prioritet än den inaktiva uppgiften. Vi kan också säga att LED-uppgiften förhindrar den inaktiva uppgiften. Om det finns mer än två uppgifter med samma prioritet kommer de att köras i rund-robin-mode under en viss tid.
Nedanför tillståndsdiagrammet, eftersom det visar växlingen av den icke-körande uppgiften till körningstillstånd.
Varje nyskapad uppgift går i klartillstånd (en del av att tillståndet inte körs). Om den skapade uppgiften (Uppgift1) har högsta prioritet än andra uppgifter kommer den att gå till körningstillstånd. Om denna löpande uppgift förhindrar den andra uppgiften, kommer den att återgå till klart läge igen. Annars om uppgift 1 blockeras med hjälp av blockerande API, kommer CPU inte att delta i den här uppgiften förrän den timeout som användaren definierat.
Om uppgift1 är avstängd i igångläge med hjälp av avstängnings-API: er, går uppgift1 till avstängt tillstånd och den är inte tillgänglig för schemaläggaren igen. Om du återupptar Task1 i avstängt tillstånd återgår det till klartillståndet som du kan se i blockschemat.
Detta är den grundläggande idén om hur uppgifterna körs och ändras. I den här handledningen implementerar vi två uppgifter i Arduino Uno med FreeRTOS API.
Ofta använda termer i RTOS
1. Uppgift: Det är en kod som kan schemaläggas på CPU: n att utföra.
2. Schemaläggare: Den ansvarar för att välja en uppgift från färdiglistan till det pågående tillståndet. Schemaläggare implementeras ofta så att de håller alla datorresurser upptagen (som vid belastningsutjämning).
3. Befrielse: Det handlar om att tillfälligt avbryta en redan utförd uppgift i avsikt att ta bort den från det löpande tillståndet utan dess samarbete.
4. Kontextväxling: I prioritetsbaserad befrielse jämför schemaläggaren prioriteten för löpande uppgifter med en prioritet för färdig uppgiftslista vid varje systickavbrott . Om det finns någon uppgift i listan vars prioritet är högre än att köra uppgiften uppstår kontextväxling. I grund och botten sparas innehåll i olika uppgifter i deras respektive stackminne.
5. Typer av schemaläggningspolicyer:
- Förebyggande schemaläggning: I denna typ av schemaläggning körs uppgifter med samma tidsskiva utan att prioriteringarna beaktas.
- Prioritetsbaserad förebyggande: Uppgift med hög prioritet körs först.
- Schemaläggning av kooperativ: Växling av sammanhang sker endast med samarbete mellan löpande uppgifter. Uppgiften körs kontinuerligt tills uppgiftsavkastning anropas.
6. Kärnobjekt: För att signalera uppgiften att utföra en del arbete används synkroniseringsprocessen. För att utföra denna process används kärnobjekt. Vissa Kernel-objekt är händelser, semaforer, köer, Mutex, brevlådor etc. Vi kommer att se hur man använder dessa objekt i kommande handledning.
Från ovanstående diskussion har vi några grundläggande idéer om RTOS-konceptet och nu kan vi implementera FreeRTOS-projektet i Arduino. Så låt oss komma igång genom att installera FreeRTOS-bibliotek i Arduino IDE.
Installerar Arduino FreeRTOS-bibliotek
1. Öppna Arduino IDE och gå till Skiss -> Inkludera bibliotek -> Hantera bibliotek . Sök efter FreeRTOS och installera biblioteket enligt nedan.
Du kan ladda ner biblioteket från github och Lägg till.zip-filen i Skiss-> Inkludera bibliotek -> Lägg till.zip- fil.
Starta nu om Arduino IDE. Det här biblioteket innehåller en del exempelkod, som också finns i Arkiv -> Exempel -> FreeRTOS som visas nedan.
Här kommer vi att skriva koden från grunden för att förstå funktionen, senare kan du kontrollera exempelkoderna och använda dem.
Kretsschema
Nedan är kretsschemat för att skapa Blinkande LED-uppgift med FreeRTOS på Arduino:
Arduino FreeRTOS Exempel - Skapa FreeRTOS-uppgifter i Arduino IDE
Låt oss se en grundläggande struktur för att skriva ett FreeRTOS-projekt.
1. Inkludera först Arduino FreeRTOS rubrikfil som
#omfatta
2. Ge funktionsprototypen för alla funktioner som du skriver för exekvering som skrivs som
ogiltig uppgift1 (ogiltig * pvParameters); ogiltig Uppgift2 (ogiltig * pvParameters); .. ….
3. Skapa nu uppgifter i ogiltig installation () -funktionen och starta uppgiftsschemaläggaren.
För att skapa en uppgift kallas xTaskCreate () API i installationsfunktionen med vissa parametrar / argument.
xTaskCreate (TaskFunction_t pvTaskCode, const char * const pcName, uint16_t usStackDepth, void * pvParameters, UBaseType_t uxPriority, TaskHandle_t * pxCreatedTask);
Det finns 6 argument som ska skickas när du skapar en uppgift. Låt oss se vad dessa argument är
- pvTaskCode: Det är helt enkelt en pekare till funktionen som genomför uppgiften (i själva verket bara namnet på funktionen).
- pcName: Ett beskrivande namn för uppgiften. Detta används inte av FreeRTOS. Den ingår endast för felsökningsändamål.
- usStackDepth: Varje uppgift har sin egen unika stack som tilldelas av kärnan till uppgiften när uppgiften skapas. Värdet anger antalet ord som stacken kan innehålla, inte antalet byte. Till exempel, om stacken är 32-bitars bred och usStackDepth skickas in som 100, allokeras 400 byte stackutrymme (100 * 4 byte) i RAM. Använd detta klokt eftersom Arduino Uno bara har 2 kB RAM.
- pvParameters: Parameter för aktivitetsinmatning (kan vara NULL).
- uxPriority: Uppgiftens prioritet (0 är den lägsta prioriteten).
- pxCreatedTask: Den kan användas för att skicka ett handtag till den uppgift som skapas. Detta handtag kan sedan användas för att referera till uppgiften i API-anrop som till exempel ändrar uppgiftsprioriteten eller tar bort uppgiften (kan vara NULL).
Exempel på skapande av uppgifter
xTaskCreate (uppgift1, "uppgift1", 128, NULL, 1, NULL); xTaskCreate (task2, "task2", 128, NULL, 2, NULL);
Här har Task2 högre prioritet och körs därför först.
4. När du har skapat uppgiften startar du schemaläggaren i en ogiltig installation med vTaskStartScheduler (); API.
5. Void loop () -funktionen förblir tom eftersom vi inte vill köra någon uppgift manuellt och oändligt. Eftersom uppgiftskörning nu hanteras av Scheduler.
6. Nu måste vi implementera uppgiftsfunktioner och skriva logiken som du vill utföra i dessa funktioner. Funktionsnamnet bör vara detsamma som det första argumentet för xTaskCreate () API.
ogiltig uppgift1 (ogiltig * pvParameters) { medan (1) { …. din logik } }
7. Det mesta av koden behöver fördröjningsfunktion för att stoppa den löpande uppgiften, men i RTOS föreslås det inte att du använder Delay () -funktionen eftersom den stoppar processorn och därför slutar RTOS också att fungera. Så FreeRTOS har ett kärn-API för att blockera uppgiften under en viss tid.
vTaskDelay (const TickType_t xTicksToDelay);
Detta API kan användas för fördröjningsändamål. Detta API fördröjer en uppgift för ett visst antal fästingar. Den faktiska tid för vilken uppgiften förblir blockerad beror på kryssfrekvensen. Den konstanta portenTICK_PERIOD_MS kan användas för att beräkna realtid utifrån krysshastigheten.
Det betyder att om du vill ha en fördröjning på 200 ms, skriv bara den här raden
vTaskDelay (200 / portTICK_PERIOD_MS);
Så för den här handledningen kommer vi att använda dessa FreeRTOS API: er för att genomföra tre uppgifter.
API: er som ska användas:
- xTaskCreate ();
- vTaskStartScheduler ();
- vTaskDelay ();
Uppgift som ska skapas för den här självstudien:
- LED blinkar vid Digital stift 8 med 200 ms frekvens
- LED blinkar vid Digital stift 7 med 300 ms frekvens
- Skriv ut nummer i seriell bildskärm med 500 ms frekvens.
FreeRTOS uppgiftsimplementering i Arduino IDE
1. Från ovanstående grundläggande strukturförklaring, inkludera Arduino FreeRTOS-rubrikfilen. Gör sedan funktionsprototyper. Eftersom vi har tre uppgifter, så gör tre funktioner så är det prototyper.
#include void TaskBlink1 (void * pvParameters); ogiltig TaskBlink2 (ogiltig * pvParameters); void Taskprint (void * pvParameters);
2. I void setup () -funktionen, initiera seriell kommunikation med 9600 bitar per sekund och skapa alla tre uppgifterna med hjälp av xTaskCreate () API. Inledningsvis gör prioriteringarna för alla uppgifter som "1" och starta schemaläggaren.
ogiltig installation () { Serial.begin (9600); xTaskCreate (TaskBlink1, "Task1", 128, NULL, 1, NULL); xTaskCreate (TaskBlink2, "Task2", 128, NULL, 1, NULL); xTaskCreate (Taskprint, "Task3", 128, NULL, 1, NULL); vTaskStartScheduler (); }
3. Implementera nu alla tre funktionerna enligt nedan för uppgift 1 LED blinkar.
ogiltig TaskBlink1 (void * pvParameters) { pinMode (8, OUTPUT); medan (1) { digitalWrite (8, HIGH); vTaskDelay (200 / portTICK_PERIOD_MS); digitalWrite (8, LOW); vTaskDelay (200 / portTICK_PERIOD_MS); } }
På samma sätt implementera TaskBlink2-funktionen. Task3-funktionen kommer att skrivas som
void Taskprint (void * pvParameters) { int counter = 0; medan (1) { counter ++; Serial.println (räknare); vTaskDelay (500 / portTICK_PERIOD_MS); } }
Det är allt. Vi har slutfört ett FreeRTOS Arduino- projekt för Arduino Uno. Du hittar fullständig kod tillsammans med en video i slutet av denna handledning.
Slutligen ansluter du två lysdioder vid den digitala stiftet 7 och 8 och laddar upp koden på ditt Arduino-kort och öppnar den seriella bildskärmen. Du ser att en räknare körs en gång i 500 ms med uppgiftsnamn som visas nedan.
Observera också lysdioderna, de blinkar med olika tidsintervall. Försök att spela med prioritetsargumentet i funktionen xTaskCreate . Ändra numret och observera beteendet på seriell bildskärm och lysdioder.
Nu kan du förstå de två första exempelkoderna där analoga läs- och digitala läsuppgifter skapas. På det här sättet kan du göra fler förskottsprojekt med bara Arduino Uno och FreeRTOS API.