12.10.2011 - Verwendung binärer Semaphoren
(EN google-translate)
(PL google-translate)
Theoretischer Teil: RTOS Grundlagen (Fortsetzung Kapitel 2 Salvo-Manual)
  | 
Übung
Schreiben Sie ein Programm mit drei Tasks:
  | 
Lexikon
| Englischer Begriff | Direkte Übersetzung (im Sinne von RTOS) | Erläuterungen | 
|---|---|---|
| Reentrancy | Eintrittsinvarianz (von Funktionen) | Wird eine Funktion während sie läuft an anderer Stelle aufgerufen, korrumpiert das nicht ihre Ausführung. | 
| to signal | melden | to signal a semaphore: Ereignis, das eine Semaphore in ihrem Zustand ändert. | 
| task control block pointer(tcb p) | Zeiger auf einen Scheduler internen Task-Steuerungs-Block | ...der eine Funktion über einen Zeiger als Task zugeordnet werden kann. | 
Tabelle 0-1: Lexikon zentraler Begriffe im Zusammenhang mit RTOS
Verständnisfragen / Themen
  | 
Lösungsbeispiel
/************************************************************
Programmidee:
Ein schneller Prozess prüft ständig, ob die Taster PB0 oder PB1
gedrückt werden und inkrementiert, bzw. dekrementiert einen
Zähler "zaehler"
Wenn dies geschieht, bekommt eine binäre Semaphore ein Signal.
Auf die Semaphore wartet ein zweiter Prozeß, der  
den Zählerstand über die serielle Schnittstelle an das
Hyperterminal schickt.
Ein dritter Prozess erzeugt ständig einen Ton von 500Hz.
************************************************************/
#include <salvo.h>
extern void board_init ( void );
extern void board_enable_interrupt ( void );
#define TASK_TASTER_P            OSTCBP(1)   // task #1
#define TASK_RS232_P             OSTCBP(2)   //  ""  #2
#define TASK_BLINK_P             OSTCBP(3)   //  ""  #3
#define PRIO_TASTER              6           // task priorities
#define PRIO_RS232               10          //  ""
#define PRIO_BLINK               4           //  ""
#define BINSEM_UPDATE_PORT_P     OSECBP(1)   // binSem #1
//Definition von Taktfrequenz und Bausrate als Konstanten
#define TAKTFREQUENZ 9216000
#define BAUDRATE 115200
volatile unsigned char zaehler;
volatile unsigned char taster;
volatile unsigned char zustand;
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) 
	{
//Weiterer Durchlauf, nur wenn binäre Semaphore ein Signal erhalten hat:
      OS_WaitBinSem(BINSEM_UPDATE_PORT_P, OSNO_TIMEOUT);
      akku = zaehler;
      //Zahl außerdem wie gewohnt nach Port C schicken:
      PORTC = akku;
      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';
    }
    // Context-switch, damit der andere Task laufen kann.
    OS_Yield();
}
void TaskBlink(void)
{
  //PD7 als Beeper benutzen:
  DDRD   = 0b10000000; 
  PORTD  = 0b00000000; 
  while (1) 
  {
    // Toggle PORTD:0
    PORTD ^= 0b10000000; //EXOR      
    // Context-switch für 1 tick.
    OS_Delay(1);               
  }
}
void TaskTaster(void)
{
  //Zähler initialiseren.
  zaehler = 0; 
  taster  = 0;
  zustand = 0;
             
  DDRB &= 0b11111100;
  while (1) 
  {
    taster = PINB;
    taster &=0b00000011; 
    if(zustand!=1 && taster==1)
	{
	    zustand = 1;
	    zaehler++;
        OSSignalBinSem(BINSEM_UPDATE_PORT_P);
        OS_Delay(5);               
	}
    if(zustand!=2 && taster==2)
	{
	    zustand = 2;
	    zaehler--;
        OSSignalBinSem(BINSEM_UPDATE_PORT_P);
        OS_Delay(5);               
	}
    if(taster==0)
	{
	    zustand = 0;
        OS_Delay(5);               
	}
    OS_Yield();
   }
}
int main (void)
{  
  //Hardware abhängige Initialisierung.  
  board_init();
  //Salvo initialisieren.
  OSInit();
  //Erzeugen von Salvo Tasks.
  OSCreateTask(TaskTaster, TASK_TASTER_P, PRIO_TASTER);
  OSCreateTask(TaskRS232,  TASK_RS232_P,  PRIO_RS232 );
  OSCreateTask(TaskBlink, TASK_BLINK_P, PRIO_BLINK);
  //Erzeugen von Salvo Events.
  OSCreateBinSem(BINSEM_UPDATE_PORT_P, 0);
  //Interrupts aktivieren wg. Scheduler bzw. Timer 1.
  board_enable_interrupt();
  //Scheduler / Multitasking starten.
  while (1) 
  {
    OSSched();
  }
  return 0;
}
Code 0-1: Lösungsbeispiel zu der Übung mit binärer Semaphore.