Guten Abend zusammen:
Guten Abend zusammen:
Folgendes Problem:
Ich habe eine Steuerung mit analogen Ein- und Ausgängen, digitalen Ein-
und Ausgängen, Display, Keyboard, RS485 Schnittstelle gebaut.
Die Software habe ich Modular aufgebaut... zB getAIN, setAot, getDin,
calculateNewParam, Eventhanlder, statemachine.........
Die Software funktioniert. Nun weiss ich aber nicht, wie man die
Speicherverwaltung richtig macht. Ich habe diverse Variablen, auf welche
ich in den unterschiedlichen Funktionen zugreifen muss.
Kann mir jemand sagen wie man sowas professionell macht? Macht man eine
Funktion, welche alle diese Parameter verwaltet?
Momentan habe ich diese einfach ausserhalb der Funktion deklariert, zB
unsigned int Setpoint.
In der header Datei habe ich diesen dann mit "extern unsigned Setpoint"
aufgelistet.... so muss ich dann in den Funktionen, in welchen ich
auf diese Variabel zugreifen möchte nur noch die headerdatei
includen....
Völlig falsch?
Vielen Dank
Hallo,
das du alles modular aufgebaut hast ist schon mal gut.
Aber denke immer daran, dass globale Variablen AUCH Schnittstellen sind
wie Funktionen.
Wenn du dir jetzt ein "Beziehungsdiagramm" zwischen deinen Modulen
zeichnest, musst du auch immer eine Pfeil zu einem Modul zeichnen, in
dem "nur" diese Variable benutzt.
"Professionell" sollte man so wenig globale Variablen benutzen. Wenn man
etwas in einem Modul machen möchte, sollte man eine entsprechende
Funktion bereitstellen, die genau das tut was man möchte und das mit
möglichst wenig Parameter.
Das sind die 2 wichtigen Regeln der Softwareentwicklung: Kopplung und
Kohäsion.
Beispiel:
Du hast ein Modul ADC_Parameter, dann solltest du das "Mitteln" der ADC
Werte nicht extern machen, sondern in dem Modul selbst, dann musst du
die ADC Werte auch nicht als Variablen nach Außen geben (Kohäsion).
Dann hast du z.b. eine Funktion
Und je weiter du ein Modul abstrahierst, also je weniger andere Module
von deinem Modul wissen MÜSSEN, z.b. über Deklarationen um so besser,
denn umso besser ist auch die Kopplung. Je geringer die Kopplung umso
besser.
Ich weiß wie schwierig das ist. Gerade bei kleinen Projekten, da wird
mal schnell ne Variable global gemacht, weil es ja einfacher ist und
schnell geht... aber irgendwann möchte man etwas erweitern und merkt
dass man dann wieder was anpassen muss, weil ja dies und das hier doch
nicht bekannt ist... hätte man gleich sauber designt, hätte man solche
Probleme nicht.
Viele Grüße
und DIE MODULE inkludieren, dann die EEPROM Schnittstelle.
Jedes Modul hat dann z.b. ne Schnittstelle wie
1
voidSaveData(void);
2
uint_8GetSaveState(void);
Und speichern dann ihre lokale Daten ins Eeprom.
Die eeprom schnittstelle selbst muss gar nicht wissen WAS sie speichert.
Sie muss nur die Adresse, den Datenpointer und die Anzahl Datenbytes
kennen.
So muss GAR NIX global sein und die Eeprom Schnittstelle bleibt
flexibel.. auch wenn du deine Daten im Modul änderst.
Vielen Dank an den ersten Tipp(Gast)! Du hast meine Frage verstanden...
Vielleicht zum besseren Verständnis. Mein Programm läuft etwa so:
- Es gibt ein kleines UI --> ein Hauptmenu und ein Einstellungsmenu.
- In Main läuft nach den init's nur eine Statusmaschine, ein
Eventhanlder und eine Kontrollfunktion. (In der Kontrollfunktion werden
die Eingänge eingelesen, ein paar Berechnungen durchgeführt und dann die
Ausgänge aktualisiert. Der eventhandler schaut ob zb eine Taste gedrückt
wurde und gibt diese dann der Statusmaschine weiter. Die Statusmaschine
managed u.a. das ganze menu
- In einer Timerinterupt werden je nach geforderter Häufigkeit Flags
gesetzt. (Zb Flag zum Keyboard einlesen, oder Kontrollfunktion
ausführen,
Nun habe ich u.a. folgende Variabeln (aufs Minimum reduziert)
werte:
- Anzahl Sensoren, welchen an den digitalen Eingängen angeschlossen sind
- Anzahl aktive digitale Eingänge
- Analoger Eingangs
- Offset
aus diesen wird berechnet
- Alarmstatus
- Analoger Ausgang
- Digitaler Ausgang
Die meisten werden in der mehreren Funktionen benötigt, (Zb muss
statusmaschine Zugriff auf diese haben, um sie auf Display auszugeben;
die calculate Funktion muss aus diesen neue Werte berechnen, die
Alarmfunktion berechnet ob ein Alarm auftritt...)
Ist es nun ziemlich unprofessionell wenn diese ca. 8 Variablen global
sind.
Der Begriff "Speicherverwaltung", ist vielleicht ein bisschen falsch
gewählt.
Die Parameter welche ich nach einem Reset noch brauche, speichere ich
direkt ins Flash. Dies ist bei den AT89C51Rx2 einfach möglich, da diese
Parameter nur selten verwendet werden.
>werte:>- Anzahl Sensoren, welchen an den digitalen Eingängen angeschlossen sind>- Anzahl aktive digitale Eingänge>- Analoger Eingangs>- Offset>aus diesen wird berechnet>- Alarmstatus>- Analoger Ausgang>- Digitaler Ausgang>Die meisten werden in der mehreren Funktionen benötigt, (Zb muss>statusmaschine Zugriff auf diese haben, um sie auf Display auszugeben;
Ein gutes Design wäre so, dass Display gar nichts davon wissen muss, was
es ausgibt.
Aber Display ist kein triviales Fall.. obwohl es erst so klingt. Denn
hier müsste man (professionell) das MVC Muster einsetzen. Modell View
Controller. Das Modell wären deine globalen Variablen.. deine Daten. Das
View, die Display Anzeige Einheit und der Controller, der Mechanismus
der die Daten aktualisiert.
Dein View, das Display Modul müsste also sehr abstrakt sein:
1
voidShowScreen(screen_struct*screen_ptr);
screen_struc wäre dann eine Struktur, die dein Display beschreibt.
1
// Struktur fuer ein 2x16 Zeichen Display
2
typedefstructSCREEN_struct_type
3
{
4
uint_8first_row[16];// Inhalt erste Zeile
5
uint_8second_row[16];// Inhalt zweite Zeile
6
boolupdate_full_screen;// Soll ganzer Bildschirm aktualisiert werden
7
struct_sign_areaareas[4];// Bis zu vier Bereiche koennen aktualisiert werden
8
}screen_struct;
Das Menü Modul benutzt dann diese Schnittstelle um das Menü auf dem
Bildschirm darzustellen.
In deinem Menü müsste es dann eine Schnittstelle geben in die sich das
Modul z.B. Analoger Ausgang "reinhängen" kann.
Z.b. über eine Callback Funktion, also einen Funktionspointer in deinem
Menü.
Wenn dann der entsprechende Eintrag aktiviert wird, wird diese Callback
Funktion aufgerufen. Denn das Modul BENUTZT ja die Menü(--> Display)
Schnittstelle und nicht umgekehrt. sowas wie:
Das Modul Analogausgang fühlt dann den struct...
Wobei das auch keine schöne Lösung ist, es müsste noch eine weitere
Schnittstelle zwischen drin geben, welche das Menü zur Verfügung stellt!
(Einen Menü struct), denn so würde das Modul (direkt) auf die Display
Schnittstelle zugreifen...
Alles nicht so einfach :-) wie gesagt ist das kein einfaches Beispiel.
Aber deine Lösung klingt ja gar nicht so schlecht ;-)
>die calculate Funktion muss aus diesen neue Werte berechnen, die>Alarmfunktion berechnet ob ein Alarm auftritt...)
vielen Dank für deine Antworten... :-) genau das habe ich in keinem Buch
bis jetzt gefunden. Hast du dazu ein guter Büchertipp?
Die Steuerung ist zwar meine BA-Thesis jedoch denke ich, dass der
Aufwand zu gross ist für so eine kleine Steuerung... (einfacher gesagt
berechne ich nur aus ein paar Parameter einen Sollwert und mit einem UI
kann man einzelne Einstellungen vornehmen) Oder wies siehts du das?
Für das nächste grössere Projekt werde ich deinen Ansatz sicher
verfolgen...
Zum Thema Entwurfsmuster (wie das angesprochene MVC) empfehle ich dir so
ein Buch:
http://www.amazon.de/Entwurfsmuster-Elemente-wiederverwendbarer-objektorientierter-Software/dp/3827328241/ref=sr_1_1?ie=UTF8&s=books&qid=1251663352&sr=8-1
Ganz allgemein zum Thema Softwareentwicklung ist dieses Buch sehr gut
geeignet:
http://www.amazon.de/Pragmatische-Programmierer-Andrew-Hunt/dp/3446223096/ref=sr_1_1?ie=UTF8&s=books&qid=1251663443&sr=1-1>Die Steuerung ist zwar meine BA-Thesis jedoch denke ich, dass der>Aufwand zu gross ist für so eine kleine Steuerung... (einfacher gesagt>berechne ich nur aus ein paar Parameter einen Sollwert und mit einem UI>kann man einzelne Einstellungen vornehmen) Oder wies siehts du das?
Ja, grundsätzlich gebe ich dir für so ein kleines Projekt recht. Aber in
einer Thesis musst du das anders verkaufen ;-)
Dort solltest du so Begriffe wie Observer-Pattern (für das Event
Handling), MVC für die Abstraktion zwischen Darstellung und Daten
verwenden.
Denn du hast ja einen Event Handler und eine State-Machine. Das sind
alles schon mal gute Architekturtechniken die du da verwandt hast!
Vielleicht kannst du deine Daten ja in einer Art "Datenpool" verwalten
mit Semaphoren, damit es bei evtl. parallelen Prozessen zu keinen
Konflikten kommt. Also quasi sammelt dieser Datenpool, deine globalen
Daten und der Rest des Systems greift dann NUR über diese Schnittstelle
auf die Daten zu. Sowas wie ein Proxy (ist auch ein Pattern).
Bei meiner Thesis hatte ich auch einige unschöne Ansätze und habe dann
nach Entwufsmustern gesucht, die das ganze dann irgendwie legitimieren..
für was professionelles ist das natürlich nix, aber zumindest wurde so
die Architektur "geschönt" ;-)
paraleller zugriff wird nicht möglich sein...
jedoch habe ich glaube ich die Lösung:
ich habe beim Hardwaredesign schon eine RS485 schnittstelle
realisiert....
Diesen Programmteil muss ich allerdings in meiner Thesis nicht
machen(wird er nach abschluss gemacht, da ich mit hardware schon
ziemlich viel zu tun hatte)... --> nun sehe ich schon ein struct vor, in
welchem ich alle variabeln ablegen kann ... Die Modbusfunktionen können
dann auch darauf zugreifen.... und ich habe "alle am gleichen ort"
(optisch)
typedef struct { // Modbus register structure
unsigned short xy;
unsigned short xz;
...
} MB_STRUCT;
2-3 varibaeln werde ich global lassen.
was meinst du dazu?
Wen wir schon dabei sind, und du auch schon eine Thesis geschrieben
hast..
Die Doke habe ich folgender massen dokumentiert:
- Statemaschine, Funktionsablaufpläne, Modulplan, Aufbau UI, was würdest
du für ein C-Programm machen?
So das war meine letzte Frage, jedenfalls vielen Dank!!!
Sorry, ich kann dir grad nicht ganz folgen :-)
Was hat deine PC Schnittstelle mit der Datenverwaltung zu tun?
Klar, die Schnittstelle muss auf die Daten zugreifen können um sie zu
übertragen.
Aber du musst dir darüber im Klaren sein, auch wenn du die Daten in
einem globalen Struct kapselst, bleiben sie dennoch global.
Du hast das ganze dann nur etwas anders verpackt ;)
Aber so dumm ist das gar nicht. Hat etwas von Datenpool. Deine PC
Schnittstelle muss dann nur noch die Datenpool Schnittstelle inkludieren
und kann so auf alle Daten zugreifen.
Aber vergiss die Zwischenschnittstelle nicht! Nicht einfach alles in
einen Pool rein hauen, sondern die Einzelnen globalen nehmen und diesen
Struct rein "mappen"... das ist dann sowas wie ein Wrapper. Wenn du dann
etwas an der Zurdnung der Daten ändern willst, kannst du es an dieser
zentralen Stelle vornehmen.
Z.b gäbe es in deinem struct eine Variable:
Analogausgang
nun war der Ausgang bisher auf die Variable "Analogausgang1" gemappt, du
willst aber nun "Analogausgang2" für diesen Kanal verwenden... dann
musst du nur im Mapper, den Pointer darauf zeigen lassen, ohne deine PC
Schnittstelle, oder deine Menüschnittstelle anzupassen...
>- Statemaschine, Funktionsablaufpläne, Modulplan, Aufbau UI, was würdest>du für ein C-Programm machen?
Wie meinst du das?
Also ich würde grundsätzliche die Architektur dokumentieren, also welche
Module gibt es überhaupt und wie sind die logisch miteinander verbunden.
Das wäre dann die statische Struktur deines Systems (sprich in diesem
Zusammenhang von System, nicht von C-Programm.. C-Programm, ist nur die
Implementierung deines Systems)
Dann noch die innere Funktion deiner Module: Statemachines,
Aktivitäsdiagramme.
Und dann noch das dynamische Verhalten: Sequenzdiagramme, wie agieren
die Module zeitlich gesehen miteinander? Wann wird welches Modul in
welcher Reihenfolge aufgerufen.
Also grundsätzlich solltest du Struktur und Verhalten beschreiben.
Viel Erfolg bei deiner Thesis!
Was studierst du eigentlich? Elektrotechnik, Informatik? Je nach dem
solltest du ja auch auf die Schwerpunkte achten..
Direkt hat die Schnittstelle nicht mit den Daten zu tun, aber so habe
ich wie du sagtest einen "Datenbehälter" geschaffen. Obwohl immer noch
alles global ist sind die Daten "am gleichen" Ort.
der Zugriff kann ich ja momentan ziemlich einfach machen
1. Stuct anlegen
typedef struct { // Modbus register structure
unsigned short DigitalIn;
...
} MB_STRUCT;
2.
MB_STRUCT MB = {0};
3. Zugriff zB
MB.DigitalIn=readDIN();
Ich denke ich werde dieses noch realisieren und mich dann an die
Dokumentaion gemacht...
Die Frage zur Dokumentation hast du gut beantwortet.
Ich studiere Systems Engnieering .... da hat man zwar von allem
etwas(Elektro, Informatik und Maschienentechink) , jedoch nicht viel bis
ins Detail.
Das Programmieren von uController habe ich mir mehr oder weniger selbst
beibringen müssen, da dazu die Zeit fehlt... somit fehlt mir auch viel
Praxis:-)