www.mikrocontroller.net

Forum: Compiler & IDEs Anfängerfrage zum Programmaufbau bei mehreren Devices


Autor: Thomas Maierhofer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich bin neu in der AVR Programmierung und habe gerade mein STK500 und 
STK501 bekommen. Ich bin allerdings berflich Softwareentwickler und 
arbeite seit 15 Jahren mit C++. Mir ist aufgefallen, dass es einen in 
meinen Augen sehr komischen Stil gibt, die AVR Programme zu schreiben.

Im Prinzip ist der Kern eines Programms immer eine große Endlosschleife. 
Das klappt ja auch hervorragend, wenn ich ein paar Ports habe, und will 
diese dann mnit ein bischen Logik verknüpft auf andere Ports ausgeben.

Aber:
Ich habe mir jetzt gerade ein LCD Modul beschafft und einen Adapter für 
den STK500 gebastelt. Jetzt ist mir aufgefallen, das ich zwar die 
Ansteuerung für das LCD prima programmieren kann, wegen dem Timing der 
AVR aber während dieser Zeit nichts anderes mehr macht als Schleifen 
absitzen usw.

Will ich gleichzeitig I/O machen wird die geschichte schon richtig 
schwierig. Durch das Warten auf den LCD Controller bekomme ich im 
Prinzip riesige Latenzzeiten in die Abwicklung der I/O Routinen. Mein 
Durcsatz reduziert sich also auf das langsamste Gerät am Controller.

Grundsätzlich passiert das doch eigentlich immer, wenn ich 2 
unterschiedliche Devices am AVR betreibe, die entsprechende Pausen für 
ihr Timing benötigen.

Ich habe hierfür keine vernünftige Lösung gesehen. Insbesondere die C 
Bibliotheken sind für dieses Problem anscheinend gar nicht vorbereitet.

Ich stelle mir vor, dass solch ein Programm als Zustands-Maschine 
abgebildet wird. (Das kann naiv sein, gebe ich ja zu). Das formale 
Beschreibungsmitte wäre dann ein Petri Netzwerk. Ich habe das in anderem 
Kontext (Multitasking auf dem PC) bereits für Simulationen verwendet.

Gibt es hierfür einen Standard Ansatz (also ein Design Pattern)?

