kramann.info
© Guido Kramann

Login: Passwort:










2 12.10.2011 - Verwendung binärer Semaphoren

2 (EN google-translate)

2 (PL google-translate)

Theoretischer Teil: RTOS Grundlagen (Fortsetzung Kapitel 2 Salvo-Manual)

  • Systemtypen S.14-28
  • Binäre Semaphoren S.29-32
  • Salvo-Anwendungen Schreiben (Vorgriff auf Kapitel 4) S.63-66
Übung

Schreiben Sie ein Programm mit drei Tasks:

  • TaskTaster: Inkrementiert Zaehler bei Taster PB0, dekrementiert bei PB1
  • TaskRS232: schickt gesteuert über binäre Semaphore nur bei Änderung der Variable "unsigned char zaehler" den Wert an das Hyperterminal, bzw. aktualisiert ihn über PortC
  • TaskBlink: Dauerton 500Hz
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 2-1: Lexikon zentraler Begriffe im Zusammenhang mit RTOS

Verständnisfragen / Themen
  • Wie sollten die drei Prozesse der Übungsaufgabe priorisiert werden?
  • Lassen sich OS_Yield(), OS_Delay(..), OS_WaitBinSem(...) beliebig mischen? - Was macht Sinn?
  • Was bedeutet OSNO_TIMEOUT in OS_WaitBinSem(...) ?
  • Welche Rückwirkungen haben Scheduler-Aufrufe auf globale und lokale (innerhalb eines Tasks definiert) Variablen?

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 2-1: Lösungsbeispiel zu der Übung mit binärer Semaphore.