Forum: Mikrocontroller und Digitale Elektronik Sauber Programmieren mit Interrupts


von Jan S. (spongebob)


Lesenswert?

Moin!
Kann mir hier vielleicht irgendwer sagen, ob es irgendwo Konventionen 
bzw. Codebeispiele zum sauberen/übersichtlichen programmieren mit 
Interrupts anzusehen gibt?
Ich habe immer das Problem das ich zwar kleine Programme schreiben kann, 
welche auch funktionieren, jedoch habe ich immer das Problem das ich bei 
steigenden Anforderungen teilweise selbst nicht mehr ohne weiteres durch 
meinen Code durchblicke. Es kommen je nach Anzahl der ISRs "Massen" an 
globalen Variablen vor und wenn ich Funktionen schreibe, die mit 
mehreren Dingen zusammenspielen (Beispiel: Timer und Externer Interrupt 
für Software-Tasterentprellung), bin ich mir auch immer unsicher, wohin 
ich die entsprechenden Funktionen auslagern soll.
Ich würde mich freuen wenn mir jemand ganz einfach eine 
Beispiel-Codesammlung, bzw. Beispielprojekte empfehlen könnte, um sich 
einfach mal eine gute Programmierweise anzusehen und sich ein bisschen 
abschauen könnte, wie andere an so etwas rangehen.

Grüße Jan

von Martin (Gast)


Angehängte Dateien:

Lesenswert?

Ich fand die Dateien im Anhang ganz hilfreich

von Jan S. (spongebob)


Lesenswert?

Danke für die schnelle Antwort!!!
Denke in Kap5 (Interrupts) sind ein paar hilfreiche Tipps drin.
Das andere werde ich mir auch mal in ruhe ansehen.

Grüße Jan

von Falk B. (falk)


Lesenswert?

Siehe Interrupt und [[Strukturierte Programmierung auf 
Mikrocontrollern]]

von Jürgen S. (starblue) Benutzerseite


Lesenswert?

Jan S. schrieb:
> Es kommen je nach Anzahl der ISRs "Massen" an
> globalen Variablen vor und wenn ich Funktionen schreibe, die mit
> mehreren Dingen zusammenspielen (Beispiel: Timer und Externer Interrupt
> für Software-Tasterentprellung), bin ich mir auch immer unsicher, wohin
> ich die entsprechenden Funktionen auslagern soll.

Mach für jedes "Thema" ein Modul:
- Jede Hardwarekomponente kriegt ihr Modul
- Jeder andere sinnvoll abkapselbare Teil auch

Variablen werden den zuständigen Modulen zugeordnet, der Zugriff erfolgt 
nur innerhalb des Moduls, globale Variablen gibt es nicht.

Jedes Modul kriegt eine Initialisierung für Daten und evtl. Hardware, 
sowie weitere Funktionen nach Bedarf.

Hier z.B.: Timer, externer Interrupt, Taster-Entprellung, Hauptprogramm

von Edi M. (Gast)


Lesenswert?

Jürgen S. schrieb:
> Variablen werden den zuständigen Modulen zugeordnet, der Zugriff erfolgt
>
> nur innerhalb des Moduls, globale Variablen gibt es nicht.

Und Semaporen?

von Thomas (kosmos)


Lesenswert?

ich gehe jetzt mal von AVR-Assembler aus

Wichtig ist es den Interrupt-Vectortabelle komplett auszufüllen notfalls 
mit einen Rücksprung, dann kann selbst ein unerwarteter Interrupt die 
Programmausführung nicht fehlleiten.

Interruptroutinen möglichst kurz halten, also nur das wichtigste darin 
ausführen z.B. einen Wert sichern, die Verarbeitung erfolgt dann später 
im Programmablauf.

Überlegen welche Register von der einzelnen Interrupt-Routine benötigt 
werden, damit du diese vorher auf den Stack legen und danach wieder vom 
Stack abholst.

von Hannes L. (hannes)


Lesenswert?

