Forum: Mikrocontroller und Digitale Elektronik Verwaltung von Variabeln


von Stive (Gast)


Lesenswert?

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

von Tipp (Gast)


Lesenswert?

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
1
// Prototyp
2
3
uint8_t ADC_GetADCValue(enum_adc_channels channel, bool averrage);

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

von Tipp (Gast)


Lesenswert?

Was meinst du mit Speicherverwaltung?

Sollen die Variablen im EEPROM gespeichert werden?

von Tipp (Gast)


Lesenswert?

Wenn es darum geht würde ich ein Modul EEPROM machen,

mit Schnittstellen wie
1
uint_8 write_eeprom (uint_8 address, uint_8 * data_ptr, uint_8 anz);
2
uint_8 read_eeprom (uint_8 address, uint_8 * data_ptr, uint_8 anz);


und DIE MODULE inkludieren, dann die EEPROM Schnittstelle.

Jedes Modul hat dann z.b. ne Schnittstelle wie
1
void SaveData(void);
2
uint_8 GetSaveState (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.

von stive (Gast)


Lesenswert?

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.

von Tipp (Gast)


Lesenswert?

>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
void ShowScreen(screen_struct * screen_ptr);

screen_struc wäre dann eine Struktur, die dein Display beschreibt.
1
// Struktur fuer ein 2x16 Zeichen Display
2
typedef struct SCREEN_struct_type
3
{
4
  uint_8 first_row[16];       // Inhalt erste Zeile
5
  uint_8 second_row[16];      // Inhalt zweite Zeile
6
  bool update_full_screen;    // Soll ganzer Bildschirm aktualisiert werden
7
  struct_sign_area areas[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:
1
void Analogausgang_UpdateDisplay(screen_struct *struct_ptr);

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...)

von stive (Gast)


Lesenswert?

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...

von Tipp (Gast)


Lesenswert?

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" ;-)

von stive (Gast)


Lesenswert?

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!!!

von Tipp (Gast)


Lesenswert?

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..

von stive (Gast)


Lesenswert?

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:-)

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.