Forum: Compiler & IDEs Einfaches µC Betriebssystem - z. B. für SPS


von EverlastingLoop (Gast)


Lesenswert?

Hallo,

mitlerweile habe ich schon kleine Erfahrungen mit den ATMEL µC
gesammelt - ATMEGA32. Mein jungstes Projekt ist eine
Gewächshaussteuerung.

Kurzbeschreibung:
-Lüftung und Temperatursteuerung durch das Öffnen/Schliessen der
Fenster und Türen
-Wasseraufladung: EInlassen durch ein Ventil in ein Kanister und
Zirkulation des Wassers durch eine kleine Gleichstrompumpe
-Beregnung: Zum Abend, wenn das Wasser einigermaßen warm geworden ist
kann ´beregnet werden - mir Garden Tropfsystem


Hardware:
1 Gleichstrommotor für Fenster (H-Brücke)
1 Gleichstrommotor für Eingangstür (H-Brücke)
1 Ventil um Wasser von der Pumpe einzulassen
1 Pumpe für die Umwälzung: Aufwärmen von Wasser
1 Pumpe für die Beregnung
1 Taster (Innen und aussen) zum Öffnen der Tür
1 LCD display
1 Keypad 4x3
1 RS232
1 Windmesser (um beim Sturm die Türen sofort zu schließen)

Die Hardware funktioniert schon. Die Software teilweise.

Jetzt bin ich fast schon an meine Grenzen gestoßen und hab mir überlegt
was wäre es wenn es ein kleines Betriebssystem in C wäre womit ich dann
die TASKS einfach parallel arbeiten lassen kann und brauche mich nicht
mehr ind die Abarbeitungsreihenfolge kümmern.

Mein Problem ist:

Wenn z. B. Ich die Tür öffnen lasse, dann dauer es ca. 10 Sekunden. In
dieser Zeit kann der µC nichts anderes machen und das ist schade.

Hat jemand hier eine goldene Lösung. Falls nötig schicke auch Bilder.

EverlastingLoop

von Andreas H. (asmhesse)


Lesenswert?

Hi,

vielleicht hilft Dir der Scheduler aus der Codesammlung:
http://www.mikrocontroller.net/forum/read-4-49709.html#new

Gruss
Andreas

von Eman (Gast)


Lesenswert?

Du musst diese 10 Sekunden für die Tür ja nicht wartend verbringen,
sondern z.B. auf die Timer zurückgreifen.

Ein Betriebsystem wäre glaube ich ein wenig viel dafür und würde die
Sache wohl auch noch unnötig erschweren.

