PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Multitasking



Exodus
19.06.2006, 09:38
Kann ich beim ATMEGA8535 Multitasking anwenden also programmabläufe parallel ablaufen lassen??
BITTE um Rückantwort

MFG
Michael

Kaiser-F
19.06.2006, 10:32
Nicht wirklich, aber du kannst das Programm ja so schreiben, dass er zB nicht in warteschleifen geht oder so, sondern diese mit hilte des Timers macht...

Also dass der programm immer durchläuft. Und nicht irgendwo hängenbleibt. Und Zeitroutinen über eine Variable im Timer runterzählen lassen, und sie immerwieder mit if überprüfen...

Exodus
19.06.2006, 10:35
hmm....
ok ich will dass machen!

will PA0 -PA7 nacheinander leuchten (0,25s)
gleichzeitig soll PB0 - PB3 nacheinander leuchten (0,50s)

ah ja noch was ich programmiere in Assembler nicht in C!

MFg
Michael

Rage_Empire
19.06.2006, 10:50
nimm 2 AVRs, dann kannst du auch 2 Dinge gleichzeitig (realtime) laufen lassen ;-)

bekoeppel
19.06.2006, 11:05
Auf www.avrfreaks.net gibt es ein Multitasking-Script. Natürlich nicht wirkliches Multitasking, sondern nur so Pseudo-Mässig.

lg

Kaiser-F
19.06.2006, 11:06
Wenn du zB zwei sachen zeitgesteuert machen willst, und neben bei noch was anderes ausgeführt werden soll, dann kannst du das so machen...

Dein Timer führt diese funktion 10 mal pro sekunde aus (zB!):


void TIMER ( void ){

if( timervar1 ){ timervar1 --; }
if( timervar2 ){ timervar2 --; }
if( timervar3 ){ timervar3 --; }

}

In der Hauptfunktion kannst du dann die Sachen so steuern:

Diese Funktion wird immer Durchlaufen:

if( timervar1 ){ "ES WERDE LICHT" }else{ "ES WERDE DUNKEL" }

Bei irgend ner Bedingung soll 10 Sekunden lang LICHT WERDEN:
also setzt man timervar1 auf 100:

timervar1 = 100;

Solange nun timervar1 UNGLEICH 0 ist, leuchtet die LED.

Und du kannst den Controller bequem was anderes machen lassen....

EDIT1: Richtiges Multitasking gehd glaub ich nicht mal bei handelsüblichen PCs (ausser bei den DUAL CORE PROZESSOREN, da glaub ich geht es...)

EDIT2: timervar1..3 sind globale Variablen!

Felix G
19.06.2006, 11:37
Naja, die Meisten meinen wenn sie von "richtigem" Multitasking reden das sog. "preemptive multitasking" wie es z.B. bei Desktop-Betriebssystemen zum Einsatz kommt.

Der Vorteil dabei ist, daß quasi mehrere Programme völlig unabhängig voneinander laufen können. Die Programme bekommen dann jeweils für eine bestimmte Zeit die CPU ganz für sich allein, und müssen die Kontrolle auch nicht freiwillig wieder abgeben. Das ist natürlich sehr praktisch, denn selbst wenn ein thread hängen bleibt, laufen die anderen noch ganz normal weiter.

Natürlich ist das wesentlich aufendiger zu realisieren, und man braucht ziemlich viel Speicher. (denn immer wenn einem thread die Kontrolle entzogen wird, müssen sämtliche Register und der komplette Stack irgendwo gesichert werden)

Exodus
19.06.2006, 12:18
avr-freaks.net funktioniert nicht!

MFG
Michael

Kaiser-F
19.06.2006, 16:09
Stimmt....
http://www.mikrocontroller.net/forum/read-7-214160.html

izaseba
19.06.2006, 16:18
will PA0 -PA7 nacheinander leuchten (0,25s)
gleichzeitig soll PB0 - PB3 nacheinander leuchten (0,50s)


und wo liegt das Problem???

Mache z.B. einen Timer mit 0,25s Zeitbasis.

Beim erstem Überlauf veränderst Du PA und prüftst ob ein Merker gesetzt ist, wenn nein setzt Dir einen Merker.

Beim zweitem veränderst Du PA sowieso und schaust ob Merker gesetzt ist und wenn ja änderst Du PB und löscht den Merker.

und so weiter von vorn....

Ist doch ganz Easy.

Gruß Sebastian

Vitis
20.06.2006, 01:32
Was man machen kann,
die Hardwarefunktionen laufen zum Teil autonom.
Du kannst z.B. ein Zeichen in die UART schreiben und
Dein Programm dann weiter laufen lassen, bis das nächste Zeichen raus muss.
Wenn Du den Print befehl für ne Zeichenkette verwendest beibt dein Prozi
bis zur Abarbeitung sonst an der Stelle stehen.
Schlussendlich kan der Prozi aber immer nur eine Sache auf Einmal ausführen, das gilt aber auch für die momentanen PCs genauso.

Kaiser-F
20.06.2006, 07:38
Genau....

Es ist echt sinnvoll, die Hardware-Zusatzfunktionen der µC zu nutzen.
Diese laufen dann wirklich parallel und eigenständig.

Wobei man beim UART auch meist mit dieser Funktio arbeitet:


void UART_transmit(uint8_t c){
while(!(UCSRA & (1<<UDRE)));
UDR = c;
}


Beim while wartet er ja auch bis er gesendet hat.....

Oder auch beim SPI:


uint8_t SPI_transmit( uint8_t data ){
SPDR = data;
while( !( SPSR & (1<<SPIF) ) );
return SPDR;
}

Vitis
20.06.2006, 18:57
Wobeis aber auch so schöne Interrupts gibt,
bei der UART z.B. der TXC, warum die verkommen lassen?

Kaiser-F
20.06.2006, 19:00
OK, das stimmt... aber das macht das Ganze schon ziemlich happig zum Proggen... wenn man mit Protokollen arbeitet....

bluelight_electronic
20.06.2006, 20:13
weil man nicht immer Interrupts brauchen kann ;) manchmal sind diese eher Störend .. gibt viele Anwendungen und grad wenn ne DualUart hast ... ist das ganze bisschen Gehässig ;).. da lieber ne while .. (kommt auf die Übertragugnsrate und dichte an) darfst halt immer nur 1 Byte senden dann schaun ob bei der andern uart was is und blah ..

Verabschiedet euch von Multitasking genauso wie von Echtzeit .. aber gerade dein Problem mit den LEDs ist kein problem .. izaseba hat es dir schön erklärt :)

Exodus
21.06.2006, 10:34
merker sind interrupts oder wie kann ich dass verstehen!?

MFG
Michael

Kaiser-F
21.06.2006, 10:37
nö...

du setzt zB ein bit auf 1. Und der Timer setzt es nach einer bestimmten Zeit auf 0.

Und wo anders überwächste du das Bit und lasst die LED leuchten solange das Bit 1 ist.


Merker ist einfach eine Variable...

Exodus
21.06.2006, 10:43
versteh dich nicht ganz !! ^^

MFG
Michael

Kaiser-F
21.06.2006, 11:11
Kein Problem...

Also, sagen wir "merker" sei eine Globale Variable.

Diese Timerfunktion wird Pro Sekunde einmal ausgeführt:
void TIMER( void ){
if( merker ){ merker = 0; }else{ merker = 1; }
}

Bedeutet, dass die Varible "merker" im sekundentakt 0...1....0...1 annimmt.


Dann kann man irgendwo anders im hautpprogramm sagen:

if(merker){ PORTA = 0xFF; }else{ PORTA = 0x00; }


Folglich Blinken die LEDs an PortA im Sekundentakt

Exodus
21.06.2006, 12:01
kannst du es mir in assembler aufschreiben diesen code den du in C geschrieben hast?
Bitte

Danke

MFg
Michael Mitteregger

Kaiser-F
21.06.2006, 12:04
Da beisst es leider aus... ich kann kein Assembler... tut mir leid...

Exodus
21.06.2006, 12:07
und ich nicht so gut in C! hmm....
kannst du es mir in worten aufschreiben?


MFG
Michael

Kaiser-F
21.06.2006, 12:13
Also, sagen wir "merker" sei eine Globale Variable.

Diese Timerfunktion wird Pro Sekunde einmal ausgeführt:
TIMER-FUNKTION{
WENN( merker ungleich 0 )Dann{ merker = 0; }Ansonsten{ merker = 1; }
}

Bedeutet, dass die Varible "merker" im sekundentakt 0...1....0...1 annimmt.


Dann kann man irgendwo anders im hautpprogramm sagen:

WENN(merker unngleich 0)Dann{ PORTA = 0xFF; }Ansonsten{ PORTA = 0x00; }


Folglich Blinken die LEDs an PortA im Sekundentakt


Hmm... ist es so verständlich?

Exodus
21.06.2006, 12:42
nien nicht so richtig! sorry!

MFG
Michael

Exodus
21.06.2006, 12:49
ah ich glaube habs jetzt so ungefähr kapiert!
Ich mache 3 Timer!
der erste soll 25us eine interrupt auslösen
der zweite 50us
der dritte 75 us

MFG
Michael

SprinterSB
21.06.2006, 13:01
Es genügt doch ein Timer... mit 25µs. Das Ereignus für 50µs führst du nur jedes 2. mal aus, das für 75µs jeder 3. mal und das für 25µs eben in jeder IRQ.

Exodus
21.06.2006, 13:05
versteh dich nicht ganz sprinter!
also alle 25us interrupt! was mache ich dann mit 50us und 75 us!!

MFg
Michael

SprinterSB
21.06.2006, 13:22
Stell dir vor du hast eine IRQ, die alle 25µs aufgerufen wird. Dann machst du folgendes; hier als irgendein Speudo-Code. Für 50µs geht's analog wie für die 75µs.


integer wert_75µs := 0

BEGIN IRQ_25µs

CALL job_25µs

wert_75µs := wert_75µs + 1

IF wert_75µs = 3
THEN
wert_75µs := 0
CALL job_75µs
ENDIF

END IRQ_25µs

Exodus
21.06.2006, 13:25
so ich verstehe nur assembler und nicht C! ^^

MFG
Michael

Felix G
21.06.2006, 13:29
Ein Interrupt ist eine Unterbrechung im normalen Programmablauf. Sobald ein Interrupt ausgelöst wird, springt der Controller automatisch in die passende ISR (Interrupt Service Routine). Das ist im Prinzip eine ganz normale Funktion, nur daß man die eben nicht selber aufruft sondern das dem Controller überlässt.

Wenn du also den Timer so einstellst daß er alle 25µs überläuft, und den passenden Interrupt aktivierst, wird eben alle 25µs die ISR aufgerufen die du für den Timer-Interrupt geschrieben hast.

Du möchtest eine LED blinken lassen? Dann schalte in der ISR eben den entsprechenden Pin um. Und wenn sie langsamer blinken soll (also 50µs an - 50µs aus etc.), dann musst du den Pin eben bei jedem zweiten Aufruf der ISR umschalten. Dazu brauchst du natürlich eine Variable die mitzählt wie oft die ISR aufgerufen wurde (also einfach bei jedem Aufruf eins hochzählen).

SprinterSB
21.06.2006, 13:30
Das ist kein C, irgendein Pseudo-Code eben. Ersetzte einfach IF-THEN-ELSE durch wenn-dann-sonst, da setzt du dann deine Tests und bedingten Sprünge rein.

Das nach Assembler codieren oder C oder Basic oder Ada oder was auch immer ist doch kein Thema mehr, wenn man weiß, was zu tun ist.

Du machst eben das, was zu tun ist nicht jedes mal sondern nur jedes 3. mal und anstatt bei 25µs bist du bei 3·25µs=75µs. Noch einfacher erklären geht nun echt nicht...

ogni42
21.06.2006, 13:30
Dann nochmal als Fließtext. In Deiner Interrupt-Routine zählst Du eine Variable hoch. Abhängig von deren Wert kannst Du jetzt zu bestimmten Zeiten, die ein Vielfaches von 25 us sind, weitere Routinen ausführen.

Kaiser-F
21.06.2006, 13:47
Aus dir machen wir schon noch nen Softwareking!

Also nochmal:

Wir betreiben jetzt 3 LEDs.
LED1: 25ms ein...25ms aus.
LED2: 50ms ein...50ms aus.
LED3: 75ms ein...75ms aus.

Also machen wir uns drei Variablen. Für jede LED eine:
LED1: irq_25ms
LED2: irq_50ms
LED3: irq_75ms


Der kleinste gemeinsame Teiler ist 25ms :-). Also stellen wir den TIMER0 zB so ein, dass er alle 25ms eine Interruptrutine ausführt.

START der Interruptrutine {
WENN irq_25ms GLEICH 25ms IST, DANN: Setze irq_25ms auf 0 Zurück ANSONSTEN zähle irq_25ms um 25ms hoch.
WENN irq_50ms GLEICH 50ms IST, DANN: Setze irq_50ms auf 0 Zurück ANSONSTEN zähle irq_50ms um 25ms hoch.
WENN irq_75ms GLEICH 75ms IST, DANN: Setze irq_70ms auf 0 Zurück ANSONSTEN zähle irq_75ms um 25ms hoch.
}ENDE