Autor: Sascha Weitkunat (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bei LC-Displays ist die sache furchtbar einfach. Das Display muss/kann 
ja garnicht bei jedem Schleifendurchlauf angesprochen werden. Wenn du 
z.B. einen Wert auf dem Display anzeigen willst:

if (AlterWert != NeuerWert)
{
  LCD_Anzeige_erneuern();
}

Nun ändert sich der Inhalt der Variable vielleicht jede Sekunde, die 
übrigen Durchläufe übergeht er einfach das IF-Statement und rennt durch 
den ürbigen Code.

Das gleiche gilt natürlich auch für andere Devices... So wird eine 
angeschlossene MMC z.B. natürlich nur ausgelesen wenn bedarf besteht - 
nicht bei jedem Durchlauf des Programms.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das Prinzip der Mainloop ist eigentlich, die einzelnen Tasks schnell 
genug zu machen, damit keine unzulässig hohe Verzögerung eintritt.

D.h. einfach größere Tasks in viele kleinere Abschnitte unterteilen. 
Eventuell benötigt man dazu ein Byte, was sich merkt, mit welchem 
Programmpunkt man beim nächsten Aufruf fortsetzen muß.

Im Falle des LCD legt man am besten einen gleich großen Puffer im RAM ab 
und jede Ausgabe erfolgt in diesen Puffer.

Die Ausgaberoutine testet dann immer nur einmal das Busy-Bit und gibt 
ein Byte aus dem Puffer aus. Das sollte dann schnell genug sein.

Alternativ kann das Busy-Testen und zyklische Ausgeben des Puffers zum 
LCD auch im Timerinterrupt erfolgen.


Also immer, wenn im Programmablauf Wartezeiten auftreten, dann die 
nächste Task an die Reihe lassen.


Peter

Autor: Joerg Wunsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Thomas:

Klar, kannste sicher gern tun, aber solch ein Automat hat
die unangenehme Eigenschaft, praktisch nicht mehr zu
pflegen zu sein.

Wenn Du zeitkritische Dinge zu erledigen hast, funktioniert
das sicher am besten, wenn man die jeweiligen Ereignisse
interruptgesteuert verwaltet.  Die Mainloop fragt dann nur
noch nach, welche Interrupts gerade anliegen und führt die
entsprechenden Aktionen aus (bzw. kann sich ggf. in einen
wohlverdienten avr_sleep() zurückziehen, wenn gerade nichts
zu tun ist ;-).  Die einzelnen Aktions-Routinen dürfen
natürlich auf keinen Fall mehr irgendwelche Warteschleifen
enthalten (und die ISRs erst recht nicht), sondern sie
schieben die jeweilige Aktion nur an und setzen dann einen
Trigger, der irgendwann zu einem Interrupt führt.  Wird
nur schwierig für Geräte, die nicht selbst interrupten
können (je nach Anschlußvariante kann ein LCD dazu gehören),
dort muß man sich dann evtl. mit einem geeigneten Timer
aus der Patsche helfen.

Autor: Sebastian Fahrner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Am besten baust Du für jeden "Task" eine Statusmaschine auf. Diese 
Statusmaschine muß ihren aktuellen Status innerhalb einer vorher 
festgelegten Zeit abarbeiten können. Dann synchronisierst Du diese 
"Tasks" mit einer festen Umlaufzeit, z.B. mit einem Timer.

Beispiel:

while(1)
  {
  /* Timerflag wird bei Timerüberlauf auf 1 gesetzt */
  while (Timerflag == 0) {;}
  Timerflag = 0;
  /* Jetzt hast Du eine feste Umlaufzeit */
  ...
  LCD_Maschine();
  IO_Maschine();
  ...
  }

In der LCD-Maschine hast Du jetzt einen switch, z.B. so:

switch (LCDStatus)
  {
  ...
  case WARTEN_BIS_LCD_FERTIG:
    if (Flag_LCD_fertig)
      {
      LCDStatus = LCD_FERTIG;
      }
    break;

  case LCD_FERTIG:
  ...
  }

Der Funktion LCD_Maschine() kann also seelenruhig auf das LCD warten, 
verbraucht dabei aber kaum Prozessorzeit.

War's verständlich?

Grüße,

Sebastian

Autor: Joerg Wunsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ach so: die Benutzung eines der vorhandenen Mini-Betriebssysteme
wäre ja vielleicht auch eine sinnvolle Variante.

Autor: Thomas Maierhofer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich bin jetzt bei Timer Interrupts gelandet. Ich verwende den Timer0 als 
Interruptquelle und habe in C auch schon eine Service Routine 
geschrieben. Hat sich eigentlich jemand mit den typischen Stack 
Manipulationen für Multitasking Betrieb auseinandergesetzt? Wenn es 
gelingt, die Rücksprungadesse - sprich den Kontext neu zu setzen, dann 
steht preemptivem Multitasking nichts mehr im Weg. Das Bedeutet es sind 
Threads möglich.
Ich habe gesen, das es Echtzeit Betriebssysteme für den AVR gibt. Das 
interessiert mich aber nicht, da ich den Mini Kernel auch selber 
schreiben kann. Wer hat bereits Erfahrung mit der notwendigen Stack 
Manipulation und dem Verwalten der Rücksprungadessen?

Ich teste momentan auf dem AT90S8515, der beim STK500 dabei ist. den 
ATMEGA128 vom STK501 hab ich noch nicht gesteckt.

Ok für alle Skeptiker:
RAM frisst das schon, das weiß ich auch!

Autor: Joerg Wunsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schau Dir exakt diese Echtzeitbetriebssysteme an, eben die,
die diese geschrieben haben (es dürfte deren kaum mehr als
eine Handvoll geben) haben sich auch mit genau Deinen
Fragen auseinandergesetzt.

Autor: Thomas Maierhofer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen, ich habe eine kleine Testroutine für einen preemtiven 
Taskwechsel geschrieben (ohne Kontextsicherung usw). Das hat mit dem 
ursprünglichen Problem zwar zu tun, ist aber wesetlich allgemeiner.

Da ich Interesse daran habe das breiter zu diskutieren beginne ich einen 
neuen Thread

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.