-
        

Ergebnis 1 bis 10 von 10

Thema: Multitasking im AVR-Studio in "C"!

  1. #1
    Neuer Benutzer Öfters hier
    Registriert seit
    02.01.2010
    Beiträge
    20

    Multitasking im AVR-Studio in "C"!

    Anzeige

    Brauche wieder einmal eure Hilfe!
    Bin noch ein Anfänger, möchte aber mehrere Dinge parallel laufen lassen.
    Was ich bräuchte ist, ein Grundgerüst, damit ich darauf aufbauen kann.
    Anbei ein Übungsprogramm, von dem ich nicht weiss, ob der Ansatz so stimmt, oder komplett falsch ist.
    Wo bekommen ich Info's bzw. kann mir jemand den Code anbei aktualisieren. Wäre euch dankbar!
    Momentan (jetziges Programm ist noch länger wie dies im Anhang) läuft mein Programm nicht gut, d.h: es macht was es will. Glaube die Funkt. im "Compare-Match-Teil sind zu lang!?!?.
    Vorab schon Mal vielen Dank!
    Mad

    //======================== Programmbeschreibung ========================
    // 1.) Die Zeitkritischen Funkt. werden über einen Switch/Case-Schleife mittels "i_ext" gesteuert
    // 2.) 1x pro Millisek. sollten jene Funktionen aufgerufen werden, die sich ausserhalb der Switch-Case-Schleife befinden.
    // 3.)Im "main-Teil" sind nur zeitunkritische Funktionen!
    //================================================== ===================

    #include "definition.h"
    #include "LCD_def.h"
    #include "lcd_drv.c"

    uint8_t Funktion_LED_1(uint16_t ms);
    uint8_t Funktion_LED_2(uint16_t ms);
    uint8_t Funktion_LED_3(uint16_t ms);

    uint8_t Tastaturabfr(uint16_t ms);
    uint8_t In_Out_Abfr(uint16_t ms);

    extern uint8_t i_ext = 0; // Eventhandler (steuert die zeitkritischen Funktionen) dekl. & init

    //************** Beginn zeitkritische Funktionen !!!**********
    ISR (TIMER0_COMP_vect)
    {
    switch(i_ext) // Eventhändler zum steuern des Ablaufs!!!
    {
    case 10: Funktion_LED_1(100); break; // bestimmen der Blinkfrequenz Led 1
    // case 11: Funktion_LED_2(100); break; // bestimmen der Blinkfrequenz Led 2
    // case 12: Funktion_LED_3(100); break; // bestimmen der Blinkfrequenz Led 3
    }
    //Tastaturabfr_4x3(100); break; // längere Funktionen mit LCD Ausgabe
    //In_Out_Abfr(100); break; // längere Funktionen mit LCD Ausgabe

    }
    //************** Ende zeitkritische Funktionen !!!**********

    int main()
    {

    //************************************************** **********************
    // Timer Konfig. (Compare Match) zählt bis xx-Wert hoch (zB.: --> IR
    //************************************************** **********************
    TIMSK |= (1 << OCIE0); // IRQ bei Compare Match
    OCR0 = 8; // Vergleichswert 8 einstellen => ca. 1000 Hz (1ms) --> (8000000/1024/
    sei(); // IRQs enable (Interrupt global einschalten)
    TCCR0 |= (1 << WGM01); // CTC-Modus (Vergleichmodus)
    TCCR0 |= (1 << CS00) | (1 << CS02); // Prescaler: 1/1024 (zB.: CPU-Takt 8000000/ Teiler 1024)
    //************************************************** **********************
    // I2C & LCD Konfiguration
    //************************************************** **********************
    lcd_init(); // LCD initialisieren
    // i2c_init(); // initialize I2C library
    //************************************************** **********************
    // Port Konfig.
    //************************************************** **********************
    DDRA = 0x00; // Eing. Def.
    PORTA= 0xFF; // Alle Pin via Pullup auf High
    DDRB = 0xFF; // Ausg. Def.
    PORTB= 0xFF; // Alle Pin via Pullup auf High
    lcd_pos(2,0);
    lcd_text("Guten Tag!");
    _delay_ms(1000);

    while(1) //endlos
    {
    lcd_clear();
    lcd_pos(2,0);
    lcd_text("Step 1!");
    _delay_ms(1000);// was mich stört sind, diese sinnlosen delay's

    i_ext = 10; //Aufruf Zeitk.-Funktion_LED_1() im Compare-Match-Modus;
    _delay_ms(1000);

    lcd_pos(2,0);
    lcd_text("Step 2!");
    _delay_ms(1000);
    i_ext = 0; // Zeitkritischen-Funktionsaufruf sperren

    LCD_Ausg();
    _delay_ms(1000);

    //usw:
    } // ENDE while(1);
    return 0;
    } ENDE main();
    //************************************************** **********************
    // ZEIT-Kritische Funktion 1 wird mit einer Variable (i_ext) gesteuert
    //************************************************** **********************
    uint8_t Funktion_LED_1 (uint16_t ms) // Funktionsaufruf mit Wertübergabe
    {
    static uint16_t i_zaehler = 0; // Zähler auf 0 setzen (einmalig)
    if (i_zaehler >= ms) // Zählerstand > wie Wert der Funktion --> rein in die Schleife
    { PORTB ^= (1 << PB1); // Toggle Pin 2 von PORT B
    i_zaehler = 0; // Zähler wieder auf 0
    }
    i_zaehler ++; // sonst erhöhe Zähler um 1
    return 0; // zurück ins HP
    }

    //************************************************** **********************
    // NICHT-Zeitkritische Funktion
    //************************************************** **********************
    void LCD_Ausg(void)
    {
    lcd_clear(); // kompl. LCD löschen!!!!
    _delay_ms(30);
    lcd_text(" Hallo wie geht ");
    lcd_pos(2,0);
    lcd_text(" es dir ");
    lcd_pos(3,0);
    lcd_text(" heute? ");
    lcd_pos(4,0);
    lcd_text(" gut/schlecht? ");
    }

  2. #2
    Neuer Benutzer Öfters hier
    Registriert seit
    08.06.2009
    Beiträge
    18
    hi, also dinge paralel laufen lassen ist eher schlcht zu realisieren da der uC nicht mehrere befehle gleichzeitig bearbeiten kann.
    Ich bin aus deiner Programmbeschreibung nicht ganz schlau geworden, aber wenn du alle paar ms einen Programmabschnitt ausführen möchtest könntest du eventuell mit einem timer arbeiten der in einem definierten Zeitabstand einen Interrupt ausführt. In dieser Interrupt routine könntest du dann Interrupts unterdrücken so das dieser Zeitkritische code vollständig ausgeführt wird.

    hier noch 2 links die dir helfen könnten: http://www.mikrocontroller.net/artic...mit_Interrupts

    http://www.mikrocontroller.net/artic...A4hler_des_AVR

    Ich hoffe ich konnte dir helfen

  3. #3
    Erfahrener Benutzer Robotik Visionär
    Registriert seit
    26.11.2005
    Ort
    bei Uelzen (Niedersachsen)
    Beiträge
    7.942
    So richtig klassisches Multitasking macht man mit µCs eher selten. Es geht, ist aber realtiv aufwendig. Besser ist es oft direkt die einzelnen Tasks auf interrupts aufzuteilen. Damit hat man mehr Kontrolle was wann gemacht wird.

    Eine Aufgabe kann man im hauptprogramm erledigen, der Rest in Interrupts. Wenn ein Task keinen Interrupt hat zu dem er natürlicherweise wegen der Hardware gehört, kann man halt einen Timerinterrupt nutzen und ihn da reinhängen.

  4. #4
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    07.02.2005
    Beiträge
    102
    ---------------o00o----' (_)' ----o00o----------------
    Wer Rechtschreibfehler findet darf sie behalten.

  5. #5
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    07.05.2006
    Beiträge
    183
    Hi,
    google mal nach AVRX.

    mfg

  6. #6
    Erfahrener Benutzer Robotik Einstein Avatar von Vitis
    Registriert seit
    06.01.2005
    Ort
    Südpfalz
    Alter
    43
    Beiträge
    2.240
    Am Einfachsten geht sowas über Statemachine
    Vor den Erfolg haben die Götter den Schweiß gesetzt

  7. #7
    Neuer Benutzer Öfters hier
    Registriert seit
    02.01.2010
    Beiträge
    20
    hi vitis!
    was ist eine statemachine, bzw. wie wird so etwas angewendet!
    gruß mad

  8. #8
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    30.05.2006
    Ort
    Pfalz
    Beiträge
    154
    Bisschen träge dieser Thread, dann werd ich mal meinen Senf dazu geben.

    Also: den Vorschlag mit der Statemachine finde ich in deinem Fall am günstigsten. Du hast keine Zeitkritischen Dinge zu erledigen und extra AVRX zu verwenden finde ich da übertrieben.

    Ich versuche mal Deinen code einfach mal was mit ein paar Kommentaren in eine Statemachine zu übersetzen
    Code:
    
    
    char SignalTimeIstUp=0;   // soll nach 1000ms im Interrupt gesetzt werden
    
    ISR (TIMER0_COMP_vect) 
    {
        // irgendwie immer nach 1000ms setzen, könnte auch einmal/ms sein und dann ein Zähler sein der bis 1000 zählt,
    	// dann könnte man auch kleinere Wartezeiten wie die 30ms realisieren
        SignalTimeIstUp=1;
    }
    
    
    // die Zeitroutine (ist nur ein Beispiel geht auch schöner)
    char  Time_is_over(void)
    {
        if( SignalTimeIstUp )
    	{
    	    // Zeit ist um, Signal zurücksetzen
    	    SignalTimeIstUp=0;
    		return 1;         
    	}
        return 0;  // Zeit ist noch nicht um
    }
    
    
    
    
    
    int main()
    {
         //  Init alles was du brauchst
    
    
        char ZustandLCD=0;  // Zustand der Statemachine
        char SignalAusgabe=0;  // Eventhändler zum steuern des Ablaufs!!! 
    
        while(1)
        {
    	    // Statemachine LCD
            switch(ZustandLCD)
    		{
    		    case 0:
    			    if( Time_is_over() )
    				{
    				    lcd_clear();
                        lcd_pos(2,0);
                        lcd_text("Step 1!"); 
    					ZustandLCD=1;
    				};				
    				break;
    			
    			case 1:  // wieder warten bis 1000ms abgelaufen
    			    if( Time_is_over() )
    				{
    					SignalAusgabe=1;
    					ZustandLCD=2;
    				};
    				break;
    				
    			case 2:
    			    if( Time_is_over() )
    				{
    			        lcd_pos(2,0);
                        lcd_text("Step 2!"); 
    					ZustandLCD=3;
    				};
    				break;
    				
    			case 3:
    			    if( Time_is_over() )
    				{
    			        LCD_Ausg(); // da in LCD_Ausg noch gewartet wird könnte man diesen in verschiede Zustände (States) aufteilen
    					ZustandLCD=0; // wieder vorne anfangen
    				};
    				break;
    		}
    		
    		// Blinken
    		
    		// hier bitte blinken je nach SignalAusgabe und Zeitpunkt, dies könnte auch eine weitere Statemachine sein
    		
        
        }
    }

  9. #9
    Was Du suchst ist ein Scheduler. Im einfachsten Fall ist es eine einfach verkette Liste mit Funktionspointern. Man kann es aber ein wenig komplizierter machen, wenn man zwei Task quasi parallel laufen lassen möchte. Da muss man PC, SP und die Register wieder passend setzten...

    Naja, eine Statemachine ist eigentlich für was anderes gedacht und seine Aufgaben auf verschiedene Interrupts zu verteile ist auch nicht das wahre. Die Interrupt-Routinen lieber klein halten und in der Run-Loop den unkritischen Rest abarbeiten.

    Ich habe mal einen einfachen Scheduler als Anhang mit drangehängt. Der Code ist leider nicht viel dokumentiert, sondern war einfach mal zum testen geschrieben worden. Eventuell ist der komplette Code nicht ganz fehlerfrei, weil ich nicht mehr weiß was ich zum Schluss damit gemacht habe. Interessant ist "list" und "main". Das ganze ist übrigens in diesem Fall so ausgelegt, dass es immer ein Element in der Liste gibt.

    Die zwei Links sind auch zu empfehlen:
    GOS: einfacher preemptive multitasking scheduler
    http://www.mikrocontroller.net/topic/74026

    Wartezeiten effektiv (Scheduler)
    http://www.mikrocontroller.net/topic/12176
    Angehängte Dateien Angehängte Dateien

  10. #10
    Erfahrener Benutzer Fleißiges Mitglied Avatar von Robotniks
    Registriert seit
    13.10.2007
    Beiträge
    168
    Hi,

    du könntest entweder RTOS bzw. Free RTOS oder http://www.femtoos.org/ benutzen oder die neue
    C-Control Pro www.c-control.de dort ist ein echtes Multithreading im Interpreter eingebaut.


    Grüße

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •