mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Parallel Programmieren


Autor: simon (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hallo!!

ich möchte einen thread im programm starten, hat mir jemand ein kleines 
codebeispiel wie so ein thread aussehen muss, wie ich ihn starte und was 
ich sonst noch so alles dafür brauche(includes prototypen usw.)?
controller ist ein attiny2313, falls es jemanden interessiert :~)

dank euch schonmal :)

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Threads hast du, wenn dein Betriebssystem dir welche anbietet.
Falls du eines hast ... :-)

Auf einem AVR wirst du das in aller Regel von Hand bauen müssen
mit Interrupts - siehe Tutorial.

Autor: simon (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klaus Wachtler schrieb:
> Auf einem AVR wirst du das in aller Regel von Hand bauen müssen
> mit Interrupts - siehe Tutorial.

interrupts sind kein problem, das tutorial habe ich auch schon fast ganz 
durch. möchte einen 2ten thread parallel zum hp starten der mir dann zb 
was einliest oder so.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
simon schrieb:
> möchte einen 2ten thread parallel zum hp starten der mir dann zb
> was einliest oder so

und genau das macht mit mit interupts, dafür braucht man keine Threads.

Autor: heinzhorst (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, Grundlangen der Mikrocontroller - Firmwareentwicklung. Weist du, was 
"kooperatives Multitasking" ist? Wenn nein - goolen und durchlesen.

Autor: simon (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
heinzhorst schrieb:
> Multitasking

genau das ist das stichwort :)
wie stelle ich es bem avr an??
die abarbeitung meines programms soll "parallel" erfolgen, also ein 
interrupt scheidet aus.

Autor: Εrnst B✶ (ernst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
simon schrieb:
> die abarbeitung meines programms soll "parallel" erfolgen, also ein
> interrupt scheidet aus.

in main:

while(1) {
  mach_ein_bischen_was_von_thread_a();
  mach_ein_bischen_was_von_thread_b();
}

Musst also nur die Einzelaufgaben in kleine Stückchen zerlegen, und die 
jeweils abwechselnd ausführen.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
simon schrieb:
> die abarbeitung meines programms soll "parallel" erfolgen, also ein
> interrupt scheidet aus.

mach es am besten so wie es die meisten leuten auf einem Amtel machen, 
also mit interupts. Man sollte auf einem µC nicht wie auf einem PC 
programmieren, threads sind nicht immer die beste wahl.

Autor: simon (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Εrnst B✶ schrieb:
> Musst also nur die Einzelaufgaben in kleine Stückchen zerlegen, und die
> jeweils abwechselnd ausführen.

das war mal meine ursprüngliche idee, wenn ich jetzt aber (nur 
beispielhaft) zb eine led blinken lassen möchte im thread 1 (also 
irgendwas prozessor blockierendes) und mit dem 2ten thread zb einen 
taster einlesen möcht (blödes beispiel :), dann sollte ich ja schon 
echtes multithreading betreiben.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Auf einem Prozessor mit nur einem Kern gibt es kein "parallel".

Es gibt höchstens ein "quasi parallel", indem laufend zwischen
den Dingern umgeschaltet wird, die du "Thread" nennst.

Und das musst du auf einem AVR von Hand programmieren, und
dazu brauchst du Interrupts.

Wenn du echte Threads (die das für dich irgendwo versteckt dann
auch machen), brauchst du ein Betriebssystem - und wahrscheinlich
einen etwas kräftigeren Prozessor.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
simon schrieb:
> das war mal meine ursprüngliche idee, wenn ich jetzt aber (nur
> beispielhaft) zb eine led blinken lassen möchte im thread 1 (also
> irgendwas prozessor blockierendes) und mit dem 2ten thread zb einen
> taster einlesen möcht (blödes beispiel :), dann sollte ich ja schon
> echtes multithreading betreiben.

nein auch dafür braucht man das nicht, die LED kann schön von interupt 
geblinkt werden dafür muss auch nichts blockieren.

Autor: simon (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klaus Wachtler schrieb:
> Wenn du echte Threads (die das für dich irgendwo versteckt dann
> auch machen), brauchst du ein Betriebssystem - und wahrscheinlich
> einen etwas kräftigeren Prozessor.

geht es nicht das ich zwei threads vom hp aus starte?
das es nicht wirklich parallel ist, ist mir klar :)

Autor: simon (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
simon schrieb:
> Klaus Wachtler schrieb:
>> Wenn du echte Threads (die das für dich irgendwo versteckt dann
>> auch machen), brauchst du ein Betriebssystem - und wahrscheinlich
>> einen etwas kräftigeren Prozessor.
>
> geht es nicht das ich zwei threads vom hp aus starte?
> das es nicht wirklich parallel ist, ist mir klar :)

@peter: war ja nur ein beispiel :)

Autor: simon (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wenn jetzt die led über einen längeren zeitraum blinkn soll und ich 
währenddessen was anderes machen möchte wie stelle ich das an, 
interrupts sollten ja nicht ewig laufen!

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
simon schrieb:
> wenn jetzt die led über einen längeren zeitraum blinkn soll und ich
> währenddessen was anderes machen möchte wie stelle ich das an,
> interrupts sollten ja nicht ewig laufen!

i++;
if ( i == 100 ) {
 LAMPE_AN
}

if ( i == 200 )  {
  LAMPE_AUS
  i = 0;
}

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
zb so


volatile uint8_t led_soll_blinken;

interrupt service routine
{
  if( led_soll_blinken )
    schalte LED in den anderen Zustand
}

int main()
{

  setze timer so auf, dass die interrupt service routine
  regelmässig aufgerufen wird

  while( 1 ) {

     if irgendwas
       led_soll_blinken = 1;

     if irgendwas anderes
       led_soll_blinken = 0;
  }
}       

In dem Moment, in dem du '_delay_ms' denkst, bist du schon falsch. Das 
wird dann nichts mehr.

Autor: der Blinker (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Interrupt regelmäßig auslösen und jedes Mal LED-Port 
setzen/zurücksetzen.

Alles andere läuft im Hauptprogramm und wird nur für das 
Setzen/Rücksetzen unterbrochen.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Imon (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn du auf ein AVR mit threads Arbeiten willst, wirst du selber denn 
Thread Wechsel Programmieren müssen. Das Läuft im Allgemeinen darauf 
hinaus das du einen Timerinterrupt hast der regelmäßig kommt und ein 
Scheduling auslöst das deine thread ggf umschaltet, ob sich das bei ein 
Tiny2313 wirklich Lohnt ist fraglich, aber eine schöner Zeitvertreib.
Zumal man dann ganz schnell solche Sachen wie Priotäten und Semaphore 
will. Dann Kommt man auf Problem wie Priotätsinversion etc. Das Ganze 
ist ein schönes aber nicht Trivialesfeld um zu verstehen wie 
Betriebsysteme Ticken.
Ich wünsch echt viel Erfolg wenn du dich da hinein Arbeiten willst, 
allerdings Driftest du da schnell vom Hundertstel ins Tausendstel.


Benutz mal die Suche,ich meine wir hatten vor ein paar Wochen eine 
Diskussion hier im Forum wo jemand seine Arbeit zu denn Thema Tasks & 
AVR vorgestellt hat. Vielleicht Hilft dir das ein Anfang zu finden.

Autor: simon (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
super, ich danke euch für die tollen antworten! ich weiß es wird nicht 
ganz trivial, aber mir geht es um den aha effekt :))

Autor: heinzhorst (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mann, da hab ich ja was losgetreten...

Für das Blinken on LEDs braucht man keine Interrupts zu verschwenden. Ob 
eine LED dabei ein paar ms früher oder Später eingeschaltet wird ist 
Sch**ßegal.

Also erstmal ganz zum Anfang. Prinzipiell sollte mal seine Firmware für 
eine bessere Portierbarkein und wiederverwertbarkeit von einmal 
erstelltem Quellcode modular aufbauen. Jedes Modul bekommt seine eigene 
Quellcode und Headerdatei. Darüber hinaus hat jedes Modul:

- Initialisierungsfunktion

Hier werden alle Aufgaben abgeaubeitet, die Das Modul beim Booten 
erledigen Muss, z.B. Variablen und Register mit Startwerten vorbelegen, 
Initialisierung der Hardware, etc.

- Task

Hier werden alle zyklisch auszuführenden Aufgaben abgearbeitet, z.B. 
Werde von externem Sensor abholen, Werte von ADC abholen. Der Task darf 
nicht durch das Warten auf irgendein Ereignis oder durch Zeitschleifen 
blockiert werden.

- IO-Funktionen

Die IO-Funtionen dienen zur Kommunikation der Module untereinander. 
Beispiel: Der im Taskabgefragte Wert aus dem ADC wird durch eine 
IO-Funktion den anderen Mudulen zur Verfügung gestellt.


So. Nun zurück zum Multitasking. Die Main ruft nacheinander alle 
initialisierungsfunktionen auf. Danach läuft sie in eine Endlosschleife, 
in der nacheinander die Tasks der einzelnen Module abgearbeitet werden. 
Das sieht dann so aus:

void main(void){

// initialisation

modu1_1_init();
modu1_2_init();
modu1_3_init();
...
modu1_n_init();

// endless loop

while(1){

modu1_1_task();
modu1_2_task();
modu1_3_task();
...
modu1_n_task();

   }
}


Autor: simon (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
das klingt gut, aber wird so nicht jeder task zyklisch abgearbeitet und 
darauf dann der nächste gestartet?

grüße und danke schon mal!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
simon schrieb:
> das klingt gut, aber wird so nicht jeder task zyklisch abgearbeitet und
> darauf dann der nächste gestartet?

Wenn jeder Task nur kurz genug ist, ist das ja kein Problem.

Autor: Bastler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das Zeitscheiben Prinzip ist simpel, aber oft auch ausreichend.

Messaufgaben, Tastenabfragen, ... können so z.B. alle 10ms aufgerufen 
werden und Display-Ausgaben alle 0,5s.

Da wird auch nur ein Timer benötigt, also echt resourcenfreundlich.
Du musst nur darauf achten, dass sie einzelnen Tasks nicht länger dauern 
als die Aufrufe.


Task_1ms(void)
{
  CheckAlarmFlags();
}

Task_10ms(void)
{
  ReadInPuts();
  ReadADC();
}

Task_100ms(void)
{
  ToggleLEDs();
  HandleWatchdog();
}

Task_1s(void)
{
  RefreshDisplay();
}

Autor: sepepe97 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn Dein Timer z.B. einen 10ms-Takt generiert und alle weiteren 
(langsameren) Zeitscheiben von der 10ms-Zeitscheibe abgeleitet werden,
darf die Summe aller Abarbeitungszeiten in allen Zeitscheiben nicht mehr 
als 10ms betragen.
Ansonsten überschreitest Du den 10ms-Basistakt und verlässt die 
Echtzeitfähigkeit. Andersrum sind die Zeitpunkte der Abarbeitung der 
einzelnen "Tasks" in den Zeitscheiben sowieso von der Abarbeitungszeit 
der restlichen vorher durchlaufenen "Tasks" abhängig und verschiebt sich 
daher ständig ein wenig hin und her.

Je nach Implementation würdest Du dann einen 10ms-Zyklus vergessen oder 
die 10ms-Zeitscheibe nach Durchlauf sofort wieder starten.

Ist aber beides nicht sinnvoll. Beim ersten wie auch beim zweiten würde 
Dein grobes Timing nicht mehr vorhersagbar sein.

Eine Ausnahmebehandlung bei Zeitüberschreitung sollte daher immer 
vorhanden sein.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.