Das war jetzt die Funktion, die der Timer alle 25ms ausführt!
In dieser Funktion, welche alle 25ms ausgeführt wird, wird jede Variable um 25ms hochgezählt. Wenn sie ihr maximum erreicht haben, setzt man wie wieder auf 0! Sie werden NUR von der Timer-Routine beeinflusst!!!




Im Hauptprogramm untersucht man jetzt diese Variablen:

WENN irq_25ms GLEICH 25ms IST, DANN verändere LED1
WENN irq_50ms GLEICH 50ms IST, DANN verändere LED2
WENN irq_75ms GLEICH 75ms IST, DANN verändere LED3

Kaiser-F
21.06.2006, 13:53
Um auf das im Hauptprogramm noch genauer einzugehen:

WENN irq_25ms GLEICH 25ms IST, DANN SCHAUE OB LED1 AN IST: WENN JA, MACH SIE AUS, WENN NEIN, MACH SIE AN!
WENN irq_50ms GLEICH 50ms IST, DANN SCHAUE OB LED2 AN IST: WENN JA, MACH SIE AUS, WENN NEIN, MACH SIE AN!
WENN irq_75ms GLEICH 75ms IST, DANN SCHAUE OB LED3 AN IST: WENN JA, MACH SIE AUS, WENN NEIN, MACH SIE AN!

Exodus
21.06.2006, 14:21
wie soll ich 25ms vegleichen?? oder 50ms oder 75 ms???
soll ich den Timer abfragen?

MFG
Michael

Kaiser-F
21.06.2006, 14:28
Das war jetzt die Funktion, die der Timer alle 25ms ausführt!
In dieser Funktion, welche alle 25ms ausgeführt wird, wird jede Variable um 25ms hochgezählt. Wenn sie ihr maximum erreicht haben, setzt man wie wieder auf 0! Sie werden NUR von der Timer-Routine beeinflusst!!!

Die Variablen frägst du ab! Die Timer-Interrupt-routine aktualisiert sie!!!
Das läuft alles völlig im hintergrund!

Du musst nur noch beobachten, wann eine dieser Variablen den maximalen wert annimmt!

Und wenn das der Fall ist, dann veränderst die LED!!!



Um auf das im Hauptprogramm noch genauer einzugehen:

WENN irq_25ms GLEICH 25ms IST, DANN SCHAUE OB LED1 AN IST: WENN JA, MACH SIE AUS, WENN NEIN, MACH SIE AN!
WENN irq_50ms GLEICH 50ms IST, DANN SCHAUE OB LED2 AN IST: WENN JA, MACH SIE AUS, WENN NEIN, MACH SIE AN!
WENN irq_75ms GLEICH 75ms IST, DANN SCHAUE OB LED3 AN IST: WENN JA, MACH SIE AUS, WENN NEIN, MACH SIE AN!

Exodus
21.06.2006, 15:05
Ich weiß nicht wie ich dass in assembler richtig schreibe!
Ich verstehe dich jetzt ganz gut.


MFG
Michael

Kaiser-F
21.06.2006, 15:10
Hm.. mit assembler kenn i ich mich nicht aus...

Evtl steigst du ja auf C um.... Ich denke das lohnt sich ;-)

Exodus
21.06.2006, 15:13
Gibts hier irgendwo im internet eine seit wo c programmieren beschrieben ist für assembler? Wenn ja welche?

MFG
Michael

izaseba
21.06.2006, 16:49
O man, das ist jetzt echt lustig hier...

Assembler...
zuerst machen wir uns einen "Merker"



.equ LED2 = 0

.def Merkerregister = R17

..
..
..
clr Merkerregister


jetzt ein Interrupt, der sagenwirmal alle 25 mS aufgeführt wird.




interrupt:
...
...
...
sbrc Merkerregister,LED2
rjmp led2sollleuchten
sbr Merkerregister,(1<<LED2)
rjmp zweiteled
led2sollleuchten:
cbr Merkerregister,(1<<LED2)
sbic PORTB,PB2
rjmp led2sollleuchten_
sbi PORTB,PB2
rjmp zweiteled
led2sollleuchten_:
cbi PORTB,PB2
zweiteled:
sbic PORTB,PB1
rjmp zweiteled_
sbi PORTB,PB1
rjmp fertig
zweiteled_:
cbi PORTB,PB1
fertig_:
...
...
reti



So in etwa PB2 wird nur jeden zweiten durchgang getoggelt, alle 50 mS und PB1 wird bei jedem Durchgang umgeschaltet...

Bedenke daß es nur ein Pseudocode ist.

Gruß Sebastian