Wie wäre es wenn du es so z.B. machen würdest (pseudo-code):
1
int main() {
2
  while (1) { task1(); task2(); task3(); }
3
  return 0;
4
}
5
6
void task1() {
7
  if (aenderung_noetig) aendere();
8
}
9
10
void task2() { ... etc usw bla

und bei länger andauernden Prozessen speicherst du einfach den
Sollzustand und fragst bei der Fallunterscheidung ("if
(aenderung_noetig)") ab, ob dieser erreicht ist.

von EverlastingLoop (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

danke für den Beitrag. Anbei noch das Gewächhausschema.

Damit könnte man gut leben. Bloß ich habe die Impulsgeber für die
Drehzahlerfassung auf ganz normale Pins gelegt und Frage die in einer
while schlafe ab solange der Motor angesteuert wird und das geht ca. 8
Sekunden.

Ich denke ich müßte alles umstrukturieren und die Pins auf die
Interrupt-Pins legen und während des Interrupts incrementieren. Wie
kann man ein Task in der Mitte der Ausführung für eine andere Task
unterbrechen?

Habt ihr Links zu einem Betriebssystem?

Aber alles Umschraiben wäre ein großer Aufwand.

//////////////////////////////////////////////////////////////////////// 
//////
void doorClose()
{
  u08 imp_state=0;
  powerCard(MOT_2_LEFT);
  door_status=CLOSING;
  //lcd_WR_string(LCD_Line_1+5,"Dcls");
  while(CHECKBIT_FOR_ZERO(PINC,7))
  {switch(imp_state)
   {   case 0:
     {if(CHECKBIT(PINA,7))
      {imp_state=1;
    }
    break;
     }
     case 1:
     {if(CHECKBIT_FOR_ZERO(PINA,7))
      {imp_state=0;iImpCount_Door--;
    }
    break;
     }
   }
   delus(5);
   if(CHECKBIT(PINC,7)) {door_status=CLOSED;iImpCount_Door=0;break;}
// if reed contact is shorted, then interrupt closing
   if(door_status==STOP_REQUEST) {door_status=MIDDLE;break;}
  }
  powerCard(MOT_2_OFF);
}
//////////////////////////////////////////////////////////////////////// 
//////

Andreas Ortner

von Karl H. (kbuchegg)


Angehängte Dateien:

Lesenswert?

Das wirst du sowieso müssen :-)
Ob du nun ein BS hast oder nicht.

Auf einem µC baut man sowas ganz anders
auf. Grundsätzlich gilt die Devise: Keine
Warteschleifen die länger als ein paar µs
sind.

Man macht das zb. so, dass man sich einen
Automaten baut, der verschiedene Zustände
hat. Deine Tür zb. hat die Zustände:
offen, öffnend, geschlossen, schliessend.

Dann überlegt man sich, welche Auslöser es
gibt um von einem Zustand in einen anderen
Zustand zu gelangen. Zb. mag die Tür im
Zustand 'geschlossen' sein. Ein Auslöser
könnte zb. das Drücken eines Tasters sein.
Dadurch wird eine Aktion ausgelöst (Motor
ein) und die Tür geht über in den Zustand
'öffnend'. Im Zustand 'öffnend' kann
ein anderes Ereignis auftreten: zb. kannst du
einen anderen Taster drücken, worauf hin
als Aktion der Motor umgeschaltet wird und
die Tür in den Zustand 'schliessend' übergeht.
Oder ein Endschalter spricht an worauf hin
als Aktion der Motor abgeschaltet wird und die
Tür in den Zustand 'offen' übergeht.

Man kann das auch schön visualisieren, schau
dir mal das beigelegte GIF an. Dort
findest du die 4 Zustände wieder und Pfeile.
Jeder Pfeil beschreibt den Übergang von einem
Zustand in einen anderen Zustand. Der jeweilige
Auslöser ist jeweils in Blau angegeben, während
die Aktion, die durch den Übergang ausgelöst wird
in Rot wiedergegeben ist.

Ist also die Tür geschlossen, so gibt es nur eine
Möglichkeit diesen Zustand zu verlassen: jemand
drückt den Taster für 'Schliessen'. Als Folge
davon, wird der Motor für Schliessen gestartet
und die Tür wechselt in den Zustand 'Schliessend'.
Natürlich wirst du da noch andere Auslöser an-
bringen wollen (Windgeschwindigkeit über dem Limit,
Lichtsensor signalisiert Nacht, Temperatursensor
meldet zu heiss), aber es geht hier nur ums Prinzip.

Sowas programmiert sich dann schon fast von alleine:

#define DOOR_OPEN     0
#define DOOR_CLOSED   1
#define DOOR_OPENING  2
#define DOOR_CLOSING  3

unsigned char DoorState = DOOR_OPEN;

Weiters gibt es eine Hauptschleife, die die
jeweiligen Auslöser überwacht und mit den Zuständen
in Beziehung setzt und die Aktionen auslöst:

int main()
{
  while( 1 ) {

    if( DoorState == DOOR_CLOSED &&
        Taster_Oeffnen_gedrückt )
      DoorOpening();

    if( DoorState == DOOR_OPENING ) {
      if( Endschalter_Open_betätigt )
        DoorOpen();

      if( Taster_Schliessen_gedrückt )
        DoorClosing();
    }

    if( DoorState == DOOR_CLOSING ) {
      if( Endschalter_Close_betätigt )
        DoorClosed();

      if( Taster_Oeffnen_gedrückt )
        DoorOpening();
    }

    if( DoorState == DOOR_OPEN &&
        Taster_Schliessen_gedrückt )
      DoorClosing();
  }
}

void DoorOpening()
{
  Schalte Motor auf Öffnen;
  DoorState = DOOR_OPENING;
}

void DoorOpen()
{
  Motor abschalten;
  DoorState = DOOR_OPEN;
}

void DoorClosing()
{
  Schalte Motor auf Schliessen;
  DoorState = DOOR_CLOSING;
}

void DoorClosed()
{
  Motor abschalten;
  DoorState = DOOR_CLOSED;
}

Siehst du: nirgendwo ist eine Warteschleife.
(Klar musst du jetzt die Abfragen wie
'Taster_Schliessen_gedrückt' durch deine entsprechenden
PIN Abfragen ersetzten).

Der µC muss nirgends warten, bis eine Aktion abgeschlossen
ist. Die Aktion (öffnen, schliessen) wird einfach als
Zustand des Systems aufgefasst, in dem es sich befinden
kann und aus dem es durch ein Ereignis (Endschalter,
was auch immer) herausgeholt wird und in einen anderen
Zustand übergeht.

von Philipp Karbach (Gast)


Lesenswert?

ich würde auch sagen der µC ist hier eher die Steuereinheit, er checkt
die lage und gibt dann den befehl. (Wind stark->Tür Zu) dass die Tür
jetzt geschlossen wird sollte nicht der µC selbst steuern, eher eine
Steuerungskarte mit einer Rückkopplung. Sobald die Tür (sensorisch)
geschlossen ist. Kann der µC der Steuerung wieder sagen Sie kann jetzt
aufhören mit dem schalten. Diese Prozesse kann er ja dauernd checken,
das dauert wahrscheinlich ein paar ms je nach anzahl der Prozesse. Ich
glaub eine einfach Steuerung ließe sich entweder mit FETs oder
Dauerrelais realisieren.

Achja noch ne frage ;). Was für motoren setzt du denn da ein? Langsame
gleichstrom getriebemotoren? oder Schrittmotoren?

von EverlastingLoop Andreas Ortner (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

danke Karl Heinz für deine ausführliche Antwort. Ähnlich habe ich es
schon realisiert (siehe Anhang). Aber ich denke ich muß noch mehr
zustände definieren. Geht es denn nicht auf die Ressourcen des Stacks
da ich ohnenhin schon viele globale Variablen definiert habe. Zur
Harware: siehe ebenfalls Anhang.

von Ingo (Gast)


Lesenswert?

Donnerwetter! Das ist doch mal ne Superdoku für ein Selbstbauprojekt.
Respekt! Ich wünschte sowas würde ich öfter im Beruf sehen.

von Karl heinz B. (kbucheg)


Lesenswert?

Ja das sieht doch schon nicht schlecht aus (Hab den
Code nur überflogen).

Zum Thema Stack: Globale Variablen haben nichts mit
dem Stack zu tun, ausser dass sie ein Byte im Speicher
verbrauchen. Am Stack kommen funktionslokale Variablen
bzw. die Informationen zum Rücksprung aus Unterprogrammen.

Was ich an deinem Code auch noch machen würde:
Die Funktionen nach Themenkreisen sortieren und für
jeden Themenkreis eine eigene *.c / *.h Datei anlegen.
Jetzt ist das ganze schon ein bischen groß geworden
und die Übersichtlichkeit leidet schon darunter.

Siehe zb.
http://www.mikrocontroller.net/articles/Funktionen_auslagern_%28C%29

Falls der Link nicht geht:
http://www.mikrocontroller.net/articles/Spezial:Allpages
und dann 'Funktionen auslagern (C)' suchen.

von Philipp Karbach (Gast)


Lesenswert?

die doku ist wirklich spitze ;). da fühle ich mich ja ganz schlecht wenn
ich an mein eigenes projekt denke. aber vielleicht schreibe ich da auch
noch was

von EverlatingLoop (Gast)


Angehängte Dateien:

Lesenswert?

Habe jetzt versucht aufzuräumen und zu strukturieren. Habe aber Probleme
wenn ich die Zeile #include "LCD_i2c.c" ausblende. Die Zeile #include
"keypad_i2c.h" ist vorher angegeben. Wenn ich die Zeile #include
xxx.c rausnehme, kommt die Fehlermeldung. Wass könnte es sein?

Fehler:

!ERROR file 'Gewaechshaus_2006_07.o': undefined symbol
'_lcd_i2c_command'
!ERROR file 'Gewaechshaus_2006_07.o': undefined symbol '_snake'
!ERROR file 'Gewaechshaus_2006_07.o': undefined symbol
'_lcd_i2c_init'
!ERROR file 'Gewaechshaus_2006_07.o': undefined symbol
'_lcd_WR_string'
!ERROR file 'Gewaechshaus_2006_07.o': undefined symbol '_lcd_goto'
F:\Eigene_Dateien\07_Mikro_electronics\Programme\ICC\Feriges_Programm\ic 
c_\bin\imakew.exe:
Error code 1
Done: there are error(s). Exit code: 1

Include Zeilen:

#include <macros.h>
#include <STDIO.h>
#include <iom32v.h>
#include <STDLIB.h>
#include <eeprom.h>
#include "STRING.H"
#include "uart.c"

#include "LCD_i2c.h"
#include "miscelaneous.h"
#include "i2cmaster.h"
#include "keypad_i2c.h"
#include "uart.h"
#include "PCF8573.h"

// Beim Ausblenden dieser Zeilen kommen die Fehlermeldungen
#include "miscelaneous.c"
#include "i2cmaster.c"
//#include "LCD_i2c.c"
#include "keypad_i2c.c"

Danke.

von Karl heinz B. (kbucheg)


Lesenswert?

erst mal:
>#include "LCD_i2c.c"
das ist gut so, dass du die raus schmeist. Das macht man
nicht in C.

C funktioniert so:
Du hast den Source code auf mehrere *.c Dateien aufgeteilt.
Dann wird jede einzelne *.c einzelen und für sich alleine
zu sog. Object-Dateien kompiliert (übliche Dateiendung dafür
ist *.o bzw *.obj).
Erst dann, wenn alle Einzelteile kompiliert sind, werden die
Einzelteile zum fertigen Program zusammen-ge-linkt (aus
dem engl. to link - verbinden).

Wenn sich der Linker bei dir also beschwert, dass er eine
Funktion nicht finden kann, dann liegt das meist daran, dass
du ihm nicht alle Einzelteile angegeben hast, die er zum fertigen
Programm zusammen linken soll.

Wie das bei deinem System gemacht wird, musst du in der Doku
nachlesen. Ich kenn den ICC nicht.

Und bevor du fragst: Nein, die
#include "irgendwas.c"
sind keine Lösung dafür. Der Mechanismus des 'Einzelteile
getrennt kompilieren und dann zusammenlinken' hat schon seinen
Grund und ist ein wichtiges Instrument das man nicht leichtfertig
aus der Hand gibt.

von EverlastingLoop Andreas Ortner (Gast)


Angehängte Dateien:

Lesenswert?

Habe jetzt alles verworfen und möchte die ganze Struktur vom Neuen
anfangen.

Bin auf die Seite
http://www.mikrocontroller.net/articles/DCF77-Funkwecker_mit_AVR
gestoßen.

Statt Header-files zu includieren werden da .c-files includiert.

##########
#include "timerfunctions.c"
#include "_7_segment.c"
#include "dcf77.c"

int main (void) {
....
##########

Warem den so.

Überall wird gesprochen nur .h zu includieren?

Bitte um Rat.

von Jürgen Schuhmacher (Gast)


Lesenswert?

"Auf einem µC baut man sowas ganz anders auf. Grundsätzlich gilt die
Devise: Keine Warteschleifen die länger als ein paar µs sind."

Naja, prinzipiell gilt "Keine Warteschleifen". Auch ein paar us sind
Verschwendung und alles worauf man als uC warten muss, lässt sich früh
genug antriggern, um es dann zum point zero abholen zu können. ("code
in code" Technik).

Wer damit nicht so kann, dem sei empfohlen, während der scheinbar
unumgänglichen Wartezeit z.B. die LEDs - oder irgendwelche Ports
abzuarbeiten.

von Karl heinz B. (kbucheg)


Lesenswert?

> Warem den so.
>
> Überall wird gesprochen nur .h zu includieren?
>

Und das ist auch richtig so.

> Bitte um Rat.

Ein Grund warum man keine *.c Files inkludierst.

Weil du dann jedesmal den kompletten Source-Code
kompilierst. Und das kann dauern.das ist im Prinzip genauso
wie wenn du ein einzelnes riesiges Source Code File hast.
Beispiel: Das letzte mittelgroße Projekt, an dem ich
beteiligt war hatte einen Unfang von ca. 1,5 Mio Lines-of-Code.
Ein 1 Ghz PC (meine Arbeitsmaschine) braucht knapp an die
2 Stunden um den Code komplett zu kompilieren. Jetzt stell dir
mal vor, ich muss einen kleinen Fehler ausbessern:
Fehler ausbessern, 2 Stunden warten. Mist: da war noch eine
Kleinigkeit. Wieder 2 Stunden warten.
Im Vergleich dazu der richtige Ansatz: In der einen Source-
Code Datei die es betrifft den Fehler korrigieren, nur diese
eine Source-Code Datei kompilieren (eine Sache von Sekunden)
und die Einzelteile zum fertigen Programm linken. Das alles ist
eine Sache von ein paar Sekunden und schon gehts zum nächsten Test.

von Karl heinz B. (kbucheg)


Lesenswert?

> Bin auf die Seite
> http://www.mikrocontroller.net/articles/DCF77-Funkwecker_mit_AVR
> gestoßen.

Das ist genau ein Beispiel dafür, wie man es nicht macht.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.