Thomas O. schrieb:
> Wichtig ist es den Interrupt-Vectortabelle komplett auszufüllen

Das sehe ich zwar auch so, die Profis bevorzugen aber .org-Orgien.

> notfalls
> mit einen Rücksprung,

Habe ich anfangs auch gemacht, inzwischen bevorzuge ich dafür eine 
Endlosschleife, in die man bei Bedarf noch eine Alarm-Ausgabe einbauen 
kann.

> dann kann selbst ein unerwarteter Interrupt die
> Programmausführung nicht fehlleiten.

Unerwartete Interrupts sind Programmierfehler. Ein Rücksprung (reti) 
vertuscht diese, eine Endlosschleife deckt sie auf.

Thomas O. schrieb:
> Interruptroutinen möglichst kurz halten, also nur das wichtigste darin
> ausführen z.B. einen Wert sichern, die Verarbeitung erfolgt dann später
> im Programmablauf.

Das kommt auf die Umstände an. Gibt es nur einen Interrupt (z.B. Timer), 
so kann es durchaus sinnvoll sein, den gesamten Code in der ISR 
abzuarbeiten. Bei mehreren Interrupts stimmt Deine Aussage natürlich.

Thomas O. schrieb:
> Überlegen

Überlegen ist immer richtig! Blind nach Schema F arbeiten ist nicht 
immer richtig...

> welche Register von der einzelnen Interrupt-Routine benötigt
> werden, damit du diese vorher auf den Stack legen und danach wieder vom
> Stack abholst.

Prinzipiell nicht falsch, aber der AVR hat 32 Register. Davon lassen 
sich ohne weiteres einige exklusiv für ISRs reservieren. Das spart dann 
viele Push/Pop-Orgien und macht die ISRs recht schnell.

Wichtig ist, dass man versteht was man macht und nicht einfach 
irgendwelche aufgeschnappte Phrasen nachplappert.

...

von Thomas (kosmos)


Lesenswert?

@Hannes: Irgendwie fühle ich mich immer persönlich von dir angegriffen. 
"Überlegen" "Blind schreiben" "Phrasen nachplappern" usw. kannst du es 
nicht ohne?

Ich persönlich nutze neben den Registern auch definierte Bytes im SRAM, 
damit mir möglichst vieles "exclusiven" Register übrig bleiben mit denen 
es etwas schneller zu arbeiten geht.

Aber wenn ein Anfänger hier schon fragt, das sag ich ihm halt die 
generelle Vorgehensweise wie sie in jedem Leerbuch steht. Also benötigte 
Register vor der Bearbeitung der Interruptroutine sichern und danach 
wiederherstellen, zusätzlich schrieb ich ja hier etwas zu überlegen um 
nicht alles sichern zu müssen.

Mir ist auch ein Programm ohne Fehler lieber, aber mein Vorschlag 
richtete sich gerade an Anfänger. Denn dort wird sicherlich ein Programm 
das trotz eines kleinen Programmierfehlers (falscher Interrupt 
freigegeben) richtig läuft einem das nicht läuft vorgezogen.

Ich simuliere meine Programme sowieso erst durch und wenn ich da 
plötzlich auf dem falschen reti stehe sehe ich das dann auch gleich. Ist 
ja nicht mein Programmierziel aber mal ein falsches Bit gesetzt und 
schon ist der falsche Interrupt aktiviert.

ja solche .ORGien meinte ich, nennt sich das etwa nicht Interruptvector?
1
.ORG  0x00
2
rjmp RESET    ; Reset handler
3
reti; rjmp EXT_INT0  ; IRQ0 handler
4
reti; rjmp PIN_CHANGE  ; Pin change handler
5
reti; rjmp TIM1_CMP1A  ; Timer1 compare match 1A
6
reti; rjmp TIM1_CMP1B  ; Timer1 compare match 1B
7
reti; rjmp TIM1_OVF  ; Timer1 overflow handler
8
reti; rjmp TIM0_OVF  ; Timer0 overflow handler
9
reti; rjmp USI_STRT  ; USI Start handler
10
reti; rjmp USI_OVF  ; USI Overflow handler
11
reti; rjmp EE_RDY  ; EEPROM Ready handler
12
reti; rjmp ANA_COMP  ; Analog Comparator handler
13
reti; rjmp ADC    ; ADC Conversion Handler

