05.10.2011 - Einführende Veranstaltung zum Umgang mit RTOS (Real-Time Operating Systems) am Beispiel von Salvo
(EN google-translate)
(PL google-translate)
Theoretischer Teil: RTOS Grundlagen (vergl. Kapitel 2 Salvo-Manual)
Möglichkeiten Tasks zu verwalten und deren Vor- und Nachteile
Englischer Begriff | Direkte Übersetzung | Bedeutung |
---|---|---|
foreground / background (or superloop)-system | Vordergrund / Hintergrund (oder auch Superschleife)-Systeme | Abarbeitung der Tasks läuft durch Aufruf von Funktionen aus einer Main-Endlos-Schleife heraus. |
Event driven Multitasking | Ereignisbasierter Multiprogrammbetrieb | Aufruf von Funktionen über Interrupts |
RTOS with preemptive context switching | RTOS mit bevorrechtigter Kontext-Umschaltung | Unterbrechung von Tasks an beliebiger Stelle und Retten und Wiederherstellen aller vom Task verwendeten Register-Inhalte |
RTOS with cooperative context switching | RTOS mit kooperativer Kontext-Umschaltung | Im Quelltext sind bei den einzelnen Task-Funktionen Stellen markiert, an denen der Scheduler Gelegenheit erhält, einen anderen Prozeß zu starten. |
Tabelle 0-1: Systeme zur Verwaltung von Tasks.
Lexikon
Englischer Begriff | Direkte Übersetzung (im Sinne von RTOS) |
---|---|
eligible | wählbar |
context switching | (Register-)Kontext Umschaltung |
Latency | Latenzzeit (Dauer, bis z.B. eine Interrupt-Funktion nach Auftritt eines Events abgearbeitet wird) |
maintain | aufrechterhalten / unterhalten (z.B. einen Task in einem bestimmten Zustand) |
provide | bereitstellen |
reliable | betriebssicher / zuverlässig |
scheduler | Zeitplanungsprogramm |
state machine | Zustandsautomat |
stack | Kellerspeicher |
system tick | Kleinste Zykluszeit eines Maschinenbefehls auf einem System |
voluntarily relinquish control | freiwillig die Kontrolle preisgeben |
yield | (Betriebssystem-)Einschub |
to yield | (etwas) abgeben |
Tabelle 0-2: Lexikon zentraler Begriffe im Zusammenhang mit RTOS
Verständnisfragen / Themen
|
Praktischer Teil: Anwendung von Salvo als RTOS für einen ATmega32
Hinweise zum herausgegebenen Material
|
|
|
Übung
Vereinfachen Sie das Projekt Tut5 so, dass ein Rechtecksignal mit 500Hz auf PD7 ausgegeben wird (TaskBlink). Als weiterer Task soll eine Datenübertragung über RS232 laufen (TaskRS232): Ein mit jedem Schleifendurchlauf in TaskBlink inkrementierter unsigned-char-Wert "zaehler" soll über die serielle Verbindung an das Hyperterminal des PCs geschickt werden.
#include <salvo.h> extern void board_init ( void ); extern void board_enable_interrupt ( void ); #define TASK_RS232_P OSTCBP(1) // task #1 #define TASK_BLINK_P OSTCBP(2) // task #2 #define PRIO_RS232 10 // niedrige Priorität #define PRIO_BLINK 2 // hohe Priorität //------------------------------------------ //Definition von Taktfrequenz und Bausrate als Konstanten #define TAKTFREQUENZ 9216000 #define BAUDRATE 115200 volatile unsigned char zaehler; void TaskRS232(void) { unsigned char l,m,r; //Variablen für Anzeige links, mitte, rechts unsigned char akku=0; DDRC = 255; //Merken des in UBRR zu speichernden Wertes. unsigned int baudregister = TAKTFREQUENZ/8/BAUDRATE-1; //setzen der Baudrate UBRRH = (unsigned char) (baudregister>>8); //Setzen des HIGH-Bytes des Baudraten-Registers UBRRL = (unsigned char) baudregister; //Setzen des LOW -Bytes des Baudraten-Registers //Einschalten des Senders und des Empfängers UCSRB = (1<<TXEN) | (1<<RXEN); //Setzen des Nachrichtenformats: 8 Datenbits, 1 Stopbits UCSRC = (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1); UCSRA = (1<<U2X); while (1) { OS_Yield(); akku = zaehler; OS_Yield(); l= akku / 100; //links = Inhalt von akku dividiert mit 100 OS_Yield(); m= (akku % 100) / 10; //mitte = Inhalt von akku modulo mit 100 , anschließend dividiert mit 10 OS_Yield(); r= akku % 10; //rechts = Inhalt von akku modulo mit 10 //Die drei Ziffern der aktuellen Zahl werden in ASCII-Zeichen umgewandelt //und mit UDR = ... seriell gesendet. //Dann muß gewartet werden, bis das Senden beendet ist. //Es folgen ein Zeilenumbruch und ein Zurücksetzen des Cursers auf den //Zeilenanfang: while( !(UCSRA & (1<<UDRE)) ) //Warten bis der Uebertragungspuffer leer ist OS_Yield(); UDR = l+48; //Daten in den Puffer schreiben und übertragen while( !(UCSRA & (1<<UDRE)) ) OS_Yield(); UDR = m+48; while( !(UCSRA & (1<<UDRE)) ) OS_Yield(); UDR = r+48; while( !(UCSRA & (1<<UDRE)) ) OS_Yield(); UDR = '\n'; while( !(UCSRA & (1<<UDRE)) ) OS_Yield(); UDR = '\r'; //Zahl außerdem wie gewohnt nach Port C schicken: PORTC = akku; } // Context-switch, damit der andere Task laufen kann. OS_Yield(); } void TaskBlink(void) { //PD7 als Beeper benutzen: zaehler=0; DDRD = 0b10000000; PORTD = 0b00000000; while (1) { // Toggle PORTC:0 PORTD ^= 0b10000000; //EXOR zaehler++; // Context-switch für 1 tick. OS_Delay(1); } } int main (void) { board_init(); OSInit(); // Erzeuge Salvo tasks. OSCreateTask(TaskRS232, TASK_RS232_P, PRIO_RS232 ); OSCreateTask(TaskBlink, TASK_BLINK_P, PRIO_BLINK ); // Benötigt: Timer1 ISR ruft den OSTimer auf. board_enable_interrupt(); // Endlosschleife für Scheduler. while (1) { OSSched(); } }
Code 0-1: Hauptprogramm
... void board_init ( void ) { TCCR1B = 0x00; // Stoppe Timer1 TCNT1H = 0x00; // Lösche Timer1 //FHB_RTOS anpassen: OCR1AH = 0x00; // Setze Compare A auf 39 OCR1AL = 0x23; // ((9.216MHz/256)/36) = 1ms //FHB_RTOS anpassen statt Vorteiler 1024, Vorteiler 64: TIMSK = _BV(OCIE1A); TCCR1B = _BV(WGM12)|_BV(CS12); } ...
Code 0-2: Änderungen in der Konfigurationsdatei