Exodus
22.06.2006, 08:03
Ich glaube ihr versteht mich nicht ganz!

Ich will von PA0 - PA7 dass eine LED mit 25ms Takt hin un herbewegt!
(fast) gleichzeitig soll von PB0 - PB4 immer eine LEd hin und herbewegt werden mit 50ms.

MFG
Michael

SprinterSB
22.06.2006, 08:26
Doch, es wird wohl verstanden was du willst.
Und der Weg zu der Lösung wurde hier auch schon mehrfach ausgetextet und erklärt, nur darfst du nicht erwarten, daß jemand hier für dich deine Fix-Fertig-Lösung programmiert...

Kaiser-F
22.06.2006, 08:47
Ich glaube ihr versteht mich nicht ganz!

Ich will von PA0 - PA7 dass eine LED mit 25ms Takt hin un herbewegt!
(fast) gleichzeitig soll von PB0 - PB4 immer eine LEd hin und herbewegt werden mit 50ms.


Quasi ein Lauflicht?:
+------+
-+----+-
--+--+--
---++---
--+--+--
-+----+-
+------+
Stellt den Zeitlichen verlaufvon PortA dar. (+) = LED AN! (-) = LED AUS!

Wo liegt das Problem?
Hier brauchst du sogar nur eine Variable die vom Timer gezählt wird!

UND SIE MACHEN ES SORAG SO GUT WIE GLEICHZEITIG.. Ich denke die 3 µC-Zyklen die machen die Suppe nicht salzig!!!

ALSO:

Nochmal dein Vorhaben:
Takt0: +------+
Takt1: -+----+-
Takt2: --+--+--
Takt3: ---++---
Takt4: --+--+--
Takt5: -+----+-
Und dann beginnt das Spiel wieder von vorne!!!

Also machen wir uns eine Variable TAKT!
Die Variable TAKT soll von 0 bis 5 hochgezählt werden.
Anstatt dann weiter auf 6 gezählt zu werden, soll sie auf 0 zurückgestellt werden. Und der Vorgang beginnt von neu!

Also machen wir das SO: Wir brauchen einen Timerinterrupt!
Der Timer wird so eingestellt, dass er den Interrupt alle 25ms ausführt!

Timerinterrupt{
WENN TAKT KLEINER 5 IST,
DANN ZÄHLE TAKT UM 1 HOCH
ANSONSTEN SETZE TAKT AUF 0.
}



IM HAUPTPROGRAMM WIRD TAKT UNTERSUCHT!

WENN TAKT GLEICH 0, DANN PORTA = 0b10000001
WENN TAKT GLEICH 1, DANN PORTA = 0b01000010
WENN TAKT GLEICH 2, DANN PORTA = 0b00100100
WENN TAKT GLEICH 3, DANN PORTA = 0b00011000
WENN TAKT GLEICH 4, DANN PORTA = 0b00100100
WENN TAKT GLEICH 5, DANN PORTA = 0b01000010



Ich denke sowas ist wirklich nicht schwierig zu realisieren....

Exodus
22.06.2006, 10:03
warum funktioniert dass nicht!
compare:
cpi Takt, R18
brlo 0x05
clr R18
inc R18
reti

MFG
Michael

izaseba
22.06.2006, 16:18
Ich glaube ihr versteht mich nicht ganz!

Ich will von PA0 - PA7 dass eine LED mit 25ms Takt hin un herbewegt!
(fast) gleichzeitig soll von PB0 - PB4 immer eine LEd hin und herbewegt werden mit 50ms.


Ich hab Dir am Anfang grob gesagt, wie das zu machen ist, man hat Dir Beispiele in C geschrieben, Du wolltest Assembler, ich hab Dir ein Assemblerbeispiel geschrieben wie man zwei LED's toggeln kann, was willst Du noch ?



warum funktioniert dass nicht!
compare:
cpi Takt, R18
brlo 0x05
clr R18
inc R18
reti

was soll uns das hier sagen ?

cpi Takt,R18 ????

was macht denn cpi ???
vergleicht einen Register mit einer Konstante, was ist Takt ein Register ? R18 ist das eine Konstante????? wohl kaum hier wäre wohl cp besser oder?

brlo 0x05 -> zur Adresse 0x05 springen?

clr R18 -> setze R18 auf Null
und direkt inc R18 inkrementiere R18 -> R18 bleibt immer 1

und danach direkt reti?
was ist mit SREG retten? nix? dann wunder Dich nicht das es nicht klappt

Naja mach mal.....

Gruß Sebastian