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