von avr (Gast)


Lesenswert?

Wenn man Assembler programmiert muss man doch nicht die Nachteile des 
C-Compilers übernehmen, wie z.B. den Overhead bei den Interruptvektoren. 
Es mag vielleicht für einen Anfänger Fehler abfangen - ein guter 
Assemblerprogrammierer aktiviert jedoch keine Interrupts ohne den 
zugehörigen Vektor zu bearbeiten. Falls doch findet sich der Fehler mit 
dem Simulator sehr schnell.

von balli (Gast)


Lesenswert?

Hallo zusammen,

mit Interesse verfolge ich die Diskussion, da ich selbst auch sehr daran 
interessiert bin meinen Stil zu verbessern.

Um die Sache zu systematisieren würde ich mir wünschen, dass mal eine 
Liste mit Nachteilen aufgeführt wird, die Globale Variablen inne haben. 
Ich selbst bin nämlich auch ein globale-variablen-nutzer :-(

von oldmax (Gast)


Lesenswert?

Hi
>Wenn man Assembler programmiert muss man doch nicht die Nachteile des
>C-Compilers übernehmen, wie z.B. den Overhead bei den Interruptvektoren.
>Es mag vielleicht für einen Anfänger Fehler abfangen - ein guter
>Assemblerprogrammierer aktiviert jedoch keine Interrupts ohne den
>zugehörigen Vektor zu bearbeiten. Falls doch findet sich der Fehler mit
>dem Simulator sehr schnell.
Nun, so ganz verstehe ich nicht, was du sagen willst. Es sollte klar 
sein, das ein Anfänger kein guter Assemblerprogrammierer ist. Das mit 
dem Overhead ist mir auch  nicht ganz klar. Ist doch nur C&P, oder 
schreibst du die IVT jedes mal ab. Den Controller belastet es nicht, da 
die nicht genutzten Interrupts ja auch nicht angesprungen werden. Sollte 
der "Anfänger" doch mal einen Interrupt ungewollt aktivieren, so sucht 
er jedenfalls nicht stundenlang in  einem merkwürdig ablaufenden 
Programm.....
Und ist er dann soweit, das er durchschaut was er macht, wird er sowieso 
seinen eigenen Stil umsetzen. Dann interessieren die hier 
niedergeschriebenen Worte nicht mehr.
Wésentlich wichtiger ist die modulare Programmierung. Arbeiten mit 
Funktionsblöcken, die helfen, den Überblick nicht zu verlieren. Dazu 
kann ich auch die Nutzung von Skizzen empfehlen. Wenn nix besseres 
verfügbar, leisteet Paint auch gute Dienste.
Gruß oldmax

von Thomas (kosmos)


Lesenswert?

im oberen Fall sind das wenige Bytes die im Flash belegt werden Overhead 
ist da was ganz anderes.

von Falk B. (falk)


Lesenswert?

@  balli (Gast)

>Um die Sache zu systematisieren würde ich mir wünschen, dass mal eine
>Liste mit Nachteilen aufgeführt wird, die Globale Variablen inne haben.

Man ist immer bestrebt, möglich viele interne Datails, so auch 
Variablen, in den Funktion zu platzieren und damit zu "verstecken", 
damit man nicht von Unmengen an Informationen erschlagen wird. Darum 
nimmt man so wenig wie möglich globale Variablen.
Ein weiteres Problem ist, dass globale Variablen während der gesammten 
Laufzeit Speicher belegen, während lokale Variablen nur während des 
Aufrufs einer Funktion Speicher benötigen. Das kann aber ggf. auch ein 
Vorteil sein, dann damit wei0 man direkt nach dem Compilieren, wieviel 
Speicher man braucht, während man mit dynamisch zugewiesenen Variablen 
schön auf's Maul fallen kann.

Hmmm, ansonsten fällt mir dazu nix ein.

von Karl H. (kbuchegg)


Lesenswert?

balli schrieb:

> Um die Sache zu systematisieren würde ich mir wünschen, dass mal eine
> Liste mit Nachteilen aufgeführt wird, die Globale Variablen inne haben.
> Ich selbst bin nämlich auch ein globale-variablen-nutzer :-(

Globale Variablen sind die, vor denen uns 'unsere Mütter immer gewarnt 
haben'.

Ohne Flax.
Eiegntlich ist es so, dass man in der Programmierung einen großen Bogen 
um globale Variablen macht. Solange es sich um Variablen mit einem 
ordentlichen Namen handelt, deren Verwendung eindeutig ist, mag es noch 
angehen, aber auch dann wird man eher Zugriffsfunktionen benutzen und 
dafür lieber die Variablen Modul-lokal machen. Diese Zugriffsfunktionen 
können nämlich dann auch Dinge wie zb Bereichsprüfungen übernehmen.
Zusätzlich hat man dann auch noch das Problem, dass nicht einfach jeder 
dahergelaufene Code sich an Variablen zuschaffen machen kann, wie er 
lustig ist.
Eine Analogie: Da gibt es eine Werkstatt mit einem Bereich in dem die 
Werkzeuge gelagert werden.
Globale Variablen wären jetzt so, wie wenn jeder einfach in das Lager 
geht und sich nimmt was er braucht.
Das funktioniert auch - bei kleinen Werkstätten.
Bei großen Werkstätten mit vielen Mitarbeitern geht das aber nicht mehr. 
Da gibt es dann einen Mann der an der Theke steht und zu dem du gehst um 
den Spezial - zöllischen - Gewindebohrer zu holen, den du gerade 
brauchst. Der holt ihn aus dem Lager, trägt ihn in sein Buch ein und 
gibt ihn dir. Bringst du ihn zurück, dann trägt er wieder aus, dass du 
den Bohrer hast und legt ihn wieder an seinen Platz zurück. Braucht wer 
anderer diesen Bohrer, dann kann er nachsehen wer ihn gerade hat und 
gezielt bei dir nachfragen.

So ähnlich ist das auch mit globalen Variablen. Bei kleinen Programmen 
ist das noch ok. Aber sobald die Programme größer werden, wird es immer 
schwieriger den Überblick zu behalten, welche Code-Teile welche 
Variablen verändern. Zudem ist die Gefahr recht groß, dass man dann zu 
schlampen anfängt und einfach wild Variablen beschreibt ohne sich um 
Zusammenhänge zu kümmern. Du magst vielleicht eine Variable haben, die 
den Radius eines bestimmten Kreises beschreibt. Das ist gut so und jeder 
der will kann einen neuen Wert für diesen Radius festlegen. Bis du dann 
eines Tages in das Problem läufst, dass dir auffällt, dass du von diesem 
Kreis nicht nur den Radius benutzt sondern auch seine Fläche. Also 
kommst du auf die glorreiche Idee, anstatt diese ständig neu 
auszurechnen, ganz einfach eine weitere Variable dafür zu spendieren. 
Nur musst du jetzt auch sicher gehen, dass wenn immer du den Radius neu 
setzt (die Variable beschreibst), auch die Fläche neu berechnet werden 
muss. Du musst also deinen ganzen Code durchgehen und alle 
Schreiboperationen auf den Radius finden. Irgendwann bist du damit 
fertig und dein Kollege baut ein neues Modul dazu. Er kommt drauf, dass 
wenn in seinem Konstruktionsprogramm ein bestimmtes Rohr benutzt wird, 
dann müsste man auch diesen Kreisradius ändern. Von der zusätzlichen 
Variablen für die Fläche weiß er nichts. Also vergisst er darauf. Und 
damit hat er dir eine schöne Debug-Session eingebrockt, denn du musst 
jetzt rausfinden warum da plötzlich Radius und Fläche nicht mehr 
zusammenstimmen. Natürlich nicht an der Stelle an der du das Problem 
bemerkst, sondern 30 Bildschirmseiten vorher, wo dein Kumpel die 
Erweiterung gemacht hat - von der allerdings du wieder nichts weißt.

Von den 'trivialen' Problemen, die sich durch

int i;

void foo()
{
  for( i = 0; i < 8; ++i )
    bar( i );
}

void bar( int j )
{
  for( i = 0; i < j; ++i )
    batz( i );
}

also einer Doppelverwendung einer Variablen, die sich durch die 
Aufrufhierarchie von Funktionen ergibt, reden wir erst mal nicht.

Kurz und gut:
Eigentlich will man überhaupt keine globalen Variablen haben.
Aber für einen kleinen AVR gilt insofern eine Sonderregel, dass man aus 
praktischen und resourcespezifischen Gründen da auch schon mal eine 
Ausnahme macht, WENN man einen guten Grund dafür hat.
Alles was besser als lokale Variable aufgehoben wäre, wie zb

void foo()
{
  int i;

  for( i = 0; i < 8; ++i )
    bar( i );
}

void bar( int j )
{
  int i;

  for( i = 0; i < j; ++i )
    batz( i );
}

ist übrigens kein guter Grund. Derartige Schleifenvariablen bzw. 
Argumente in Funktionen können NICHT vernünftig durch globale Variablen 
ersetzt werden. Das wäre ein Spiel mit dem Feuer.

Das größte Problem in der ganzen Prorgrammierung ist es den Überblick zu 
bewahren bzw. Querbeeinflussungen von einem Codemodul auf ein anderes 
Codemodul entweder zu minimieren oder ganz auszuschliessen. Globale 
Variablen sind das genaue Gegenteil zu diesen Bestrebungen.

von Fabian O. (xfr)


Lesenswert?

In C kann man im Prinzip zwischen folgenden vier Arten von Variablen 
unterscheiden:
1
int var_global;
2
static int var_modul_global;
3
4
void meine_funktion(void)
5
{
6
  int var_stack;
7
  static int var_funktions_lokal;
8
}

Globale Variablen wie var_global sollte man strikt vermeiden. Sie sind 
im gesamten Programm sichtbar, brauchen also einen eindeutigen Namen, 
und können von überall aus verändert werden. Man kann sie immer durch 
eine modul-globale Variable und eine get- und set-Funktion ersetzen. Der 
einzige Grund für eine globale Variable ist, dass man sich den Overhead 
des Funktionsaufruf und Rücksprungs spart. Das spielt aber nur bei 
extremst zeitkrischen Operationen eine Rolle, die normalerweise dann 
sowieso in ein Modul gebündelt gehören.

Gegen modul-globale Variablen ist dagegen nichts einzuwenden. Sie sind 
nur für Funktionen innerhalb des Moduls (der C-Datei) sichtbar. Sie 
brauchen also keinen programmweit eindeutigen Namen und man kann 
überblicken, wer darauf zugreift. Modul-globale Variablen nimmt man, 
wenn mehrere Funktionen innerhalb des Moduls auf die gleichen Daten 
zugreifen müssen.

Für alle Daten, die nur temporär innerhalb einer Funktion gebraucht 
werden, gibt es die automatischen Variablen, die auf dem Stack angelegt 
werden. Sie sind nur innerhalb der Funktion (genauer: innerhalb des 
Blocks) gültig, in der sie angelegt sind. Sie benötigen nur Speicher, 
während man sich innerhalb der Funktion befindet. Wenn die Funktion 
verlassen wird, kann der Speicher wieder für andere Stackvariablen 
verwendet werden. Das ist also Mittel der Wahl für alles, was nicht über 
den Funktionsaufruf hinaus überdauern muss.

Die letzte Art von Variablen sind funktions-lokal: Sie sind nur 
innerhalb der Funktion sichtbar, allerdings behalten sie ihren Wert 
auch, wenn die Funktion verlassen wird. Beim nächsten Betreten der 
Funktion steht der zuletzt darin abgelegte Wert wieder zur Verfügung. 
Sie belegen allerdings entsprechend dauerhaft den Speicher. Im Prinzip 
sind sie also nichts anderes als modul-globale Variablen, nur dass ihre 
Gültigkeit auf genau eine Funktion und nicht alle Funktionen im Modul 
beschränkt ist. Imo kann sie eher selten gebrauchen.

Zusammengefasst kommt man also in den allermeisten Fällen mit 
modul-globalen Variablen für dauerhaft zu speichernden Daten (ggf. mit 
set- und get-Funktionen) und Stack-Variablen für alle temporären Werte 
wunderbar aus.

von Fabian O. (xfr)


Lesenswert?

Noch zum eigentlichen Thema "Sauber Programmieren mit Interrupts":

Das ganze "Geheimnis" ist, sein Programm in sinnvolle Module zu 
zerlegen, die jeweils eine Aufgabe in sich kapseln. Jedes Modul muss 
eine geeignete Schnittsstelle anbieten, über die mit ihm kommuniziert 
wird. Das Modul selber darf auch mit anderen Modulen kommunizieren. 
Allerdings sollte man möglichst gegenseitige oder zyklische 
Abhängigkeiten vermeiden, sonst erhält man Spaghetti-Code.

Ein guter Ansatz ist, sein Programm hierarchisch oder in Schichten zu 
unterteilen. Auf oberster Ebene steht das Hauptmodul mit der 
main-Funktion. Von dort aus werden die Untermodule initialisiert und 
aufgerufen. Die Untermodule rufen wiederum Unteruntermodule oder andere 
Untermodule (aber wie gesagt möglichst nur in eine Richtung) auf. Auf 
unterster Ebene stehen Module, die bestimmte Teile der Hardware kapseln. 
Und in genau diesen befinden sich die ISRs.

Die ISRs greifen nur auf Daten innerhalb des Moduls zu. Im UART-Modul 
könnte zum Beispiel ein Puffer liegen, den die UART-ISR befüllt. Das 
Modul, das die UART-Daten weiterverarbeitet, weiß von dem Puffer nichts. 
Es fragt lediglich ab und zu per uart_getc() nach, ob ein neues Zeichen 
angekommen ist. Was dahinter passiert, geht außerhalb der 
UART-Implementierung niemanden etwas an. So kommt auch niemand auf die 
Idee, sich die Zeichen selber direkt aus dem Puffer zu holen und die 
Indizes zu verändern. Das vermeidet Fehler und ermöglicht, die 
UART-Implementierung jederzeit auszutauschen. Zum Beispiel gegen eine 
andere Art von Puffer oder vielleicht sogar gegen eine ganz ohne Puffer. 
Ganz nebenbei kann man sein Programm so auch gut auf andere Hardware 
portieren, da man nur die untersten, hardwareabhängigen Module 
austauschen muss.

von balli (Gast)


Lesenswert?

@ Karl Heinz & Fabian,

erstmal herzlichen Dank für die ausführlichen Ratschläge. Ich habe 
diesbezüglich eine Frage:

Nehmen wir an ich binde eine c-Datei "uart.c" in mein Projekt ein und in 
dieser c-Datei stehen nur Funktionen die ich benötige um den UART 
anzusprechen  (also nicht die main-Funktion). Ferner steht in dieser 
c-Datei ganz oben (außerhalb der Funktionen) eine Variable "buffer" in 
die ein empfangener String hineinkommt. Diese Variable ist ja innerhalb 
der c-datei "uart.c" global angelegt, kann aber in einer anderen c-Datei 
"main.c" in der dann mein main-programm steht gar nicht angesprochen 
werden (weil ich sie nicht als extern deklariert habe).

Ist das dann auch noch sauber, wenn ich den String dann mit einer 
getstring-funktion die einen Zeiger übergibt in der main-funktion 
abhole? Oder gilt die Variable buffer schon als unsauber, da sie 
innerhalb der uart.c ja global definiert ist?

lg
balli

von F. F. (foldi)


Lesenswert?

oldmax schrieb:
> Wenn nix besseres
> verfügbar, leistet Paint auch gute Dienste.
> Gruß oldmax

PapDesigner ist da sehr nützlich. Gerade wenn es umfangreich wird, wird 
"die alte Schule" wohl unerlässlich.

Früher hab ich mal Datenbanken unter Access gemacht, da hatte ich nichts 
in "meiner eigenen" Datenbank dokumentiert (weil ich ja so ein tolles 
Gedächtnis habe*lol*), nach drei Jahren habe ich etliche Stunden 
gebraucht meinen eigenen Kram zu verstehen.
Dieser PapDesigner ist kostenlos und gute Dokumentation gibt es auch. 
Ist aber nicht nötig, geht quasi alles von selbst.

von Jan S. (spongebob)


Lesenswert?

Also erst einmal danke für die vielen Kommentare!!!
Hab mir gerade alles mal in ruhe durchgelesen. Mit den Assemblersachen 
kann ich als "Anfänger" wirklich noch nicht viel anfangen, die danach 
folgenden Kommentare haben mich jedoch echt weitergebracht, denke ich...
Ausprobiert habe ich es mit den ISRs in extra Modulen noch nicht. 
Funktionen in Module auslagern versuche ich sowieso immer.
Ich werde in Zukunft mal versuchen die Modul-spezifische ISR auch in das 
Passende Modul zu legen.
Dort dann Modul-globale variablen für die Arbeit damit verwenden.
Denke damit wird auf jeden Fall etwas mehr Struktur in mein Gedöns 
kommen.
Aber wie ich sehe is das Struktorierte Programmieren besonders mit 
Interrupts eine interessante Sache an der ich in jedem Fall dranbleiben 
will.

Grüße Jan.

von Bernd (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Globale Variablen wären jetzt so, wie wenn jeder einfach in das Lager
> geht und sich nimmt was er braucht.
> Das funktioniert auch - bei kleinen Werkstätten.

schöner Vergleich,
und ein AVR ist eine eine kleine Werkstätte

Jürgen S. schrieb:
> globale Variablen gibt es nicht.

kannst Du mir erklären wie Du Informationen mit dem Hauptprogramm bzw. 
anderen Modulen austauscht?

von Jan S. (spongebob)


Lesenswert?

Ein Informationsaustausch kann denk ich wie folgt geschehen:
Ins Hauptprogramm:
Eine Funktion mit rückgabewert (return ...) welche im modul definiert 
wird.
Oder mit übergabe eines Pointers.
In die Module:
Übergabewerte von Funktionen, welche auch im Modul definiert werden -> 
void funktion(uebergabewert1, uebergabewert2)

Grüße Jan.

von W.S. (Gast)


Lesenswert?

balli schrieb:
> Nehmen wir an ich binde eine c-Datei "uart.c" in mein Projekt ein und in
> dieser c-Datei stehen nur Funktionen die ich benötige um den UART
> anzusprechen..

Nun, wenn wir hier über C reden, dann reden wir auch über 
Header-Dateien. Dort sollte man sogenannte Prototypen reinschreiben, 
damit auch andere Programmteile in anderen Quellen auf diese Funktionen 
richtig zugreifen können.

z.B. in uart.h

extern bool IsCharAvailable (int uartnummer);

Wie man das im Falle eines UART-Anschlusses macht, kannst du hier im 
Forum in der "LernBetty" (Codesammlung) dir anschauen. Dort kannst du 
auch sehen, wie man einen Ringpuffer organisiert, um z.B. die 
Zusammenarbeit zwischen einem Interrupt-Programm und dem Rest der 
Firmware zu organisieren.

W.S.

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.